From 6dd6eecf6955341bf31644bb6cacbc4cb3729fae Mon Sep 17 00:00:00 2001 From: jsphuebner Date: Sun, 10 Nov 2019 21:08:25 +0100 Subject: [PATCH] !! Fixed shoot-through when starting second time in active low mode !! Fixed Blue Pill break input - again Changed PWM frequency handling - always same controller frequency and 3 possible PWM frequencies - 4.4, 8.8, 17.6kHz Two different d-current controllers, one for regen, one for acceleration --- include/digio_prj.h | 2 +- include/param_prj.h | 8 +++---- libopeninv | 2 +- sinus.cbp | 8 +++---- src/pwmgeneration-foc.cpp | 38 +++++++++++++++++++------------ src/pwmgeneration.cpp | 48 +++++++++++++++++++++++++-------------- 6 files changed, 64 insertions(+), 42 deletions(-) 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()