From 0bf6b0652d45c3b34f9e759e15b9161b1e8dd298 Mon Sep 17 00:00:00 2001 From: Benjamin Vedder Date: Sat, 20 Jul 2024 13:40:58 +0200 Subject: [PATCH] Added option to short all phases on full brake --- CHANGELOG.md | 1 + conf_general.h | 2 +- confgenerator.c | 3 ++ confgenerator.h | 2 +- datatypes.h | 1 + motor/foc_math.h | 8 +++- motor/mc_interface.c | 2 +- motor/mcconf_default.h | 3 ++ motor/mcpwm_foc.c | 94 ++++++++++++++++++++++++++++++++++++++---- 9 files changed, 104 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45b45a27..69ffdd0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ * Fixed some braking glitches. * Configurable HFI error truncation to reject noise. * Removed GPDrive. +* FOC: Option to short phases on 0 duty. ### 6.02 #### 2023-03-12 diff --git a/conf_general.h b/conf_general.h index a03b9069..d8a5ff13 100755 --- a/conf_general.h +++ b/conf_general.h @@ -24,7 +24,7 @@ #define FW_VERSION_MAJOR 6 #define FW_VERSION_MINOR 05 // Set to 0 for building a release and iterate during beta test builds -#define FW_TEST_VERSION_NUMBER 30 +#define FW_TEST_VERSION_NUMBER 31 #include "datatypes.h" diff --git a/confgenerator.c b/confgenerator.c index 025653c3..5f0547a4 100644 --- a/confgenerator.c +++ b/confgenerator.c @@ -141,6 +141,7 @@ int32_t confgenerator_serialize_mcconf(uint8_t *buffer, const mc_configuration * buffer_append_float16(buffer, conf->foc_fw_ramp_time, 1000, &ind); buffer_append_float16(buffer, conf->foc_fw_q_current_factor, 10000, &ind); buffer[ind++] = conf->foc_speed_soure; + buffer[ind++] = conf->foc_short_ls_on_zero_duty; buffer[ind++] = conf->sp_pid_loop_rate; buffer_append_float32_auto(buffer, conf->s_pid_kp, &ind); buffer_append_float32_auto(buffer, conf->s_pid_ki, &ind); @@ -476,6 +477,7 @@ bool confgenerator_deserialize_mcconf(const uint8_t *buffer, mc_configuration *c conf->foc_fw_ramp_time = buffer_get_float16(buffer, 1000, &ind); conf->foc_fw_q_current_factor = buffer_get_float16(buffer, 10000, &ind); conf->foc_speed_soure = buffer[ind++]; + conf->foc_short_ls_on_zero_duty = buffer[ind++]; conf->sp_pid_loop_rate = buffer[ind++]; conf->s_pid_kp = buffer_get_float32_auto(buffer, &ind); conf->s_pid_ki = buffer_get_float32_auto(buffer, &ind); @@ -807,6 +809,7 @@ void confgenerator_set_defaults_mcconf(mc_configuration *conf) { conf->foc_fw_ramp_time = MCCONF_FOC_FW_RAMP_TIME; conf->foc_fw_q_current_factor = MCCONF_FOC_FW_Q_CURRENT_FACTOR; conf->foc_speed_soure = MCCONF_FOC_SPEED_SOURCE; + conf->foc_short_ls_on_zero_duty = MCCONF_FOC_SHORT_LS_ON_ZERO_DUTY; conf->sp_pid_loop_rate = MCCONF_SP_PID_LOOP_RATE; conf->s_pid_kp = MCCONF_S_PID_KP; conf->s_pid_ki = MCCONF_S_PID_KI; diff --git a/confgenerator.h b/confgenerator.h index 7d51c852..22401abe 100644 --- a/confgenerator.h +++ b/confgenerator.h @@ -8,7 +8,7 @@ #include // Constants -#define MCCONF_SIGNATURE 4193379058 +#define MCCONF_SIGNATURE 2490415037 #define APPCONF_SIGNATURE 2099347128 // Functions diff --git a/datatypes.h b/datatypes.h index 77b23301..0c756ff8 100644 --- a/datatypes.h +++ b/datatypes.h @@ -487,6 +487,7 @@ typedef struct { float foc_fw_ramp_time; float foc_fw_q_current_factor; FOC_SPEED_SRC foc_speed_soure; + bool foc_short_ls_on_zero_duty; PID_RATE sp_pid_loop_rate; diff --git a/motor/foc_math.h b/motor/foc_math.h index ac8574d9..32f8f89d 100644 --- a/motor/foc_math.h +++ b/motor/foc_math.h @@ -127,6 +127,12 @@ typedef struct { float sample_voltage; } mc_audio_state; +typedef enum { + FOC_PWM_DISABLED = 0, + FOC_PWM_ENABLED, + FOC_PWM_FULL_BRAKE +} foc_pwm_mode; + typedef struct { mc_configuration *m_conf; mc_state m_state; @@ -143,7 +149,7 @@ typedef struct { float m_current_off_delay; float m_openloop_speed; float m_openloop_phase; - bool m_output_on; + foc_pwm_mode m_pwm_mode; float m_pos_pid_set; float m_speed_pid_set_rpm; float m_speed_command_rpm; diff --git a/motor/mc_interface.c b/motor/mc_interface.c index f9ec0f5d..a2e3519d 100644 --- a/motor/mc_interface.c +++ b/motor/mc_interface.c @@ -2176,7 +2176,7 @@ void mc_interface_mc_timer_isr(bool is_second_motor) { m_vzero_samples[m_sample_now] = zero; m_curr_fir_samples[m_sample_now] = (int16_t)(current * (8.0 / FAC_CURRENT)); - m_f_sw_samples[m_sample_now] = (int16_t)(0.1 / t_samp); + m_f_sw_samples[m_sample_now] = (int16_t)(0.1 / t_samp / m_sample_int); m_status_samples[m_sample_now] = mcpwm_get_comm_step() | (mcpwm_read_hall_phase() << 3); m_sample_now++; diff --git a/motor/mcconf_default.h b/motor/mcconf_default.h index 2ecfb6e0..a54f1fa5 100644 --- a/motor/mcconf_default.h +++ b/motor/mcconf_default.h @@ -493,6 +493,9 @@ #ifndef MCCONF_FOC_SPEED_SOURCE #define MCCONF_FOC_SPEED_SOURCE FOC_SPEED_SRC_CORRECTED // Position source for speed trackers #endif +#ifndef MCCONF_FOC_SHORT_LS_ON_ZERO_DUTY +#define MCCONF_FOC_SHORT_LS_ON_ZERO_DUTY false // Short low-side phases on zero duty cycle +#endif // GPD #ifndef MCCONF_GPD_BUFFER_NOTIFY_LEFT diff --git a/motor/mcpwm_foc.c b/motor/mcpwm_foc.c index d465cb39..9975c09c 100644 --- a/motor/mcpwm_foc.c +++ b/motor/mcpwm_foc.c @@ -57,6 +57,7 @@ static void control_current(motor_all_state_t *motor, float dt); static void update_valpha_vbeta(motor_all_state_t *motor, float mod_alpha, float mod_beta); static void stop_pwm_hw(motor_all_state_t *motor); static void start_pwm_hw(motor_all_state_t *motor); +static void full_brake_hw(motor_all_state_t *motor); static void terminal_tmp(int argc, const char **argv); static void terminal_plot_hfi(int argc, const char **argv); static void timer_update(motor_all_state_t *motor, float dt); @@ -4669,10 +4670,19 @@ static void control_current(motor_all_state_t *motor, float dt) { #endif } - // do not allow to turn on PWM outputs if virtual motor is used if(virtual_motor_is_connected() == false) { - if (!motor->m_output_on) { - start_pwm_hw(motor); + // If all duty cycles are equal the phases should be shorted. Instead of + // modulating the short we keep all low-side FETs on - that will draw less + // power and not suffer from dead-time distortion. It also gives more + // braking torque at low speed. + if (conf_now->foc_short_ls_on_zero_duty && duty1 == duty2 && duty2 == duty3) { + if (motor->m_pwm_mode != FOC_PWM_FULL_BRAKE) { + full_brake_hw(motor); + } + } else { + if (motor->m_pwm_mode != FOC_PWM_ENABLED) { + start_pwm_hw(motor); + } } } } @@ -4871,8 +4881,6 @@ static void stop_pwm_hw(motor_all_state_t *motor) { #ifdef HW_HAS_DRV8313 DISABLE_BR(); #endif - - motor->m_output_on = false; PHASE_FILTER_OFF(); } else { TIM_SelectOCxM(TIM8, TIM_Channel_1, TIM_ForcedAction_InActive); @@ -4893,9 +4901,10 @@ static void stop_pwm_hw(motor_all_state_t *motor) { DISABLE_BR_2(); #endif - motor->m_output_on = false; PHASE_FILTER_OFF_M2(); } + + motor->m_pwm_mode = FOC_PWM_DISABLED; } static void start_pwm_hw(motor_all_state_t *motor) { @@ -4926,6 +4935,10 @@ static void start_pwm_hw(motor_all_state_t *motor) { TIM_CCxNCmd(TIM8, TIM_Channel_3, TIM_CCxN_Enable); PHASE_FILTER_ON_M2(); + +#ifdef HW_HAS_DRV8313_2 + ENABLE_BR_2(); +#endif #endif // Generate COM event in ADC interrupt to get better synchronization @@ -4934,7 +4947,6 @@ static void start_pwm_hw(motor_all_state_t *motor) { #ifdef HW_HAS_DRV8313 ENABLE_BR(); #endif - motor->m_output_on = true; PHASE_FILTER_ON(); } else { TIM_SelectOCxM(TIM8, TIM_Channel_1, TIM_OCMode_PWM1); @@ -4952,9 +4964,75 @@ static void start_pwm_hw(motor_all_state_t *motor) { #ifdef HW_HAS_DRV8313_2 ENABLE_BR_2(); #endif - motor->m_output_on = true; PHASE_FILTER_ON_M2(); } + + motor->m_pwm_mode = FOC_PWM_ENABLED; +} + +static void full_brake_hw(motor_all_state_t *motor) { + if (motor == &m_motor_1) { + TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Enable); + TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Enable); + + TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Enable); + TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Enable); + + TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Enable); + TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Enable); + + TIM_GenerateEvent(TIM1, TIM_EventSource_COM); + PHASE_FILTER_ON(); + +#ifdef HW_HAS_DRV8313 + ENABLE_BR(); +#endif + +#ifdef HW_HAS_DUAL_PARALLEL + TIM_SelectOCxM(TIM8, TIM_Channel_1, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM8, TIM_Channel_1, TIM_CCx_Enable); + TIM_CCxNCmd(TIM8, TIM_Channel_1, TIM_CCxN_Enable); + + TIM_SelectOCxM(TIM8, TIM_Channel_2, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM8, TIM_Channel_2, TIM_CCx_Enable); + TIM_CCxNCmd(TIM8, TIM_Channel_2, TIM_CCxN_Enable); + + TIM_SelectOCxM(TIM8, TIM_Channel_3, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM8, TIM_Channel_3, TIM_CCx_Enable); + TIM_CCxNCmd(TIM8, TIM_Channel_3, TIM_CCxN_Enable); + + TIM_GenerateEvent(TIM8, TIM_EventSource_COM); + PHASE_FILTER_ON_M2(); + +#ifdef HW_HAS_DRV8313_2 + ENABLE_BR_2(); +#endif +#endif + } else { + TIM_SelectOCxM(TIM8, TIM_Channel_1, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM8, TIM_Channel_1, TIM_CCx_Enable); + TIM_CCxNCmd(TIM8, TIM_Channel_1, TIM_CCxN_Enable); + + TIM_SelectOCxM(TIM8, TIM_Channel_2, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM8, TIM_Channel_2, TIM_CCx_Enable); + TIM_CCxNCmd(TIM8, TIM_Channel_2, TIM_CCxN_Enable); + + TIM_SelectOCxM(TIM8, TIM_Channel_3, TIM_ForcedAction_InActive); + TIM_CCxCmd(TIM8, TIM_Channel_3, TIM_CCx_Enable); + TIM_CCxNCmd(TIM8, TIM_Channel_3, TIM_CCxN_Enable); + + TIM_GenerateEvent(TIM8, TIM_EventSource_COM); + PHASE_FILTER_ON_M2(); + +#ifdef HW_HAS_DRV8313_2 + ENABLE_BR_2(); +#endif + } + + motor->m_pwm_mode = FOC_PWM_FULL_BRAKE; } static void terminal_plot_hfi(int argc, const char **argv) {