test_pwm.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <unistd.h>
  8. #include "unity.h"
  9. #include "test_utils.h"
  10. #include "freertos/FreeRTOS.h"
  11. #include "freertos/task.h"
  12. #include "soc/soc_caps.h"
  13. #include "hal/gpio_hal.h"
  14. #include "esp_rom_gpio.h"
  15. #include "soc/rtc.h"
  16. #if SOC_MCPWM_SUPPORTED
  17. #include "soc/mcpwm_periph.h"
  18. #include "driver/pcnt.h"
  19. #include "driver/mcpwm.h"
  20. #include "driver/gpio.h"
  21. #define TEST_PWMA_PCNT_UNIT (0)
  22. #define TEST_PWMB_PCNT_UNIT (1)
  23. #define TEST_PWMA_GPIO (2)
  24. #define TEST_PWMB_GPIO (4)
  25. #define TEST_FAULT_GPIO (21)
  26. #define TEST_SYNC_GPIO_0 (21)
  27. #define TEST_SYNC_GPIO_1 (18)
  28. #define TEST_SYNC_GPIO_2 (19)
  29. #define TEST_CAP_GPIO (21)
  30. #define MCPWM_TEST_GROUP_CLK_HZ (SOC_MCPWM_BASE_CLK_HZ / 16)
  31. #define MCPWM_TEST_TIMER_CLK_HZ (MCPWM_TEST_GROUP_CLK_HZ / 10)
  32. const static mcpwm_io_signals_t pwma[] = {MCPWM0A, MCPWM1A, MCPWM2A};
  33. const static mcpwm_io_signals_t pwmb[] = {MCPWM0B, MCPWM1B, MCPWM2B};
  34. const static mcpwm_fault_signal_t fault_sig_array[] = {MCPWM_SELECT_F0, MCPWM_SELECT_F1, MCPWM_SELECT_F2};
  35. const static mcpwm_io_signals_t fault_io_sig_array[] = {MCPWM_FAULT_0, MCPWM_FAULT_1, MCPWM_FAULT_2};
  36. const static mcpwm_sync_signal_t sync_sig_array[] = {MCPWM_SELECT_GPIO_SYNC0, MCPWM_SELECT_GPIO_SYNC1, MCPWM_SELECT_GPIO_SYNC2};
  37. const static mcpwm_io_signals_t sync_io_sig_array[] = {MCPWM_SYNC_0, MCPWM_SYNC_1, MCPWM_SYNC_2};
  38. const static mcpwm_capture_signal_t cap_sig_array[] = {MCPWM_SELECT_CAP0, MCPWM_SELECT_CAP1, MCPWM_SELECT_CAP2};
  39. const static mcpwm_io_signals_t cap_io_sig_array[] = {MCPWM_CAP_0, MCPWM_CAP_1, MCPWM_CAP_2};
  40. // This GPIO init function is almost the same to public API `mcpwm_gpio_init()`, except that
  41. // this function will configure all MCPWM GPIOs into output and input capable
  42. // which is useful to simulate a trigger source
  43. static esp_err_t test_mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int gpio_num)
  44. {
  45. if (gpio_num < 0) { // ignore on minus gpio number
  46. return ESP_OK;
  47. }
  48. if (io_signal <= MCPWM2B) { // Generator output signal
  49. gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
  50. int operator_id = io_signal / 2;
  51. int generator_id = io_signal % 2;
  52. esp_rom_gpio_connect_out_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].operators[operator_id].generators[generator_id].pwm_sig, 0, 0);
  53. } else if (io_signal <= MCPWM_SYNC_2) { // External sync input signal
  54. gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
  55. int gpio_sync_id = io_signal - MCPWM_SYNC_0;
  56. esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_synchros[gpio_sync_id].sync_sig, 0);
  57. } else if (io_signal <= MCPWM_FAULT_2) { // Fault input signal
  58. gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
  59. int fault_id = io_signal - MCPWM_FAULT_0;
  60. esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].gpio_faults[fault_id].fault_sig, 0);
  61. } else if (io_signal >= MCPWM_CAP_0 && io_signal <= MCPWM_CAP_2) { // Capture input signal
  62. gpio_set_direction(gpio_num, GPIO_MODE_INPUT_OUTPUT);
  63. int capture_id = io_signal - MCPWM_CAP_0;
  64. esp_rom_gpio_connect_in_signal(gpio_num, mcpwm_periph_signals.groups[mcpwm_num].captures[capture_id].cap_sig, 0);
  65. }
  66. gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
  67. return ESP_OK;
  68. }
  69. static void mcpwm_setup_testbench(mcpwm_unit_t group, mcpwm_timer_t timer, uint32_t pwm_freq, float pwm_duty,
  70. unsigned long int group_resolution, unsigned long int timer_resolution)
  71. {
  72. // PWMA <--> PCNT UNIT0
  73. pcnt_config_t pcnt_config = {
  74. .pulse_gpio_num = TEST_PWMA_GPIO,
  75. .ctrl_gpio_num = -1, // don't care level signal
  76. .channel = PCNT_CHANNEL_0,
  77. .unit = TEST_PWMA_PCNT_UNIT,
  78. .pos_mode = PCNT_COUNT_INC,
  79. .neg_mode = PCNT_COUNT_DIS,
  80. .lctrl_mode = PCNT_MODE_KEEP,
  81. .hctrl_mode = PCNT_MODE_KEEP,
  82. .counter_h_lim = 10000,
  83. .counter_l_lim = -10000,
  84. };
  85. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  86. mcpwm_io_signals_t mcpwm_a = pwma[timer];
  87. TEST_ESP_OK(test_mcpwm_gpio_init(group, mcpwm_a, TEST_PWMA_GPIO));
  88. // PWMB <--> PCNT UNIT1
  89. pcnt_config.pulse_gpio_num = TEST_PWMB_GPIO;
  90. pcnt_config.unit = TEST_PWMB_PCNT_UNIT;
  91. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  92. mcpwm_io_signals_t mcpwm_b = pwmb[timer];
  93. TEST_ESP_OK(test_mcpwm_gpio_init(group, mcpwm_b, TEST_PWMB_GPIO));
  94. // Set PWM freq and duty, start immediately
  95. mcpwm_config_t pwm_config = {
  96. .frequency = pwm_freq,
  97. .cmpr_a = pwm_duty,
  98. .cmpr_b = pwm_duty,
  99. .counter_mode = MCPWM_UP_COUNTER,
  100. .duty_mode = MCPWM_DUTY_MODE_0,
  101. };
  102. mcpwm_group_set_resolution(group, group_resolution);
  103. mcpwm_timer_set_resolution(group, timer, timer_resolution);
  104. TEST_ESP_OK(mcpwm_init(group, timer, &pwm_config));
  105. }
  106. static uint32_t mcpwm_pcnt_get_pulse_number(pcnt_unit_t pwm_pcnt_unit, int capture_window_ms)
  107. {
  108. int16_t count_value = 0;
  109. TEST_ESP_OK(pcnt_counter_pause(pwm_pcnt_unit));
  110. TEST_ESP_OK(pcnt_counter_clear(pwm_pcnt_unit));
  111. TEST_ESP_OK(pcnt_counter_resume(pwm_pcnt_unit));
  112. usleep(capture_window_ms * 1000);
  113. TEST_ESP_OK(pcnt_get_counter_value(pwm_pcnt_unit, &count_value));
  114. printf("count value: %d\r\n", count_value);
  115. return (uint32_t)count_value;
  116. }
  117. static void mcpwm_timer_duty_test(mcpwm_unit_t unit, mcpwm_timer_t timer, unsigned long int group_resolution, unsigned long int timer_resolution)
  118. {
  119. mcpwm_setup_testbench(unit, timer, 1000, 50.0, group_resolution, timer_resolution);
  120. vTaskDelay(pdMS_TO_TICKS(100));
  121. TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_A, 10.0));
  122. TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_B, 20.0));
  123. TEST_ASSERT_FLOAT_WITHIN(0.1, 10.0, mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
  124. TEST_ASSERT_FLOAT_WITHIN(0.1, 20.0, mcpwm_get_duty(unit, timer, MCPWM_OPR_B));
  125. vTaskDelay(pdMS_TO_TICKS(100));
  126. TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_A, 55.5f));
  127. TEST_ESP_OK(mcpwm_set_duty_type(unit, timer, MCPWM_OPR_A, MCPWM_DUTY_MODE_0));
  128. TEST_ASSERT_FLOAT_WITHIN(0.1, 55.5, mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
  129. vTaskDelay(pdMS_TO_TICKS(100));
  130. TEST_ESP_OK(mcpwm_set_duty_in_us(unit, timer, MCPWM_OPR_B, 500));
  131. TEST_ASSERT_INT_WITHIN(5, 500, mcpwm_get_duty_in_us(unit, timer, MCPWM_OPR_B));
  132. vTaskDelay(pdMS_TO_TICKS(100));
  133. TEST_ESP_OK(mcpwm_stop(unit, timer));
  134. vTaskDelay(pdMS_TO_TICKS(100));
  135. }
  136. TEST_CASE("MCPWM duty test", "[mcpwm]")
  137. {
  138. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  139. for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
  140. mcpwm_timer_duty_test(i, j, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
  141. mcpwm_timer_duty_test(i, j, MCPWM_TEST_GROUP_CLK_HZ / 2, MCPWM_TEST_TIMER_CLK_HZ * 2);
  142. }
  143. }
  144. }
  145. // -------------------------------------------------------------------------------------
  146. static void mcpwm_start_stop_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  147. {
  148. uint32_t pulse_number = 0;
  149. mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ); // Period: 1000us, 1ms
  150. // count the pulse number within 100ms
  151. pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMA_PCNT_UNIT, 100);
  152. TEST_ASSERT_INT_WITHIN(2, 100, pulse_number);
  153. pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 100);
  154. TEST_ASSERT_INT_WITHIN(2, 100, pulse_number);
  155. TEST_ESP_OK(mcpwm_set_frequency(unit, timer, 100));
  156. pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 100);
  157. TEST_ASSERT_INT_WITHIN(2, 10, pulse_number);
  158. // stop timer, then no pwm pulse should be generating
  159. TEST_ESP_OK(mcpwm_stop(unit, timer));
  160. usleep(10000); // wait until timer stopped
  161. pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMA_PCNT_UNIT, 100);
  162. TEST_ASSERT_INT_WITHIN(2, 0, pulse_number);
  163. pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 100);
  164. TEST_ASSERT_INT_WITHIN(2, 0, pulse_number);
  165. }
  166. TEST_CASE("MCPWM start and stop test", "[mcpwm]")
  167. {
  168. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  169. for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
  170. mcpwm_start_stop_test(i, j);
  171. }
  172. }
  173. }
  174. // -------------------------------------------------------------------------------------
  175. static void mcpwm_deadtime_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  176. {
  177. mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ); // Period: 1000us, 1ms
  178. mcpwm_deadtime_type_t deadtime_type[] = {MCPWM_BYPASS_RED, MCPWM_BYPASS_FED, MCPWM_ACTIVE_HIGH_MODE,
  179. MCPWM_ACTIVE_LOW_MODE, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, MCPWM_ACTIVE_LOW_COMPLIMENT_MODE,
  180. MCPWM_ACTIVE_RED_FED_FROM_PWMXA, MCPWM_ACTIVE_RED_FED_FROM_PWMXB
  181. };
  182. for (size_t i = 0; i < sizeof(deadtime_type) / sizeof(deadtime_type[0]); i++) {
  183. mcpwm_stop(unit, timer);
  184. usleep(10000);
  185. mcpwm_deadtime_enable(unit, timer, deadtime_type[i], 1000, 1000);
  186. mcpwm_start(unit, timer);
  187. vTaskDelay(pdMS_TO_TICKS(100));
  188. mcpwm_deadtime_disable(unit, timer);
  189. }
  190. mcpwm_stop(unit, timer);
  191. }
  192. TEST_CASE("MCPWM deadtime test", "[mcpwm]")
  193. {
  194. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  195. for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
  196. mcpwm_deadtime_test(i, j);
  197. }
  198. }
  199. }
  200. // -------------------------------------------------------------------------------------
  201. static void mcpwm_carrier_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_carrier_out_ivt_t invert_or_not,
  202. uint8_t period, uint8_t duty, uint8_t os_width)
  203. {
  204. uint32_t pulse_number = 0;
  205. mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
  206. mcpwm_set_signal_high(unit, timer, MCPWM_GEN_A);
  207. mcpwm_set_signal_high(unit, timer, MCPWM_GEN_B);
  208. TEST_ESP_OK(mcpwm_carrier_enable(unit, timer));
  209. TEST_ESP_OK(mcpwm_carrier_set_period(unit, timer, period)); //carrier revolution
  210. TEST_ESP_OK(mcpwm_carrier_set_duty_cycle(unit, timer, duty)); // carrier duty
  211. TEST_ESP_OK(mcpwm_carrier_output_invert(unit, timer, invert_or_not));
  212. TEST_ESP_OK(mcpwm_carrier_oneshot_mode_enable(unit, timer, os_width));
  213. vTaskDelay(pdMS_TO_TICKS(100));
  214. pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMA_PCNT_UNIT, 10);
  215. TEST_ASSERT_INT_WITHIN(50, 2500, pulse_number);
  216. usleep(10000);
  217. pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 10);
  218. TEST_ASSERT_INT_WITHIN(50, 2500, pulse_number);
  219. TEST_ESP_OK(mcpwm_carrier_disable(unit, timer));
  220. TEST_ESP_OK(mcpwm_stop(unit, timer));
  221. }
  222. TEST_CASE("MCPWM carrier test", "[mcpwm]")
  223. {
  224. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  225. for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
  226. // carrier should be 10MHz/8/(4+1) = 250KHz, (10MHz is the group resolution, it's fixed in the driver), carrier duty cycle is 4/8 = 50%
  227. mcpwm_carrier_test(i, j, MCPWM_CARRIER_OUT_IVT_DIS, 4, 4, 3);
  228. mcpwm_carrier_test(i, j, MCPWM_CARRIER_OUT_IVT_EN, 4, 4, 3);
  229. }
  230. }
  231. }
  232. // -------------------------------------------------------------------------------------
  233. static void mcpwm_check_generator_level_on_fault(mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
  234. {
  235. if (action_a == MCPWM_ACTION_FORCE_LOW) {
  236. TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_PWMA_GPIO));
  237. } else if (action_a == MCPWM_ACTION_FORCE_HIGH) {
  238. TEST_ASSERT_EQUAL(1, gpio_get_level(TEST_PWMA_GPIO));
  239. }
  240. if (action_b == MCPWM_ACTION_FORCE_LOW) {
  241. TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_PWMB_GPIO));
  242. } else if (action_b == MCPWM_ACTION_FORCE_HIGH) {
  243. TEST_ASSERT_EQUAL(1, gpio_get_level(TEST_PWMB_GPIO));
  244. }
  245. }
  246. static void mcpwm_fault_cbc_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  247. {
  248. mcpwm_action_on_pwmxa_t action_a[] = {MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_HIGH};
  249. mcpwm_action_on_pwmxb_t action_b[] = {MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_HIGH};
  250. mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
  251. mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
  252. mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
  253. TEST_ESP_OK(test_mcpwm_gpio_init(unit, fault_io_sig, TEST_FAULT_GPIO));
  254. gpio_set_level(TEST_FAULT_GPIO, 0);
  255. TEST_ESP_OK(mcpwm_fault_init(unit, MCPWM_HIGH_LEVEL_TGR, fault_sig));
  256. for (int i = 0; i < sizeof(action_a) / sizeof(action_a[0]); i++) {
  257. for (int j = 0; j < sizeof(action_b) / sizeof(action_b[0]); j++) {
  258. TEST_ESP_OK(mcpwm_fault_set_cyc_mode(unit, timer, fault_sig, action_a[i], action_b[j]));
  259. gpio_set_level(TEST_FAULT_GPIO, 1); // trigger the fault event
  260. usleep(10000);
  261. mcpwm_check_generator_level_on_fault(action_a[i], action_b[j]);
  262. gpio_set_level(TEST_FAULT_GPIO, 0); // remove the fault signal
  263. usleep(10000);
  264. }
  265. }
  266. TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
  267. }
  268. TEST_CASE("MCPWM fault cbc test", "[mcpwm]")
  269. {
  270. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  271. for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
  272. mcpwm_fault_cbc_test(i, j);
  273. }
  274. }
  275. }
  276. // -------------------------------------------------------------------------------------
  277. static void mcpwm_fault_ost_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  278. {
  279. mcpwm_action_on_pwmxa_t action_a[] = {MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_HIGH};
  280. mcpwm_action_on_pwmxb_t action_b[] = {MCPWM_ACTION_FORCE_LOW, MCPWM_ACTION_FORCE_HIGH};
  281. mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
  282. mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
  283. mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
  284. TEST_ESP_OK(test_mcpwm_gpio_init(unit, fault_io_sig, TEST_FAULT_GPIO));
  285. gpio_set_level(TEST_FAULT_GPIO, 0);
  286. TEST_ESP_OK(mcpwm_fault_init(unit, MCPWM_HIGH_LEVEL_TGR, fault_sig));
  287. for (int i = 0; i < sizeof(action_a) / sizeof(action_a[0]); i++) {
  288. for (int j = 0; j < sizeof(action_b) / sizeof(action_b[0]); j++) {
  289. TEST_ESP_OK(mcpwm_fault_set_oneshot_mode(unit, timer, fault_sig, action_a[i], action_b[j]));
  290. gpio_set_level(TEST_FAULT_GPIO, 1); // trigger the fault event
  291. usleep(10000);
  292. mcpwm_check_generator_level_on_fault(action_a[i], action_b[j]);
  293. gpio_set_level(TEST_FAULT_GPIO, 0); // remove the fault signal
  294. usleep(10000);
  295. }
  296. }
  297. TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
  298. }
  299. TEST_CASE("MCPWM fault ost test", "[mcpwm]")
  300. {
  301. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  302. for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
  303. mcpwm_fault_ost_test(i, j);
  304. }
  305. }
  306. }
  307. // -------------------------------------------------------------------------------------
  308. static void mcpwm_sync_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  309. {
  310. mcpwm_sync_signal_t sync_sig = sync_sig_array[timer];
  311. mcpwm_io_signals_t sync_io_sig = sync_io_sig_array[timer];
  312. mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
  313. TEST_ESP_OK(test_mcpwm_gpio_init(unit, sync_io_sig, TEST_SYNC_GPIO_0));
  314. gpio_set_level(TEST_SYNC_GPIO_0, 0);
  315. mcpwm_sync_config_t sync_conf = {
  316. .sync_sig = sync_sig,
  317. .timer_val = 200,
  318. .count_direction = MCPWM_TIMER_DIRECTION_UP,
  319. };
  320. TEST_ESP_OK(mcpwm_sync_configure(unit, timer, &sync_conf));
  321. vTaskDelay(pdMS_TO_TICKS(50));
  322. gpio_set_level(TEST_SYNC_GPIO_0, 1); // trigger an external sync event
  323. vTaskDelay(pdMS_TO_TICKS(50));
  324. mcpwm_timer_trigger_soft_sync(unit, timer); // trigger a software sync event
  325. vTaskDelay(pdMS_TO_TICKS(50));
  326. TEST_ESP_OK(mcpwm_sync_disable(unit, timer));
  327. TEST_ESP_OK(mcpwm_stop(unit, timer));
  328. }
  329. TEST_CASE("MCPWM timer GPIO sync test", "[mcpwm]")
  330. {
  331. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  332. for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
  333. mcpwm_sync_test(i, j);
  334. }
  335. }
  336. }
  337. static void mcpwm_swsync_test(mcpwm_unit_t unit) {
  338. const uint32_t test_sync_phase = 20;
  339. // used only in this area but need to be reset every time. mutex is not needed
  340. // store timestamps captured from ISR callback
  341. static uint64_t cap_timestamp[3];
  342. cap_timestamp[0] = 0;
  343. cap_timestamp[1] = 0;
  344. cap_timestamp[2] = 0;
  345. // control the start of capture to avoid unstable data
  346. static volatile bool log_cap;
  347. log_cap = false;
  348. // cb function, to update capture value
  349. // only log when channel1 comes at first, then channel2, and do not log further more.
  350. bool capture_callback(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata,
  351. void *user_data) {
  352. if (log_cap && (cap_timestamp[1] == 0 || cap_timestamp[2] == 0)) {
  353. if (cap_channel == MCPWM_SELECT_CAP1 && cap_timestamp[1] == 0) {
  354. cap_timestamp[1] = edata->cap_value;
  355. }
  356. if (cap_channel == MCPWM_SELECT_CAP2 && cap_timestamp[1] != 0) {
  357. cap_timestamp[2] = edata->cap_value;
  358. }
  359. }
  360. return false;
  361. }
  362. // configure all timer output 10% PWM
  363. for (int i = 0; i < 3; ++i) {
  364. mcpwm_setup_testbench(unit, i, 1000, 10.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
  365. }
  366. vTaskDelay(pdMS_TO_TICKS(10));
  367. // configure capture for verification
  368. mcpwm_capture_config_t conf = {
  369. .cap_edge = MCPWM_POS_EDGE,
  370. .cap_prescale = 1,
  371. .capture_cb = capture_callback,
  372. .user_data = NULL,
  373. };
  374. TEST_ESP_OK(test_mcpwm_gpio_init(unit, MCPWM_CAP_0, TEST_SYNC_GPIO_0));
  375. TEST_ESP_OK(test_mcpwm_gpio_init(unit, MCPWM_CAP_1, TEST_SYNC_GPIO_1));
  376. TEST_ESP_OK(test_mcpwm_gpio_init(unit, MCPWM_CAP_2, TEST_SYNC_GPIO_2));
  377. TEST_ESP_OK(mcpwm_capture_enable_channel(unit, MCPWM_SELECT_CAP0, &conf));
  378. TEST_ESP_OK(mcpwm_capture_enable_channel(unit, MCPWM_SELECT_CAP1, &conf));
  379. TEST_ESP_OK(mcpwm_capture_enable_channel(unit, MCPWM_SELECT_CAP2, &conf));
  380. // timer0 produce sync sig at TEZ, timer1 and timer2 consume, to make sure last two can be synced precisely
  381. // timer1 and timer2 will be synced with TEZ of timer0 at a known phase.
  382. mcpwm_sync_config_t sync_conf = {
  383. .sync_sig = MCPWM_SELECT_TIMER0_SYNC,
  384. .timer_val = 0,
  385. .count_direction = MCPWM_TIMER_DIRECTION_UP,
  386. };
  387. TEST_ESP_OK(mcpwm_sync_configure(unit, MCPWM_TIMER_1, &sync_conf));
  388. sync_conf.timer_val = 1000 - test_sync_phase;
  389. TEST_ESP_OK(mcpwm_sync_configure(unit, MCPWM_TIMER_2, &sync_conf));
  390. TEST_ESP_OK(mcpwm_set_timer_sync_output(unit, MCPWM_TIMER_0, MCPWM_SWSYNC_SOURCE_TEZ));
  391. // init gpio at the end
  392. TEST_ESP_OK(test_mcpwm_gpio_init(unit, MCPWM0A, TEST_SYNC_GPIO_0));
  393. TEST_ESP_OK(test_mcpwm_gpio_init(unit, MCPWM1A, TEST_SYNC_GPIO_1));
  394. TEST_ESP_OK(test_mcpwm_gpio_init(unit, MCPWM2A, TEST_SYNC_GPIO_2));
  395. vTaskDelay(pdMS_TO_TICKS(100));
  396. log_cap = true;
  397. vTaskDelay(pdMS_TO_TICKS(100));
  398. uint32_t delta_timestamp_us = (cap_timestamp[2] - cap_timestamp[1]) * 1000000 / rtc_clk_apb_freq_get();
  399. uint32_t expected_phase_us = 1000000 / mcpwm_get_frequency(unit, MCPWM_TIMER_0) * test_sync_phase / 1000;
  400. // accept +-2 error
  401. TEST_ASSERT_UINT32_WITHIN(2, expected_phase_us, delta_timestamp_us);
  402. // tear down
  403. for (int i = 0; i < 3; ++i) {
  404. TEST_ESP_OK(mcpwm_capture_disable_channel(unit, i));
  405. TEST_ESP_OK(mcpwm_sync_disable(unit, i));
  406. TEST_ESP_OK(mcpwm_stop(unit, i));
  407. }
  408. }
  409. TEST_CASE("MCPWM timer swsync test", "[mcpwm]")
  410. {
  411. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  412. mcpwm_swsync_test(i);
  413. }
  414. }
  415. // -------------------------------------------------------------------------------------
  416. typedef struct {
  417. mcpwm_unit_t unit;
  418. TaskHandle_t task_hdl;
  419. } test_capture_callback_data_t;
  420. static bool test_mcpwm_intr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata, void *arg) {
  421. BaseType_t high_task_wakeup = pdFALSE;
  422. test_capture_callback_data_t *cb_data = (test_capture_callback_data_t *)arg;
  423. vTaskNotifyGiveFromISR(cb_data->task_hdl, &high_task_wakeup);
  424. return high_task_wakeup == pdTRUE;
  425. }
  426. static void mcpwm_capture_test(mcpwm_unit_t unit, mcpwm_capture_signal_t cap_chan)
  427. {
  428. test_capture_callback_data_t callback_data = {
  429. .unit = unit,
  430. .task_hdl = xTaskGetCurrentTaskHandle(),
  431. };
  432. //each timer test the capture sig with the same id with it.
  433. mcpwm_io_signals_t cap_io = cap_io_sig_array[cap_chan];
  434. mcpwm_capture_channel_id_t cap_channel = cap_sig_array[cap_chan];
  435. TEST_ESP_OK(test_mcpwm_gpio_init(unit, cap_io, TEST_CAP_GPIO));
  436. mcpwm_capture_config_t conf = {
  437. .cap_edge = MCPWM_POS_EDGE,
  438. .cap_prescale = 1,
  439. .capture_cb = test_mcpwm_intr_handler,
  440. .user_data = &callback_data
  441. };
  442. TEST_ESP_OK(mcpwm_capture_enable_channel(unit, cap_channel, &conf));
  443. // generate an posage
  444. gpio_set_level(TEST_CAP_GPIO, 0);
  445. gpio_set_level(TEST_CAP_GPIO, 1);
  446. vTaskDelay(pdMS_TO_TICKS(100));
  447. TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(40)));
  448. uint32_t cap_val0 = mcpwm_capture_signal_get_value(unit, cap_chan);
  449. // generate another posage
  450. gpio_set_level(TEST_CAP_GPIO, 0);
  451. gpio_set_level(TEST_CAP_GPIO, 1);
  452. TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(40)));
  453. uint32_t cap_val1 = mcpwm_capture_signal_get_value(unit, cap_chan);
  454. // capture clock source is APB (80MHz), 100ms means 8000000 ticks
  455. TEST_ASSERT_UINT_WITHIN(100000, 8000000, cap_val1 - cap_val0);
  456. TEST_ESP_OK(mcpwm_capture_disable_channel(unit, cap_channel));
  457. }
  458. TEST_CASE("MCPWM capture test", "[mcpwm]")
  459. {
  460. // we assume each group has one capture timer
  461. for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
  462. for (int j = 0; j < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER; j++) {
  463. mcpwm_capture_test(i, j);
  464. }
  465. }
  466. }
  467. #endif // SOC_MCPWM_SUPPORTED