Page 1 of 1

[SOLVED] MCPWM works in app_main but not in a FreeRTOS task

Posted: Tue Dec 19, 2023 9:51 pm
by twadek
Hello,

I am experiencing an issue with MCPWM when inside a FreeRTOS task. My code is adapted from the esp-idf BLDC MCPWM example:https://github.com/espressif/esp-idf/tr ... dc_control.

When executed in app_main as a standalone function, motor control works as expected. When I use the same function implemented as a task, I get an error in either mcpwm_comparator_set_compare_value or mcpwm_generator_set_force_level.

I've been chasing this for a while; does anyone have a clue as to what may be causing this? Any help would be appreciated.

Example of error:
  1. Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
  2. Core  0 register dump:
  3. PC      : 0x4200ba9e  PS      : 0x00060030  A0      : 0x82008635  A1      : 0x3fc9da60
  4. 0x4200ba9e: mcpwm_comparator_set_compare_value at C:/Espressif/frameworks/esp-idf-v5.0.4-2/components/driver/mcpwm/mcpwm_cmpr.c:128 (discriminator 2)
  5. A2      : 0xb33fffff  A3      : 0x00000000  A4      : 0x3fc99948  A5      : 0x00000000
  6. A6      : 0x00000000  A7      : 0x3fc93d8c  A8      : 0x8037b0b5  A9      : 0x3fc9da30
  7. A10     : 0x3fc93d8c  A11     : 0x3fc942b4  A12     : 0x00060020  A13     : 0x00060023
  8. A14     : 0x00060223  A15     : 0x0000cdcd  SAR     : 0x00000000  EXCCAUSE: 0x0000001c
  9. EXCVADDR: 0xb3400003  LBEG    : 0x40056f5c  LEND    : 0x40056f72  LCOUNT  : 0xffffffff
  10. ClearCommError failed (PermissionError(13, 'The device does not recognize the command.', None, 22))
  11. Waiting for the device to reconnect
  12. Backtrace: 0x4200ba9b:0x3fc9da60 0x42008632:0x3fc9da90 0x4037a049:0x3fc9dab0
  13. 0x4200ba9b: mcpwm_comparator_set_compare_value at C:/Espressif/frameworks/esp-idf-v5.0.4-2/components/driver/mcpwm/mcpwm_cmpr.c:127 (discriminator 5)
  14. 0x42008632: vChangeSpeedFromQueue at C:/Espressif/esp_applications_working/motor_commutation/main/main.c:115
  15. 0x4037a049: vPortTaskWrapper at C:/Espressif/frameworks/esp-idf-v5.0.4-2/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:149
  16. ELF file SHA256: f039a8f7c9e5c080
  17. Rebooting...
  18. ESP-ROM:esp32s3-20210327
  19. Build:Mar 27 2021
  20. rst:0x3 (RTC_SW_SYS_RST),boot:0xa (SPI_FAST_FLASH_BOOT)
  21. Saved PC:0x4037576d
  22. 0x4037576d: esp_restart_noos_dig at C:/Espressif/frameworks/esp-idf-v5.0.4-2/components/esp_system/esp_system.c:64 (discriminator 1)
  23.  
  24. SPIWP:0xee
  25. mode:DIO, clock div:1
  26. load:0x3fce3810,len:0x168c
  27. load:0x403c9700,len:0xbf4
  28. load:0x403cc700,len:0x2da8
  29. entry 0x403c9904
Here is my code (some sections removed for brevity). There are other tasks as well that are running properly when the vCommutateMotor is run outside of a task.
  1.  
  2. static portMUX_TYPE xSpinLock = portMUX_INITIALIZER_UNLOCKED;
  3.  
  4. const bldc_hall_phase_action_t xHallStates[] = {
  5.     [6] = vSetState1,
  6.     [4] = vSetState2,
  7.     [5] = vSetState3,
  8.     [1] = vSetState4,
  9.     [3] = vSetState5,
  10.     [2] = vSetState6,
  11. };
  12.  
  13. // Representative function, vSetState2-vSetState6 are not shown.
  14. void vSetState1(mcpwm_gen_handle_t (*pxGenerators)[2])
  15. {
  16.     mcpwm_generator_set_force_level(pxGenerators[PWM_OP_INDEX_1][PWM_GEN_INDEX_EN], 0, true);
  17.     mcpwm_generator_set_force_level(pxGenerators[PWM_OP_INDEX_1][PWM_GEN_INDEX_MOTOR], 0, true);
  18.     mcpwm_generator_set_force_level(pxGenerators[PWM_OP_INDEX_3][PWM_GEN_INDEX_EN], 1, true);
  19.     mcpwm_generator_set_force_level(pxGenerators[PWM_OP_INDEX_3][PWM_GEN_INDEX_MOTOR], 0, true);
  20.     mcpwm_generator_set_force_level(pxGenerators[PWM_OP_INDEX_2][PWM_GEN_INDEX_EN], 1, true);
  21.     mcpwm_generator_set_force_level(pxGenerators[PWM_OP_INDEX_2][PWM_GEN_INDEX_MOTOR], -1, true);
  22. }
  23.  
  24. uint32_t ulGetHallSensorValue(bool xMotorDirectionCounterClockwise)
  25. {
  26.     uint32_t ulHallValue = gpio_get_level(DIN_HALL_1) * 4 + gpio_get_level(DIN_HALL_2) * 2 + gpio_get_level(DIN_HALL_3) * 1;
  27.     return xMotorDirectionCounterClockwise ? ulHallValue ^ (0x07) : ulHallValue;
  28. }
  29.  
  30. void vChangeSpeedFromQueue(void *pvParameters)
  31. {
  32.     static uint32_t ulCurrentSpeedValue;
  33.     mcpwm_cmpr_handle_t *xComparators = (mcpwm_cmpr_handle_t *)pvParameters;
  34.     while (1) {
  35.         if (xQueueReceive(xSpeedControlQueue, &ulCurrentSpeedValue, 0)) {
  36.             for (int i = 0; i < 3; i++) {
  37.                 if (ulCurrentSpeedValue < PWM_PERIOD) {
  38.                     ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(xComparators[i], ulCurrentSpeedValue));
  39.                 } else {
  40.                     ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(xComparators[i], PWM_PERIOD));
  41.                 }
  42.             }
  43.         }
  44.     }
  45. }
  46.  
  47. void vCommutateMotor(void *pvParameters) {
  48.     mcpwm_gen_handle_t (*xGenerators)[3][2] = pvParameters;
  49.     uint32_t ulHallSensorValue = 0;
  50.  
  51.     while (1) {
  52.         ulHallSensorValue = ulGetHallSensorValue(SPIN_DIRECTION_CCW);
  53.         if (ulHallSensorValue >= 1 && ulHallSensorValue <= 6) {
  54.             taskENTER_CRITICAL(&xSpinLock);
  55.             xHallStates[ulHallSensorValue](xGenerators);
  56.             taskEXIT_CRITICAL(&xSpinLock);
  57.         } else {
  58.             ESP_LOGE(TAG, "invalid bldc phase, wrong hall sensor value:%"PRIu32, ulHallSensorValue);
  59.         }
  60.  
  61.         ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
  62.     }
  63. }
  64.  
  65. void app_main(void) {
  66.     mcpwm_cmpr_handle_t xComparators[3];
  67.     mcpwm_gen_handle_t xGenerators[3][2] = {};
  68.  
  69.     xTaskCreate(vChangeSpeedFromQueue, "vChangeSpeedFromQueue", 8192, &xComparators, tskIDLE_PRIORITY, NULL);
  70.  
  71.     // Throws error, core panics and restarts.
  72.     xTaskCreate(vCommutateMotor, "vCommutateMotor", 8192, xGenerators, tskIDLE_PRIORITY + 1, NULL);
  73.  
  74.     // Controls BLDC motor as expected.
  75.     vCommutateMotor(xGenerators);
  76. }

Re: MCPWM works in app_main but not in a FreeRTOS task

Posted: Wed Dec 20, 2023 5:41 am
by ESP_Sprite
Not sure what exactly is wrong, but to add some info: app_main is also running as a plain old RTOS task (just one that is started and cleaned up within ESP-IDF rather than explicitly), so there's not really much difference there. If any, I'd look at how you pass xGenerators as an argument; something feels off there but I can't lay my finger on it exactly.

Re: MCPWM works in app_main but not in a FreeRTOS task

Posted: Wed Dec 20, 2023 10:40 am
by MicroController

Code: Select all

xTaskCreate(vCommutateMotor, "vCommutateMotor", 8192, xGenerators, tskIDLE_PRIORITY + 1, NULL);
Sprite is correct: You're passing a pointer to xGenerators to the new task, but xGenerators is a local variable in app_main(). When, after starting the new task, app_main() exits, the pointer to xGenerators becomes invalid, but vCommutateMotor will continue to use it.
Same thing with xComparators in

Code: Select all

xTaskCreate(vChangeSpeedFromQueue, "vChangeSpeedFromQueue", 8192, &xComparators, tskIDLE_PRIORITY, NULL);
.
Make xComparators and xGenerators global variables, or make them local in their respective task's function.

Re: MCPWM works in app_main but not in a FreeRTOS task

Posted: Wed Dec 20, 2023 3:45 pm
by twadek
That worked. Thank you for the help!