99#include "../../hardware_api.h"
101#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC)
103#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0)
104#define ESP_IDF_VERSION_UNDER_5_4_0
106#pragma message("SimpleFOC: ESP IDF version under 5.4.0, consider upgrading!")
108#else ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
109#define ESP_IDF_VERSION_ABOVE_5_4_0
116mcpwm_timer_handle_t timers[2][3] = {NULL};
118uint32_t pwm_periods[2][3];
120uint8_t group_pins_used[2] = {0};
122mcpwm_oper_handle_t last_operator[2];
124void _notifyLowSideUsingComparator(
int group_id){
125 group_pins_used[group_id] +=1;
129bool _hasAvailablePins(
int group,
int no_pins){
130 if(group_pins_used[group] + no_pins > 6){
138uint8_t _findLastTimer(
int group){
141 if(timers[group][i] == NULL){
150uint8_t _findNextTimer(
int group){
153 if(timers[group][i] == NULL){
194int _findBestGroup(
int no_pins,
long pwm_freq,
int* group,
int* timer){
196 for(
int i=0; i<SOC_MCPWM_GROUPS; i++){
197 if(!group_pins_used[i]){
207 if(no_pins == 3 || no_pins==1){
211 for(
int i=0; i<SOC_MCPWM_GROUPS; i++){
212 if(_hasAvailablePins(i, no_pins+1)) {
214 *timer = _findNextTimer(i);
219 for(
int i=0; i<SOC_MCPWM_GROUPS; i++){
220 if(_hasAvailablePins(i, no_pins)) {
222 *timer = _findLastTimer(i);
231 if(no_pins == 2 || no_pins==4){
233 for(
int i=0; i<2; i++){
234 if(_hasAvailablePins(i, no_pins)) {
236 *timer = _findNextTimer(i);
241 int half_no_pins = (int)no_pins/2;
242 if(_hasAvailablePins(0,half_no_pins) && _hasAvailablePins(1 ,half_no_pins)){
254int _configureCenterAlign(mcpwm_gen_handle_t gena, mcpwm_cmpr_handle_t cmpa,
bool inverted =
false){
256 return mcpwm_generator_set_actions_on_compare_event(gena,
257 MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
258 MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_LOW),
259 MCPWM_GEN_COMPARE_EVENT_ACTION_END());
261 return mcpwm_generator_set_actions_on_compare_event(gena,
262 MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
263 MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_HIGH),
264 MCPWM_GEN_COMPARE_EVENT_ACTION_END());
272uint32_t _calcPWMPeriod(
long pwm_frequency) {
273 return (uint32_t)(1 * _PWM_TIMEBASE_RESOLUTION_HZ / pwm_frequency);
280long _calcPWMFreq(
long pwm_period) {
281 return (uint32_t)(1 * _PWM_TIMEBASE_RESOLUTION_HZ / pwm_period / 2);
284void* _configure6PWMPinsMCPWM(
long pwm_frequency,
int mcpwm_group,
int timer_no,
float dead_zone,
int* pins){
285 ESP32MCPWMDriverParams*
params =
new ESP32MCPWMDriverParams{
286 .pwm_frequency = pwm_frequency,
287 .group_id = mcpwm_group
290 mcpwm_timer_config_t pwm_config;
291 pwm_config.group_id = mcpwm_group;
292 pwm_config.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT;
293 pwm_config.resolution_hz = _PWM_TIMEBASE_RESOLUTION_HZ;
294 pwm_config.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN;
295 pwm_config.intr_priority = 0;
296 pwm_config.period_ticks = _calcPWMPeriod(pwm_frequency);
297#ifdef ESP_IDF_VERSION_ABOVE_5_4_0
298 pwm_config.flags.allow_pd = 0;
301 CHECK_ERR(mcpwm_new_timer(&pwm_config, &timers[mcpwm_group][timer_no]),
"Could not initialize the timer in group: " + String(mcpwm_group));
302 pwm_periods[mcpwm_group][timer_no] = pwm_config.period_ticks / 2;
303 params->timers[0] = timers[mcpwm_group][timer_no];
304 params->mcpwm_period = pwm_periods[mcpwm_group][timer_no];
306 uint8_t no_operators = 3;
307 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring " + String(no_operators) +
" operators.");
308 mcpwm_operator_config_t operator_config = { .group_id = mcpwm_group };
309 operator_config.intr_priority = 0;
310 operator_config.flags.update_gen_action_on_tep =
true;
311 operator_config.flags.update_gen_action_on_tez =
true;
312 for (
int i = 0; i < no_operators; i++) {
313 CHECK_ERR(mcpwm_new_operator(&operator_config, &
params->oper[i]),
"Could not create operator "+String(i));
314 CHECK_ERR(mcpwm_operator_connect_timer(
params->oper[i],
params->timers[0]),
"Could not connect timer to operator: " + String(i));
317#if SIMPLEFOC_ESP32_HW_DEADTIME == true
319 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring 6PWM with hardware dead-time");
321 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring " + String(no_operators) +
" comparators.");
323 mcpwm_comparator_config_t comparator_config = {0};
324 comparator_config.flags.update_cmp_on_tez =
true;
325 for (
int i = 0; i < no_operators; i++) {
326 CHECK_ERR(mcpwm_new_comparator(
params->oper[i], &comparator_config, &
params->comparator[i]),
"Could not create comparator: " + String(i));
327 CHECK_ERR(mcpwm_comparator_set_compare_value(
params->comparator[i], (0)),
"Could not set duty on comparator: " + String(i));
332 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring 6PWM with software dead-time");
335 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring " + String(no_pins) +
" comparators.");
337 mcpwm_comparator_config_t comparator_config = {0};
338 comparator_config.flags.update_cmp_on_tez =
true;
339 for (
int i = 0; i < no_pins; i++) {
340 int oper_index = (int)floor(i / 2);
341 CHECK_ERR(mcpwm_new_comparator(
params->oper[oper_index], &comparator_config, &
params->comparator[i]),
"Could not create comparator: " + String(i));
342 CHECK_ERR(mcpwm_comparator_set_compare_value(
params->comparator[i], (0)),
"Could not set duty on comparator: " + String(i));
346 int no_generators = 6;
347 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring " + String(no_generators) +
" generators.");
349 mcpwm_generator_config_t generator_config = {};
350 for (
int i = 0; i < no_generators; i++) {
351 generator_config.gen_gpio_num = pins[i];
352 int oper_index = (int)floor(i / 2);
353 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]));
356 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring Center-Aligned 6 pwm.");
358#if SIMPLEFOC_ESP32_HW_DEADTIME == true
359 for (
int i = 0; i < no_operators; i++) {
360 CHECK_ERR(_configureCenterAlign(
params->generator[2*i],
params->comparator[i]),
"Failed to configure high-side center align pwm: " + String(2*i));
361 CHECK_ERR(_configureCenterAlign(
params->generator[2*i+1],
params->comparator[i]),
"Failed to configure low-side center align pwm: " + String(2*i+1));
365 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring dead-time.");
366 uint32_t dead_time = (int)pwm_periods[mcpwm_group][timer_no] *
dead_zone;
367 mcpwm_dead_time_config_t dt_config_high;
368 dt_config_high.posedge_delay_ticks = dead_time;
369 dt_config_high.negedge_delay_ticks = 0;
371 mcpwm_dead_time_config_t dt_config_low;
372 dt_config_low.posedge_delay_ticks = 0;
373 dt_config_low.negedge_delay_ticks = dead_time;
375 for (
int i = 0; i < no_operators; i++) {
376 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));
377 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));
380 for (
int i = 0; i < 3; i++) {
386 SIMPLEFOC_ESP32_DRV_DEBUG(
"Enabling timer: "+String(timer_no));
388 CHECK_ERR(mcpwm_timer_enable(
params->timers[0]),
"Failed to enable timer!");
389 CHECK_ERR(mcpwm_timer_start_stop(
params->timers[0], MCPWM_TIMER_START_NO_STOP),
"Failed to start the timer!");
392 SIMPLEFOC_ESP32_DRV_DEBUG(
"MCPWM configured!");
395 group_pins_used[mcpwm_group] = 6;
411void* _configurePinsMCPWM(
long pwm_frequency,
int mcpwm_group,
int timer_no,
int no_pins,
int* pins){
413 ESP32MCPWMDriverParams*
params =
new ESP32MCPWMDriverParams{
414 .pwm_frequency = pwm_frequency,
415 .group_id = mcpwm_group
418 bool shared_timer =
false;
420 if (timers[mcpwm_group][timer_no] == NULL){
421 mcpwm_timer_config_t pwm_config;
422 pwm_config.group_id = mcpwm_group;
423 pwm_config.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT;
424 pwm_config.resolution_hz = _PWM_TIMEBASE_RESOLUTION_HZ;
425 pwm_config.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN;
426 pwm_config.intr_priority = 0;
427 pwm_config.period_ticks = _calcPWMPeriod(pwm_frequency);
428#ifdef ESP_IDF_VERSION_ABOVE_5_4_0
429 pwm_config.flags.allow_pd = 0;
432 CHECK_ERR(mcpwm_new_timer(&pwm_config, &timers[mcpwm_group][timer_no]),
"Could not initialize the timer in group: " + String(mcpwm_group));
434 pwm_periods[mcpwm_group][timer_no] = pwm_config.period_ticks / 2;
435 params->timers[0] = timers[mcpwm_group][timer_no];
439 if(group_pins_used[mcpwm_group] %2) group_pins_used[mcpwm_group]++;
442 params->timers[0] = timers[mcpwm_group][timer_no];
443 SIMPLEFOC_ESP32_DRV_DEBUG(
"Using previously configured timer: " + String(timer_no));
446 if(_calcPWMPeriod(pwm_frequency)/2 != pwm_periods[mcpwm_group][timer_no]){
447 SIMPLEFOC_ESP32_DRV_DEBUG(
"ERR: Timer: "+String(timer_no)+
" is confgured for freq: "+String(_calcPWMFreq(pwm_periods[mcpwm_group][timer_no]))+
", not for freq:" +String(pwm_frequency));
450 CHECK_ERR(mcpwm_timer_start_stop(
params->timers[0], MCPWM_TIMER_STOP_EMPTY),
"Failed to stop the timer!");
455 uint8_t no_operators = ceil(no_pins / 2.0);
456 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring " + String(no_operators) +
" operators.");
457 mcpwm_operator_config_t operator_config = { .group_id = mcpwm_group };
458 operator_config.intr_priority = 0;
459 operator_config.flags.update_gen_action_on_tep =
true;
460 operator_config.flags.update_gen_action_on_tez =
true;
461 for (
int i = 0; i < no_operators; i++) {
462 if (shared_timer && i == 0) {
463 params->oper[0] = last_operator[mcpwm_group];
466 CHECK_ERR(mcpwm_new_operator(&operator_config, &
params->oper[i]),
"Could not create operator "+String(i));
467 CHECK_ERR(mcpwm_operator_connect_timer(
params->oper[i],
params->timers[0]),
"Could not connect timer to operator: " + String(i));
470 last_operator[mcpwm_group] =
params->oper[no_operators - 1];
472 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring " + String(no_pins) +
" comparators.");
474 mcpwm_comparator_config_t comparator_config = {0};
475 comparator_config.flags.update_cmp_on_tez =
true;
476 for (
int i = 0; i < no_pins; i++) {
477 int oper_index = shared_timer ? (int)floor((i + 1) / 2) : (int)floor(i / 2);
478 CHECK_ERR(mcpwm_new_comparator(
params->oper[oper_index], &comparator_config, &
params->comparator[i]),
"Could not create comparator: " + String(i));
479 CHECK_ERR(mcpwm_comparator_set_compare_value(
params->comparator[i], (0)),
"Could not set duty on comparator: " + String(i));
482 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring " + String(no_pins) +
" generators.");
484 mcpwm_generator_config_t generator_config = {};
485 for (
int i = 0; i < no_pins; i++) {
486 generator_config.gen_gpio_num = pins[i];
487 int oper_index = shared_timer ? (int)floor((i + 1) / 2) : (int)floor(i / 2);
488 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]));
492 SIMPLEFOC_ESP32_DRV_DEBUG(
"Configuring center-aligned pwm.");
493 for (
int i = 0; i < no_pins; i++) {
497 SIMPLEFOC_ESP32_DRV_DEBUG(
"Enabling timer: "+String(timer_no));
499 if (!shared_timer) CHECK_ERR(mcpwm_timer_enable(
params->timers[0]),
"Failed to enable timer!");
501 CHECK_ERR(mcpwm_timer_start_stop(
params->timers[0], MCPWM_TIMER_START_NO_STOP),
"Failed to start the timer!");
504 SIMPLEFOC_ESP32_DRV_DEBUG(
"MCPWM configured!");
506 params->mcpwm_period = pwm_periods[mcpwm_group][timer_no];
507 group_pins_used[mcpwm_group] += no_pins;
512void IRAM_ATTR _setDutyCycle(mcpwm_cmpr_handle_t cmpr, uint32_t mcpwm_period,
float duty_cycle){
513 float duty =
_constrain(duty_cycle, 0.0, 1.0);
514 mcpwm_comparator_set_compare_value(cmpr, (uint32_t)(mcpwm_period*duty));
518void _forcePhaseState(mcpwm_gen_handle_t generator_high, mcpwm_gen_handle_t generator_low,
PhaseState phase_state){
GenericCurrentSenseParams * params
#define SIMPLEFOC_PWM_ACTIVE_HIGH
#define SIMPLEFOC_DRIVER_INIT_FAILED
#define SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH
#define SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH
float float PhaseState * phase_state
#define _constrain(amt, low, high)
void _delay(unsigned long ms)