SimpleFOClibrary 2.4.0
Loading...
Searching...
No Matches
esp32_driver_mcpwm.cpp
Go to the documentation of this file.
1
2/*
3* MCPWM in espressif v5.x has
4* - 2x groups (units)
5* each one has
6* - 3 timers
7* - 3 operators (that can be associated with any timer)
8* which control a 2xPWM signals
9* - 1x comparator + 1x generator per PWM signal
10
11
12* Independent mode:
13* ------------------
14* 6 PWM independent signals per unit
15* unit(0/1) > timer(0-2) > operator(0-2) > comparator(0-1) > generator(0-1) > pwm(A/B)
16*
17* -------------------------------------- Table View -----------------------------
18*
19* group | timer | operator | comparator | generator | pwm
20* --------------------------------------------------------------------------------
21* 0-1 | 0-2 | 0 | 0 | 0 | A
22* 0-1 | 0-2 | 0 | 1 | 1 | B
23* 0-1 | 0-2 | 1 | 0 | 0 | A
24* 0-1 | 0-2 | 1 | 1 | 1 | B
25* 0-1 | 0-2 | 2 | 0 | 0 | A
26* 0-1 | 0-2 | 2 | 1 | 1 | B
27*
28* ------------------------------------- Example 3PWM ------------------------------
29* ┌─ comparator 0 - generator 0 -> pwm A
30* ┌─ operator 0 -|
31* | └─ comparator 1 - generator 1 -> pmw B
32* unit - timer 0-2 -|
33* 0-1 └─ operator 1 - comparator 0 - generator 0 - pwm C
34*
35* ------------------------------------- Example 2PWM ------------------------------
36* ┌─ comparator 0 - generator 0 -> pwm A
37* unit - timer 0-2 - operator 0 -|
38* 0-1 └─ comparator 1 - generator 1 -> pmw B
39*
40* -------------------------------------- Example 4PWM -----------------------------
41* ┌─ comparator 0 - generator 0 -> pwm A
42* ┌─ operator 0 -|
43* | └─ comparator 1 - generator 1 -> pmw B
44* unit - timer 0-2 -|
45* 0-1 | ┌─ comparator 0 - generator 0 -> pwm C
46* └─ operator 1 -|
47* └─ comparator 0 - generator 0 -> pwm D
48
49
50* Complementary mode
51* ------------------
52* - : 3 pairs of complementary PWM signals per unit
53* unit(0/1) > timer(0) > operator(0-2) > comparator(0-1) > generator(0-1) > pwm(high/low pair)
54*
55* -------------------------------------- Table View -----------------------------
56*
57* group | timer | operator | comparator | generator | pwm
58* ------------------------------------------------------------------------
59* 0-1 | 0 | 0 | 0 | 0 | A
60* 0-1 | 0 | 0 | 1 | 1 | B
61* 0-1 | 0 | 1 | 0 | 0 | A
62* 0-1 | 0 | 1 | 1 | 1 | B
63* 0-1 | 0 | 2 | 0 | 0 | A
64* 0-1 | 0 | 2 | 1 | 1 | B
65*
66* -------------------------------------- Example 6PWM -----------------------------
67*
68* ┌─ comparator 0 - generator 0 -> pwm A_h
69* ┌─ operator 0 -|
70* | └─ comparator 1 - generator 1 -> pmw A_l
71* |
72* unit | ┌─ comparator 0 - generator 0 -> pwm B_h
73* (group) - timer 0 -|- operator 1 -|
74* 0-1 | └─ comparator 1 - generator 1 -> pmw B_l
75* |
76* | ┌─ comparator 0 - generator 0 -> pwm C_h
77* └─ operator 2 -|
78* └─ comparator 1 - generator 1 -> pmw C_l
79*
80
81
82* More info
83* ----------
84* - timers can be associated with any operator, and multiple operators can be associated with the same timer
85* - comparators can be associated with any operator
86* - two comparators per operator for independent mode
87* - one comparator per operator for complementary mode
88* - generators can be associated with any comparator
89* - one generator per PWM signal for independent mode
90* - two generators per pair of PWM signals for complementary mode (not used in simplefoc)
91* - dead-time can be set for each generator pair in complementary mode
92*
93* Docs
94* -------
95* More info here: https:*www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf#mcpwm
96* and here: // https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/migration-guides/release-5.x/5.0/peripherals.html
97*/
98
99#include "../../hardware_api.h"
100
101#if defined(ESP_H) && defined(ARDUINO_ARCH_ESP32) && defined(SOC_MCPWM_SUPPORTED) && !defined(SIMPLEFOC_ESP32_USELEDC)
102
103#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0)
104#define ESP_IDF_VERSION_UNDER_5_4_0
105#pragma message("")
106#pragma message("SimpleFOC: ESP IDF version under 5.4.0, consider upgrading!")
107#pragma message("")
108#else ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
109#define ESP_IDF_VERSION_ABOVE_5_4_0
110#endif
111
112
113#include "esp32_driver_mcpwm.h"
114
115// MCPWM driver hardware timer pointers
116mcpwm_timer_handle_t timers[2][3] = {NULL};
117// MCPWM timer periods configured (directly related to the pwm frequency)
118uint32_t pwm_periods[2][3];
119// how many pins from the groups 6 pins is used
120uint8_t group_pins_used[2] = {0};
121// last operator in the group
122mcpwm_oper_handle_t last_operator[2];
123
124void _notifyLowSideUsingComparator(int group_id){
125 group_pins_used[group_id] +=1;
126}
127
128// checking if group has pins available
129bool _hasAvailablePins(int group, int no_pins){
130 if(group_pins_used[group] + no_pins > 6){
131 return false;
132 }
133 return true;
134}
135
136// returns the index of the last timer in the group
137// -1 if no timer instantiated yet
138uint8_t _findLastTimer(int group){
139 int i = 0;
140 for(; i<3; i++){
141 if(timers[group][i] == NULL){
142 return i-1;
143 }
144 }
145 // return the last index
146 return i;
147}
148// returns the index of the next timer to instantiate
149// -1 if no timers available
150uint8_t _findNextTimer(int group){
151 int i = 0;
152 for(; i<3; i++){
153 if(timers[group][i] == NULL){
154 return i;
155 }
156 }
157 return -1;
158}
159
160/*
161 * find the best group for the pins
162 * if 6pwm
163 * - Only option is an an empty group
164 * if 3pwm
165 * - Best is an empty group (we can set a pwm frequency)
166 * - Second best is a group with 4pwms (2 operators) available (we can set the pwm frequency -> new timer+new operator)
167 * - Third best option is any group which has 3pwms available (but uses previously defined pwm_frequency)
168 * if 1pwm
169 * - Best option is an empty group (we can set the pwm frequency)
170 * - Second best is a group with 2pwms (one operator) available (we can set the pwm frequency -> new timer+new operator)
171 * - Third best is a group with 1pwm available (but uses previously defined pwm_frequency )
172 * if 2pwm
173 * - Best option is an empty group (we can set the pwm frequency)
174 * - Second best is a group with 2pwms available (we can set the pwm frequency -> new timer+new operator)
175 * - Third best is one pin per group (but uses previously defined pwm_frequency )
176 * if 4pwm
177 * - best option is an empty group (we can set the pwm frequency)
178 * - second best is a group with 4pwms available (we can set the pwm frequency -> new timer + new operators)
179 * - third best is 2pwms per group (we can set the pwm frequency -> new timers + new operators)
180 *
181 * PROBLEM: Skipping/loosing channels happens in some cases when the group has already used some odd number of pwm channels (for example 3pwm or 1pwm)
182 * For example if the group has already used 3pwms, there is one generator that has one pwm channel left.
183 * 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.
184 * Current implementation does use the remaining channel only if there isn't other options that would allow changing the pwm frequency.
185 * In this example where we have 3pwms already configured, if we try to configure 2pws after, we will skip the remaining channel
186 * and use a new timer and operator to allow changing the pwm frequency. In such cases we loose (cannot be used) the remaining channel.
187 * TODO: use the pwm_frequency to avoid skipping pwm channels !
188 *
189 * returns
190 * - 1 if solution found in one group
191 * - 2 if solution requires using both groups
192 * - 0 if no solution possible
193*/
194int _findBestGroup(int no_pins, long pwm_freq, int* group, int* timer){
195 // an empty group is always the best option
196 for(int i=0; i<SOC_MCPWM_GROUPS; i++){
197 if(!group_pins_used[i]){
198 *group = i;
199 *timer=0; // use the first timer in an empty group
200 return 1;
201 }
202 }
203
204 // if 3 or 1pwm
205 // check if there is available space in one of the groups
206 // otherwise fail
207 if(no_pins == 3 || no_pins==1){
208 // second best option is if there is a group with
209 // pair number of pwms available as we can then
210 // set the pwm frequency
211 for(int i=0; i<SOC_MCPWM_GROUPS; i++){
212 if(_hasAvailablePins(i, no_pins+1)) {
213 *group=i;
214 *timer = _findNextTimer(i);
215 return 1;
216 }
217 }
218 // third best option is any group that has enough pins
219 for(int i=0; i<SOC_MCPWM_GROUPS; i++){
220 if(_hasAvailablePins(i, no_pins)) {
221 *group=i;
222 *timer = _findLastTimer(i);
223 return 1;
224 }
225 }
226 }
227
228 // if 2 or 4 pwm
229 // check if there is available space in one of the groups
230 // if not check if they can be separated in two groups
231 if(no_pins == 2 || no_pins==4){
232 // second best option is any group that has enough pins
233 for(int i=0; i<2; i++){
234 if(_hasAvailablePins(i, no_pins)) {
235 *group=i;
236 *timer = _findNextTimer(i);
237 return 1;
238 }
239 }
240 // third best option is half pwms per group
241 int half_no_pins = (int)no_pins/2;
242 if(_hasAvailablePins(0,half_no_pins) && _hasAvailablePins(1 ,half_no_pins)){
243 return 2;
244 }
245 }
246
247 // otherwise fail
248 return 0;
249}
250
251
252// configuring center aligned pwm
253// More info here: https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/api-reference/peripherals/mcpwm.html#symmetric-dual-edge-active-low
254int _configureCenterAlign(mcpwm_gen_handle_t gena, mcpwm_cmpr_handle_t cmpa, bool inverted = false){
255 if(inverted)
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());
260 else
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());
265}
266
267
268
269// Helper function calculating the pwm period from the pwm frequency
270// - pwm_frequency - pwm frequency in hertz
271// returns pwm period in ticks (uint32_t)
272uint32_t _calcPWMPeriod(long pwm_frequency) {
273 return (uint32_t)(1 * _PWM_TIMEBASE_RESOLUTION_HZ / pwm_frequency);
274}
275/*
276 Helper function calculating the pwm frequency from the pwm period
277 - pwm_period - pwm period in ticks
278 returns pwm frequency in hertz (long)
279*/
280long _calcPWMFreq(long pwm_period) {
281 return (uint32_t)(1 * _PWM_TIMEBASE_RESOLUTION_HZ / pwm_period / 2);
282}
283
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
288 };
289
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;
299#endif
300
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];
305
306 uint8_t no_operators = 3; // use 3 comparators one per pair of pwms
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));
315 }
316
317#if SIMPLEFOC_ESP32_HW_DEADTIME == true // hardware dead-time (hardware 6pwm)
318
319 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring 6PWM with hardware dead-time");
320
321 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_operators) + " comparators.");
322 // Create and configure 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));
328 }
329
330#else // software dead-time (software 6pwm)
331// software dead-time (software 6pwm)
332 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring 6PWM with software dead-time");
333
334 int no_pins = 6;
335 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_pins) + " comparators.");
336 // Create and configure 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));
343 }
344#endif
345
346 int no_generators = 6; // one per pwm
347 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_generators) + " generators.");
348 // Create and configure 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]));
354 }
355
356 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring Center-Aligned 6 pwm.");
357
358#if SIMPLEFOC_ESP32_HW_DEADTIME == true // hardware dead-time (hardware 6pwm)
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));
362
363 }
364 // only available for 6pwm
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;
370 dt_config_high.flags.invert_output = !SIMPLEFOC_PWM_HIGHSIDE_ACTIVE_HIGH;
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;
374 dt_config_low.flags.invert_output = SIMPLEFOC_PWM_LOWSIDE_ACTIVE_HIGH;
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));
378 }
379#else // software dead-time (software 6pwm)
380 for (int i = 0; i < 3; i++) {
381 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));
382 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));
383 }
384#endif
385
386 SIMPLEFOC_ESP32_DRV_DEBUG("Enabling timer: "+String(timer_no));
387 // Enable and start timer
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!");
390
391 _delay(1);
392 SIMPLEFOC_ESP32_DRV_DEBUG("MCPWM configured!");
393 params->dead_zone = dead_zone;
394 // save the configuration variables for later
395 group_pins_used[mcpwm_group] = 6;
396 return params;
397}
398
399
400/*
401 function configuring the pins for the mcpwm
402 - pwm_frequency - pwm frequency
403 - mcpwm_group - mcpwm group
404 - timer_no - timer number
405 - no_pins - number of pins
406 - pins - array of pins
407 - dead_zone - dead zone
408
409 returns the driver parameters
410*/
411void* _configurePinsMCPWM(long pwm_frequency, int mcpwm_group, int timer_no, int no_pins, int* pins){
412
413 ESP32MCPWMDriverParams* params = new ESP32MCPWMDriverParams{
414 .pwm_frequency = pwm_frequency,
415 .group_id = mcpwm_group
416 };
417
418 bool shared_timer = false;
419 // check if timer is configured
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;
430#endif
431 // initialise the timer
432 CHECK_ERR(mcpwm_new_timer(&pwm_config, &timers[mcpwm_group][timer_no]), "Could not initialize the timer in group: " + String(mcpwm_group));
433 // save variables for later
434 pwm_periods[mcpwm_group][timer_no] = pwm_config.period_ticks / 2;
435 params->timers[0] = timers[mcpwm_group][timer_no];
436 // if the numer of used channels it not pair skip one channel
437 // the skipped channel cannot be used with the new timer
438 // TODO avoid loosing channels like this
439 if(group_pins_used[mcpwm_group] %2) group_pins_used[mcpwm_group]++;
440 }else{
441 // we will use an already instantiated timer
442 params->timers[0] = timers[mcpwm_group][timer_no];
443 SIMPLEFOC_ESP32_DRV_DEBUG("Using previously configured timer: " + String(timer_no));
444 // but we cannot change its configuration without affecting the other drivers
445 // so let's first verify that the configuration is the same
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));
449 }
450 CHECK_ERR(mcpwm_timer_start_stop( params->timers[0], MCPWM_TIMER_STOP_EMPTY), "Failed to stop the timer!");
451
452 shared_timer = true;
453 }
454
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) { // first operator already configured
463 params->oper[0] = last_operator[mcpwm_group];
464 continue;
465 }
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));
468 }
469 // save the last operator in this group
470 last_operator[mcpwm_group] = params->oper[no_operators - 1];
471
472 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_pins) + " comparators.");
473 // Create and configure 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));
480 }
481
482 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring " + String(no_pins) + " generators.");
483 // Create and configure 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]));
489 }
490
491
492 SIMPLEFOC_ESP32_DRV_DEBUG("Configuring center-aligned pwm.");
493 for (int i = 0; i < no_pins; i++) {
494 CHECK_ERR(_configureCenterAlign(params->generator[i],params->comparator[i], !SIMPLEFOC_PWM_ACTIVE_HIGH), "Failed to configure center align pwm: " + String(i));
495 }
496
497 SIMPLEFOC_ESP32_DRV_DEBUG("Enabling timer: "+String(timer_no));
498 // Enable and start timer if not shared
499 if (!shared_timer) CHECK_ERR(mcpwm_timer_enable(params->timers[0]), "Failed to enable timer!");
500 // start the timer
501 CHECK_ERR(mcpwm_timer_start_stop(params->timers[0], MCPWM_TIMER_START_NO_STOP), "Failed to start the timer!");
502
503 _delay(1);
504 SIMPLEFOC_ESP32_DRV_DEBUG("MCPWM configured!");
505 // save the configuration variables for later
506 params->mcpwm_period = pwm_periods[mcpwm_group][timer_no];
507 group_pins_used[mcpwm_group] += no_pins;
508 return params;
509}
510
511// function setting the duty cycle to the MCPWM pin
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));
515}
516
517// function setting the duty cycle to the MCPWM pin
518void _forcePhaseState(mcpwm_gen_handle_t generator_high, mcpwm_gen_handle_t generator_low, PhaseState phase_state){
519 // phase state is forced in hardware pwm mode
520 // esp-idf docs: https://docs.espressif.com/projects/esp-idf/en/v5.1.4/esp32/api-reference/peripherals/mcpwm.html#generator-force-actions
521 // github issue: https://github.com/espressif/esp-idf/issues/12237
522 mcpwm_generator_set_force_level(generator_high, (phase_state == PHASE_ON || phase_state == PHASE_HI) ? -1 : 0, true);
523 mcpwm_generator_set_force_level(generator_low, (phase_state == PHASE_ON || phase_state == PHASE_LO) ? -1 : 1, true);
524}
525
526#endif
PhaseState
Definition FOCDriver.h:7
@ PHASE_HI
Definition FOCDriver.h:10
@ PHASE_ON
Definition FOCDriver.h:9
@ PHASE_LO
Definition FOCDriver.h:11
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)
Definition foc_utils.h:11
void _delay(unsigned long ms)
Definition time_utils.cpp:5