diff --git a/include/digio_prj.h b/include/digio_prj.h
index ae5c2aa..7455b2c 100644
--- a/include/digio_prj.h
+++ b/include/digio_prj.h
@@ -32,7 +32,7 @@
DIG_IO_ENTRY(cruise_in, GPIOB, GPIO5, PinMode::INPUT_FLT) \
DIG_IO_ENTRY(mprot_in, GPIOB, GPIO1, PinMode::INPUT_FLT) \
DIG_IO_ENTRY(emcystop_in, GPIOB, GPIO1, PinMode::INPUT_FLT) \
- DIG_IO_ENTRY(bk_in, GPIOB, GPIO12, PinMode::INPUT_FLT) \
+ DIG_IO_ENTRY(bk_in, GPIOB, GPIO12, PinMode::INPUT_PU) \
DIG_IO_ENTRY(bms_in, GPIOD, GPIO15, PinMode::INPUT_FLT) /* non-existant */ \
DIG_IO_ENTRY(ocur_in, GPIOD, GPIO15, PinMode::INPUT_FLT) /* non-existant */ \
DIG_IO_ENTRY(desat_in, GPIOD, GPIO15, PinMode::INPUT_FLT) /* non-existant */ \
diff --git a/include/param_prj.h b/include/param_prj.h
index aa14c8f..92f93fe 100644
--- a/include/param_prj.h
+++ b/include/param_prj.h
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-#define VER 4.64.R
+#define VER 4.65.R
/* Entries must be ordered as follows:
1. Saveable parameters (id != 0)
@@ -47,7 +47,7 @@
PARAM_ENTRY(CAT_MOTOR, dirmode, DIRMODES, 0, 3, 1, 95 ) \
PARAM_ENTRY(CAT_MOTOR, syncofs, "dig", 0, 65535, 0, 70 ) \
PARAM_ENTRY(CAT_MOTOR, snsm, SNS_M, 12, 14, 12, 46 ) \
- PARAM_ENTRY(CAT_INVERTER,pwmfrq, PWMFRQS, 0, 4, 1, 13 ) \
+ PARAM_ENTRY(CAT_INVERTER,pwmfrq, PWMFRQS, 0, 2, 1, 13 ) \
PARAM_ENTRY(CAT_INVERTER,pwmpol, PWMPOLS, 0, 1, 0, 52 ) \
PARAM_ENTRY(CAT_INVERTER,deadtime, "dig", 0, 255, 63, 14 ) \
PARAM_ENTRY(CAT_INVERTER,ocurlim, "A", -65536, 65536, 100, 22 ) \
@@ -168,7 +168,7 @@
PARAM_ENTRY(CAT_MOTOR, syncofs, "dig", 0, 65535, 0, 70 ) \
PARAM_ENTRY(CAT_MOTOR, syncadv, "dig/hz",-100, 100, 0, 101 ) \
PARAM_ENTRY(CAT_MOTOR, snsm, SNS_M, 12, 14, 12, 46 ) \
- PARAM_ENTRY(CAT_INVERTER,pwmfrq, PWMFRQS, 0, 4, 1, 13 ) \
+ PARAM_ENTRY(CAT_INVERTER,pwmfrq, PWMFRQS, 0, 2, 1, 13 ) \
PARAM_ENTRY(CAT_INVERTER,pwmpol, PWMPOLS, 0, 1, 0, 52 ) \
PARAM_ENTRY(CAT_INVERTER,deadtime, "dig", 0, 255, 63, 14 ) \
PARAM_ENTRY(CAT_INVERTER,ocurlim, "A", -65536, 65536, 100, 22 ) \
@@ -273,7 +273,7 @@
/***** Enum String definitions *****/
#define OPMODES "0=Off, 1=Run, 2=ManualRun, 3=Boost, 4=Buck, 5=Sine, 6=AcHeat"
-#define PWMFRQS "0=17.6kHz, 1=8.8kHz, 2=4.4KHz, 3=2.2kHz, 4=1.1kHz"
+#define PWMFRQS "0=17.6kHz, 1=8.8kHz, 2=4.4KHz"
#define PWMPOLS "0=ACTHIGH, 1=ACTLOW"
#define DIRS "-1=Reverse, 0=Neutral, 1=Forward"
#define TRIPMODES "0=AllOff, 1=DcSwOn, 2=PrechargeOn"
diff --git a/libopeninv b/libopeninv
index 103cbec..4c2590d 160000
--- a/libopeninv
+++ b/libopeninv
@@ -1 +1 @@
-Subproject commit 103cbec2b6026666134a9d2926ec1b136ba1d64f
+Subproject commit 4c2590d99f1e77a2df7dfaf652c0828c3d6adcc1
diff --git a/sinus.cbp b/sinus.cbp
index 4ab1282..eb01906 100644
--- a/sinus.cbp
+++ b/sinus.cbp
@@ -140,11 +140,11 @@
-
-
-
-
+
+
+
+
diff --git a/src/pwmgeneration-foc.cpp b/src/pwmgeneration-foc.cpp
index 90c0419..eb9193c 100644
--- a/src/pwmgeneration-foc.cpp
+++ b/src/pwmgeneration-foc.cpp
@@ -39,6 +39,7 @@ static bool regen = false;
static s32fp idref = 0;
static PiController qController;
static PiController dController;
+static PiController dControllerRegen;
static PiController fwController;
void PwmGeneration::Run()
@@ -48,7 +49,7 @@ void PwmGeneration::Run()
int dir = Param::GetInt(Param::dir);
uint16_t dc[3];
s32fp id, iq;
- static int32_t offsetRamped = 0, fwIdRef = 0;
+ static int32_t fwIdRef = 0, udRamped = 0;
Encoder::UpdateRotorAngle(dir);
@@ -61,40 +62,42 @@ void PwmGeneration::Run()
ProcessCurrents(id, iq);
- int32_t dofs = regen ? 0 : FP_TOINT(-Param::GetInt(Param::frqfac) * frq);
+ int32_t dofs = FP_TOINT(-Param::GetInt(Param::frqfac) * frq);
int32_t qofs = FP_TOINT(Param::GetInt(Param::frqfac) * frq);
- if (dofs < offsetRamped)
+ dController.SetOffset(dofs);
+ qController.SetOffset(qofs);
+
+ dController.SetRef(idref + fwIdRef);
+ dControllerRegen.SetRef(idref + fwIdRef);
+ int32_t ud = regen ? dControllerRegen.Run(id) : dController.Run(id);
+
+ if (ud < udRamped)
{
- offsetRamped = RAMPDOWN(offsetRamped, dofs, Param::GetInt(Param::dofsramp));
+ udRamped = RAMPDOWN(udRamped, ud, Param::GetInt(Param::dofsramp));
}
else
{
- offsetRamped = RAMPUP(offsetRamped, dofs, Param::GetInt(Param::dofsramp));
+ udRamped = RAMPUP(udRamped, ud, Param::GetInt(Param::dofsramp));
}
- dController.SetOffset(offsetRamped);
- qController.SetOffset(qofs);
-
- dController.SetRef(idref + fwIdRef);
- int32_t ud = dController.Run(id);
- int32_t qlimit = FOC::GetQLimit(ud);
+ int32_t qlimit = FOC::GetQLimit(udRamped);
qController.SetMinMaxY(-qlimit, qlimit);
int32_t uq = qController.Run(iq);
- FOC::InvParkClarke(ud, uq, angle);
+ FOC::InvParkClarke(udRamped, uq, angle);
//Calculate extra field weakening current for the next cycle
- fwIdRef = fwController.Run(FOC::GetTotalVoltage(ud, uq) >> 5);
+ fwIdRef = fwController.Run(FOC::GetTotalVoltage(udRamped, uq) >> 5);
s32fp idc = (iq * uq) / FOC::GetMaximumModulationIndex();
Param::SetFlt(Param::fstat, frq);
Param::SetFlt(Param::angle, DIGIT_TO_DEGREE(angle));
- Param::SetInt(Param::ud, ud);
+ Param::SetInt(Param::ud, udRamped);
Param::SetInt(Param::uq, uq);
Param::SetInt(Param::qofs, qofs);
Param::SetInt(Param::dofs, dofs);
Param::SetFlt(Param::idc, idc);
- Param::SetFlt(Param::dspnt, dController.GetRef());
+ Param::SetFlt(Param::dspnt, fwIdRef);
Param::SetFlt(Param::qspnt, qController.GetRef());
/* Shut down PWM on stopped motor, neutral gear or init phase */
@@ -102,6 +105,7 @@ void PwmGeneration::Run()
{
timer_disable_break_main_output(PWM_TIMER);
dController.ResetIntegrator();
+ dControllerRegen.ResetIntegrator();
qController.ResetIntegrator();
fwController.ResetIntegrator();
}
@@ -178,6 +182,7 @@ void PwmGeneration::SetControllerGains(int kp, int ki, int fwkp)
{
qController.SetGains(kp, ki);
dController.SetGains(kp, ki);
+ dControllerRegen.SetGains(kp, ki);
fwController.SetGains(fwkp, 0);
}
@@ -194,6 +199,9 @@ void PwmGeneration::PwmInit()
dController.ResetIntegrator();
dController.SetCallingFrequency(pwmfrq);
dController.SetMinMaxY(-maxVd, maxVd);
+ dControllerRegen.ResetIntegrator();
+ dControllerRegen.SetCallingFrequency(pwmfrq);
+ dControllerRegen.SetMinMaxY(-maxVd, maxVd);
fwController.ResetIntegrator();
fwController.SetCallingFrequency(pwmfrq);
fwController.SetMinMaxY(-FP_FROMINT(500), 0);
diff --git a/src/pwmgeneration.cpp b/src/pwmgeneration.cpp
index f9756ae..a0c71fa 100644
--- a/src/pwmgeneration.cpp
+++ b/src/pwmgeneration.cpp
@@ -33,6 +33,7 @@
#define SHIFT_90DEG (uint16_t)16384
#define FRQ_TO_ANGLE(frq) FP_TOINT((frq << SineCore::BITS) / pwmfrq)
#define DIGIT_TO_DEGREE(a) FP_FROMINT(angle) / (65536 / 360)
+#define FRQ_DIVIDER 8192 //PWM ISR callback frequency divider
uint16_t PwmGeneration::pwmfrq;
uint16_t PwmGeneration::angle;
@@ -89,7 +90,7 @@ void PwmGeneration::SetCurrentOffset(int offset1, int offset2)
int PwmGeneration::GetCpuLoad()
{
//PWM period 2x counter because of center aligned mode
- return (1000 * execTicks) / (2 << pwmdigits);
+ return (1000 * execTicks) / FRQ_DIVIDER;
}
void PwmGeneration::SetOpmode(int _opmode)
@@ -153,7 +154,7 @@ extern "C" void tim1_brk_isr(void)
}
extern "C" void pwm_timer_isr(void)
-{
+{
int start = timer_get_counter(PWM_TIMER);
/* Clear interrupt pending flag */
timer_clear_flag(PWM_TIMER, TIM_SR_UIF);
@@ -301,19 +302,33 @@ s32fp PwmGeneration::GetCurrent(AnaIn::AnaIns input, s32fp offset, s32fp gain)
*
* @param[in] deadtime Deadtime between bottom and top (coded value, consult STM32 manual)
* @param[in] pwmpol Output Polarity. 0=Active High, 1=Active Low
-* @return PWM frequency
+* @return PWM ISR callback frequency
*/
uint16_t PwmGeneration::TimerSetup(uint16_t deadtime, int pwmpol)
-{
+{
+ ///There are two update events per PWM period
+ ///One when counter reaches top, one when it reaches bottom
+ ///We set the repetition counter in a way, that the ISR
+ ///Callback frequency is constant i.e. independent from PWM frequency
+ ///- for 17.6 kHz: call ISR every four update events (that is every other period)
+ ///- for 8.8kHz: call ISR every other update event (that is once per PWM period)
+ ///- for 4.4kHz: call ISR on every update event (that is twice per period)
+ const uint8_t repCounters[] = { 3, 1, 0 };
const uint16_t pwmmax = 1U << pwmdigits;
- uint8_t outputMode = pwmpol ? GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN : GPIO_CNF_OUTPUT_ALTFN_PUSHPULL;
+ const uint8_t outputMode = pwmpol ? GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN : GPIO_CNF_OUTPUT_ALTFN_PUSHPULL;
+
+ //Disable output in active low mode before resetting timer, otherwise shoot through will occur!
+ if (pwmpol)
+ {
+ gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO8 | GPIO9 | GPIO10);
+ gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO13 | GPIO14 | GPIO15);
+ }
+
+ rcc_periph_reset_pulse(PWM_TIMRST);
- rcc_periph_reset_pulse(PWM_TIMRST);
- /* disable timer */
- timer_disable_counter(PWM_TIMER);
/* Center aligned PWM */
timer_set_alignment(PWM_TIMER, TIM_CR1_CMS_CENTER_1);
- timer_enable_preload(PWM_TIMER);
+ timer_enable_preload(PWM_TIMER);
for (int channel = TIM_OC1; channel <= TIM_OC3N; channel++)
{
@@ -322,7 +337,7 @@ uint16_t PwmGeneration::TimerSetup(uint16_t deadtime, int pwmpol)
timer_set_oc_idle_state_unset(PWM_TIMER, (tim_oc_id)channel);
timer_set_oc_value(PWM_TIMER, (tim_oc_id)channel, 0);
- if (pwmpol)
+ if (pwmpol) //Active low
timer_set_oc_polarity_low(PWM_TIMER, (tim_oc_id)channel);
else
timer_set_oc_polarity_high(PWM_TIMER, (tim_oc_id)channel);
@@ -339,14 +354,13 @@ uint16_t PwmGeneration::TimerSetup(uint16_t deadtime, int pwmpol)
timer_set_enabled_off_state_in_run_mode(PWM_TIMER);
timer_set_enabled_off_state_in_idle_mode(PWM_TIMER);
timer_set_deadtime(PWM_TIMER, deadtime);
- timer_clear_flag(PWM_TIMER, TIM_SR_BIF);
- timer_enable_irq(PWM_TIMER, TIM_DIER_UIE);
- timer_enable_irq(PWM_TIMER, TIM_DIER_BIE);
+ timer_clear_flag(PWM_TIMER, TIM_SR_UIF | TIM_SR_BIF);
+ timer_enable_irq(PWM_TIMER, TIM_DIER_UIE | TIM_DIER_BIE);
timer_set_prescaler(PWM_TIMER, 0);
/* PWM frequency */
- timer_set_period(PWM_TIMER, pwmmax);
- timer_set_repetition_counter(PWM_TIMER, 1);
+ timer_set_period(PWM_TIMER, pwmmax);
+ timer_set_repetition_counter(PWM_TIMER, repCounters[pwmdigits - MIN_PWM_DIGITS]);
timer_generate_event(PWM_TIMER, TIM_EGR_UG);
@@ -354,8 +368,8 @@ uint16_t PwmGeneration::TimerSetup(uint16_t deadtime, int pwmpol)
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, outputMode, GPIO8 | GPIO9 | GPIO10);
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, outputMode, GPIO13 | GPIO14 | GPIO15);
-
- return rcc_apb2_frequency / (uint32_t)(2 * pwmmax);
+ //Callback frequency is constant because we use the repetition counter
+ return rcc_apb2_frequency / FRQ_DIVIDER;
}
void PwmGeneration::AcHeatTimerSetup()