Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 50 additions & 50 deletions src/drivers/hardware_specific/esp32/esp32_driver_mcpwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* 6 PWM independent signals per unit
* unit(0/1) > timer(0-2) > operator(0-2) > comparator(0-1) > generator(0-1) > pwm(A/B)
*
* -------------------------------------- Table View -----------------------------
* -------------------------------------- Table View -----------------------------
*
* group | timer | operator | comparator | generator | pwm
* --------------------------------------------------------------------------------
Expand All @@ -28,31 +28,31 @@
* ------------------------------------- Example 3PWM ------------------------------
* ┌─ comparator 0 - generator 0 -> pwm A
* ┌─ operator 0 -|
* | └─ comparator 1 - generator 1 -> pmw B
* | └─ comparator 1 - generator 1 -> pmw B
* unit - timer 0-2 -|
* 0-1 └─ operator 1 - comparator 0 - generator 0 - pwm C
*
*
* ------------------------------------- Example 2PWM ------------------------------
* ┌─ comparator 0 - generator 0 -> pwm A
* unit - timer 0-2 - operator 0 -|
* 0-1 └─ comparator 1 - generator 1 -> pmw B
* 0-1 └─ comparator 1 - generator 1 -> pmw B
*
* -------------------------------------- Example 4PWM -----------------------------
* -------------------------------------- Example 4PWM -----------------------------
* ┌─ comparator 0 - generator 0 -> pwm A
* ┌─ operator 0 -|
* | └─ comparator 1 - generator 1 -> pmw B
* unit - timer 0-2 -|
* | └─ comparator 1 - generator 1 -> pmw B
* unit - timer 0-2 -|
* 0-1 | ┌─ comparator 0 - generator 0 -> pwm C
* └─ operator 1 -|
* └─ comparator 0 - generator 0 -> pwm D
* └─ comparator 0 - generator 0 -> pwm D


* Complementary mode
* ------------------
* - : 3 pairs of complementary PWM signals per unit
* unit(0/1) > timer(0) > operator(0-2) > comparator(0-1) > generator(0-1) > pwm(high/low pair)
*
* -------------------------------------- Table View -----------------------------
*
* -------------------------------------- Table View -----------------------------
*
* group | timer | operator | comparator | generator | pwm
* ------------------------------------------------------------------------
Expand All @@ -63,26 +63,26 @@
* 0-1 | 0 | 2 | 0 | 0 | A
* 0-1 | 0 | 2 | 1 | 1 | B
*
* -------------------------------------- Example 6PWM -----------------------------
*
* -------------------------------------- Example 6PWM -----------------------------
*
* ┌─ comparator 0 - generator 0 -> pwm A_h
* ┌─ operator 0 -|
* ┌─ operator 0 -|
* | └─ comparator 1 - generator 1 -> pmw A_l
* |
* |
* unit | ┌─ comparator 0 - generator 0 -> pwm B_h
* (group) - timer 0 -|- operator 1 -|
* 0-1 | └─ comparator 1 - generator 1 -> pmw B_l
* |
* | ┌─ comparator 0 - generator 0 -> pwm C_h
* └─ operator 2 -|
* └─ comparator 1 - generator 1 -> pmw C_l
*
*


* More info
* ----------
* - timers can be associated with any operator, and multiple operators can be associated with the same timer
* - comparators can be associated with any operator
* - comparators can be associated with any operator
* - two comparators per operator for independent mode
* - one comparator per operator for complementary mode
* - generators can be associated with any comparator
Expand All @@ -96,7 +96,7 @@
* and here: // https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/migration-guides/release-5.x/5.0/peripherals.html
*/

#include "../../hardware_api.h"
#include "../../hardware_api.h"

#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC)

Expand All @@ -114,7 +114,7 @@

// MCPWM driver hardware timer pointers
mcpwm_timer_handle_t timers[2][3] = {NULL};
// MCPWM timer periods configured (directly related to the pwm frequency)
// MCPWM timer periods configured (directly related to the pwm frequency)
uint32_t pwm_periods[2][3];
// how many pins from the groups 6 pins is used
uint8_t group_pins_used[2] = {0};
Expand Down Expand Up @@ -143,7 +143,7 @@ uint8_t _findLastTimer(int group){
// return the last index
return i;
}
// returns the index of the next timer to instantiate
// returns the index of the next timer to instantiate
// -1 if no timers available
uint8_t _findNextTimer(int group){
int i = 0;
Expand All @@ -157,7 +157,7 @@ uint8_t _findNextTimer(int group){

/*
* find the best group for the pins
* if 6pwm
* if 6pwm
* - Only option is an an empty group
* if 3pwm
* - Best is an empty group (we can set a pwm frequency)
Expand All @@ -180,11 +180,11 @@ uint8_t _findNextTimer(int group){
* For example if the group has already used 3pwms, there is one generator that has one pwm channel left.
* If we use this channel we have to use the same timer it has been used with before, so we cannot change the pwm frequency.
* Current implementation does use the remaining channel only if there isn't other options that would allow changing the pwm frequency.
* In this example where we have 3pwms already configured, if we try to configure 2pws after, we will skip the remaining channel
* In this example where we have 3pwms already configured, if we try to configure 2pws after, we will skip the remaining channel
* and use a new timer and operator to allow changing the pwm frequency. In such cases we loose (cannot be used) the remaining channel.
* TODO: use the pwm_frequency to avoid skipping pwm channels !
*
* returns
* returns
* - 1 if solution found in one group
* - 2 if solution requires using both groups
* - 0 if no solution possible
Expand All @@ -199,13 +199,13 @@ int _findBestGroup(int no_pins, long pwm_freq, int* group, int* timer){
}
}

// if 3 or 1pwm
// if 3 or 1pwm
// check if there is available space in one of the groups
// otherwise fail
if(no_pins == 3 || no_pins==1){
// second best option is if there is a group with
// pair number of pwms available as we can then
// set the pwm frequency
// second best option is if there is a group with
// pair number of pwms available as we can then
// set the pwm frequency
for(int i=0; i<SOC_MCPWM_GROUPS; i++){
if(_hasAvailablePins(i, no_pins+1)) {
*group=i;
Expand Down Expand Up @@ -284,13 +284,13 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,
.pwm_frequency = pwm_frequency,
.group_id = mcpwm_group
};

mcpwm_timer_config_t pwm_config;
pwm_config.group_id = mcpwm_group;
pwm_config.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT;
pwm_config.resolution_hz = _PWM_TIMEBASE_RESOLUTION_HZ;
pwm_config.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN;
pwm_config.intr_priority = 0;
pwm_config.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN;
pwm_config.intr_priority = 0;
pwm_config.period_ticks = _calcPWMPeriod(pwm_frequency);
#ifdef ESP_IDF_VERSION_ABOVE_5_4_0
pwm_config.flags.allow_pd = 0;
Expand All @@ -302,7 +302,7 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,
params->mcpwm_period = pwm_periods[mcpwm_group][timer_no];

uint8_t no_operators = 3; // use 3 comparators one per pair of pwms
SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_operators) + " operators.");
SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_operators) + " operators.");
mcpwm_operator_config_t operator_config = { .group_id = mcpwm_group };
operator_config.intr_priority = 0;
operator_config.flags.update_gen_action_on_tep = true;
Expand All @@ -313,9 +313,9 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,
}

#if SIMPLEFOC_ESP32_HW_DEADTIME == true // hardware dead-time (hardware 6pwm)

SIMPLEFOC_ESP32_DRV_DEBUG("Configuring 6PWM with hardware dead-time");

SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_operators) + " comparators.");
// Create and configure comparators
mcpwm_comparator_config_t comparator_config = {0};
Expand All @@ -324,7 +324,7 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,
CHECK_ERR(mcpwm_new_comparator(params->oper[i], &comparator_config, &params->comparator[i]),"Could not create comparator: " + String(i));
CHECK_ERR(mcpwm_comparator_set_compare_value(params->comparator[i], (0)), "Could not set duty on comparator: " + String(i));
}

#else // software dead-time (software 6pwm)
// software dead-time (software 6pwm)
SIMPLEFOC_ESP32_DRV_DEBUG("Configuring 6PWM with software dead-time");
Expand All @@ -339,7 +339,7 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,
CHECK_ERR(mcpwm_new_comparator(params->oper[oper_index], &comparator_config, &params->comparator[i]),"Could not create comparator: " + String(i));
CHECK_ERR(mcpwm_comparator_set_compare_value(params->comparator[i], (0)), "Could not set duty on comparator: " + String(i));
}
#endif
#endif

int no_generators = 6; // one per pwm
SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_generators) + " generators.");
Expand All @@ -355,9 +355,9 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,

#if SIMPLEFOC_ESP32_HW_DEADTIME == true // hardware dead-time (hardware 6pwm)
for (int i = 0; i < no_operators; i++) {
CHECK_ERR(_configureCenterAlign(params->generator[2*i],params->comparator[i]), "Failed to configure high-side center align pwm: " + String(2*i));
CHECK_ERR(_configureCenterAlign(params->generator[2*i+1],params->comparator[i]), "Failed to configure low-side center align pwm: " + String(2*i+1));
CHECK_ERR(_configureCenterAlign(params->generator[2*i],params->comparator[i]), "Failed to configure high-side center align pwm: " + String(2*i));
CHECK_ERR(_configureCenterAlign(params->generator[2*i+1],params->comparator[i]), "Failed to configure low-side center align pwm: " + String(2*i+1));

}
// only available for 6pwm
SIMPLEFOC_ESP32_DRV_DEBUG("Configuring dead-time.");
Expand All @@ -369,15 +369,15 @@ void* _configure6PWMPinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no,
mcpwm_dead_time_config_t dt_config_low;
dt_config_low.posedge_delay_ticks = 0;
dt_config_low.negedge_delay_ticks = dead_time;
dt_config_low.flags.invert_output = SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH;
dt_config_low.flags.invert_output = SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH;
for (int i = 0; i < no_operators; i++) {
CHECK_ERR(mcpwm_generator_set_dead_time(params->generator[2*i], params->generator[2*i], &dt_config_high),"Could not set dead time for generator: " + String(i));
CHECK_ERR(mcpwm_generator_set_dead_time(params->generator[2*i+1], params->generator[2*i+1], &dt_config_low),"Could not set dead time for generator: " + String(i+1));
}
#else // software dead-time (software 6pwm)
for (int i = 0; i < 3; i++) {
CHECK_ERR(_configureCenterAlign(params->generator[2*i],params->comparator[2*i], !SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH), "Failed to configure high-side center align pwm: " + String(2*i));
CHECK_ERR(_configureCenterAlign(params->generator[2*i+1],params->comparator[2*i+1], SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH) , "Failed to configure low-side center align pwm: " + String(2*i+1));
CHECK_ERR(_configureCenterAlign(params->generator[2*i],params->comparator[2*i], !SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH), "Failed to configure high-side center align pwm: " + String(2*i));
CHECK_ERR(_configureCenterAlign(params->generator[2*i+1],params->comparator[2*i+1], SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH) , "Failed to configure low-side center align pwm: " + String(2*i+1));
}
#endif

Expand Down Expand Up @@ -412,16 +412,16 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
.pwm_frequency = pwm_frequency,
.group_id = mcpwm_group
};

bool shared_timer = false;
// check if timer is configured
if (timers[mcpwm_group][timer_no] == NULL){
mcpwm_timer_config_t pwm_config;
pwm_config.group_id = mcpwm_group;
pwm_config.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT;
pwm_config.resolution_hz = _PWM_TIMEBASE_RESOLUTION_HZ;
pwm_config.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN;
pwm_config.intr_priority = 0;
pwm_config.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN;
pwm_config.intr_priority = 0;
pwm_config.period_ticks = _calcPWMPeriod(pwm_frequency);
#ifdef ESP_IDF_VERSION_ABOVE_5_4_0
pwm_config.flags.allow_pd = 0;
Expand All @@ -430,10 +430,10 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
CHECK_ERR(mcpwm_new_timer(&pwm_config, &timers[mcpwm_group][timer_no]), "Could not initialize the timer in group: " + String(mcpwm_group));
// save variables for later
pwm_periods[mcpwm_group][timer_no] = pwm_config.period_ticks / 2;
params->timers[0] = timers[mcpwm_group][timer_no];
params->timers[0] = timers[mcpwm_group][timer_no];
// if the numer of used channels it not pair skip one channel
// the skipped channel cannot be used with the new timer
// TODO avoid loosing channels like this
// TODO avoid loosing channels like this
if(group_pins_used[mcpwm_group] %2) group_pins_used[mcpwm_group]++;
}else{
// we will use an already instantiated timer
Expand All @@ -446,7 +446,7 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
return SIMPLEFOC_DRIVER_INIT_FAILED;
}
CHECK_ERR(mcpwm_timer_start_stop( params->timers[0], MCPWM_TIMER_STOP_EMPTY), "Failed to stop the timer!");

shared_timer = true;
}

Expand All @@ -463,7 +463,7 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
}
CHECK_ERR(mcpwm_new_operator(&operator_config, &params->oper[i]),"Could not create operator "+String(i));
CHECK_ERR(mcpwm_operator_connect_timer(params->oper[i], params->timers[0]),"Could not connect timer to operator: " + String(i));
}
}
// save the last operator in this group
last_operator[mcpwm_group] = params->oper[no_operators - 1];

Expand All @@ -485,7 +485,7 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
int oper_index = shared_timer ? (int)floor((i + 1) / 2) : (int)floor(i / 2);
CHECK_ERR(mcpwm_new_generator(params->oper[oper_index], &generator_config, &params->generator[i]), "Could not create generator " + String(i) +String(" on pin: ")+String(pins[i]));
}


SIMPLEFOC_ESP32_DRV_DEBUG("Configuring center-aligned pwm.");
for (int i = 0; i < no_pins; i++) {
Expand All @@ -507,15 +507,15 @@ void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int
}

// function setting the duty cycle to the MCPWM pin
void _setDutyCycle(mcpwm_cmpr_handle_t cmpr, uint32_t mcpwm_period, float duty_cycle){
void IRAM_ATTR _setDutyCycle(mcpwm_cmpr_handle_t cmpr, uint32_t mcpwm_period, float duty_cycle){
float duty = _constrain(duty_cycle, 0.0, 1.0);
mcpwm_comparator_set_compare_value(cmpr, (uint32_t)(mcpwm_period*duty));
}

// function setting the duty cycle to the MCPWM pin
void _forcePhaseState(mcpwm_gen_handle_t generator_high, mcpwm_gen_handle_t generator_low, PhaseState phase_state){
// phase state is forced in hardware pwm mode
// esp-idf docs: https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/api-reference/peripherals/mcpwm.html#generator-force-actions
// esp-idf docs: https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/api-reference/peripherals/mcpwm.html#generator-force-actions
// github issue: https://github.com/espressif/esp-idf/issues/12237
mcpwm_generator_set_force_level(generator_high, (phase_state == PHASE_ON || phase_state == PHASE_HI) ? -1 : 0, true);
mcpwm_generator_set_force_level(generator_low, (phase_state == PHASE_ON || phase_state == PHASE_LO) ? -1 : 1, true);
Expand Down
Loading