From a68e35a9c5f6458e564e49709555108c50ee2262 Mon Sep 17 00:00:00 2001 From: lolwheel Date: Sat, 28 Sep 2024 17:44:52 -0700 Subject: [PATCH 1/4] WIP: Incremental change, Floatwheel rides fine and every target compiles. --- motor/mcpwm_foc.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/motor/mcpwm_foc.c b/motor/mcpwm_foc.c index 4a2c2d403..3a4870b8f 100644 --- a/motor/mcpwm_foc.c +++ b/motor/mcpwm_foc.c @@ -79,31 +79,35 @@ static volatile bool pid_thd_stop; // Macros #ifdef HW_HAS_3_SHUNTS -#define TIMER_UPDATE_DUTY_M1(duty1, duty2, duty3) \ +#define TIMER_UPDATE_DUTY_M1(top, duty1, duty2, duty3) \ TIM1->CR1 |= TIM_CR1_UDIS; \ TIM1->CCR1 = duty1; \ TIM1->CCR2 = duty2; \ TIM1->CCR3 = duty3; \ + TIM1->ARR = top; \ TIM1->CR1 &= ~TIM_CR1_UDIS; -#define TIMER_UPDATE_DUTY_M2(duty1, duty2, duty3) \ +#define TIMER_UPDATE_DUTY_M2(top, duty1, duty2, duty3) \ TIM8->CR1 |= TIM_CR1_UDIS; \ TIM8->CCR1 = duty1; \ TIM8->CCR2 = duty2; \ TIM8->CCR3 = duty3; \ + TIM8->ARR = top; \ TIM8->CR1 &= ~TIM_CR1_UDIS; #else -#define TIMER_UPDATE_DUTY_M1(duty1, duty2, duty3) \ +#define TIMER_UPDATE_DUTY_M1(top, duty1, duty2, duty3) \ TIM1->CR1 |= TIM_CR1_UDIS; \ TIM1->CCR1 = duty1; \ TIM1->CCR2 = duty3; \ TIM1->CCR3 = duty2; \ + TIM1->ARR = top; \ TIM1->CR1 &= ~TIM_CR1_UDIS; -#define TIMER_UPDATE_DUTY_M2(duty1, duty2, duty3) \ +#define TIMER_UPDATE_DUTY_M2(top, duty1, duty2, duty3) \ TIM8->CR1 |= TIM_CR1_UDIS; \ TIM8->CCR1 = duty1; \ TIM8->CCR2 = duty3; \ TIM8->CCR3 = duty2; \ + TIM8->ARR = top; \ TIM8->CR1 &= ~TIM_CR1_UDIS; #endif @@ -2474,7 +2478,8 @@ int mcpwm_foc_dc_cal(bool cal_undriven) { float current_sum[3] = {0.0, 0.0, 0.0}; float voltage_sum[3] = {0.0, 0.0, 0.0}; - TIMER_UPDATE_DUTY_M1(TIM1->ARR / 2, TIM1->ARR / 2, TIM1->ARR / 2); + const uint32_t top = SYSTEM_CORE_CLOCK / (int)m_motor_1.m_conf->foc_f_zv; + TIMER_UPDATE_DUTY_M1(top, top / 2, top / 2, top / 2); // Start PWM on phase 1 stop_pwm_hw((motor_all_state_t*)&m_motor_1); @@ -2487,7 +2492,7 @@ int mcpwm_foc_dc_cal(bool cal_undriven) { #ifdef HW_HAS_DUAL_MOTORS float current_sum_m2[3] = {0.0, 0.0, 0.0}; float voltage_sum_m2[3] = {0.0, 0.0, 0.0}; - TIMER_UPDATE_DUTY_M2(TIM8->ARR / 2, TIM8->ARR / 2, TIM8->ARR / 2); + TIMER_UPDATE_DUTY_M2(top / 2, top / 2, top / 2); stop_pwm_hw((motor_all_state_t*)&m_motor_2); PHASE_FILTER_ON_M2(); @@ -2683,7 +2688,8 @@ int mcpwm_foc_dc_cal(bool cal_undriven) { float current_sum[3] = {0.0, 0.0, 0.0}; float voltage_sum[3] = {0.0, 0.0, 0.0}; - TIMER_UPDATE_DUTY_M1(TIM1->ARR / 2, TIM1->ARR / 2, TIM1->ARR / 2); + const uint32_t top = SYSTEM_CORE_CLOCK / (int)m_motor_1.m_conf->foc_f_zv; + TIMER_UPDATE_DUTY_M1(top, top / 2, top / 2, top / 2); stop_pwm_hw((motor_all_state_t*)&m_motor_1); PHASE_FILTER_ON(); @@ -2850,6 +2856,7 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { mc_configuration *conf_now = motor_now->m_conf; mc_configuration *conf_other = motor_other->m_conf; + const uint32_t top = SYSTEM_CORE_CLOCK / (int)conf_other->foc_f_zv; bool skip_interpolation = motor_other->m_cc_was_hfi; @@ -2874,9 +2881,9 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { float curr0 = (GET_CURRENT1() - conf_other->foc_offsets_current[0]) * FAC_CURRENT1; float curr1 = (GET_CURRENT2() - conf_other->foc_offsets_current[1]) * FAC_CURRENT2; - TIMER_UPDATE_DUTY_M1(motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); + TIMER_UPDATE_DUTY_M1(top, motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); #ifdef HW_HAS_DUAL_PARALLEL - TIMER_UPDATE_DUTY_M2(motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); + TIMER_UPDATE_DUTY_M2(top, motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); #endif #endif @@ -2922,8 +2929,7 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { state_m->mod_alpha_raw = c * state_m->mod_d - s * state_m->mod_q; state_m->mod_beta_raw = c * state_m->mod_q + s * state_m->mod_d; - uint32_t duty1, duty2, duty3, top; - top = TIM1->ARR; + uint32_t duty1, duty2, duty3; foc_svm(state_m->mod_alpha_raw, state_m->mod_beta_raw, top, &duty1, &duty2, &duty3, (uint32_t*)&state_m->svm_sector); @@ -2939,7 +2945,7 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { #endif } #else - TIMER_UPDATE_DUTY_M1(duty1, duty2, duty3); + TIMER_UPDATE_DUTY_M1(top, duty1, duty2, duty3); #endif } @@ -4652,11 +4658,11 @@ static void control_current(motor_all_state_t *motor, float dt) { state_m->mod_beta_raw = mod_beta_v0; } #endif - + const uint32_t top = SYSTEM_CORE_CLOCK / (int)motor->m_conf->foc_f_zv; // Delay adding the HFI voltage when not sampling in both 0 vectors, as it will cancel // itself with the opposite pulse from the previous HFI sample. This makes more sense // when drawing the SVM waveform. - foc_svm(mod_alpha_v7, mod_beta_v7, TIM1->ARR, + foc_svm(mod_alpha_v7, mod_beta_v7, top, (uint32_t*)&motor->m_duty1_next, (uint32_t*)&motor->m_duty2_next, (uint32_t*)&motor->m_duty3_next, @@ -4681,21 +4687,21 @@ static void control_current(motor_all_state_t *motor, float dt) { } // Set output (HW Dependent) - uint32_t duty1, duty2, duty3, top; - top = TIM1->ARR; + uint32_t duty1, duty2, duty3; + const uint32_t top = SYSTEM_CORE_CLOCK / (int)conf_now->foc_f_zv; // Calculate the duty cycles for all the phases. This also injects a zero modulation signal to // be able to fully utilize the bus voltage. See https://microchipdeveloper.com/mct5001:start foc_svm(state_m->mod_alpha_raw, state_m->mod_beta_raw, top, &duty1, &duty2, &duty3, (uint32_t*)&state_m->svm_sector); if (motor == &m_motor_1) { - TIMER_UPDATE_DUTY_M1(duty1, duty2, duty3); + TIMER_UPDATE_DUTY_M1(top, duty1, duty2, duty3); #ifdef HW_HAS_DUAL_PARALLEL - TIMER_UPDATE_DUTY_M2(duty1, duty2, duty3); + TIMER_UPDATE_DUTY_M2(top, duty1, duty2, duty3); #endif } else { #ifndef HW_HAS_DUAL_PARALLEL - TIMER_UPDATE_DUTY_M2(duty1, duty2, duty3); + TIMER_UPDATE_DUTY_M2(top, duty1, duty2, duty3); #endif } From 9748f7ec75d78a06ea2e1a85c74f8b878ce68fb5 Mon Sep 17 00:00:00 2001 From: lolwheel Date: Sat, 28 Sep 2024 18:11:23 -0700 Subject: [PATCH 2/4] WIP, TESTED: Removed earsy-to-remove reads from ARR. Also removed timer reinit logic that was triggered if ARR differed from the calfulated zvf. Verified that floatwheel still rides fine. --- motor/mcpwm_foc.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/motor/mcpwm_foc.c b/motor/mcpwm_foc.c index 3a4870b8f..fc1870352 100644 --- a/motor/mcpwm_foc.c +++ b/motor/mcpwm_foc.c @@ -173,7 +173,7 @@ static void update_hfi_samples(foc_hfi_samples samples, volatile motor_all_state #pragma GCC push_options #pragma GCC optimize ("Os") -static void timer_reinit(int f_zv) { +static void timer_reinit(const int f_zv) { utils_sys_lock_cnt(); TIM_DeInit(TIM1); @@ -191,9 +191,10 @@ static void timer_reinit(int f_zv) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE); + const uint32_t period = (SYSTEM_CORE_CLOCK / f_zv); TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; - TIM_TimeBaseStructure.TIM_Period = (SYSTEM_CORE_CLOCK / f_zv); + TIM_TimeBaseStructure.TIM_Period = period; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; @@ -203,7 +204,7 @@ static void timer_reinit(int f_zv) { TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; - TIM_OCInitStructure.TIM_Pulse = TIM1->ARR / 2; + TIM_OCInitStructure.TIM_Pulse = period / 2; #ifndef INVERTED_TOP_DRIVER_INPUT TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // gpio high = top fets on @@ -312,7 +313,7 @@ static void timer_reinit(int f_zv) { #endif #ifdef HW_HAS_DUAL_MOTORS - TIM8->CNT = TIM1->ARR; + TIM8->CNT = period; #else TIM8->CNT = 0; #endif @@ -641,30 +642,6 @@ void mcpwm_foc_set_configuration(mc_configuration *configuration) { foc_precalc_values((motor_all_state_t*)get_motor_now()); // Below we check if anything in the configuration changed that requires stopping the motor. - - uint32_t top = SYSTEM_CORE_CLOCK / (int)configuration->foc_f_zv; - if (TIM1->ARR != top) { -#ifdef HW_HAS_DUAL_MOTORS - m_motor_1.m_control_mode = CONTROL_MODE_NONE; - m_motor_1.m_state = MC_STATE_OFF; - stop_pwm_hw((motor_all_state_t*)&m_motor_1); - - m_motor_2.m_control_mode = CONTROL_MODE_NONE; - m_motor_2.m_state = MC_STATE_OFF; - stop_pwm_hw((motor_all_state_t*)&m_motor_2); - - timer_reinit((int)configuration->foc_f_zv); -#else - get_motor_now()->m_control_mode = CONTROL_MODE_NONE; - get_motor_now()->m_state = MC_STATE_OFF; - stop_pwm_hw((motor_all_state_t*)get_motor_now()); - TIMER_UPDATE_SAMP_TOP_M1(MCPWM_FOC_CURRENT_SAMP_OFFSET, top); -#ifdef HW_HAS_DUAL_PARALLEL - TIMER_UPDATE_SAMP_TOP_M2(MCPWM_FOC_CURRENT_SAMP_OFFSET, top); -#endif -#endif - } - if (((1 << get_motor_now()->m_conf->foc_hfi_samples) * 8) != get_motor_now()->m_hfi.samples) { get_motor_now()->m_control_mode = CONTROL_MODE_NONE; get_motor_now()->m_state = MC_STATE_OFF; From 4201e111c6e4e464b9fc468057d3cb4000f774a5 Mon Sep 17 00:00:00 2001 From: lolwheel Date: Sun, 29 Sep 2024 13:04:02 -0700 Subject: [PATCH 3/4] WIP, UNTESTED: Stash, started parametrizing the bandwidth. --- datatypes.h | 1 + motor/mcpwm_foc.c | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/datatypes.h b/datatypes.h index dc4d97000..60da1e9d9 100644 --- a/datatypes.h +++ b/datatypes.h @@ -425,6 +425,7 @@ typedef struct { float foc_current_kp; float foc_current_ki; float foc_f_zv; + float foc_f_zv_bandwidth; float foc_dt_us; float foc_encoder_offset; bool foc_encoder_inverted; diff --git a/motor/mcpwm_foc.c b/motor/mcpwm_foc.c index fc1870352..4dd3b6532 100644 --- a/motor/mcpwm_foc.c +++ b/motor/mcpwm_foc.c @@ -204,7 +204,7 @@ static void timer_reinit(const int f_zv) { TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; - TIM_OCInitStructure.TIM_Pulse = period / 2; + TIM_OCInitStructure.TIM_Pulse = 0; #ifndef INVERTED_TOP_DRIVER_INPUT TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // gpio high = top fets on @@ -339,6 +339,20 @@ static void timer_reinit(const int f_zv) { nvicEnableVector(TIM2_IRQn, 6); } +/** + * Calculates rendomized timer period reload value based on passed + * center frequency and bandwidth. + * Assumes that the timer is clocked at system core clock frequency. + * @param zvf Center frequency in Hz. + * @param bandwidth Bandwidth, ratio. Must satisfy 0 <= bandwidth <=1. + */ +static uint32_t get_randomized_timer_period(const uint32_t zvf, const float bandwidth) { + const uint32_t period_center = SYSTEM_CORE_CLOCK / zvf; + const uint32_t period_bandwidth = period_center * bandwidth; + const uint32_t period_bottom = period_center - period_bandwidth / 2; + return period_bottom + rand() % period_bandwidth; +} + static void init_audio_state(volatile mc_audio_state *s) { memset((void*)s, 0, sizeof(mc_audio_state)); @@ -2455,7 +2469,7 @@ int mcpwm_foc_dc_cal(bool cal_undriven) { float current_sum[3] = {0.0, 0.0, 0.0}; float voltage_sum[3] = {0.0, 0.0, 0.0}; - const uint32_t top = SYSTEM_CORE_CLOCK / (int)m_motor_1.m_conf->foc_f_zv; + const uint32_t top = get_randomized_timer_period((uint32_t)m_motor_1.m_conf->foc_f_zv, m_motor_1.m_conf->foc_f_zv_bandwidth); TIMER_UPDATE_DUTY_M1(top, top / 2, top / 2, top / 2); // Start PWM on phase 1 @@ -2665,7 +2679,7 @@ int mcpwm_foc_dc_cal(bool cal_undriven) { float current_sum[3] = {0.0, 0.0, 0.0}; float voltage_sum[3] = {0.0, 0.0, 0.0}; - const uint32_t top = SYSTEM_CORE_CLOCK / (int)m_motor_1.m_conf->foc_f_zv; + const uint32_t top = get_randomized_timer_period((uint32_t)m_motor_1.m_conf->foc_f_zv, m_motor_1.m_conf->foc_f_zv_bandwidth); TIMER_UPDATE_DUTY_M1(top, top / 2, top / 2, top / 2); stop_pwm_hw((motor_all_state_t*)&m_motor_1); @@ -2833,7 +2847,7 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { mc_configuration *conf_now = motor_now->m_conf; mc_configuration *conf_other = motor_other->m_conf; - const uint32_t top = SYSTEM_CORE_CLOCK / (int)conf_other->foc_f_zv; + const uint32_t top = get_randomized_timer_period((uint32_t)conf_other->foc_f_zv, conf_other->foc_f_zv_bandwidth); bool skip_interpolation = motor_other->m_cc_was_hfi; @@ -2848,11 +2862,11 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { if (is_second_motor) { curr0 = (GET_CURRENT1() - conf_other->foc_offsets_current[0]) * FAC_CURRENT1; curr1 = (GET_CURRENT2() - conf_other->foc_offsets_current[1]) * FAC_CURRENT2; - TIMER_UPDATE_DUTY_M1(motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); + TIMER_UPDATE_DUTY_M1(top, motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); } else { curr0 = (GET_CURRENT1_M2() - conf_other->foc_offsets_current[0]) * FAC_CURRENT1_M2; curr1 = (GET_CURRENT2_M2() - conf_other->foc_offsets_current[1]) * FAC_CURRENT2_M2; - TIMER_UPDATE_DUTY_M2(motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); + TIMER_UPDATE_DUTY_M2(top, motor_other->m_duty1_next, motor_other->m_duty2_next, motor_other->m_duty3_next); } #else float curr0 = (GET_CURRENT1() - conf_other->foc_offsets_current[0]) * FAC_CURRENT1; @@ -4635,7 +4649,7 @@ static void control_current(motor_all_state_t *motor, float dt) { state_m->mod_beta_raw = mod_beta_v0; } #endif - const uint32_t top = SYSTEM_CORE_CLOCK / (int)motor->m_conf->foc_f_zv; + const uint32_t top = get_randomized_timer_period((uint32_t)motor->m_conf->foc_f_zv, motor->m_conf->foc_f_zv_bandwidth); // Delay adding the HFI voltage when not sampling in both 0 vectors, as it will cancel // itself with the opposite pulse from the previous HFI sample. This makes more sense // when drawing the SVM waveform. @@ -4665,7 +4679,7 @@ static void control_current(motor_all_state_t *motor, float dt) { // Set output (HW Dependent) uint32_t duty1, duty2, duty3; - const uint32_t top = SYSTEM_CORE_CLOCK / (int)conf_now->foc_f_zv; + const uint32_t top = get_randomized_timer_period((uint32_t) conf_now->foc_f_zv, conf_now->foc_f_zv_bandwidth); // Calculate the duty cycles for all the phases. This also injects a zero modulation signal to // be able to fully utilize the bus voltage. See https://microchipdeveloper.com/mct5001:start From 7bd3fb7884c1e23d15bf45baa2429b6c4b0b82ab Mon Sep 17 00:00:00 2001 From: lolwheel Date: Sun, 29 Sep 2024 16:42:04 -0700 Subject: [PATCH 4/4] Added setting in the tool and tested everything on floatwheel. --- confgenerator.c | 3 +++ confgenerator.h | 2 +- datatypes.h | 2 +- motor/mcconf_default.h | 3 +++ motor/mcpwm_foc.c | 21 +++++++++++++-------- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/confgenerator.c b/confgenerator.c index 5f0547a47..279f9366c 100644 --- a/confgenerator.c +++ b/confgenerator.c @@ -64,6 +64,7 @@ int32_t confgenerator_serialize_mcconf(uint8_t *buffer, const mc_configuration * buffer_append_float32_auto(buffer, conf->foc_current_kp, &ind); buffer_append_float32_auto(buffer, conf->foc_current_ki, &ind); buffer_append_float32_auto(buffer, conf->foc_f_zv, &ind); + buffer_append_uint32(buffer, conf->foc_f_zv_bandwidth_pct, &ind); buffer_append_float32_auto(buffer, conf->foc_dt_us, &ind); buffer[ind++] = conf->foc_encoder_inverted; buffer_append_float32_auto(buffer, conf->foc_encoder_offset, &ind); @@ -400,6 +401,7 @@ bool confgenerator_deserialize_mcconf(const uint8_t *buffer, mc_configuration *c conf->foc_current_kp = buffer_get_float32_auto(buffer, &ind); conf->foc_current_ki = buffer_get_float32_auto(buffer, &ind); conf->foc_f_zv = buffer_get_float32_auto(buffer, &ind); + conf->foc_f_zv_bandwidth_pct = buffer_get_uint32(buffer, &ind); conf->foc_dt_us = buffer_get_float32_auto(buffer, &ind); conf->foc_encoder_inverted = buffer[ind++]; conf->foc_encoder_offset = buffer_get_float32_auto(buffer, &ind); @@ -732,6 +734,7 @@ void confgenerator_set_defaults_mcconf(mc_configuration *conf) { conf->foc_current_kp = MCCONF_FOC_CURRENT_KP; conf->foc_current_ki = MCCONF_FOC_CURRENT_KI; conf->foc_f_zv = MCCONF_FOC_F_ZV; + conf->foc_f_zv_bandwidth_pct = MCCONF_FOC_F_ZV_BANDWIDTH_PCT; conf->foc_dt_us = MCCONF_FOC_DT_US; conf->foc_encoder_inverted = MCCONF_FOC_ENCODER_INVERTED; conf->foc_encoder_offset = MCCONF_FOC_ENCODER_OFFSET; diff --git a/confgenerator.h b/confgenerator.h index 6a4649136..b8d94a42e 100644 --- a/confgenerator.h +++ b/confgenerator.h @@ -8,7 +8,7 @@ #include // Constants -#define MCCONF_SIGNATURE 1065524471 +#define MCCONF_SIGNATURE 2002097102 #define APPCONF_SIGNATURE 2099347128 // Functions diff --git a/datatypes.h b/datatypes.h index 60da1e9d9..7d233b135 100644 --- a/datatypes.h +++ b/datatypes.h @@ -425,7 +425,7 @@ typedef struct { float foc_current_kp; float foc_current_ki; float foc_f_zv; - float foc_f_zv_bandwidth; + uint32_t foc_f_zv_bandwidth_pct; float foc_dt_us; float foc_encoder_offset; bool foc_encoder_inverted; diff --git a/motor/mcconf_default.h b/motor/mcconf_default.h index 613193f5c..86a5f4816 100644 --- a/motor/mcconf_default.h +++ b/motor/mcconf_default.h @@ -262,6 +262,9 @@ #ifndef MCCONF_FOC_F_ZV #define MCCONF_FOC_F_ZV 25000.0 #endif +#ifndef MCCONF_FOC_F_ZV_BANDWIDTH_PCT +#define MCCONF_FOC_F_ZV_BANDWIDTH_PCT 0 +#endif #ifndef MCCONF_FOC_DT_US #define MCCONF_FOC_DT_US 0.12 // Microseconds for dead time compensation #endif diff --git a/motor/mcpwm_foc.c b/motor/mcpwm_foc.c index 4dd3b6532..9e075f716 100644 --- a/motor/mcpwm_foc.c +++ b/motor/mcpwm_foc.c @@ -344,11 +344,16 @@ static void timer_reinit(const int f_zv) { * center frequency and bandwidth. * Assumes that the timer is clocked at system core clock frequency. * @param zvf Center frequency in Hz. - * @param bandwidth Bandwidth, ratio. Must satisfy 0 <= bandwidth <=1. + * @param bandwidth Bandwidth, percent. */ -static uint32_t get_randomized_timer_period(const uint32_t zvf, const float bandwidth) { +static uint32_t get_randomized_timer_period(const uint32_t zvf, const uint32_t bandwidth_pct) { const uint32_t period_center = SYSTEM_CORE_CLOCK / zvf; - const uint32_t period_bandwidth = period_center * bandwidth; + // mod zero is undefined, return early. + if (bandwidth_pct == 0) { + return period_center; + } + // Period * 100 is well within uint32_t range because timer prescaler is 1. + const uint32_t period_bandwidth = period_center * bandwidth_pct / 100; const uint32_t period_bottom = period_center - period_bandwidth / 2; return period_bottom + rand() % period_bandwidth; } @@ -2469,7 +2474,7 @@ int mcpwm_foc_dc_cal(bool cal_undriven) { float current_sum[3] = {0.0, 0.0, 0.0}; float voltage_sum[3] = {0.0, 0.0, 0.0}; - const uint32_t top = get_randomized_timer_period((uint32_t)m_motor_1.m_conf->foc_f_zv, m_motor_1.m_conf->foc_f_zv_bandwidth); + const uint32_t top = get_randomized_timer_period((uint32_t)m_motor_1.m_conf->foc_f_zv, m_motor_1.m_conf->foc_f_zv_bandwidth_pct); TIMER_UPDATE_DUTY_M1(top, top / 2, top / 2, top / 2); // Start PWM on phase 1 @@ -2679,7 +2684,7 @@ int mcpwm_foc_dc_cal(bool cal_undriven) { float current_sum[3] = {0.0, 0.0, 0.0}; float voltage_sum[3] = {0.0, 0.0, 0.0}; - const uint32_t top = get_randomized_timer_period((uint32_t)m_motor_1.m_conf->foc_f_zv, m_motor_1.m_conf->foc_f_zv_bandwidth); + const uint32_t top = get_randomized_timer_period((uint32_t)m_motor_1.m_conf->foc_f_zv, m_motor_1.m_conf->foc_f_zv_bandwidth_pct); TIMER_UPDATE_DUTY_M1(top, top / 2, top / 2, top / 2); stop_pwm_hw((motor_all_state_t*)&m_motor_1); @@ -2847,7 +2852,7 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { mc_configuration *conf_now = motor_now->m_conf; mc_configuration *conf_other = motor_other->m_conf; - const uint32_t top = get_randomized_timer_period((uint32_t)conf_other->foc_f_zv, conf_other->foc_f_zv_bandwidth); + const uint32_t top = get_randomized_timer_period((uint32_t)conf_other->foc_f_zv, conf_other->foc_f_zv_bandwidth_pct); bool skip_interpolation = motor_other->m_cc_was_hfi; @@ -4649,7 +4654,7 @@ static void control_current(motor_all_state_t *motor, float dt) { state_m->mod_beta_raw = mod_beta_v0; } #endif - const uint32_t top = get_randomized_timer_period((uint32_t)motor->m_conf->foc_f_zv, motor->m_conf->foc_f_zv_bandwidth); + const uint32_t top = get_randomized_timer_period((uint32_t)motor->m_conf->foc_f_zv, motor->m_conf->foc_f_zv_bandwidth_pct); // Delay adding the HFI voltage when not sampling in both 0 vectors, as it will cancel // itself with the opposite pulse from the previous HFI sample. This makes more sense // when drawing the SVM waveform. @@ -4679,7 +4684,7 @@ static void control_current(motor_all_state_t *motor, float dt) { // Set output (HW Dependent) uint32_t duty1, duty2, duty3; - const uint32_t top = get_randomized_timer_period((uint32_t) conf_now->foc_f_zv, conf_now->foc_f_zv_bandwidth); + const uint32_t top = get_randomized_timer_period((uint32_t) conf_now->foc_f_zv, conf_now->foc_f_zv_bandwidth_pct); // Calculate the duty cycles for all the phases. This also injects a zero modulation signal to // be able to fully utilize the bus voltage. See https://microchipdeveloper.com/mct5001:start