Merge branch 'feature/mcpwm_bldc_hall_example' into 'master'

mcpwm: bldc hall example

Closes IDF-3648

See merge request espressif/esp-idf!14578
This commit is contained in:
Michael (XIAO Xufeng) 2021-08-26 08:28:27 +00:00
commit 375145ecdb
17 changed files with 10960 additions and 7238 deletions

View File

@ -139,7 +139,7 @@ typedef enum {
* @brief MCPWM select triggering level of fault signal
*/
typedef enum {
MCPWM_LOW_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes from high to low, currently not supported*/
MCPWM_LOW_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes from high to low*/
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
} mcpwm_fault_input_level_t;

View File

@ -41,15 +41,20 @@ extern "C" {
/********************* Group registers *******************/
// Set/Get group clock: PWM_clk = CLK_160M / (clk_cfg.prescale + 1)
// Set/Get group clock: PWM_clk = CLK_160M / (prescale + 1)
static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre_scale)
{
mcpwm->clk_cfg.prescale = pre_scale - 1;
// In case the compiler optimise a 32bit instruction (e.g. s32i) into 8bit instruction (e.g. s8i, which is not allowed to access a register)
// We take care of the "read-modify-write" procedure by ourselves.
mcpwm_clk_cfg_reg_t clkcfg = mcpwm->clk_cfg;
clkcfg.clk_prescale = pre_scale - 1;
mcpwm->clk_cfg = clkcfg;
}
static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm)
{
return mcpwm->clk_cfg.prescale + 1;
mcpwm_clk_cfg_reg_t clkcfg = mcpwm->clk_cfg;
return clkcfg.clk_prescale + 1;
}
static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm)
@ -265,20 +270,25 @@ static inline void mcpwm_ll_intr_enable_capture(mcpwm_dev_t *mcpwm, uint32_t cap
static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id, uint32_t prescale)
{
mcpwm->timer[timer_id].period.prescale = prescale - 1;
// In case the compiler optimise a 32bit instruction (e.g. s32i) into 8bit instruction (e.g. s8i, which is not allowed to access a register)
// We take care of the "read-modify-write" procedure by ourselves.
mcpwm_timer_cfg0_reg_t cfg0 = mcpwm->timer[timer_id].timer_cfg0;
cfg0.timer_prescale = prescale - 1;
mcpwm->timer[timer_id].timer_cfg0 = cfg0;
}
static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].period.prescale + 1;
mcpwm_timer_cfg0_reg_t cfg0 = mcpwm->timer[timer_id].timer_cfg0;
return cfg0.timer_prescale + 1;
}
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
mcpwm->timer[timer_id].period.period = peak - 1;
mcpwm->timer[timer_id].timer_cfg0.timer_period = peak - 1;
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
mcpwm->timer[timer_id].period.period = peak;
mcpwm->timer[timer_id].timer_cfg0.timer_period = peak;
}
}
@ -286,32 +296,32 @@ static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id,
{
// asymmetric mode
if (!symmetric) {
return mcpwm->timer[timer_id].period.period + 1;
return mcpwm->timer[timer_id].timer_cfg0.timer_period + 1;
}
// symmetric mode
return mcpwm->timer[timer_id].period.period;
return mcpwm->timer[timer_id].timer_cfg0.timer_period;
}
static inline void mcpwm_ll_timer_update_period_at_once(mcpwm_dev_t *mcpwm, int timer_id)
{
mcpwm->timer[timer_id].period.upmethod = 0;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod = 0;
}
static inline void mcpwm_ll_timer_enable_update_period_on_tez(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
{
if (enable) {
mcpwm->timer[timer_id].period.upmethod |= 0x01;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod |= 0x01;
} else {
mcpwm->timer[timer_id].period.upmethod &= ~0x01;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod &= ~0x01;
}
}
static inline void mcpwm_ll_timer_enable_update_period_on_sync(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
{
if (enable) {
mcpwm->timer[timer_id].period.upmethod |= 0x02;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod |= 0x02;
} else {
mcpwm->timer[timer_id].period.upmethod &= ~0x02;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod &= ~0x02;
}
}
@ -319,23 +329,23 @@ static inline void mcpwm_ll_timer_set_count_mode(mcpwm_dev_t *mcpwm, int timer_i
{
switch (mode) {
case MCPWM_TIMER_COUNT_MODE_PAUSE:
mcpwm->timer[timer_id].mode.mode = 0;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 0;
break;
case MCPWM_TIMER_COUNT_MODE_UP:
mcpwm->timer[timer_id].mode.mode = 1;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 1;
break;
case MCPWM_TIMER_COUNT_MODE_DOWN:
mcpwm->timer[timer_id].mode.mode = 2;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 2;
break;
case MCPWM_TIMER_COUNT_MODE_UP_DOWN:
mcpwm->timer[timer_id].mode.mode = 3;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 3;
break;
}
}
static inline mcpwm_timer_count_mode_t mcpwm_ll_timer_get_count_mode(mcpwm_dev_t *mcpwm, int timer_id)
{
switch (mcpwm->timer[timer_id].mode.mode) {
switch (mcpwm->timer[timer_id].timer_cfg1.timer_mod) {
case 0:
return MCPWM_TIMER_COUNT_MODE_PAUSE;
case 1:
@ -344,6 +354,9 @@ static inline mcpwm_timer_count_mode_t mcpwm_ll_timer_get_count_mode(mcpwm_dev_t
return MCPWM_TIMER_COUNT_MODE_DOWN;
case 3:
return MCPWM_TIMER_COUNT_MODE_UP_DOWN;
default:
HAL_ASSERT(false && "unknown count mode");
return mcpwm->timer[timer_id].timer_cfg1.timer_mod;
}
}
@ -351,74 +364,74 @@ static inline void mcpwm_ll_timer_set_execute_command(mcpwm_dev_t *mcpwm, int ti
{
switch (cmd) {
case MCPWM_TIMER_STOP_AT_ZERO:
mcpwm->timer[timer_id].mode.start = 0;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 0;
break;
case MCPWM_TIMER_STOP_AT_PEAK:
mcpwm->timer[timer_id].mode.start = 1;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 1;
break;
case MCPWM_TIMER_START_NO_STOP:
mcpwm->timer[timer_id].mode.start = 2;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 2;
break;
case MCPWM_TIMER_START_STOP_AT_ZERO:
mcpwm->timer[timer_id].mode.start = 3;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 3;
break;
case MCPWM_TIMER_START_STOP_AT_PEAK:
mcpwm->timer[timer_id].mode.start = 4;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 4;
break;
}
}
static inline uint32_t mcpwm_ll_timer_get_count_value(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].status.value;
return mcpwm->timer[timer_id].timer_status.timer_value;
}
static inline mcpwm_timer_direction_t mcpwm_ll_timer_get_count_direction(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].status.direction ? MCPWM_TIMER_DIRECTION_DOWN : MCPWM_TIMER_DIRECTION_UP;
return mcpwm->timer[timer_id].timer_status.timer_direction ? MCPWM_TIMER_DIRECTION_DOWN : MCPWM_TIMER_DIRECTION_UP;
}
static inline void mcpwm_ll_timer_enable_sync_input(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
{
mcpwm->timer[timer_id].sync.in_en = enable;
mcpwm->timer[timer_id].timer_sync.timer_synci_en = enable;
}
static inline void mcpwm_ll_timer_sync_out_penetrate(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out is selected to sync_in
mcpwm->timer[timer_id].sync.out_sel = 0;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 0;
}
static inline void mcpwm_ll_timer_sync_out_on_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_event_t event)
{
if (event == MCPWM_TIMER_EVENT_ZERO) {
mcpwm->timer[timer_id].sync.out_sel = 1;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 1;
} else if (event == MCPWM_TIMER_EVENT_PEAK) {
mcpwm->timer[timer_id].sync.out_sel = 2;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 2;
} else {
HAL_ASSERT(false);
HAL_ASSERT(false && "unknown sync out event");
}
}
static inline void mcpwm_ll_timer_disable_sync_out(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out will always be zero
mcpwm->timer[timer_id].sync.out_sel = 3;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 3;
}
static inline void mcpwm_ll_timer_trigger_soft_sync(mcpwm_dev_t *mcpwm, int timer_id)
{
mcpwm->timer[timer_id].sync.sync_sw = ~mcpwm->timer[timer_id].sync.sync_sw;
mcpwm->timer[timer_id].timer_sync.timer_sync_sw = ~mcpwm->timer[timer_id].timer_sync.timer_sync_sw;
}
static inline void mcpwm_ll_timer_set_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t phase_value)
{
mcpwm->timer[timer_id].sync.timer_phase = phase_value;
mcpwm->timer[timer_id].timer_sync.timer_phase = phase_value;
}
static inline void mcpwm_ll_timer_set_sync_phase_direction(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_direction_t direction)
{
mcpwm->timer[timer_id].sync.phase_direct = direction;
mcpwm->timer[timer_id].timer_sync.timer_phase_direction = direction;
}
static inline void mcpwm_ll_timer_set_gpio_synchro(mcpwm_dev_t *mcpwm, int timer, int gpio_sync_id)
@ -458,117 +471,117 @@ static inline void mcpwm_ll_operator_flush_shadow(mcpwm_dev_t *mcpwm, int operat
static inline void mcpwm_ll_operator_select_timer(mcpwm_dev_t *mcpwm, int operator_id, int timer_id)
{
if (operator_id == 0) {
mcpwm->timer_sel.operator0_sel = timer_id;
mcpwm->operator_timersel.operator0_timersel = timer_id;
} else if (operator_id == 1) {
mcpwm->timer_sel.operator1_sel = timer_id;
mcpwm->operator_timersel.operator1_timersel = timer_id;
} else {
mcpwm->timer_sel.operator2_sel = timer_id;
mcpwm->operator_timersel.operator2_timersel = timer_id;
}
}
static inline void mcpwm_ll_operator_update_compare_at_once(mcpwm_dev_t *mcpwm, int operator_id, int compare_id)
{
mcpwm->channel[operator_id].cmpr_cfg.val &= ~(0x0F << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~(0x0F << (4 * compare_id));
}
static inline void mcpwm_ll_operator_enable_update_compare_on_tez(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].cmpr_cfg.val |= (1 << 0) << (4 * compare_id);
mcpwm->operator[operator_id].gen_stmp_cfg.val |= (1 << 0) << (4 * compare_id);
} else {
mcpwm->channel[operator_id].cmpr_cfg.val &= ~((1 << 0) << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~((1 << 0) << (4 * compare_id));
}
}
static inline void mcpwm_ll_operator_enable_update_compare_on_tep(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].cmpr_cfg.val |= (1 << 1) << (4 * compare_id);
mcpwm->operator[operator_id].gen_stmp_cfg.val |= (1 << 1) << (4 * compare_id);
} else {
mcpwm->channel[operator_id].cmpr_cfg.val &= ~((1 << 1) << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~((1 << 1) << (4 * compare_id));
}
}
static inline void mcpwm_ll_operator_enable_update_compare_on_sync(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].cmpr_cfg.val |= (1 << 2) << (4 * compare_id);
mcpwm->operator[operator_id].gen_stmp_cfg.val |= (1 << 2) << (4 * compare_id);
} else {
mcpwm->channel[operator_id].cmpr_cfg.val &= ~((1 << 2) << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~((1 << 2) << (4 * compare_id));
}
}
static inline void mcpwm_ll_operator_set_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, uint32_t compare_value)
{
mcpwm->channel[operator_id].cmpr_value[compare_id].cmpr_val = compare_value;
mcpwm->operator[operator_id].timestamp[compare_id].gen = compare_value;
}
static inline uint32_t mcpwm_ll_operator_get_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int compare_id)
{
return mcpwm->channel[operator_id].cmpr_value[compare_id].cmpr_val;
return mcpwm->operator[operator_id].timestamp[compare_id].gen;
}
static inline void mcpwm_ll_operator_update_action_at_once(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].gen_cfg0.upmethod = 0;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod = 0;
}
static inline void mcpwm_ll_operator_enable_update_action_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].gen_cfg0.upmethod |= 1 << 0;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod |= 1 << 0;
} else {
mcpwm->channel[operator_id].gen_cfg0.upmethod &= ~(1 << 0);
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod &= ~(1 << 0);
}
}
static inline void mcpwm_ll_operator_enable_update_action_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].gen_cfg0.upmethod |= 1 << 1;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod |= 1 << 1;
} else {
mcpwm->channel[operator_id].gen_cfg0.upmethod &= ~(1 << 1);
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod &= ~(1 << 1);
}
}
static inline void mcpwm_ll_operator_enable_update_action_on_sync(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].gen_cfg0.upmethod |= 1 << 2;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod |= 1 << 2;
} else {
mcpwm->channel[operator_id].gen_cfg0.upmethod &= ~(1 << 2);
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod &= ~(1 << 2);
}
}
static inline void mcpwm_ll_operator_set_trigger_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_id)
{
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (fault_id << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val |= (fault_id << (4 + 3 * trig_id));
}
static inline void mcpwm_ll_operator_set_trigger_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id)
{
// the timer here is not selectable, must be the one connected with the operator
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (3 << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val |= (3 << (4 + 3 * trig_id));
}
/********************* Generator registers *******************/
static inline void mcpwm_ll_generator_reset_actions(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
mcpwm->channel[operator_id].generator[generator_id].val = 0;
mcpwm->operator[operator_id].generator[generator_id].val = 0;
}
static inline void mcpwm_ll_generator_set_action_on_timer_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_timer_event_t event, mcpwm_generator_action_t action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) { // utez, utep
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (event * 2);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (event * 2);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dtez, dtep
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2 + 12));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (event * 2 + 12);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2 + 12));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (event * 2 + 12);
}
}
@ -576,11 +589,11 @@ static inline void mcpwm_ll_generator_set_action_on_compare_event(mcpwm_dev_t *m
mcpwm_timer_direction_t direction, int cmp_id, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) { // utea, uteb
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 4));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 4);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 4));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 4);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dtea, dteb
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 16));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 16);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 16));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 16);
}
}
@ -588,58 +601,58 @@ static inline void mcpwm_ll_generator_set_action_on_trigger_event(mcpwm_dev_t *m
mcpwm_timer_direction_t direction, int trig_id, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) { // ut0, ut1
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 8));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 8);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 8));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 8);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dt0, dt1
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 20));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 20);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 20));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 20);
}
}
static inline void mcpwm_ll_gen_trigger_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce = ~mcpwm->channel[operator_id].gen_force.a_nciforce;
mcpwm->operator[operator_id].gen_force.gen_a_nciforce = ~mcpwm->operator[operator_id].gen_force.gen_a_nciforce;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce = ~mcpwm->channel[operator_id].gen_force.b_nciforce;
mcpwm->operator[operator_id].gen_force.gen_b_nciforce = ~mcpwm->operator[operator_id].gen_force.gen_b_nciforce;
}
}
static inline void mcpwm_ll_gen_disable_continue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
mcpwm->operator[operator_id].gen_force.gen_cntuforce_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_a_cntuforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_b_cntuforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_disable_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_a_nciforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_b_nciforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_set_continue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
mcpwm->operator[operator_id].gen_force.gen_cntuforce_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_a_cntuforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_b_cntuforce_mode = level + 1;
}
}
static inline void mcpwm_ll_gen_set_noncontinue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_a_nciforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_b_nciforce_mode = level + 1;
}
}
@ -648,116 +661,116 @@ static inline void mcpwm_ll_gen_set_noncontinue_force_level(mcpwm_dev_t *mcpwm,
static inline void mcpwm_ll_deadtime_resolution_to_timer(mcpwm_dev_t *mcpwm, int operator_id, bool same)
{
// whether to make the resolution of dead time delay module the same to the timer connected with operator
mcpwm->channel[operator_id].db_cfg.clk_sel = same;
mcpwm->operator[operator_id].dt_cfg.dt_clk_sel = same;
}
static inline void mcpwm_ll_deadtime_red_select_generator(mcpwm_dev_t *mcpwm, int operator_id, int generator)
{
mcpwm->channel[operator_id].db_cfg.red_insel = generator;
mcpwm->operator[operator_id].dt_cfg.dt_red_insel = generator;
}
static inline void mcpwm_ll_deadtime_fed_select_generator(mcpwm_dev_t *mcpwm, int operator_id, int generator)
{
mcpwm->channel[operator_id].db_cfg.fed_insel = generator;
mcpwm->operator[operator_id].dt_cfg.dt_fed_insel = generator;
}
static inline void mcpwm_ll_deadtime_bypass_path(mcpwm_dev_t *mcpwm, int operator_id, int path, bool bypass)
{
if (bypass) {
mcpwm->channel[operator_id].db_cfg.val |= 1 << (path + 15);
mcpwm->operator[operator_id].dt_cfg.val |= 1 << (path + 15);
} else {
mcpwm->channel[operator_id].db_cfg.val &= ~(1 << (path + 15));
mcpwm->operator[operator_id].dt_cfg.val &= ~(1 << (path + 15));
}
}
static inline void mcpwm_ll_deadtime_invert_outpath(mcpwm_dev_t *mcpwm, int operator_id, int path, bool invert)
{
if (invert) {
mcpwm->channel[operator_id].db_cfg.val |= 1 << (path + 13);
mcpwm->operator[operator_id].dt_cfg.val |= 1 << (path + 13);
} else {
mcpwm->channel[operator_id].db_cfg.val &= ~(1 << (path + 13));
mcpwm->operator[operator_id].dt_cfg.val &= ~(1 << (path + 13));
}
}
static inline void mcpwm_ll_deadtime_swap_out_path(mcpwm_dev_t *mcpwm, int operator_id, int path, bool swap)
{
if (swap) {
mcpwm->channel[operator_id].db_cfg.val |= 1 << (path + 9);
mcpwm->operator[operator_id].dt_cfg.val |= 1 << (path + 9);
} else {
mcpwm->channel[operator_id].db_cfg.val &= ~(1 << (path + 9));
mcpwm->operator[operator_id].dt_cfg.val &= ~(1 << (path + 9));
}
}
static inline void mcpwm_ll_deadtime_enable_deb(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].db_cfg.deb_mode = enable;
mcpwm->operator[operator_id].dt_cfg.dt_deb_mode = enable;
}
static inline uint32_t mcpwm_ll_deadtime_get_switch_topology(mcpwm_dev_t *mcpwm, int operator_id)
{
return (mcpwm->channel[operator_id].db_cfg.deb_mode << 8) | (mcpwm->channel[operator_id].db_cfg.b_outswap << 7) |
(mcpwm->channel[operator_id].db_cfg.a_outswap << 6) | (mcpwm->channel[operator_id].db_cfg.fed_insel << 5) |
(mcpwm->channel[operator_id].db_cfg.red_insel << 4) | (mcpwm->channel[operator_id].db_cfg.fed_outinvert << 3) |
(mcpwm->channel[operator_id].db_cfg.red_outinvert << 2) | (mcpwm->channel[operator_id].db_cfg.a_outbypass << 1) |
(mcpwm->channel[operator_id].db_cfg.b_outbypass << 0);
return (mcpwm->operator[operator_id].dt_cfg.dt_deb_mode << 8) | (mcpwm->operator[operator_id].dt_cfg.dt_b_outswap << 7) |
(mcpwm->operator[operator_id].dt_cfg.dt_a_outswap << 6) | (mcpwm->operator[operator_id].dt_cfg.dt_fed_insel << 5) |
(mcpwm->operator[operator_id].dt_cfg.dt_red_insel << 4) | (mcpwm->operator[operator_id].dt_cfg.dt_fed_outinvert << 3) |
(mcpwm->operator[operator_id].dt_cfg.dt_red_outinvert << 2) | (mcpwm->operator[operator_id].dt_cfg.dt_a_outbypass << 1) |
(mcpwm->operator[operator_id].dt_cfg.dt_b_outbypass << 0);
}
static inline void mcpwm_ll_deadtime_set_falling_delay(mcpwm_dev_t *mcpwm, int operator_id, uint32_t fed)
{
mcpwm->channel[operator_id].db_fed_cfg.fed = fed - 1;
mcpwm->operator[operator_id].dt_fed_cfg.dt_fed = fed - 1;
}
static inline uint32_t mcpwm_ll_deadtime_get_falling_delay(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].db_fed_cfg.fed + 1;
return mcpwm->operator[operator_id].dt_fed_cfg.dt_fed + 1;
}
static inline void mcpwm_ll_deadtime_set_rising_delay(mcpwm_dev_t *mcpwm, int operator_id, uint32_t red)
{
mcpwm->channel[operator_id].db_red_cfg.red = red - 1;
mcpwm->operator[operator_id].dt_red_cfg.dt_red = red - 1;
}
static inline uint32_t mcpwm_ll_deadtime_get_rising_delay(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].db_red_cfg.red + 1;
return mcpwm->operator[operator_id].dt_red_cfg.dt_red + 1;
}
static inline void mcpwm_ll_deadtime_update_delay_at_once(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].db_cfg.fed_upmethod = 0;
mcpwm->channel[operator_id].db_cfg.red_upmethod = 0;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod = 0;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod = 0;
}
static inline void mcpwm_ll_deadtime_enable_update_delay_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].db_cfg.fed_upmethod |= 1 << 0;
mcpwm->channel[operator_id].db_cfg.red_upmethod |= 1 << 0;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod |= 1 << 0;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod |= 1 << 0;
} else {
mcpwm->channel[operator_id].db_cfg.fed_upmethod &= ~(1 << 0);
mcpwm->channel[operator_id].db_cfg.red_upmethod &= ~(1 << 0);
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod &= ~(1 << 0);
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod &= ~(1 << 0);
}
}
static inline void mcpwm_ll_deadtime_enable_update_delay_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].db_cfg.fed_upmethod |= 1 << 1;
mcpwm->channel[operator_id].db_cfg.red_upmethod |= 1 << 1;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod |= 1 << 1;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod |= 1 << 1;
} else {
mcpwm->channel[operator_id].db_cfg.fed_upmethod &= ~(1 << 1);
mcpwm->channel[operator_id].db_cfg.red_upmethod &= ~(1 << 1);
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod &= ~(1 << 1);
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod &= ~(1 << 1);
}
}
static inline void mcpwm_ll_deadtime_enable_update_delay_on_sync(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].db_cfg.fed_upmethod |= 1 << 2;
mcpwm->channel[operator_id].db_cfg.red_upmethod |= 1 << 2;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod |= 1 << 2;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod |= 1 << 2;
} else {
mcpwm->channel[operator_id].db_cfg.fed_upmethod &= ~(1 << 2);
mcpwm->channel[operator_id].db_cfg.red_upmethod &= ~(1 << 2);
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod &= ~(1 << 2);
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod &= ~(1 << 2);
}
}
@ -765,47 +778,47 @@ static inline void mcpwm_ll_deadtime_enable_update_delay_on_sync(mcpwm_dev_t *mc
static inline void mcpwm_ll_carrier_enable(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].carrier_cfg.en = enable;
mcpwm->operator[operator_id].carrier_cfg.carrier_en = enable;
}
static inline void mcpwm_ll_carrier_set_prescale(mcpwm_dev_t *mcpwm, int operator_id, uint8_t prescale)
{
mcpwm->channel[operator_id].carrier_cfg.prescale = prescale - 1;
mcpwm->operator[operator_id].carrier_cfg.carrier_prescale = prescale - 1;
}
static inline uint8_t mcpwm_ll_carrier_get_prescale(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].carrier_cfg.prescale + 1;
return mcpwm->operator[operator_id].carrier_cfg.carrier_prescale + 1;
}
static inline void mcpwm_ll_carrier_set_duty(mcpwm_dev_t *mcpwm, int operator_id, uint8_t carrier_duty)
{
mcpwm->channel[operator_id].carrier_cfg.duty = carrier_duty;
mcpwm->operator[operator_id].carrier_cfg.carrier_duty = carrier_duty;
}
static inline uint8_t mcpwm_ll_carrier_get_duty(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].carrier_cfg.duty;
return mcpwm->operator[operator_id].carrier_cfg.carrier_duty;
}
static inline void mcpwm_ll_carrier_out_invert(mcpwm_dev_t *mcpwm, int operator_id, bool invert)
{
mcpwm->channel[operator_id].carrier_cfg.out_invert = invert;
mcpwm->operator[operator_id].carrier_cfg.carrier_out_invert = invert;
}
static inline void mcpwm_ll_carrier_in_invert(mcpwm_dev_t *mcpwm, int operator_id, bool invert)
{
mcpwm->channel[operator_id].carrier_cfg.in_invert = invert;
mcpwm->operator[operator_id].carrier_cfg.carrier_in_invert = invert;
}
static inline void mcpwm_ll_carrier_set_oneshot_width(mcpwm_dev_t *mcpwm, int operator_id, uint8_t pulse_width)
{
mcpwm->channel[operator_id].carrier_cfg.oshtwth = pulse_width - 1;
mcpwm->operator[operator_id].carrier_cfg.carrier_oshtwth = pulse_width - 1;
}
static inline uint8_t mcpwm_ll_carrier_get_oneshot_width(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].carrier_cfg.oshtwth + 1;
return mcpwm->operator[operator_id].carrier_cfg.carrier_oshtwth + 1;
}
/********************* Fault detector registers *******************/
@ -831,155 +844,155 @@ static inline void mcpwm_ll_fault_set_active_level(mcpwm_dev_t *mcpwm, int fault
static inline void mcpwm_ll_fault_clear_ost(mcpwm_dev_t *mcpwm, int operator_id)
{
// a posedge can clear the ost fault status
mcpwm->channel[operator_id].tz_cfg1.clr_ost = 0;
mcpwm->channel[operator_id].tz_cfg1.clr_ost = 1;
mcpwm->operator[operator_id].fh_cfg1.fh_clr_ost = 0;
mcpwm->operator[operator_id].fh_cfg1.fh_clr_ost = 1;
}
static inline void mcpwm_ll_fault_enable_oneshot_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (7 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (7 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val &= ~(1 << (7 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val |= (enable << (7 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (3 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (3 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val &= ~(1 << (3 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val |= (enable << (3 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 1;
mcpwm->operator[operator_id].fh_cfg1.val |= 1 << 1;
} else {
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 1);
mcpwm->operator[operator_id].fh_cfg1.val &= ~(1 << 1);
}
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 2;
mcpwm->operator[operator_id].fh_cfg1.val |= 1 << 2;
} else {
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 2);
mcpwm->operator[operator_id].fh_cfg1.val &= ~(1 << 2);
}
}
static inline void mcpwm_ll_fault_enable_sw_cbc(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.sw_cbc = enable;
mcpwm->operator[operator_id].fh_cfg0.fh_sw_cbc = enable;
}
static inline void mcpwm_ll_fault_enable_sw_oneshot(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.sw_ost = enable;
mcpwm->operator[operator_id].fh_cfg0.fh_sw_ost = enable;
}
static inline void mcpwm_ll_fault_trigger_sw_cbc(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].tz_cfg1.force_cbc = ~mcpwm->channel[operator_id].tz_cfg1.force_cbc;
mcpwm->operator[operator_id].fh_cfg1.fh_force_cbc = ~mcpwm->operator[operator_id].fh_cfg1.fh_force_cbc;
}
static inline void mcpwm_ll_fault_trigger_sw_ost(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].tz_cfg1.force_ost = ~mcpwm->channel[operator_id].tz_cfg1.force_ost;
mcpwm->operator[operator_id].fh_cfg1.fh_force_ost = ~mcpwm->operator[operator_id].fh_cfg1.fh_force_ost;
}
static inline void mcpwm_ll_generator_set_action_on_trip_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_trip_type_t trip, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip + 2));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip + 2);
mcpwm->operator[operator_id].fh_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip + 2));
mcpwm->operator[operator_id].fh_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip + 2);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip);
mcpwm->operator[operator_id].fh_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip));
mcpwm->operator[operator_id].fh_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip);
}
}
static inline bool mcpwm_ll_fault_is_ost_on(mcpwm_dev_t *mcpwm, int op)
{
return mcpwm->channel[op].tz_status.ost_on;
return mcpwm->operator[op].fh_status.fh_ost_on;
}
static inline bool mcpwm_ll_fault_is_cbc_on(mcpwm_dev_t *mcpwm, int op)
{
return mcpwm->channel[op].tz_status.cbc_on;
return mcpwm->operator[op].fh_status.fh_cbc_on;
}
/********************* Capture registers *******************/
static inline void mcpwm_ll_capture_enable_timer(mcpwm_dev_t *mcpwm, bool enable)
{
mcpwm->cap_timer_cfg.timer_en = enable;
mcpwm->cap_timer_cfg.cap_timer_en = enable;
}
static inline void mcpwm_ll_capture_enable_channel(mcpwm_dev_t *mcpwm, int channel, bool enable)
{
mcpwm->cap_cfg_ch[channel].en = enable;
mcpwm->cap_chn_cfg[channel].capn_en = enable;
}
static inline void mcpwm_ll_capture_set_sync_phase_value(mcpwm_dev_t *mcpwm, uint32_t phase_value)
{
mcpwm->cap_timer_phase = phase_value;
mcpwm->cap_timer_phase.cap_timer_phase = phase_value;
}
static inline uint32_t mcpwm_ll_capture_get_sync_phase_value(mcpwm_dev_t *mcpwm)
{
return mcpwm->cap_timer_phase;
return mcpwm->cap_timer_phase.cap_timer_phase;
}
static inline void mcpwm_ll_capture_enable_timer_sync(mcpwm_dev_t *mcpwm, bool enable)
{
mcpwm->cap_timer_cfg.synci_en = enable;
mcpwm->cap_timer_cfg.cap_synci_en = enable;
}
static inline void mcpwm_ll_capture_set_internal_timer_synchro(mcpwm_dev_t *mcpwm, int sync_out_timer)
{
mcpwm->cap_timer_cfg.synci_sel = sync_out_timer + 1;
mcpwm->cap_timer_cfg.cap_synci_sel = sync_out_timer + 1;
}
static inline void mcpwm_ll_capture_set_external_synchro(mcpwm_dev_t *mcpwm, int extern_synchro)
{
mcpwm->cap_timer_cfg.synci_sel = extern_synchro + 4;
mcpwm->cap_timer_cfg.cap_synci_sel = extern_synchro + 4;
}
static inline void mcpwm_ll_capture_trigger_sw_sync(mcpwm_dev_t *mcpwm)
{
mcpwm->cap_timer_cfg.sync_sw = 1; // auto clear
mcpwm->cap_timer_cfg.cap_sync_sw = 1; // auto clear
}
static inline void mcpwm_ll_capture_enable_posedge(mcpwm_dev_t *mcpwm, int channel, bool enable)
{
if (enable) {
mcpwm->cap_cfg_ch[channel].val |= 1 << 2;
mcpwm->cap_chn_cfg[channel].val |= 1 << 2;
} else {
mcpwm->cap_cfg_ch[channel].val &= ~(1 << 2);
mcpwm->cap_chn_cfg[channel].val &= ~(1 << 2);
}
}
static inline void mcpwm_ll_capture_enable_negedge(mcpwm_dev_t *mcpwm, int channel, bool enable)
{
if (enable) {
mcpwm->cap_cfg_ch[channel].val |= 1 << 1;
mcpwm->cap_chn_cfg[channel].val |= 1 << 1;
} else {
mcpwm->cap_cfg_ch[channel].val &= ~(1 << 1);
mcpwm->cap_chn_cfg[channel].val &= ~(1 << 1);
}
}
static inline void mcpwm_ll_invert_input(mcpwm_dev_t *mcpwm, int channel, bool invert)
{
mcpwm->cap_cfg_ch[channel].in_invert = invert;
mcpwm->cap_chn_cfg[channel].capn_in_invert = invert;
}
static inline void mcpwm_ll_trigger_soft_capture(mcpwm_dev_t *mcpwm, int channel)
{
mcpwm->cap_cfg_ch[channel].sw = 1; // auto clear
mcpwm->cap_chn_cfg[channel].capn_sw = 1; // auto clear
}
static inline uint32_t mcpwm_ll_capture_get_value(mcpwm_dev_t *mcpwm, int channel)
{
return mcpwm->cap_val_ch[channel];
return mcpwm->cap_chn[channel].capn_value;
}
static inline bool mcpwm_ll_capture_is_negedge(mcpwm_dev_t *mcpwm, int channel)
@ -989,12 +1002,12 @@ static inline bool mcpwm_ll_capture_is_negedge(mcpwm_dev_t *mcpwm, int channel)
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
{
mcpwm->cap_cfg_ch[channel].prescale = prescale - 1;
mcpwm->cap_chn_cfg[channel].capn_prescale = prescale - 1;
}
static inline uint32_t mcpwm_ll_capture_get_prescale(mcpwm_dev_t *mcpwm, int channel)
{
return mcpwm->cap_cfg_ch[channel].prescale + 1;
return mcpwm->cap_chn_cfg[channel].capn_prescale + 1;
}
#ifdef __cplusplus

View File

@ -41,20 +41,20 @@ extern "C" {
/********************* Group registers *******************/
// Set/Get group clock: PWM_clk = CLK_160M / (clk_cfg.prescale + 1)
// Set/Get group clock: PWM_clk = CLK_160M / (prescale + 1)
static inline void mcpwm_ll_group_set_clock_prescale(mcpwm_dev_t *mcpwm, int pre_scale)
{
// In case the compiler optimise a 32bit instruction (e.g. s32i) into 8bit instruction (e.g. s8i, which is not allowed to access a register)
// We take care of the "read-modify-write" procedure by ourselves.
typeof(mcpwm->clk_cfg) clkcfg = mcpwm->clk_cfg;
clkcfg.prescale = pre_scale - 1;
mcpwm_clk_cfg_reg_t clkcfg = mcpwm->clk_cfg;
clkcfg.clk_prescale = pre_scale - 1;
mcpwm->clk_cfg = clkcfg;
}
static inline uint32_t mcpwm_ll_group_get_clock_prescale(mcpwm_dev_t *mcpwm)
{
typeof(mcpwm->clk_cfg) clkcfg = mcpwm->clk_cfg;
return clkcfg.prescale + 1;
mcpwm_clk_cfg_reg_t clkcfg = mcpwm->clk_cfg;
return clkcfg.clk_prescale + 1;
}
static inline void mcpwm_ll_group_enable_shadow_mode(mcpwm_dev_t *mcpwm)
@ -272,23 +272,23 @@ static inline void mcpwm_ll_timer_set_clock_prescale(mcpwm_dev_t *mcpwm, int tim
{
// In case the compiler optimise a 32bit instruction (e.g. s32i) into 8bit instruction (e.g. s8i, which is not allowed to access a register)
// We take care of the "read-modify-write" procedure by ourselves.
typeof(mcpwm->timer[timer_id].period) period = mcpwm->timer[timer_id].period;
period.prescale = prescale - 1;
mcpwm->timer[timer_id].period = period;
mcpwm_timer_cfg0_reg_t cfg0 = mcpwm->timer[timer_id].timer_cfg0;
cfg0.timer_prescale = prescale - 1;
mcpwm->timer[timer_id].timer_cfg0 = cfg0;
}
static inline uint32_t mcpwm_ll_timer_get_clock_prescale(mcpwm_dev_t *mcpwm, int timer_id)
{
typeof(mcpwm->timer[timer_id].period) period = mcpwm->timer[timer_id].period;
return period.prescale + 1;
mcpwm_timer_cfg0_reg_t cfg0 = mcpwm->timer[timer_id].timer_cfg0;
return cfg0.timer_prescale + 1;
}
static inline void mcpwm_ll_timer_set_peak(mcpwm_dev_t *mcpwm, int timer_id, uint32_t peak, bool symmetric)
{
if (!symmetric) { // in asymmetric mode, period = [0,peak-1]
mcpwm->timer[timer_id].period.period = peak - 1;
mcpwm->timer[timer_id].timer_cfg0.timer_period = peak - 1;
} else { // in symmetric mode, period = [0,peak-1] + [peak,1]
mcpwm->timer[timer_id].period.period = peak;
mcpwm->timer[timer_id].timer_cfg0.timer_period = peak;
}
}
@ -296,32 +296,32 @@ static inline uint32_t mcpwm_ll_timer_get_peak(mcpwm_dev_t *mcpwm, int timer_id,
{
// asymmetric mode
if (!symmetric) {
return mcpwm->timer[timer_id].period.period + 1;
return mcpwm->timer[timer_id].timer_cfg0.timer_period + 1;
}
// symmetric mode
return mcpwm->timer[timer_id].period.period;
return mcpwm->timer[timer_id].timer_cfg0.timer_period;
}
static inline void mcpwm_ll_timer_update_period_at_once(mcpwm_dev_t *mcpwm, int timer_id)
{
mcpwm->timer[timer_id].period.upmethod = 0;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod = 0;
}
static inline void mcpwm_ll_timer_enable_update_period_on_tez(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
{
if (enable) {
mcpwm->timer[timer_id].period.upmethod |= 0x01;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod |= 0x01;
} else {
mcpwm->timer[timer_id].period.upmethod &= ~0x01;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod &= ~0x01;
}
}
static inline void mcpwm_ll_timer_enable_update_period_on_sync(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
{
if (enable) {
mcpwm->timer[timer_id].period.upmethod |= 0x02;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod |= 0x02;
} else {
mcpwm->timer[timer_id].period.upmethod &= ~0x02;
mcpwm->timer[timer_id].timer_cfg0.timer_period_upmethod &= ~0x02;
}
}
@ -329,23 +329,23 @@ static inline void mcpwm_ll_timer_set_count_mode(mcpwm_dev_t *mcpwm, int timer_i
{
switch (mode) {
case MCPWM_TIMER_COUNT_MODE_PAUSE:
mcpwm->timer[timer_id].mode.mode = 0;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 0;
break;
case MCPWM_TIMER_COUNT_MODE_UP:
mcpwm->timer[timer_id].mode.mode = 1;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 1;
break;
case MCPWM_TIMER_COUNT_MODE_DOWN:
mcpwm->timer[timer_id].mode.mode = 2;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 2;
break;
case MCPWM_TIMER_COUNT_MODE_UP_DOWN:
mcpwm->timer[timer_id].mode.mode = 3;
mcpwm->timer[timer_id].timer_cfg1.timer_mod = 3;
break;
}
}
static inline mcpwm_timer_count_mode_t mcpwm_ll_timer_get_count_mode(mcpwm_dev_t *mcpwm, int timer_id)
{
switch (mcpwm->timer[timer_id].mode.mode) {
switch (mcpwm->timer[timer_id].timer_cfg1.timer_mod) {
case 0:
return MCPWM_TIMER_COUNT_MODE_PAUSE;
case 1:
@ -354,6 +354,9 @@ static inline mcpwm_timer_count_mode_t mcpwm_ll_timer_get_count_mode(mcpwm_dev_t
return MCPWM_TIMER_COUNT_MODE_DOWN;
case 3:
return MCPWM_TIMER_COUNT_MODE_UP_DOWN;
default:
HAL_ASSERT(false && "unknown count mode");
return mcpwm->timer[timer_id].timer_cfg1.timer_mod;
}
}
@ -361,19 +364,19 @@ static inline void mcpwm_ll_timer_set_execute_command(mcpwm_dev_t *mcpwm, int ti
{
switch (cmd) {
case MCPWM_TIMER_STOP_AT_ZERO:
mcpwm->timer[timer_id].mode.start = 0;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 0;
break;
case MCPWM_TIMER_STOP_AT_PEAK:
mcpwm->timer[timer_id].mode.start = 1;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 1;
break;
case MCPWM_TIMER_START_NO_STOP:
mcpwm->timer[timer_id].mode.start = 2;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 2;
break;
case MCPWM_TIMER_START_STOP_AT_ZERO:
mcpwm->timer[timer_id].mode.start = 3;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 3;
break;
case MCPWM_TIMER_START_STOP_AT_PEAK:
mcpwm->timer[timer_id].mode.start = 4;
mcpwm->timer[timer_id].timer_cfg1.timer_start = 4;
break;
}
}
@ -382,62 +385,62 @@ static inline uint32_t mcpwm_ll_timer_get_count_value(mcpwm_dev_t *mcpwm, int ti
{
// status.value saves the "next count value", so need an extra round up here to get the current count value according to count mode
// timer is paused
if (mcpwm->timer[timer_id].mode.mode == 0) {
return mcpwm->timer[timer_id].status.value;
if (mcpwm->timer[timer_id].timer_cfg1.timer_mod == 0) {
return mcpwm->timer[timer_id].timer_status.timer_value;
}
if (mcpwm->timer[timer_id].status.direction) { // down direction
return (mcpwm->timer[timer_id].status.value + 1) % (mcpwm->timer[timer_id].period.period + 1);
if (mcpwm->timer[timer_id].timer_status.timer_direction) { // down direction
return (mcpwm->timer[timer_id].timer_status.timer_value + 1) % (mcpwm->timer[timer_id].timer_cfg0.timer_period + 1);
}
// up direction
return (mcpwm->timer[timer_id].status.value + mcpwm->timer[timer_id].period.period) % (mcpwm->timer[timer_id].period.period + 1);
return (mcpwm->timer[timer_id].timer_status.timer_value + mcpwm->timer[timer_id].timer_cfg0.timer_period) % (mcpwm->timer[timer_id].timer_cfg0.timer_period + 1);
}
static inline mcpwm_timer_direction_t mcpwm_ll_timer_get_count_direction(mcpwm_dev_t *mcpwm, int timer_id)
{
return mcpwm->timer[timer_id].status.direction ? MCPWM_TIMER_DIRECTION_DOWN : MCPWM_TIMER_DIRECTION_UP;
return mcpwm->timer[timer_id].timer_status.timer_direction ? MCPWM_TIMER_DIRECTION_DOWN : MCPWM_TIMER_DIRECTION_UP;
}
static inline void mcpwm_ll_timer_enable_sync_input(mcpwm_dev_t *mcpwm, int timer_id, bool enable)
{
mcpwm->timer[timer_id].sync.in_en = enable;
mcpwm->timer[timer_id].timer_sync.timer_synci_en = enable;
}
static inline void mcpwm_ll_timer_sync_out_penetrate(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out is selected to sync_in
mcpwm->timer[timer_id].sync.out_sel = 0;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 0;
}
static inline void mcpwm_ll_timer_sync_out_on_timer_event(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_event_t event)
{
if (event == MCPWM_TIMER_EVENT_ZERO) {
mcpwm->timer[timer_id].sync.out_sel = 1;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 1;
} else if (event == MCPWM_TIMER_EVENT_PEAK) {
mcpwm->timer[timer_id].sync.out_sel = 2;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 2;
} else {
HAL_ASSERT(false);
HAL_ASSERT(false && "unknown sync out event");
}
}
static inline void mcpwm_ll_timer_disable_sync_out(mcpwm_dev_t *mcpwm, int timer_id)
{
// sync_out will always be zero
mcpwm->timer[timer_id].sync.out_sel = 3;
mcpwm->timer[timer_id].timer_sync.timer_synco_sel = 3;
}
static inline void mcpwm_ll_timer_trigger_soft_sync(mcpwm_dev_t *mcpwm, int timer_id)
{
mcpwm->timer[timer_id].sync.sync_sw = ~mcpwm->timer[timer_id].sync.sync_sw;
mcpwm->timer[timer_id].timer_sync.timer_sync_sw = ~mcpwm->timer[timer_id].timer_sync.timer_sync_sw;
}
static inline void mcpwm_ll_timer_set_sync_phase_value(mcpwm_dev_t *mcpwm, int timer_id, uint32_t phase_value)
{
mcpwm->timer[timer_id].sync.timer_phase = phase_value;
mcpwm->timer[timer_id].timer_sync.timer_phase = phase_value;
}
static inline void mcpwm_ll_timer_set_sync_phase_direction(mcpwm_dev_t *mcpwm, int timer_id, mcpwm_timer_direction_t direction)
{
mcpwm->timer[timer_id].sync.phase_direct = direction;
mcpwm->timer[timer_id].timer_sync.timer_phase_direction = direction;
}
static inline void mcpwm_ll_timer_set_gpio_synchro(mcpwm_dev_t *mcpwm, int timer, int gpio_sync_id)
@ -477,117 +480,117 @@ static inline void mcpwm_ll_operator_flush_shadow(mcpwm_dev_t *mcpwm, int operat
static inline void mcpwm_ll_operator_select_timer(mcpwm_dev_t *mcpwm, int operator_id, int timer_id)
{
if (operator_id == 0) {
mcpwm->timer_sel.operator0_sel = timer_id;
mcpwm->operator_timersel.operator0_timersel = timer_id;
} else if (operator_id == 1) {
mcpwm->timer_sel.operator1_sel = timer_id;
mcpwm->operator_timersel.operator1_timersel = timer_id;
} else {
mcpwm->timer_sel.operator2_sel = timer_id;
mcpwm->operator_timersel.operator2_timersel = timer_id;
}
}
static inline void mcpwm_ll_operator_update_compare_at_once(mcpwm_dev_t *mcpwm, int operator_id, int compare_id)
{
mcpwm->channel[operator_id].cmpr_cfg.val &= ~(0x0F << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~(0x0F << (4 * compare_id));
}
static inline void mcpwm_ll_operator_enable_update_compare_on_tez(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].cmpr_cfg.val |= (1 << 0) << (4 * compare_id);
mcpwm->operator[operator_id].gen_stmp_cfg.val |= (1 << 0) << (4 * compare_id);
} else {
mcpwm->channel[operator_id].cmpr_cfg.val &= ~((1 << 0) << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~((1 << 0) << (4 * compare_id));
}
}
static inline void mcpwm_ll_operator_enable_update_compare_on_tep(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].cmpr_cfg.val |= (1 << 1) << (4 * compare_id);
mcpwm->operator[operator_id].gen_stmp_cfg.val |= (1 << 1) << (4 * compare_id);
} else {
mcpwm->channel[operator_id].cmpr_cfg.val &= ~((1 << 1) << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~((1 << 1) << (4 * compare_id));
}
}
static inline void mcpwm_ll_operator_enable_update_compare_on_sync(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].cmpr_cfg.val |= (1 << 2) << (4 * compare_id);
mcpwm->operator[operator_id].gen_stmp_cfg.val |= (1 << 2) << (4 * compare_id);
} else {
mcpwm->channel[operator_id].cmpr_cfg.val &= ~((1 << 2) << (4 * compare_id));
mcpwm->operator[operator_id].gen_stmp_cfg.val &= ~((1 << 2) << (4 * compare_id));
}
}
static inline void mcpwm_ll_operator_set_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int compare_id, uint32_t compare_value)
{
mcpwm->channel[operator_id].cmpr_value[compare_id].cmpr_val = compare_value;
mcpwm->operator[operator_id].timestamp[compare_id].gen = compare_value;
}
static inline uint32_t mcpwm_ll_operator_get_compare_value(mcpwm_dev_t *mcpwm, int operator_id, int compare_id)
{
return mcpwm->channel[operator_id].cmpr_value[compare_id].cmpr_val;
return mcpwm->operator[operator_id].timestamp[compare_id].gen;
}
static inline void mcpwm_ll_operator_update_action_at_once(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].gen_cfg0.upmethod = 0;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod = 0;
}
static inline void mcpwm_ll_operator_enable_update_action_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].gen_cfg0.upmethod |= 1 << 0;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod |= 1 << 0;
} else {
mcpwm->channel[operator_id].gen_cfg0.upmethod &= ~(1 << 0);
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod &= ~(1 << 0);
}
}
static inline void mcpwm_ll_operator_enable_update_action_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].gen_cfg0.upmethod |= 1 << 1;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod |= 1 << 1;
} else {
mcpwm->channel[operator_id].gen_cfg0.upmethod &= ~(1 << 1);
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod &= ~(1 << 1);
}
}
static inline void mcpwm_ll_operator_enable_update_action_on_sync(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].gen_cfg0.upmethod |= 1 << 2;
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod |= 1 << 2;
} else {
mcpwm->channel[operator_id].gen_cfg0.upmethod &= ~(1 << 2);
mcpwm->operator[operator_id].gen_cfg0.gen_cfg_upmethod &= ~(1 << 2);
}
}
static inline void mcpwm_ll_operator_set_trigger_gpio_fault(mcpwm_dev_t *mcpwm, int operator_id, int trig_id, int fault_id)
{
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (fault_id << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val |= (fault_id << (4 + 3 * trig_id));
}
static inline void mcpwm_ll_operator_set_trigger_timer_sync(mcpwm_dev_t *mcpwm, int operator_id, int trig_id)
{
// the timer here is not selectable, must be the one connected with the operator
mcpwm->channel[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->channel[operator_id].gen_cfg0.val |= (3 << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val &= ~(0x07 << (4 + 3 * trig_id));
mcpwm->operator[operator_id].gen_cfg0.val |= (3 << (4 + 3 * trig_id));
}
/********************* Generator registers *******************/
static inline void mcpwm_ll_generator_reset_actions(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
mcpwm->channel[operator_id].generator[generator_id].val = 0;
mcpwm->operator[operator_id].generator[generator_id].val = 0;
}
static inline void mcpwm_ll_generator_set_action_on_timer_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_timer_event_t event, mcpwm_generator_action_t action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) { // utez, utep
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (event * 2);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (event * 2);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dtez, dtep
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2 + 12));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (event * 2 + 12);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (event * 2 + 12));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (event * 2 + 12);
}
}
@ -595,11 +598,11 @@ static inline void mcpwm_ll_generator_set_action_on_compare_event(mcpwm_dev_t *m
mcpwm_timer_direction_t direction, int cmp_id, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) { // utea, uteb
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 4));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 4);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 4));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 4);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dtea, dteb
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 16));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 16);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (cmp_id * 2 + 16));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (cmp_id * 2 + 16);
}
}
@ -607,58 +610,58 @@ static inline void mcpwm_ll_generator_set_action_on_trigger_event(mcpwm_dev_t *m
mcpwm_timer_direction_t direction, int trig_id, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) { // ut0, ut1
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 8));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 8);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 8));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 8);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) { // dt0, dt1
mcpwm->channel[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 20));
mcpwm->channel[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 20);
mcpwm->operator[operator_id].generator[generator_id].val &= ~(0x03 << (trig_id * 2 + 20));
mcpwm->operator[operator_id].generator[generator_id].val |= action << (trig_id * 2 + 20);
}
}
static inline void mcpwm_ll_gen_trigger_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce = ~mcpwm->channel[operator_id].gen_force.a_nciforce;
mcpwm->operator[operator_id].gen_force.gen_a_nciforce = ~mcpwm->operator[operator_id].gen_force.gen_a_nciforce;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce = ~mcpwm->channel[operator_id].gen_force.b_nciforce;
mcpwm->operator[operator_id].gen_force.gen_b_nciforce = ~mcpwm->operator[operator_id].gen_force.gen_b_nciforce;
}
}
static inline void mcpwm_ll_gen_disable_continue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
mcpwm->operator[operator_id].gen_force.gen_cntuforce_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_a_cntuforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_b_cntuforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_disable_noncontinue_force_action(mcpwm_dev_t *mcpwm, int operator_id, int generator_id)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_a_nciforce_mode = 0;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = 0;
mcpwm->operator[operator_id].gen_force.gen_b_nciforce_mode = 0;
}
}
static inline void mcpwm_ll_gen_set_continue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
mcpwm->channel[operator_id].gen_force.cntu_force_upmethod = 0; // update force method immediately
mcpwm->operator[operator_id].gen_force.gen_cntuforce_upmethod = 0; // update force method immediately
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_cntuforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_a_cntuforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_cntuforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_b_cntuforce_mode = level + 1;
}
}
static inline void mcpwm_ll_gen_set_noncontinue_force_level(mcpwm_dev_t *mcpwm, int operator_id, int generator_id, int level)
{
if (generator_id == 0) {
mcpwm->channel[operator_id].gen_force.a_nciforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_a_nciforce_mode = level + 1;
} else {
mcpwm->channel[operator_id].gen_force.b_nciforce_mode = level + 1;
mcpwm->operator[operator_id].gen_force.gen_b_nciforce_mode = level + 1;
}
}
@ -667,116 +670,116 @@ static inline void mcpwm_ll_gen_set_noncontinue_force_level(mcpwm_dev_t *mcpwm,
static inline void mcpwm_ll_deadtime_resolution_to_timer(mcpwm_dev_t *mcpwm, int operator_id, bool same)
{
// whether to make the resolution of dead time delay module the same to the timer connected with operator
mcpwm->channel[operator_id].db_cfg.clk_sel = same;
mcpwm->operator[operator_id].dt_cfg.dt_clk_sel = same;
}
static inline void mcpwm_ll_deadtime_red_select_generator(mcpwm_dev_t *mcpwm, int operator_id, int generator)
{
mcpwm->channel[operator_id].db_cfg.red_insel = generator;
mcpwm->operator[operator_id].dt_cfg.dt_red_insel = generator;
}
static inline void mcpwm_ll_deadtime_fed_select_generator(mcpwm_dev_t *mcpwm, int operator_id, int generator)
{
mcpwm->channel[operator_id].db_cfg.fed_insel = generator;
mcpwm->operator[operator_id].dt_cfg.dt_fed_insel = generator;
}
static inline void mcpwm_ll_deadtime_bypass_path(mcpwm_dev_t *mcpwm, int operator_id, int path, bool bypass)
{
if (bypass) {
mcpwm->channel[operator_id].db_cfg.val |= 1 << (path + 15);
mcpwm->operator[operator_id].dt_cfg.val |= 1 << (path + 15);
} else {
mcpwm->channel[operator_id].db_cfg.val &= ~(1 << (path + 15));
mcpwm->operator[operator_id].dt_cfg.val &= ~(1 << (path + 15));
}
}
static inline void mcpwm_ll_deadtime_invert_outpath(mcpwm_dev_t *mcpwm, int operator_id, int path, bool invert)
{
if (invert) {
mcpwm->channel[operator_id].db_cfg.val |= 1 << (path + 13);
mcpwm->operator[operator_id].dt_cfg.val |= 1 << (path + 13);
} else {
mcpwm->channel[operator_id].db_cfg.val &= ~(1 << (path + 13));
mcpwm->operator[operator_id].dt_cfg.val &= ~(1 << (path + 13));
}
}
static inline void mcpwm_ll_deadtime_swap_out_path(mcpwm_dev_t *mcpwm, int operator_id, int path, bool swap)
{
if (swap) {
mcpwm->channel[operator_id].db_cfg.val |= 1 << (path + 9);
mcpwm->operator[operator_id].dt_cfg.val |= 1 << (path + 9);
} else {
mcpwm->channel[operator_id].db_cfg.val &= ~(1 << (path + 9));
mcpwm->operator[operator_id].dt_cfg.val &= ~(1 << (path + 9));
}
}
static inline void mcpwm_ll_deadtime_enable_deb(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].db_cfg.deb_mode = enable;
mcpwm->operator[operator_id].dt_cfg.dt_deb_mode = enable;
}
static inline uint32_t mcpwm_ll_deadtime_get_switch_topology(mcpwm_dev_t *mcpwm, int operator_id)
{
return (mcpwm->channel[operator_id].db_cfg.deb_mode << 8) | (mcpwm->channel[operator_id].db_cfg.b_outswap << 7) |
(mcpwm->channel[operator_id].db_cfg.a_outswap << 6) | (mcpwm->channel[operator_id].db_cfg.fed_insel << 5) |
(mcpwm->channel[operator_id].db_cfg.red_insel << 4) | (mcpwm->channel[operator_id].db_cfg.fed_outinvert << 3) |
(mcpwm->channel[operator_id].db_cfg.red_outinvert << 2) | (mcpwm->channel[operator_id].db_cfg.a_outbypass << 1) |
(mcpwm->channel[operator_id].db_cfg.b_outbypass << 0);
return (mcpwm->operator[operator_id].dt_cfg.dt_deb_mode << 8) | (mcpwm->operator[operator_id].dt_cfg.dt_b_outswap << 7) |
(mcpwm->operator[operator_id].dt_cfg.dt_a_outswap << 6) | (mcpwm->operator[operator_id].dt_cfg.dt_fed_insel << 5) |
(mcpwm->operator[operator_id].dt_cfg.dt_red_insel << 4) | (mcpwm->operator[operator_id].dt_cfg.dt_fed_outinvert << 3) |
(mcpwm->operator[operator_id].dt_cfg.dt_red_outinvert << 2) | (mcpwm->operator[operator_id].dt_cfg.dt_a_outbypass << 1) |
(mcpwm->operator[operator_id].dt_cfg.dt_b_outbypass << 0);
}
static inline void mcpwm_ll_deadtime_set_falling_delay(mcpwm_dev_t *mcpwm, int operator_id, uint32_t fed)
{
mcpwm->channel[operator_id].db_fed_cfg.fed = fed - 1;
mcpwm->operator[operator_id].dt_fed_cfg.dt_fed = fed - 1;
}
static inline uint32_t mcpwm_ll_deadtime_get_falling_delay(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].db_fed_cfg.fed + 1;
return mcpwm->operator[operator_id].dt_fed_cfg.dt_fed + 1;
}
static inline void mcpwm_ll_deadtime_set_rising_delay(mcpwm_dev_t *mcpwm, int operator_id, uint32_t red)
{
mcpwm->channel[operator_id].db_red_cfg.red = red - 1;
mcpwm->operator[operator_id].dt_red_cfg.dt_red = red - 1;
}
static inline uint32_t mcpwm_ll_deadtime_get_rising_delay(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].db_red_cfg.red + 1;
return mcpwm->operator[operator_id].dt_red_cfg.dt_red + 1;
}
static inline void mcpwm_ll_deadtime_update_delay_at_once(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].db_cfg.fed_upmethod = 0;
mcpwm->channel[operator_id].db_cfg.red_upmethod = 0;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod = 0;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod = 0;
}
static inline void mcpwm_ll_deadtime_enable_update_delay_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].db_cfg.fed_upmethod |= 1 << 0;
mcpwm->channel[operator_id].db_cfg.red_upmethod |= 1 << 0;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod |= 1 << 0;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod |= 1 << 0;
} else {
mcpwm->channel[operator_id].db_cfg.fed_upmethod &= ~(1 << 0);
mcpwm->channel[operator_id].db_cfg.red_upmethod &= ~(1 << 0);
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod &= ~(1 << 0);
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod &= ~(1 << 0);
}
}
static inline void mcpwm_ll_deadtime_enable_update_delay_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].db_cfg.fed_upmethod |= 1 << 1;
mcpwm->channel[operator_id].db_cfg.red_upmethod |= 1 << 1;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod |= 1 << 1;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod |= 1 << 1;
} else {
mcpwm->channel[operator_id].db_cfg.fed_upmethod &= ~(1 << 1);
mcpwm->channel[operator_id].db_cfg.red_upmethod &= ~(1 << 1);
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod &= ~(1 << 1);
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod &= ~(1 << 1);
}
}
static inline void mcpwm_ll_deadtime_enable_update_delay_on_sync(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].db_cfg.fed_upmethod |= 1 << 2;
mcpwm->channel[operator_id].db_cfg.red_upmethod |= 1 << 2;
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod |= 1 << 2;
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod |= 1 << 2;
} else {
mcpwm->channel[operator_id].db_cfg.fed_upmethod &= ~(1 << 2);
mcpwm->channel[operator_id].db_cfg.red_upmethod &= ~(1 << 2);
mcpwm->operator[operator_id].dt_cfg.dt_fed_upmethod &= ~(1 << 2);
mcpwm->operator[operator_id].dt_cfg.dt_red_upmethod &= ~(1 << 2);
}
}
@ -784,47 +787,47 @@ static inline void mcpwm_ll_deadtime_enable_update_delay_on_sync(mcpwm_dev_t *mc
static inline void mcpwm_ll_carrier_enable(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].carrier_cfg.en = enable;
mcpwm->operator[operator_id].carrier_cfg.carrier_en = enable;
}
static inline void mcpwm_ll_carrier_set_prescale(mcpwm_dev_t *mcpwm, int operator_id, uint8_t prescale)
{
mcpwm->channel[operator_id].carrier_cfg.prescale = prescale - 1;
mcpwm->operator[operator_id].carrier_cfg.carrier_prescale = prescale - 1;
}
static inline uint8_t mcpwm_ll_carrier_get_prescale(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].carrier_cfg.prescale + 1;
return mcpwm->operator[operator_id].carrier_cfg.carrier_prescale + 1;
}
static inline void mcpwm_ll_carrier_set_duty(mcpwm_dev_t *mcpwm, int operator_id, uint8_t carrier_duty)
{
mcpwm->channel[operator_id].carrier_cfg.duty = carrier_duty;
mcpwm->operator[operator_id].carrier_cfg.carrier_duty = carrier_duty;
}
static inline uint8_t mcpwm_ll_carrier_get_duty(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].carrier_cfg.duty;
return mcpwm->operator[operator_id].carrier_cfg.carrier_duty;
}
static inline void mcpwm_ll_carrier_out_invert(mcpwm_dev_t *mcpwm, int operator_id, bool invert)
{
mcpwm->channel[operator_id].carrier_cfg.out_invert = invert;
mcpwm->operator[operator_id].carrier_cfg.carrier_out_invert = invert;
}
static inline void mcpwm_ll_carrier_in_invert(mcpwm_dev_t *mcpwm, int operator_id, bool invert)
{
mcpwm->channel[operator_id].carrier_cfg.in_invert = invert;
mcpwm->operator[operator_id].carrier_cfg.carrier_in_invert = invert;
}
static inline void mcpwm_ll_carrier_set_oneshot_width(mcpwm_dev_t *mcpwm, int operator_id, uint8_t pulse_width)
{
mcpwm->channel[operator_id].carrier_cfg.oshtwth = pulse_width - 1;
mcpwm->operator[operator_id].carrier_cfg.carrier_oshtwth = pulse_width - 1;
}
static inline uint8_t mcpwm_ll_carrier_get_oneshot_width(mcpwm_dev_t *mcpwm, int operator_id)
{
return mcpwm->channel[operator_id].carrier_cfg.oshtwth + 1;
return mcpwm->operator[operator_id].carrier_cfg.carrier_oshtwth + 1;
}
/********************* Fault detector registers *******************/
@ -850,155 +853,155 @@ static inline void mcpwm_ll_fault_set_active_level(mcpwm_dev_t *mcpwm, int fault
static inline void mcpwm_ll_fault_clear_ost(mcpwm_dev_t *mcpwm, int operator_id)
{
// a posedge can clear the ost fault status
mcpwm->channel[operator_id].tz_cfg1.clr_ost = 0;
mcpwm->channel[operator_id].tz_cfg1.clr_ost = 1;
mcpwm->operator[operator_id].fh_cfg1.fh_clr_ost = 0;
mcpwm->operator[operator_id].fh_cfg1.fh_clr_ost = 1;
}
static inline void mcpwm_ll_fault_enable_oneshot_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (7 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (7 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val &= ~(1 << (7 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val |= (enable << (7 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_mode(mcpwm_dev_t *mcpwm, int operator_id, int fault_sig, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.val &= ~(1 << (3 - fault_sig));
mcpwm->channel[operator_id].tz_cfg0.val |= (enable << (3 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val &= ~(1 << (3 - fault_sig));
mcpwm->operator[operator_id].fh_cfg0.val |= (enable << (3 - fault_sig));
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tez(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 1;
mcpwm->operator[operator_id].fh_cfg1.val |= 1 << 1;
} else {
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 1);
mcpwm->operator[operator_id].fh_cfg1.val &= ~(1 << 1);
}
}
static inline void mcpwm_ll_fault_enable_cbc_refresh_on_tep(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
if (enable) {
mcpwm->channel[operator_id].tz_cfg1.val |= 1 << 2;
mcpwm->operator[operator_id].fh_cfg1.val |= 1 << 2;
} else {
mcpwm->channel[operator_id].tz_cfg1.val &= ~(1 << 2);
mcpwm->operator[operator_id].fh_cfg1.val &= ~(1 << 2);
}
}
static inline void mcpwm_ll_fault_enable_sw_cbc(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.sw_cbc = enable;
mcpwm->operator[operator_id].fh_cfg0.fh_sw_cbc = enable;
}
static inline void mcpwm_ll_fault_enable_sw_oneshot(mcpwm_dev_t *mcpwm, int operator_id, bool enable)
{
mcpwm->channel[operator_id].tz_cfg0.sw_ost = enable;
mcpwm->operator[operator_id].fh_cfg0.fh_sw_ost = enable;
}
static inline void mcpwm_ll_fault_trigger_sw_cbc(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].tz_cfg1.force_cbc = ~mcpwm->channel[operator_id].tz_cfg1.force_cbc;
mcpwm->operator[operator_id].fh_cfg1.fh_force_cbc = ~mcpwm->operator[operator_id].fh_cfg1.fh_force_cbc;
}
static inline void mcpwm_ll_fault_trigger_sw_ost(mcpwm_dev_t *mcpwm, int operator_id)
{
mcpwm->channel[operator_id].tz_cfg1.force_ost = ~mcpwm->channel[operator_id].tz_cfg1.force_ost;
mcpwm->operator[operator_id].fh_cfg1.fh_force_ost = ~mcpwm->operator[operator_id].fh_cfg1.fh_force_ost;
}
static inline void mcpwm_ll_generator_set_action_on_trip_event(mcpwm_dev_t *mcpwm, int operator_id, int generator_id,
mcpwm_timer_direction_t direction, mcpwm_trip_type_t trip, int action)
{
if (direction == MCPWM_TIMER_DIRECTION_UP) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip + 2));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip + 2);
mcpwm->operator[operator_id].fh_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip + 2));
mcpwm->operator[operator_id].fh_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip + 2);
} else if (direction == MCPWM_TIMER_DIRECTION_DOWN) {
mcpwm->channel[operator_id].tz_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip));
mcpwm->channel[operator_id].tz_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip);
mcpwm->operator[operator_id].fh_cfg0.val &= ~(0x03 << (8 + 8 * generator_id + 4 * trip));
mcpwm->operator[operator_id].fh_cfg0.val |= action << (8 + 8 * generator_id + 4 * trip);
}
}
static inline bool mcpwm_ll_fault_is_ost_on(mcpwm_dev_t *mcpwm, int op)
{
return mcpwm->channel[op].tz_status.ost_on;
return mcpwm->operator[op].fh_status.fh_ost_on;
}
static inline bool mcpwm_ll_fault_is_cbc_on(mcpwm_dev_t *mcpwm, int op)
{
return mcpwm->channel[op].tz_status.cbc_on;
return mcpwm->operator[op].fh_status.fh_cbc_on;
}
/********************* Capture registers *******************/
static inline void mcpwm_ll_capture_enable_timer(mcpwm_dev_t *mcpwm, bool enable)
{
mcpwm->cap_timer_cfg.timer_en = enable;
mcpwm->cap_timer_cfg.cap_timer_en = enable;
}
static inline void mcpwm_ll_capture_enable_channel(mcpwm_dev_t *mcpwm, int channel, bool enable)
{
mcpwm->cap_cfg_ch[channel].en = enable;
mcpwm->cap_chn_cfg[channel].capn_en = enable;
}
static inline void mcpwm_ll_capture_set_sync_phase_value(mcpwm_dev_t *mcpwm, uint32_t phase_value)
{
mcpwm->cap_timer_phase = phase_value;
mcpwm->cap_timer_phase.cap_timer_phase = phase_value;
}
static inline uint32_t mcpwm_ll_capture_get_sync_phase_value(mcpwm_dev_t *mcpwm)
{
return mcpwm->cap_timer_phase;
return mcpwm->cap_timer_phase.cap_timer_phase;
}
static inline void mcpwm_ll_capture_enable_timer_sync(mcpwm_dev_t *mcpwm, bool enable)
{
mcpwm->cap_timer_cfg.synci_en = enable;
mcpwm->cap_timer_cfg.cap_synci_en = enable;
}
static inline void mcpwm_ll_capture_set_internal_timer_synchro(mcpwm_dev_t *mcpwm, int sync_out_timer)
{
mcpwm->cap_timer_cfg.synci_sel = sync_out_timer + 1;
mcpwm->cap_timer_cfg.cap_synci_sel = sync_out_timer + 1;
}
static inline void mcpwm_ll_capture_set_external_synchro(mcpwm_dev_t *mcpwm, int extern_synchro)
{
mcpwm->cap_timer_cfg.synci_sel = extern_synchro + 4;
mcpwm->cap_timer_cfg.cap_synci_sel = extern_synchro + 4;
}
static inline void mcpwm_ll_capture_trigger_sw_sync(mcpwm_dev_t *mcpwm)
{
mcpwm->cap_timer_cfg.sync_sw = 1; // auto clear
mcpwm->cap_timer_cfg.cap_sync_sw = 1; // auto clear
}
static inline void mcpwm_ll_capture_enable_posedge(mcpwm_dev_t *mcpwm, int channel, bool enable)
{
if (enable) {
mcpwm->cap_cfg_ch[channel].val |= 1 << 2;
mcpwm->cap_chn_cfg[channel].val |= 1 << 2;
} else {
mcpwm->cap_cfg_ch[channel].val &= ~(1 << 2);
mcpwm->cap_chn_cfg[channel].val &= ~(1 << 2);
}
}
static inline void mcpwm_ll_capture_enable_negedge(mcpwm_dev_t *mcpwm, int channel, bool enable)
{
if (enable) {
mcpwm->cap_cfg_ch[channel].val |= 1 << 1;
mcpwm->cap_chn_cfg[channel].val |= 1 << 1;
} else {
mcpwm->cap_cfg_ch[channel].val &= ~(1 << 1);
mcpwm->cap_chn_cfg[channel].val &= ~(1 << 1);
}
}
static inline void mcpwm_ll_invert_input(mcpwm_dev_t *mcpwm, int channel, bool invert)
{
mcpwm->cap_cfg_ch[channel].in_invert = invert;
mcpwm->cap_chn_cfg[channel].capn_in_invert = invert;
}
static inline void mcpwm_ll_trigger_soft_capture(mcpwm_dev_t *mcpwm, int channel)
{
mcpwm->cap_cfg_ch[channel].sw = 1; // auto clear
mcpwm->cap_chn_cfg[channel].capn_sw = 1; // auto clear
}
static inline uint32_t mcpwm_ll_capture_get_value(mcpwm_dev_t *mcpwm, int channel)
{
return mcpwm->cap_val_ch[channel];
return mcpwm->cap_chn[channel].capn_value;
}
static inline bool mcpwm_ll_capture_is_negedge(mcpwm_dev_t *mcpwm, int channel)
@ -1008,12 +1011,12 @@ static inline bool mcpwm_ll_capture_is_negedge(mcpwm_dev_t *mcpwm, int channel)
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int channel, uint32_t prescale)
{
mcpwm->cap_cfg_ch[channel].prescale = prescale - 1;
mcpwm->cap_chn_cfg[channel].capn_prescale = prescale - 1;
}
static inline uint32_t mcpwm_ll_capture_get_prescale(mcpwm_dev_t *mcpwm, int channel)
{
return mcpwm->cap_cfg_ch[channel].prescale + 1;
return mcpwm->cap_chn_cfg[channel].capn_prescale + 1;
}
#ifdef __cplusplus

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -179,7 +179,7 @@ Application Example
MCPWM example are located under: :example:`peripherals/mcpwm`:
* Demonstration how to use each submodule of the MCPWM - :example:`peripherals/mcpwm/mcpwm_basic_config`
* Control of BLDC (brushless DC) motor with hall sensor feedback - :example:`peripherals/mcpwm/mcpwm_bldc_control`
* Control of BLDC (brushless DC) motor with hall sensor feedback - :example:`peripherals/mcpwm/mcpwm_bldc_hall_control`
* Brushed DC motor control - :example:`peripherals/mcpwm/mcpwm_brushed_dc_control`
* Servo motor control - :example:`peripherals/mcpwm/mcpwm_servo_control`
* HC-SR04 sensor with capture - :example:`peripherals/mcpwm/mcpwm_capture_hc_sr04`

View File

@ -1,46 +0,0 @@
| Supported Targets | ESP32 | ESP32-S3 |
| ----------------- | ----- | -------- |
# MCPWM BLDC motor control (hall sensor feedback) Example
This example will show you how to use MCPWM module to control BLDC motor with hall sensor feedback.
The following examples uses MCPWM module to control bldc motor and vary its speed continuously
The bldc motor used for testing this code had hall sensor capture sequence of 6-->4-->5-->1-->3-->2-->6-->4--> and so on
IR2136 3-ph bridge driver is used for testing this example code
User needs to make changes according to the motor and gate driver ic used
## Step 1: Pin assignment
* The gpio init function initializes:
* GPIO15 is assigned as the MCPWM signal for 1H(UH)
* GPIO02 is assigned as the MCPWM signal for 1L(UL)
* GPIO00 is assigned as the MCPWM signal for 2H(VH)
* GPIO04 is assigned as the MCPWM signal for 2L(VL)
* GPIO16 is assigned as the MCPWM signal for 3H(WH)
* GPIO17 is assigned as the MCPWM signal for 3L(WL)
* GPIO25 is assigned as the MCPWM capture signal for Hall A
* GPIO26 is assigned as the MCPWM capture signal for HALL B
* GPIO27 is assigned as the MCPWM capture signal for HALL C
## Step 2: Connection
* Connect GPIO15 with 1H/UH of BLDC motor driver
* Connect GPIO02 with 1L/UL of BLDC motor driver
* Connect GPIO00 with 2H/VH of BLDC motor driver
* Connect GPIO04 with 2L/VL of BLDC motor driver
* Connect GPIO16 with 3H/WH of BLDC motor driver
* Connect GPIO17 with 3L/WL of BLDC motor driver
* Connect GPIO25 to hall sensor A output
* Connect GPIO26 to hall sensor B output
* Connect GPIO27 to hall sensor C output
## Step 3: Initialize MCPWM
* You need to set the frequency and duty cycle of MCPWM timer
* You need to set the MCPWM channel you want to use, and bind the channel with one of the timers
* You need to set the capture unit, for POS/NEG edge capture
* Also reversing the hall sensor BIT weight, will make bldc motor rotate CW or CCW

View File

@ -1,2 +0,0 @@
idf_component_register(SRCS "mcpwm_bldc_control_hall_sensor_example.c"
INCLUDE_DIRS ".")

View File

@ -1,319 +0,0 @@
/* MCPWM BLDC control Test code
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* The following examples uses mcpwm module to control bldc motor vary its speed continiously
* The BLDC motor used for testing this code had sequence of 6-->4-->5-->1-->3-->2-->6-->4--> and so on
* IR2136 3-ph bridge driver is used for testing this example code
* User needs to make changes according to the motor and gate driver ic used
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/rtc.h"
#include "driver/mcpwm.h"
#define INITIAL_DUTY 10.0 //initial duty cycle is 10.0%
#define MCPWM_GPIO_INIT 0 //select which function to use to initialize gpio signals
#define GPIO_HALL_TEST_SIGNAL 0 //Make this 1 to enable generation of hall sensors test signal on GPIO13, 12, 14
#define CHANGE_DUTY_CONTINUOUSLY 0 //Make this 1 to change duty continuously
#define CAP_SIG_NUM 3 //three capture signals from HALL-A, HALL-B, HALL-C
#define CAP0_INT_EN BIT(27) //Capture 0 interrupt bit
#define CAP1_INT_EN BIT(28) //Capture 1 interrupt bit
#define CAP2_INT_EN BIT(29) //Capture 2 interrupt bit
#define GPIO_PWM0A_OUT 15 //Set GPIO 15 as PWM0A
#define GPIO_PWM0B_OUT 02 //Set GPIO 02 as PWM0B
#define GPIO_PWM1A_OUT 00 //Set GPIO 00 as PWM1A
#define GPIO_PWM1B_OUT 04 //Set GPIO 04 as PWM1B
#define GPIO_PWM2A_OUT 16 //Set GPIO 16 as PWM2A
#define GPIO_PWM2B_OUT 17 //Set GPIO 17 as PWM2B
#define GPIO_CAP0_IN 25 //Set GPIO 25 as CAP0
#define GPIO_CAP1_IN 26 //Set GPIO 26 as CAP1
#define GPIO_CAP2_IN 27 //Set GPIO 27 as CAP2
typedef struct {
uint32_t capture_signal;
mcpwm_capture_signal_t sel_cap_signal;
} capture;
static uint32_t hall_sensor_value = 0;
static uint32_t hall_sensor_previous = 0;
xQueueHandle cap_queue;
static void mcpwm_example_gpio_initialize(void)
{
printf("initializing mcpwm bldc control gpio...\n");
#if MCPWM_GPIO_INIT
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_PWM1A_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1B, GPIO_PWM1B_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM2A, GPIO_PWM2A_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM2B, GPIO_PWM2B_OUT);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, GPIO_CAP0_IN);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_1, GPIO_CAP1_IN);
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_2, GPIO_CAP2_IN);
#else
mcpwm_pin_config_t pin_config = {
.mcpwm0a_out_num = GPIO_PWM0A_OUT,
.mcpwm0b_out_num = GPIO_PWM0B_OUT,
.mcpwm1a_out_num = GPIO_PWM1A_OUT,
.mcpwm1b_out_num = GPIO_PWM1B_OUT,
.mcpwm2a_out_num = GPIO_PWM2A_OUT,
.mcpwm2b_out_num = GPIO_PWM2B_OUT,
.mcpwm_cap0_in_num = GPIO_CAP0_IN,
.mcpwm_cap1_in_num = GPIO_CAP1_IN,
.mcpwm_cap2_in_num = GPIO_CAP2_IN,
.mcpwm_sync0_in_num = -1, //Not used
.mcpwm_sync1_in_num = -1, //Not used
.mcpwm_sync2_in_num = -1, //Not used
.mcpwm_fault0_in_num = -1, //Not used
.mcpwm_fault1_in_num = -1, //Not used
.mcpwm_fault2_in_num = -1 //Not used
};
mcpwm_set_pin(MCPWM_UNIT_0, &pin_config);
#endif
gpio_pulldown_en(GPIO_CAP0_IN); //Enable pull down on CAP0 signal
gpio_pulldown_en(GPIO_CAP1_IN); //Enable pull down on CAP1 signal
gpio_pulldown_en(GPIO_CAP2_IN); //Enable pull down on CAP2 signal
}
#if GPIO_HALL_TEST_SIGNAL
/**
* @brief Set gpio 13, 12, 14 as our test signal of hall sensors, that generates high-low waveform continuously
* Attach this pins to GPIO 27, 26, 25 respectively for capture unit
*/
static void gpio_test_signal(void *arg)
{
printf("intializing test signal...\n");
gpio_config_t gp;
gp.intr_type = GPIO_INTR_DISABLE;
gp.mode = GPIO_MODE_OUTPUT;
gp.pin_bit_mask = GPIO_SEL_13 | GPIO_SEL_12 | GPIO_SEL_14;
gpio_config(&gp);
while (1) {
gpio_set_level(GPIO_NUM_13, 1); //Set H1 high
gpio_set_level(GPIO_NUM_12, 0); //Set H2 low
gpio_set_level(GPIO_NUM_14, 1); //Set H3 high
vTaskDelay(1);
gpio_set_level(GPIO_NUM_14, 0); //Set H3 low
vTaskDelay(1);
gpio_set_level(GPIO_NUM_12, 1); //Set H2 high
vTaskDelay(1);
gpio_set_level(GPIO_NUM_13, 0); //Set H1 low
vTaskDelay(1);
gpio_set_level(GPIO_NUM_14, 1); //Set H3 high
vTaskDelay(1);
gpio_set_level(GPIO_NUM_12, 0); //Set H2 high
vTaskDelay(1);
}
}
#endif
/**
* @brief When interrupt occurs, we receive the counter value and display the time between two rising edge
*/
static void disp_captured_signal(void *arg)
{
uint32_t *current_cap_value = (uint32_t *)malloc(sizeof(CAP_SIG_NUM));
uint32_t *previous_cap_value = (uint32_t *)malloc(sizeof(CAP_SIG_NUM));
capture evt;
while (1) {
xQueueReceive(cap_queue, &evt, portMAX_DELAY);
if (evt.sel_cap_signal == MCPWM_SELECT_CAP0) {
current_cap_value[0] = evt.capture_signal - previous_cap_value[0];
previous_cap_value[0] = evt.capture_signal;
current_cap_value[0] = (current_cap_value[0] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
//printf("CAP0 : %d us\n", current_cap_value[0]);
}
if (evt.sel_cap_signal == MCPWM_SELECT_CAP1) {
current_cap_value[1] = evt.capture_signal - previous_cap_value[1];
previous_cap_value[1] = evt.capture_signal;
current_cap_value[1] = (current_cap_value[1] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
//printf("CAP1 : %d us\n", current_cap_value[1]);
}
if (evt.sel_cap_signal == MCPWM_SELECT_CAP2) {
current_cap_value[2] = evt.capture_signal - previous_cap_value[2];
previous_cap_value[2] = evt.capture_signal;
current_cap_value[2] = (current_cap_value[2] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
//printf("CAP2 : %d us\n", current_cap_value[2]);
}
}
}
/**
* @brief this is ISR handler function, here we check for interrupt that triggers rising edge on CAP0 signal and according take action
*/
static bool isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata, void *arg)
{
capture evt;
if (cap_sig == MCPWM_SELECT_CAP0) { //Check for interrupt on rising edge on CAP0 signal
evt.capture_signal = edata->cap_value; //get capture signal counter value
evt.sel_cap_signal = MCPWM_SELECT_CAP0;
xQueueSendFromISR(cap_queue, &evt, NULL);
}
if (cap_sig == MCPWM_SELECT_CAP1) { //Check for interrupt on rising edge on CAP1 signal
evt.capture_signal = edata->cap_value; //get capture signal counter value
evt.sel_cap_signal = MCPWM_SELECT_CAP1;
xQueueSendFromISR(cap_queue, &evt, NULL);
}
if (cap_sig == MCPWM_SELECT_CAP2) { //Check for interrupt on rising edge on CAP2 signal
evt.capture_signal = edata->cap_value; //get capture signal counter value
evt.sel_cap_signal = MCPWM_SELECT_CAP2;
xQueueSendFromISR(cap_queue, &evt, NULL);
}
return false;
}
#if CHANGE_DUTY_CONTINUOUSLY
static void change_duty(void *arg)
{
int j;
while (1) {
for (j = 0; j < 18; j++) {
//printf("duty cycle: %d\n", (0 +j*50));
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, (INITIAL_DUTY + j * 5.0));
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, (INITIAL_DUTY + j * 5.0));
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A, (INITIAL_DUTY + j * 5.0));
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_B, (INITIAL_DUTY + j * 5.0));
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_A, (INITIAL_DUTY + j * 5.0));
mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_B, (INITIAL_DUTY + j * 5.0));
vTaskDelay(500 / portTICK_RATE_MS);
}
}
}
#endif
/**
* @brief Configure whole MCPWM module for bldc motor control
*/
static void mcpwm_example_bldc_control(void *arg)
{
//1. mcpwm gpio initialization
mcpwm_example_gpio_initialize();
//2. initial mcpwm configuration
printf("Configuring Initial Parameters of mcpwm bldc control...\n");
mcpwm_config_t pwm_config;
pwm_config.frequency = 14400; //frequency = 1000Hz
pwm_config.cmpr_a = 50.0; //duty cycle of PWMxA = 50.0%
pwm_config.cmpr_b = 50.0; //duty cycle of PWMxb = 50.0%
pwm_config.counter_mode = MCPWM_UP_COUNTER;
pwm_config.duty_mode = MCPWM_DUTY_MODE_1;
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config); //Configure PWM1A & PWM1B with above settings
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_2, &pwm_config); //Configure PWM2A & PWM2B with above settings
//3. Capture configuration
//configure CAP0, CAP1 and CAP2 signal to start capture counter on rising edge
//we generate a gpio_test_signal of 20ms on GPIO 12 and connect it to one of the capture signal, the disp_captured_function displays the time between rising edge
//In general practice you can connect Capture to external signal, measure time between rising edge or falling edge and take action accordingly
mcpwm_capture_config_t conf = {
.cap_edge = MCPWM_POS_EDGE,
.cap_prescale = 1,
.capture_cb = isr_handler,
.user_data = NULL,
};
mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &conf); //capture signal on rising edge, pulse num = 0 i.e. 800,000,000 counts is equal to one second
mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP1, &conf); //capture signal on rising edge, pulse num = 0 i.e. 800,000,000 counts is equal to one second
mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP2, &conf); //capture signal on rising edge, pulse num = 0 i.e. 800,000,000 counts is equal to one second
//According to the hall sensor input value take action on PWM0A/0B/1A/1B/2A/2B
while (1) {
hall_sensor_value = (gpio_get_level(GPIO_NUM_27) * 1) + (gpio_get_level(GPIO_NUM_26) * 2) + (gpio_get_level(GPIO_NUM_25) * 4);
if (hall_sensor_value != hall_sensor_previous) {
//printf("hall_sen val: %d\n", hall_sensor_value);
if (hall_sensor_value == 2) {
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_A);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_B);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A);
mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_B);
//MCPWMXA to duty mode 1 and MCPWMXB to duty mode 0 or vice versa will generate MCPWM compliment signal of each other, there are also other ways to do it
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MCPWM_DUTY_MODE_1); //Set PWM0A to duty mode one
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //Set PWM0B back to duty mode zero
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_BYPASS_FED, 100, 100); //Deadtime of 10us
}
if (hall_sensor_value == 6) {
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
mcpwm_deadtime_disable(MCPWM_UNIT_0, MCPWM_TIMER_0);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A);
mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_B);
//MCPWMXA to duty mode 1 and MCPWMXB to duty mode 0 or vice versa will generate MCPWM compliment signal of each other, there are also other ways to do it
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_A, MCPWM_DUTY_MODE_1); //Set PWM2A to duty mode one
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //Set PWM2B back to duty mode zero
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_BYPASS_FED, 100, 100); //Deadtime of 10us
}
if (hall_sensor_value == 4) {
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_B);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
//MCPWMXA to duty mode 1 and MCPWMXB to duty mode 0 or vice versa will generate MCPWM compliment signal of each other, there are also other ways to do it
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_A, MCPWM_DUTY_MODE_1); //Set PWM2A to duty mode one
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //Set PWM2B back to duty mode zero
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_BYPASS_FED, 100, 100); //Deadtime of 10us
}
if (hall_sensor_value == 5) {
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_A);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_B);
mcpwm_deadtime_disable(MCPWM_UNIT_0, MCPWM_TIMER_2);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
//MCPWMXA to duty mode 1 and MCPWMXB to duty mode 0 or vice versa will generate MCPWM compliment signal of each other, there are also other ways to do it
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A, MCPWM_DUTY_MODE_1); //Set PWM1A to duty mode one
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //Set PWM1B back to duty mode zero
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_BYPASS_FED, 100, 100); //Deadtime of 10uss
}
if (hall_sensor_value == 1) {
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_A);
mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_B);
//MCPWMXA to duty mode 1 and MCPWMXB to duty mode 0 or vice versa will generate MCPWM compliment signal of each other, there are also other ways to do it
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A, MCPWM_DUTY_MODE_1); //Set PWM1A to duty mode one
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //Set PWM1B back to duty mode zero
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_BYPASS_FED, 100, 100); //Deadtime of 10uss
}
if (hall_sensor_value == 3) {
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_B);
mcpwm_deadtime_disable(MCPWM_UNIT_0, MCPWM_TIMER_1);
mcpwm_set_signal_low(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_A);
mcpwm_set_signal_high(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_OPR_B);
//MCPWMXA to duty mode 1 and MCPWMXB to duty mode 0 or vice versa will generate MCPWM compliment signal of each other, there are also other ways to do it
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MCPWM_DUTY_MODE_1); //Set PWM0A to duty mode one
mcpwm_set_duty_type(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_B, MCPWM_DUTY_MODE_0); //Set PWM0B back to duty mode zero
mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_BYPASS_FED, 100, 100); //Deadtime of 10us
}
hall_sensor_previous = hall_sensor_value;
}
}
}
void app_main(void)
{
printf("Testing MCPWM BLDC Control...\n");
#if CHANGE_DUTY_CONTINUOUSLY
xTaskCreate(change_duty, "change_duty", 2048, NULL, 2, NULL);
#endif
cap_queue = xQueueCreate(1, sizeof(capture)); //comment if you don't want to use capture module
#if GPIO_HALL_TEST_SIGNAL
xTaskCreate(gpio_test_signal, "gpio_test_signal", 2048, NULL, 2, NULL);
#endif
xTaskCreate(disp_captured_signal, "mcpwm_config", 4096, NULL, 2, NULL); //comment if you don't want to use capture module
xTaskCreate(mcpwm_example_bldc_control, "mcpwm_example_bldc_control", 4096, NULL, 2, NULL);
}

View File

@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mcpwm_bldc_control_hall_sensor)
project(mcpwm_bldc_hall_control)

View File

@ -3,6 +3,6 @@
# project subdirectory.
#
PROJECT_NAME := mcpwm_bldc_control_hall_sensor
PROJECT_NAME := mcpwm_bldc_hall_control
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,81 @@
| Supported Targets | ESP32 | ESP32-S3 |
| ----------------- | ----- | -------- |
# MCPWM BLDC Hall motor control Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example will illustrate how to use MCPWM driver to control BLDC motor with hall sensor feedback. In the example, a timer is running at the background to update the motor speed periodically.
With the hardware fault detection feature of MCPWM, the example will shut down the MOSFETs when over current happens.
## How to Use Example
### Hardware Required
1. The BLDC motor used in this example has a hall sensor capture sequence of `6-->4-->5-->1-->3-->2-->6-->4-->` and so on.
2. A three-phase gate driver, this example uses [IR2136](https://www.infineon.com/cms/en/product/power/gate-driver-ics/ir2136s/).
3. Six N-MOSFETs, this example uses [IRF540NS](https://www.infineon.com/cms/en/product/power/mosfet/12v-300v-n-channel-power-mosfet/irf540ns/).
4. A development board with any Espressif SoC which features MCPWM peripheral (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
5. A USB cable for Power supply and programming.
Connection :
```
┌─────────────────────────────────────────────┐
│ │
│ ┌───────────────────────────┐ │
│ │ │ │
┌─────────┴─────────┴───────────┐ ┌────────┴───────┴──────────┐
│ GPIO19 GPIO18 │ │ EN FAULT │
│ GPIO21├──────┤PWM_UH │ ┌────────────┐
│ GPIO22├──────┤PWM_UL U├────────┤ │
│ │ │ │ │ │
│ GPIO23├──────┤PWM_VH V├────────┤ BLDC │
│ ESP Board GPIO25├──────┤PWM_VL 3-Phase Bridge │ │ │
│ │ │ + W├────────┤ │
│ GPIO26├──────┤PWM_WH MOSFET │ └─┬───┬───┬──┘
│ GPIO27├──────┤PWM_WL │ │ │ │
│ GPIO5 GPIO4 GPIO2 │ │ │ │ │ │
└─────┬──────┬──────┬───────────┘ └───────────────────────────┘ │ │ │
│ │ │ Hall U │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ Hall V │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ Hall W │
└───────────────────────────────────────────────────────────────────────────────┘
```
### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
Run the example, you will see the following output log:
```
...
I (0) cpu_start: Starting scheduler on APP CPU.
I (327) example: Disable gate driver
I (327) gpio: GPIO[18]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (337) example: Setup PWM and Hall GPIO (pull up internally)
I (347) example: Initialize PWM (default to turn off all MOSFET)
I (357) example: Initialize over current fault action
I (357) example: Initialize Hall sensor capture
I (367) example: Please turn on the motor power
I (5367) example: Enable gate driver
I (5367) example: Changing speed at background
...
```
## Dive into the example
1. How to change the rotation direction?
The rotation direction is controlled by how the hall sensor value is parsed. If you pass `false` to `bldc_get_hall_sensor_value`, the BLDC should rotate in clock wise. Likewise, passing `true` to that function will make tha BLDC rotate in counter clock wise.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "mcpwm_bldc_hall_control_example_main.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,255 @@
/* MCPWM BLDC control with Hall sensor
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/mcpwm.h"
#include "esp_timer.h"
#include "esp_attr.h"
#include "esp_log.h"
#define PWM_DEFAULT_FREQ 14400
#define PWM_MIN_DUTY 40.0
#define PWM_MAX_DUTY 80.0
#define PWM_DUTY_STEP 5.0
#define BLDC_MCPWM_GROUP 0
#define BLDC_MCPWM_TIMER_U 0
#define BLDC_MCPWM_TIMER_V 1
#define BLDC_MCPWM_TIMER_W 2
#define BLDC_MCPWM_GEN_HIGH MCPWM_GEN_A
#define BLDC_MCPWM_GEN_LOW MCPWM_GEN_B
#define BLDC_DRV_EN_GPIO 18
#define BLDC_DRV_FAULT_GPIO 19
#define BLDC_DRV_OVER_CURRENT_FAULT MCPWM_SELECT_F0
#define BLDC_PWM_UH_GPIO 21
#define BLDC_PWM_UL_GPIO 22
#define BLDC_PWM_VH_GPIO 23
#define BLDC_PWM_VL_GPIO 25
#define BLDC_PWM_WH_GPIO 26
#define BLDC_PWM_WL_GPIO 27
#define HALL_CAP_U_GPIO 2
#define HALL_CAP_V_GPIO 4
#define HALL_CAP_W_GPIO 5
static const char *TAG = "example";
static inline uint32_t bldc_get_hall_sensor_value(bool ccw)
{
uint32_t hall_val = gpio_get_level(HALL_CAP_U_GPIO) * 4 + gpio_get_level(HALL_CAP_V_GPIO) * 2 + gpio_get_level(HALL_CAP_W_GPIO) * 1;
return ccw ? hall_val ^ (0x07) : hall_val;
}
static bool IRAM_ATTR bldc_hall_updated(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata, void *user_data)
{
TaskHandle_t task_to_notify = (TaskHandle_t)user_data;
BaseType_t high_task_wakeup = pdFALSE;
vTaskNotifyGiveFromISR(task_to_notify, &high_task_wakeup);
return high_task_wakeup == pdTRUE;
}
static void update_bldc_speed(void *arg)
{
static float duty = PWM_MIN_DUTY;
static float duty_step = PWM_DUTY_STEP;
duty += duty_step;
if (duty > PWM_MAX_DUTY || duty < PWM_MIN_DUTY) {
duty_step *= -1;
}
mcpwm_set_duty(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_HIGH, duty);
mcpwm_set_duty(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_LOW, duty);
mcpwm_set_duty(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_HIGH, duty);
mcpwm_set_duty(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_LOW, duty);
mcpwm_set_duty(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_HIGH, duty);
mcpwm_set_duty(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_LOW, duty);
}
// U+V- / A+B-
static void bldc_set_phase_up_vm(void)
{
mcpwm_set_duty_type(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_HIGH, MCPWM_DUTY_MODE_0); // U+ = PWM
mcpwm_deadtime_enable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, 3, 3); // U- = _PWM_
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_HIGH); // V+ = 0
mcpwm_set_signal_high(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_LOW); // V- = 1
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_HIGH); // W+ = 0
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_LOW); // W- = 0
}
// W+U- / C+A-
static void bldc_set_phase_wp_um(void)
{
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_HIGH); // U+ = 0
mcpwm_set_signal_high(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_LOW); // U- = 1
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_HIGH); // V+ = 0
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_LOW); // V- = 0
mcpwm_set_duty_type(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_HIGH, MCPWM_DUTY_MODE_0); // W+ = PWM
mcpwm_deadtime_enable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, 3, 3); // W- = _PWM_
}
// W+V- / C+B-
static void bldc_set_phase_wp_vm(void)
{
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_HIGH); // U+ = 0
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_LOW); // U- = 0
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_HIGH); // V+ = 0
mcpwm_set_signal_high(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_LOW); // V- = 1
mcpwm_set_duty_type(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_HIGH, MCPWM_DUTY_MODE_0); // W+ = PWM
mcpwm_deadtime_enable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, 3, 3); // W- = _PWM_
}
// V+U- / B+A-
static void bldc_set_phase_vp_um(void)
{
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_HIGH); // U+ = 0
mcpwm_set_signal_high(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_LOW); // U- = 1
mcpwm_set_duty_type(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_HIGH, MCPWM_DUTY_MODE_0); // V+ = PWM
mcpwm_deadtime_enable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, 3, 3); // V- = _PWM_
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_HIGH); // W+ = 0
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_LOW); // W- = 0
}
// V+W- / B+C-
static void bldc_set_phase_vp_wm(void)
{
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_HIGH); // U+ = 0
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_LOW); // U- = 0
mcpwm_set_duty_type(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_HIGH, MCPWM_DUTY_MODE_0); // V+ = PWM
mcpwm_deadtime_enable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, 3, 3); // V- = _PWM_
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_HIGH); // W+ = 0
mcpwm_set_signal_high(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_LOW); // W- = 1
}
// U+W- / A+C-
static void bldc_set_phase_up_wm(void)
{
mcpwm_set_duty_type(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_MCPWM_GEN_HIGH, MCPWM_DUTY_MODE_0); // U+ = PWM
mcpwm_deadtime_enable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, 3, 3); // U- = _PWM_
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_HIGH); // V+ = 0
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_MCPWM_GEN_LOW); // V- = 0
mcpwm_deadtime_disable(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W);
mcpwm_set_signal_low(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_HIGH); // W+ = 0
mcpwm_set_signal_high(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_MCPWM_GEN_LOW); // W- = 1
}
typedef void (*bldc_hall_phase_action_t)(void);
static const bldc_hall_phase_action_t s_hall_actions[] = {
[2] = bldc_set_phase_up_vm,
[6] = bldc_set_phase_wp_vm,
[4] = bldc_set_phase_wp_um,
[5] = bldc_set_phase_vp_um,
[1] = bldc_set_phase_vp_wm,
[3] = bldc_set_phase_up_wm,
};
void app_main(void)
{
uint32_t hall_sensor_value = 0;
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ESP_LOGI(TAG, "Disable gate driver");
gpio_config_t drv_en_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1 << BLDC_DRV_EN_GPIO,
};
ESP_ERROR_CHECK(gpio_config(&drv_en_config));
gpio_set_level(BLDC_DRV_EN_GPIO, 0);
ESP_LOGI(TAG, "Setup PWM and Hall GPIO (pull up internally)");
mcpwm_pin_config_t mcpwm_gpio_config = {
.mcpwm0a_out_num = BLDC_PWM_UH_GPIO,
.mcpwm0b_out_num = BLDC_PWM_UL_GPIO,
.mcpwm1a_out_num = BLDC_PWM_VH_GPIO,
.mcpwm1b_out_num = BLDC_PWM_VL_GPIO,
.mcpwm2a_out_num = BLDC_PWM_WH_GPIO,
.mcpwm2b_out_num = BLDC_PWM_WL_GPIO,
.mcpwm_cap0_in_num = HALL_CAP_U_GPIO,
.mcpwm_cap1_in_num = HALL_CAP_V_GPIO,
.mcpwm_cap2_in_num = HALL_CAP_W_GPIO,
.mcpwm_sync0_in_num = -1, //Not used
.mcpwm_sync1_in_num = -1, //Not used
.mcpwm_sync2_in_num = -1, //Not used
.mcpwm_fault0_in_num = BLDC_DRV_FAULT_GPIO,
.mcpwm_fault1_in_num = -1, //Not used
.mcpwm_fault2_in_num = -1 //Not used
};
ESP_ERROR_CHECK(mcpwm_set_pin(BLDC_MCPWM_GROUP, &mcpwm_gpio_config));
// In case there's no pull-up resister for hall sensor on board
gpio_pullup_en(HALL_CAP_U_GPIO);
gpio_pullup_en(HALL_CAP_V_GPIO);
gpio_pullup_en(HALL_CAP_W_GPIO);
gpio_pullup_en(BLDC_DRV_FAULT_GPIO);
ESP_LOGI(TAG, "Initialize PWM (default to turn off all MOSFET)");
mcpwm_config_t pwm_config = {
.frequency = PWM_DEFAULT_FREQ,
.cmpr_a = PWM_MIN_DUTY,
.cmpr_b = PWM_MIN_DUTY,
.counter_mode = MCPWM_UP_COUNTER,
.duty_mode = MCPWM_HAL_GENERATOR_MODE_FORCE_LOW,
};
ESP_ERROR_CHECK(mcpwm_init(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, &pwm_config));
ESP_ERROR_CHECK(mcpwm_init(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, &pwm_config));
ESP_ERROR_CHECK(mcpwm_init(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, &pwm_config));
ESP_LOGI(TAG, "Initialize over current fault action");
ESP_ERROR_CHECK(mcpwm_fault_init(BLDC_MCPWM_GROUP, MCPWM_LOW_LEVEL_TGR, BLDC_DRV_OVER_CURRENT_FAULT));
ESP_ERROR_CHECK(mcpwm_fault_set_cyc_mode(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_U, BLDC_DRV_OVER_CURRENT_FAULT, MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_LOW));
ESP_ERROR_CHECK(mcpwm_fault_set_cyc_mode(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_V, BLDC_DRV_OVER_CURRENT_FAULT, MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_LOW));
ESP_ERROR_CHECK(mcpwm_fault_set_cyc_mode(BLDC_MCPWM_GROUP, BLDC_MCPWM_TIMER_W, BLDC_DRV_OVER_CURRENT_FAULT, MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_LOW));
ESP_LOGI(TAG, "Initialize Hall sensor capture");
mcpwm_capture_config_t cap_config = {
.cap_edge = MCPWM_BOTH_EDGE,
.cap_prescale = 1,
.capture_cb = bldc_hall_updated,
.user_data = cur_task,
};
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(BLDC_MCPWM_GROUP, 0, &cap_config));
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(BLDC_MCPWM_GROUP, 1, &cap_config));
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(BLDC_MCPWM_GROUP, 2, &cap_config));
ESP_LOGI(TAG, "Please turn on the motor power");
vTaskDelay(pdMS_TO_TICKS(5000));
ESP_LOGI(TAG, "Enable gate driver");
gpio_set_level(BLDC_DRV_EN_GPIO, 1);
ESP_LOGI(TAG, "Changing speed at background");
const esp_timer_create_args_t bldc_timer_args = {
.callback = update_bldc_speed,
.name = "bldc_speed"
};
esp_timer_handle_t bldc_speed_timer;
ESP_ERROR_CHECK(esp_timer_create(&bldc_timer_args, &bldc_speed_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(bldc_speed_timer, 2000000));
while (1) {
// The rotation direction is controlled by inverting the hall sensor value
hall_sensor_value = bldc_get_hall_sensor_value(false);
if (hall_sensor_value >= 1 && hall_sensor_value <= sizeof(s_hall_actions) / sizeof(s_hall_actions[0])) {
s_hall_actions[hall_sensor_value]();
} else {
ESP_LOGE(TAG, "invalid bldc phase, wrong hall sensor value:%d", hall_sensor_value);
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}