test_pwm.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. /**
  2. * To test PWM, use the PCNT to calculateit to judge it work right or not.
  3. * e.g: judge the start and stop.
  4. * If started right, the PCNT will count the pulse.
  5. * If stopped right, the PCNT will count no pulse.
  6. *
  7. *
  8. * test environment UT_T1_MCPWM:
  9. * 1. connect GPIO4 to GPIO5
  10. * 2. connect GPIO13 to GPIO12
  11. * 3. connect GPIO27 to GPIO14
  12. *
  13. * all of case separate different timer to test in case that one case cost too much time
  14. */
  15. #include <stdio.h>
  16. #include "esp_system.h"
  17. #include "unity.h"
  18. #include "test_utils.h"
  19. #include "freertos/FreeRTOS.h"
  20. #include "freertos/task.h"
  21. #include "freertos/queue.h"
  22. #include "esp_attr.h"
  23. #include "esp_log.h"
  24. #include "soc/rtc.h"
  25. #include "soc/soc_caps.h"
  26. #if SOC_MCPWM_SUPPORTED
  27. #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
  28. #include "soc/mcpwm_periph.h"
  29. #include "driver/pcnt.h"
  30. #include "driver/mcpwm.h"
  31. #define GPIO_PWMA_OUT 4
  32. #define GPIO_PWMB_OUT 13
  33. #define GPIO_CAP_IN 27
  34. #define GPIO_SYNC_IN 27
  35. #define GPIO_FAULT_IN 27
  36. #define CAP_SIG_NUM 14
  37. #define SYN_SIG_NUM 14
  38. #define FAULT_SIG_NUM 14
  39. #define GPIO_PWMA_PCNT_INPUT 5
  40. #define GPIO_PWMB_PCNT_INPUT 12
  41. #define PCNT_CTRL_FLOATING_IO1 25
  42. #define PCNT_CTRL_FLOATING_IO2 26
  43. #define CAP0_INT_EN BIT(27)
  44. #define CAP1_INT_EN BIT(28)
  45. #define CAP2_INT_EN BIT(29)
  46. #define INITIAL_DUTY 10.0
  47. #define MCPWM_GPIO_INIT 0
  48. #define HIGHEST_LIMIT 10000
  49. #define LOWEST_LIMIT -10000
  50. static mcpwm_dev_t *MCPWM[2] = {&MCPWM0, &MCPWM1};
  51. static xQueueHandle cap_queue;
  52. static volatile int cap0_times = 0;
  53. static volatile int cap1_times = 0;
  54. static volatile int cap2_times = 0;
  55. typedef struct {
  56. uint32_t capture_signal;
  57. mcpwm_capture_signal_t sel_cap_signal;
  58. } capture;
  59. static const char TAG[] = "test_pwm";
  60. const static mcpwm_io_signals_t pwma[] = {MCPWM0A, MCPWM1A, MCPWM2A};
  61. const static mcpwm_io_signals_t pwmb[] = {MCPWM0B, MCPWM1B, MCPWM2B};
  62. const static mcpwm_fault_signal_t fault_sig_array[] = {MCPWM_SELECT_F0, MCPWM_SELECT_F1, MCPWM_SELECT_F2};
  63. const static mcpwm_io_signals_t fault_io_sig_array[] = {MCPWM_FAULT_0, MCPWM_FAULT_1, MCPWM_FAULT_2};
  64. const static mcpwm_sync_signal_t sync_sig_array[] = {MCPWM_SELECT_SYNC0, MCPWM_SELECT_SYNC1, MCPWM_SELECT_SYNC2};
  65. const static mcpwm_io_signals_t sync_io_sig_array[] = {MCPWM_SYNC_0, MCPWM_SYNC_1, MCPWM_SYNC_2};
  66. const static mcpwm_capture_signal_t cap_sig_array[] = {MCPWM_SELECT_CAP0, MCPWM_SELECT_CAP1, MCPWM_SELECT_CAP2};
  67. const static mcpwm_io_signals_t cap_io_sig_array[] = {MCPWM_CAP_0, MCPWM_CAP_1, MCPWM_CAP_2};
  68. // universal settings of mcpwm
  69. static void mcpwm_basic_config(mcpwm_unit_t unit, mcpwm_timer_t timer)
  70. {
  71. mcpwm_io_signals_t mcpwm_a = pwma[timer];
  72. mcpwm_io_signals_t mcpwm_b = pwmb[timer];
  73. mcpwm_gpio_init(unit, mcpwm_a, GPIO_PWMA_OUT);
  74. mcpwm_gpio_init(unit, mcpwm_b, GPIO_PWMB_OUT);
  75. mcpwm_config_t pwm_config = {
  76. .frequency = 1000,
  77. .cmpr_a = 50.0, //duty cycle of PWMxA = 50.0%
  78. .cmpr_b = 50.0, //duty cycle of PWMxb = 50.0%
  79. .counter_mode = MCPWM_UP_COUNTER,
  80. .duty_mode = MCPWM_DUTY_MODE_0,
  81. };
  82. mcpwm_init(unit, timer, &pwm_config);
  83. }
  84. static void pcnt_init(int pulse_gpio_num, int ctrl_gpio_num)
  85. {
  86. pcnt_config_t pcnt_config = {
  87. .pulse_gpio_num = pulse_gpio_num,
  88. .ctrl_gpio_num = ctrl_gpio_num,
  89. .channel = PCNT_CHANNEL_0,
  90. .unit = PCNT_UNIT_0,
  91. .pos_mode = PCNT_COUNT_INC,
  92. .neg_mode = PCNT_COUNT_DIS,
  93. .lctrl_mode = PCNT_MODE_REVERSE,
  94. .hctrl_mode = PCNT_MODE_KEEP,
  95. .counter_h_lim = HIGHEST_LIMIT,
  96. .counter_l_lim = LOWEST_LIMIT,
  97. };
  98. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  99. }
  100. // initialize the PCNT
  101. // PCNT is used to count the MCPWM pulse
  102. static int16_t pcnt_count(int pulse_gpio_num, int ctrl_gpio_num, int last_time)
  103. {
  104. pcnt_config_t pcnt_config = {
  105. .pulse_gpio_num = pulse_gpio_num,
  106. .ctrl_gpio_num = ctrl_gpio_num,
  107. .channel = PCNT_CHANNEL_0,
  108. .unit = PCNT_UNIT_0,
  109. .pos_mode = PCNT_COUNT_INC,
  110. .neg_mode = PCNT_COUNT_DIS,
  111. .lctrl_mode = PCNT_MODE_REVERSE,
  112. .hctrl_mode = PCNT_MODE_KEEP,
  113. .counter_h_lim = HIGHEST_LIMIT,
  114. .counter_l_lim = LOWEST_LIMIT,
  115. };
  116. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  117. int16_t test_counter;
  118. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  119. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  120. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  121. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  122. printf("COUNT (before): %d\n", test_counter);
  123. vTaskDelay(last_time / portTICK_RATE_MS);
  124. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  125. printf("COUNT (after): %d\n", test_counter);
  126. return test_counter;
  127. }
  128. // judge the counting value right or not in specific error
  129. static void judge_count_value(int allow_error ,int expect_freq)
  130. {
  131. int16_t countA, countB;
  132. countA = pcnt_count(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1, 1000);
  133. countB = pcnt_count(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2, 1000);
  134. TEST_ASSERT_INT16_WITHIN(allow_error, countA, expect_freq);
  135. TEST_ASSERT_INT16_WITHIN(allow_error, countB, expect_freq);
  136. }
  137. // test the duty configuration
  138. static void timer_duty_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  139. {
  140. mcpwm_basic_config(unit, timer);
  141. vTaskDelay(1000 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
  142. TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_A, (INITIAL_DUTY * 1)));
  143. TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_B, (INITIAL_DUTY * 2)));
  144. TEST_ASSERT_EQUAL_INT(mcpwm_get_duty(unit, timer, MCPWM_OPR_A), INITIAL_DUTY * 1);
  145. TEST_ASSERT_EQUAL_INT(mcpwm_get_duty(unit, timer, MCPWM_OPR_B), INITIAL_DUTY * 2);
  146. vTaskDelay(100 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
  147. mcpwm_set_duty(unit, timer, MCPWM_OPR_A, 55.5f);
  148. mcpwm_set_duty_type(unit, timer, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
  149. printf("mcpwm check = %f\n", mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
  150. mcpwm_set_duty_in_us(unit, timer, MCPWM_OPR_B, 500);
  151. printf("mcpwm check = %f\n", mcpwm_get_duty(unit, timer, MCPWM_OPR_B));
  152. vTaskDelay(100 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
  153. mcpwm_stop(unit, timer);
  154. }
  155. // test the start and stop function work or not
  156. static void start_stop_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  157. {
  158. mcpwm_basic_config(unit, timer);
  159. judge_count_value(2, 1000);
  160. TEST_ESP_OK(mcpwm_stop(unit, timer));
  161. vTaskDelay(10 / portTICK_RATE_MS); // wait for a while, stop totally
  162. judge_count_value(0, 0);
  163. TEST_ESP_OK(mcpwm_start(unit, timer));
  164. vTaskDelay(10 / portTICK_RATE_MS); // wait for a while, start totally
  165. judge_count_value(2, 1000);
  166. }
  167. // test the deadtime
  168. static void deadtime_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
  169. {
  170. mcpwm_basic_config(unit, timer);
  171. mcpwm_deadtime_type_t deadtime_type[8] = {MCPWM_BYPASS_RED, MCPWM_BYPASS_FED, MCPWM_ACTIVE_HIGH_MODE,
  172. MCPWM_ACTIVE_LOW_MODE, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, MCPWM_ACTIVE_LOW_COMPLIMENT_MODE,
  173. MCPWM_ACTIVE_RED_FED_FROM_PWMXA, MCPWM_ACTIVE_RED_FED_FROM_PWMXB};
  174. for(int i=0; i<8; i++) {
  175. mcpwm_deadtime_enable(unit, timer, deadtime_type[i], 1000, 1000);
  176. vTaskDelay(100 / portTICK_RATE_MS);
  177. mcpwm_deadtime_disable(unit, timer);
  178. //add a small gap between tests to make the waveform more clear
  179. mcpwm_stop(unit, timer);
  180. vTaskDelay(10);
  181. mcpwm_start(unit, timer);
  182. }
  183. }
  184. /**
  185. * there are two kind of methods to set the carrier:
  186. * 1. by mcpwm_carrier_init
  187. * 2. by different single setting function
  188. */
  189. static void carrier_with_set_function_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_carrier_out_ivt_t invert_or_not,
  190. uint8_t period, uint8_t duty, uint8_t os_width)
  191. {
  192. // no inversion and no one shot
  193. mcpwm_basic_config(unit, timer);
  194. TEST_ESP_OK(mcpwm_carrier_enable(unit, timer));
  195. TEST_ESP_OK(mcpwm_carrier_set_period(unit, timer, period)); //carrier revolution
  196. TEST_ESP_OK(mcpwm_carrier_set_duty_cycle(unit, timer, duty)); // carrier duty
  197. judge_count_value(500, 50000/5.6);
  198. // with invert
  199. TEST_ESP_OK(mcpwm_carrier_output_invert(unit, timer, invert_or_not));
  200. vTaskDelay(2000 / portTICK_RATE_MS);
  201. }
  202. static void carrier_with_configuration_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_carrier_os_t oneshot_or_not,
  203. mcpwm_carrier_out_ivt_t invert_or_not, uint8_t period, uint8_t duty,
  204. uint8_t os_width)
  205. {
  206. mcpwm_basic_config(unit, timer);
  207. mcpwm_carrier_config_t chop_config;
  208. chop_config.carrier_period = period; //carrier period = (period + 1)*800ns
  209. chop_config.carrier_duty = duty; // carrier duty cycle, carrier_duty should be less then 8(increment every 12.5%). carrier duty = (3)*12.5%
  210. chop_config.carrier_os_mode = oneshot_or_not; //If one shot mode is enabled then set pulse width, if disabled no need to set pulse width
  211. chop_config.pulse_width_in_os = os_width; //pulse width of first pulse in one shot mode = (carrier period)*(pulse_width_in_os + 1), should be less then 16.first pulse width = (3 + 1)*carrier_period
  212. chop_config.carrier_ivt_mode = invert_or_not; //output signal inversion enable
  213. mcpwm_carrier_init(unit, timer, &chop_config);
  214. if(!oneshot_or_not) {
  215. // the pwm frequency is 1000
  216. // the carrrier duration in one second is 500ms
  217. // the carrier wave count is: 500ms/carrier_period = 500ms/(period + 1)*800ns
  218. // = 62500/(period + 1)
  219. judge_count_value(500, 62500/(period + 1));
  220. } else {
  221. judge_count_value(500, 40000/((period + 1))); // (500-500*0.125*3)/((period + 1)*800)
  222. }
  223. TEST_ESP_OK(mcpwm_carrier_disable(unit, timer));
  224. judge_count_value(2, 1000);
  225. }
  226. static void get_action_level(mcpwm_fault_input_level_t input_sig, mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b, int freq, int allow_err)
  227. {
  228. if(action_a == MCPWM_NO_CHANGE_IN_MCPWMXA) {
  229. TEST_ASSERT_INT16_WITHIN(allow_err, pcnt_count(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1, 1000), freq);
  230. } else if(action_a == MCPWM_FORCE_MCPWMXA_LOW) {
  231. TEST_ASSERT(gpio_get_level(GPIO_PWMA_PCNT_INPUT) == 0);
  232. } else if(action_a == MCPWM_FORCE_MCPWMXA_HIGH) {
  233. TEST_ASSERT(gpio_get_level(GPIO_PWMA_PCNT_INPUT) == 1);
  234. }else {
  235. int level = gpio_get_level(GPIO_PWMA_PCNT_INPUT);
  236. vTaskDelay(100 / portTICK_RATE_MS);
  237. TEST_ASSERT(gpio_get_level(GPIO_PWMA_PCNT_INPUT) == level);
  238. }
  239. if(action_b == MCPWM_NO_CHANGE_IN_MCPWMXB) {
  240. TEST_ASSERT_INT16_WITHIN(allow_err, pcnt_count(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1, 1000), freq);
  241. } else if(action_b == MCPWM_FORCE_MCPWMXB_LOW) {
  242. TEST_ASSERT(gpio_get_level(GPIO_PWMB_PCNT_INPUT) == 0);
  243. } else if(action_b == MCPWM_FORCE_MCPWMXB_HIGH) {
  244. TEST_ASSERT(gpio_get_level(GPIO_PWMB_PCNT_INPUT) == 1);
  245. }else {
  246. int level = gpio_get_level(GPIO_PWMB_PCNT_INPUT);
  247. vTaskDelay(100 / portTICK_RATE_MS);
  248. TEST_ASSERT(gpio_get_level(GPIO_PWMB_PCNT_INPUT) == level);
  249. }
  250. }
  251. // test the fault event
  252. static void cycle_fault_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_fault_signal_t fault_sig,
  253. mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
  254. mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
  255. {
  256. gpio_config_t gp;
  257. gp.intr_type = GPIO_INTR_DISABLE;
  258. gp.mode = GPIO_MODE_OUTPUT;
  259. gp.pin_bit_mask = (1ULL << FAULT_SIG_NUM);
  260. gpio_config(&gp); // gpio configure should be more previous than mcpwm configuration
  261. gpio_set_level(FAULT_SIG_NUM, !input_sig);
  262. pcnt_init(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1);
  263. pcnt_init(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2);
  264. mcpwm_basic_config(unit, timer);
  265. mcpwm_gpio_init(unit, fault_io, GPIO_FAULT_IN);
  266. // cycle mode, it can be triggered more than once
  267. printf("cyc test:\n");
  268. gpio_set_level(FAULT_SIG_NUM, !input_sig);
  269. TEST_ESP_OK(mcpwm_fault_init(unit, input_sig, fault_sig));
  270. TEST_ESP_OK(mcpwm_fault_set_cyc_mode(unit, timer, fault_sig, action_a, action_b));
  271. vTaskDelay(1000 / portTICK_RATE_MS);
  272. gpio_set_level(FAULT_SIG_NUM, input_sig); // trigger the fault event
  273. vTaskDelay(1000 / portTICK_RATE_MS);
  274. get_action_level(input_sig, action_a, action_b, 1000, 5);
  275. TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
  276. }
  277. static void oneshot_fault_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_fault_signal_t fault_sig,
  278. mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
  279. mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
  280. {
  281. gpio_config_t gp;
  282. gp.intr_type = GPIO_INTR_DISABLE;
  283. gp.mode = GPIO_MODE_OUTPUT;
  284. gp.pin_bit_mask = (1ULL << FAULT_SIG_NUM);
  285. gpio_config(&gp); // gpio configure should be more previous than mcpwm configuration
  286. gpio_set_level(FAULT_SIG_NUM, !input_sig);
  287. pcnt_init(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1);
  288. pcnt_init(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2);
  289. mcpwm_basic_config(unit, timer);
  290. mcpwm_gpio_init(unit, fault_io, GPIO_FAULT_IN);
  291. // one shot mode, it just can be triggered once
  292. TEST_ESP_OK(mcpwm_fault_init(unit, input_sig, fault_sig));
  293. TEST_ESP_OK(mcpwm_fault_set_oneshot_mode(unit, timer, fault_sig, action_a, action_b));
  294. vTaskDelay(10 / portTICK_RATE_MS);
  295. // trigger it
  296. gpio_set_level(FAULT_SIG_NUM, input_sig);
  297. vTaskDelay(10 / portTICK_RATE_MS);
  298. get_action_level(input_sig, action_a, action_b, 1000, 5);
  299. TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
  300. }
  301. // test the sync event
  302. static void sync_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_sync_signal_t sync_sig, mcpwm_io_signals_t sync_io)
  303. {
  304. gpio_config_t gp;
  305. gp.intr_type = GPIO_INTR_DISABLE;
  306. gp.mode = GPIO_MODE_OUTPUT;
  307. gp.pin_bit_mask = (1ULL << SYN_SIG_NUM);
  308. gpio_config(&gp);
  309. gpio_set_level(SYN_SIG_NUM, 0);
  310. mcpwm_io_signals_t mcpwm_a = pwma[timer];
  311. mcpwm_io_signals_t mcpwm_b = pwmb[timer];
  312. mcpwm_gpio_init(unit, mcpwm_a, GPIO_PWMA_OUT);
  313. mcpwm_gpio_init(unit, mcpwm_b, GPIO_PWMB_OUT);
  314. mcpwm_gpio_init(unit, sync_io, GPIO_SYNC_IN);
  315. mcpwm_config_t pwm_config = {
  316. .frequency = 1000,
  317. .cmpr_a = 50.0, //duty cycle of PWMxA = 50.0%
  318. .cmpr_b = 50.0, //duty cycle of PWMxb = 50.0%
  319. .counter_mode = MCPWM_UP_COUNTER,
  320. .duty_mode = MCPWM_DUTY_MODE_0,
  321. };
  322. mcpwm_init(unit, timer, &pwm_config);
  323. gpio_pulldown_en(GPIO_SYNC_IN);
  324. mcpwm_sync_enable(unit, timer, sync_sig, 200);
  325. //wait for some pulses before sync
  326. vTaskDelay(10);
  327. gpio_set_level(SYN_SIG_NUM, 1);
  328. vTaskDelay(100 / portTICK_RATE_MS);
  329. gpio_set_level(SYN_SIG_NUM, 0);
  330. mcpwm_sync_disable(unit, timer);
  331. vTaskDelay(100 / portTICK_RATE_MS);
  332. }
  333. /**
  334. * use interruption to test the capture event
  335. * there are two kinds of methods to trigger the capture event:
  336. * 1. high level trigger
  337. * 2. low level trigger
  338. */
  339. static volatile int flag = 0;
  340. // once capture event happens, will show it
  341. static void disp_captured_signal(void *arg)
  342. {
  343. uint32_t *current_cap_value = (uint32_t *)malloc(sizeof(uint32_t) * CAP_SIG_NUM);
  344. uint32_t *previous_cap_value = (uint32_t *)malloc(sizeof(uint32_t) * CAP_SIG_NUM);
  345. capture evt;
  346. for (int i=0; i<1000; i++) {
  347. xQueueReceive(cap_queue, &evt, portMAX_DELAY);
  348. if (evt.sel_cap_signal == MCPWM_SELECT_CAP0) {
  349. current_cap_value[0] = evt.capture_signal - previous_cap_value[0];
  350. previous_cap_value[0] = evt.capture_signal;
  351. current_cap_value[0] = (current_cap_value[0] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
  352. printf("CAP0 : %d us\n", current_cap_value[0]);
  353. cap0_times++;
  354. }
  355. if (evt.sel_cap_signal == MCPWM_SELECT_CAP1) {
  356. current_cap_value[1] = evt.capture_signal - previous_cap_value[1];
  357. previous_cap_value[1] = evt.capture_signal;
  358. current_cap_value[1] = (current_cap_value[1] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
  359. printf("CAP1 : %d us\n", current_cap_value[1]);
  360. cap1_times++;
  361. }
  362. if (evt.sel_cap_signal == MCPWM_SELECT_CAP2) {
  363. current_cap_value[2] = evt.capture_signal - previous_cap_value[2];
  364. previous_cap_value[2] = evt.capture_signal;
  365. current_cap_value[2] = (current_cap_value[2] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
  366. printf("CAP2 : %d us\n", current_cap_value[2]);
  367. cap2_times++;
  368. }
  369. }
  370. free(current_cap_value);
  371. free(previous_cap_value);
  372. vTaskDelete(NULL);
  373. }
  374. // mcpwm event
  375. static void IRAM_ATTR isr_handler(void *arg)
  376. {
  377. mcpwm_unit_t unit = (mcpwm_unit_t)arg;
  378. uint32_t mcpwm_intr_status;
  379. capture evt;
  380. mcpwm_intr_status = MCPWM[unit]->int_st.val; //Read interrupt status
  381. if (mcpwm_intr_status & CAP0_INT_EN) { //Check for interrupt on rising edge on CAP0 signal
  382. evt.capture_signal = mcpwm_capture_signal_get_value(unit, MCPWM_SELECT_CAP0); //get capture signal counter value
  383. evt.sel_cap_signal = MCPWM_SELECT_CAP0;
  384. xQueueSendFromISR(cap_queue, &evt, NULL);
  385. }
  386. if (mcpwm_intr_status & CAP1_INT_EN) { //Check for interrupt on rising edge on CAP0 signal
  387. evt.capture_signal = mcpwm_capture_signal_get_value(unit, MCPWM_SELECT_CAP1); //get capture signal counter value
  388. evt.sel_cap_signal = MCPWM_SELECT_CAP1;
  389. xQueueSendFromISR(cap_queue, &evt, NULL);
  390. }
  391. if (mcpwm_intr_status & CAP2_INT_EN) { //Check for interrupt on rising edge on CAP0 signal
  392. evt.capture_signal = mcpwm_capture_signal_get_value(unit, MCPWM_SELECT_CAP2); //get capture signal counter value
  393. evt.sel_cap_signal = MCPWM_SELECT_CAP2;
  394. xQueueSendFromISR(cap_queue, &evt, NULL);
  395. }
  396. MCPWM[unit]->int_clr.val = mcpwm_intr_status;
  397. }
  398. // the produce the capture triggering signal to trigger the capture event
  399. static void gpio_test_signal(void *arg)
  400. {
  401. printf("intializing test signal...\n");
  402. gpio_config_t gp = {};
  403. gp.intr_type = GPIO_INTR_DISABLE;
  404. gp.mode = GPIO_MODE_OUTPUT;
  405. gp.pin_bit_mask = 1ULL << CAP_SIG_NUM;
  406. gpio_config(&gp);
  407. for (int i=0; i<1000; i++) {
  408. //here the period of test signal is 20ms
  409. gpio_set_level(CAP_SIG_NUM, 1); //Set high
  410. vTaskDelay(10); //delay of 10ms
  411. gpio_set_level(CAP_SIG_NUM, 0); //Set low
  412. vTaskDelay(10); //delay of 10ms
  413. }
  414. flag = 1;
  415. vTaskDelete(NULL);
  416. }
  417. // capture event test function
  418. static void capture_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_capture_on_edge_t cap_edge)
  419. {
  420. // initialize the capture times
  421. cap0_times = 0;
  422. cap1_times = 0;
  423. cap2_times = 0;
  424. //each timer test the capture sig with the same id with it.
  425. mcpwm_io_signals_t cap_io = cap_io_sig_array[timer];
  426. mcpwm_capture_signal_t cap_sig = cap_sig_array[timer];
  427. mcpwm_gpio_init(unit, cap_io, GPIO_CAP_IN);
  428. cap_queue = xQueueCreate(1, sizeof(capture));
  429. xTaskCreate(disp_captured_signal, "mcpwm_config", 4096, (void *)unit, 5, NULL);
  430. xTaskCreate(gpio_test_signal, "gpio_test_signal", 4096, NULL, 5, NULL);
  431. mcpwm_capture_enable(unit, cap_sig, cap_edge, 0);
  432. MCPWM[unit]->int_ena.val = CAP0_INT_EN | CAP1_INT_EN | CAP2_INT_EN; //Enable interrupt on CAP0, CAP1 and CAP2 signal
  433. mcpwm_isr_register(unit, isr_handler, (void *)unit, ESP_INTR_FLAG_IRAM, NULL);
  434. while(flag != 1) {
  435. vTaskDelay(10 / portTICK_RATE_MS);
  436. }
  437. if(cap_sig == MCPWM_SELECT_CAP0) {
  438. TEST_ASSERT(1000 == cap0_times);
  439. } else if(cap_sig == MCPWM_SELECT_CAP1) {
  440. TEST_ASSERT(1000 == cap1_times);
  441. }else {
  442. TEST_ASSERT(1000 == cap2_times);
  443. }
  444. flag = 0; // set flag to 0 that it can be used in other case
  445. mcpwm_capture_disable(unit, cap_sig);
  446. }
  447. /**
  448. * duty test:
  449. * 1. mcpwm_set_duty
  450. * 2. mcpwm_get_duty
  451. *
  452. * This case's phenomenon should be viewed by logic analyzer
  453. * so set it ignore
  454. */
  455. TEST_CASE("MCPWM timer0 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
  456. {
  457. timer_duty_test(MCPWM_UNIT_0, MCPWM_TIMER_0);
  458. timer_duty_test(MCPWM_UNIT_1, MCPWM_TIMER_0);
  459. }
  460. TEST_CASE("MCPWM timer1 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
  461. {
  462. timer_duty_test(MCPWM_UNIT_0, MCPWM_TIMER_1);
  463. timer_duty_test(MCPWM_UNIT_1, MCPWM_TIMER_1);
  464. }
  465. TEST_CASE("MCPWM timer2 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
  466. {
  467. timer_duty_test(MCPWM_UNIT_0, MCPWM_TIMER_2);
  468. timer_duty_test(MCPWM_UNIT_1, MCPWM_TIMER_2);
  469. }
  470. // the deadtime configuration test
  471. // use the logic analyzer to make sure it goes right
  472. TEST_CASE("MCPWM timer0 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
  473. {
  474. deadtime_test(MCPWM_UNIT_0, MCPWM_TIMER_0);
  475. deadtime_test(MCPWM_UNIT_1, MCPWM_TIMER_0);
  476. }
  477. TEST_CASE("MCPWM timer1 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
  478. {
  479. deadtime_test(MCPWM_UNIT_0, MCPWM_TIMER_1);
  480. deadtime_test(MCPWM_UNIT_1, MCPWM_TIMER_1);
  481. }
  482. TEST_CASE("MCPWM timer2 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
  483. {
  484. deadtime_test(MCPWM_UNIT_0, MCPWM_TIMER_2);
  485. deadtime_test(MCPWM_UNIT_1, MCPWM_TIMER_2);
  486. }
  487. TEST_CASE("MCPWM timer0 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
  488. {
  489. start_stop_test(MCPWM_UNIT_0, MCPWM_TIMER_0);
  490. start_stop_test(MCPWM_UNIT_1, MCPWM_TIMER_0);
  491. }
  492. // mcpwm start and stop test
  493. TEST_CASE("MCPWM timer1 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
  494. {
  495. start_stop_test(MCPWM_UNIT_0, MCPWM_TIMER_1);
  496. start_stop_test(MCPWM_UNIT_1, MCPWM_TIMER_1);
  497. }
  498. TEST_CASE("MCPWM timer2 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
  499. {
  500. start_stop_test(MCPWM_UNIT_0, MCPWM_TIMER_2);
  501. start_stop_test(MCPWM_UNIT_1, MCPWM_TIMER_2);
  502. }
  503. TEST_CASE("MCPWM timer0 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
  504. {
  505. carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_0,
  506. MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
  507. carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_0,
  508. MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
  509. carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_0,
  510. MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
  511. carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_0,
  512. MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
  513. }
  514. TEST_CASE("MCPWM timer1 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
  515. {
  516. carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_1,
  517. MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
  518. carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_1,
  519. MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
  520. carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_1,
  521. MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
  522. carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_1,
  523. MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
  524. }
  525. TEST_CASE("MCPWM timer2 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
  526. {
  527. carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_2,
  528. MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
  529. carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM_TIMER_2,
  530. MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
  531. carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_2,
  532. MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
  533. carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM_TIMER_2,
  534. MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
  535. }
  536. static void test_carrier_with_config_func(mcpwm_unit_t unit, mcpwm_timer_t timer)
  537. {
  538. mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
  539. mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
  540. ESP_LOGI(TAG, "test unit%d timer%d", unit, timer);
  541. for(int i=0; i<2; i++){
  542. for(int j=0; j<2; j++) {
  543. printf("i=%d, j=%d\n", i, j);
  544. carrier_with_configuration_test(unit, timer, oneshot[i], invert[j], 6, 3, 3);
  545. }
  546. }
  547. }
  548. TEST_CASE("MCPWM timer0 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
  549. {
  550. test_carrier_with_config_func(MCPWM_UNIT_0, MCPWM_TIMER_0);
  551. test_carrier_with_config_func(MCPWM_UNIT_1, MCPWM_TIMER_0);
  552. }
  553. TEST_CASE("MCPWM timer1 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]") {
  554. test_carrier_with_config_func(MCPWM_UNIT_0, MCPWM_TIMER_1);
  555. test_carrier_with_config_func(MCPWM_UNIT_1, MCPWM_TIMER_1);
  556. }
  557. TEST_CASE("MCPWM timer2 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
  558. {
  559. test_carrier_with_config_func(MCPWM_UNIT_0, MCPWM_TIMER_2);
  560. test_carrier_with_config_func(MCPWM_UNIT_1, MCPWM_TIMER_2);
  561. }
  562. /**
  563. * Fault event:
  564. * Just support high level triggering
  565. * There are two types fault event:
  566. * 1. one-shot: it just can be triggered once, its effect is forever and it will never be changed although the fault signal change
  567. * 2. cycle: it can be triggered more than once, it will changed just as the fault signal changes. If set it triggered by high level,
  568. * when the fault signal is high level, the event will be triggered. But the event will disappear as the fault signal disappears
  569. */
  570. void test_cycle_fault(mcpwm_unit_t unit, mcpwm_timer_t timer)
  571. {
  572. // API just supports the high level trigger now, so comment it
  573. // mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
  574. mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
  575. mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
  576. ESP_LOGI(TAG, "test unit%d timer%d", unit, timer);
  577. //each timer test the fault sig with the same id with it.
  578. mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
  579. mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
  580. for(int i=0; i<4; i++){
  581. for(int j=0; j<4; j++) {
  582. printf("i=%d, j=%d\n",i, j);
  583. cycle_fault_test(unit, timer, fault_sig, MCPWM_HIGH_LEVEL_TGR, fault_io_sig, action_a[i], action_b[j]);
  584. }
  585. }
  586. }
  587. TEST_CASE("MCPWM timer0 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
  588. {
  589. test_cycle_fault(MCPWM_UNIT_0, MCPWM_TIMER_0);
  590. test_cycle_fault(MCPWM_UNIT_1, MCPWM_TIMER_0);
  591. }
  592. TEST_CASE("MCPWM timer1 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
  593. {
  594. test_cycle_fault(MCPWM_UNIT_0, MCPWM_TIMER_1);
  595. test_cycle_fault(MCPWM_UNIT_1, MCPWM_TIMER_1);
  596. }
  597. TEST_CASE("MCPWM timer2 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
  598. {
  599. test_cycle_fault(MCPWM_UNIT_0, MCPWM_TIMER_2);
  600. test_cycle_fault(MCPWM_UNIT_1, MCPWM_TIMER_2);
  601. }
  602. static void test_oneshot_fault(mcpwm_unit_t unit, mcpwm_timer_t timer)
  603. {
  604. // API just supports the high level trigger now, so comment it
  605. // mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
  606. mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
  607. mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
  608. //each timer test the fault sig with the same id with it.
  609. mcpwm_fault_signal_t fault_sig = fault_sig_array[timer];
  610. mcpwm_io_signals_t fault_io_sig = fault_io_sig_array[timer];
  611. ESP_LOGI(TAG, "test pwm unit%d, timer%d fault_sig%d", unit, timer, fault_sig);
  612. for(int i=0; i<4; i++){
  613. for(int j=0; j<4; j++) {
  614. printf("action (%d, %d)\n", i, j);
  615. oneshot_fault_test(unit, timer, fault_sig, MCPWM_HIGH_LEVEL_TGR, fault_io_sig, action_a[i], action_b[j]);
  616. }
  617. }
  618. }
  619. TEST_CASE("MCPWM timer0 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  620. {
  621. test_oneshot_fault(MCPWM_UNIT_0, MCPWM_TIMER_0);
  622. test_oneshot_fault(MCPWM_UNIT_1, MCPWM_TIMER_0);
  623. }
  624. TEST_CASE("MCPWM timer1 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  625. {
  626. test_oneshot_fault(MCPWM_UNIT_0, MCPWM_TIMER_1);
  627. test_oneshot_fault(MCPWM_UNIT_1, MCPWM_TIMER_1);
  628. }
  629. TEST_CASE("MCPWM timer2 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  630. {
  631. test_oneshot_fault(MCPWM_UNIT_0, MCPWM_TIMER_2);
  632. test_oneshot_fault(MCPWM_UNIT_1, MCPWM_TIMER_2);
  633. }
  634. static void test_sync(mcpwm_timer_t timer)
  635. {
  636. //each timer test the sync sig with the same id with it.
  637. mcpwm_sync_signal_t sync_sig = sync_sig_array[timer];
  638. mcpwm_io_signals_t sync_io_sig = sync_io_sig_array[timer];
  639. sync_test(MCPWM_UNIT_0, timer, sync_sig, sync_io_sig);
  640. TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, timer)); // make sure can view the next sync signal clearly
  641. vTaskDelay(100 / portTICK_RATE_MS);
  642. TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, timer));
  643. sync_test(MCPWM_UNIT_1, timer, sync_sig, sync_io_sig);
  644. }
  645. // need to view its phenomenon in logic analyzer
  646. // set it ignore
  647. TEST_CASE("MCPWM timer0 sync test(logic analyzer)", "[mcpwm][ignore]")
  648. {
  649. test_sync(MCPWM_TIMER_0);
  650. }
  651. // need to view its phenomenon in logic analyzer
  652. // set it ignore
  653. TEST_CASE("MCPWM timer1 sync test(logic analyzer)", "[mcpwm][ignore]")
  654. {
  655. test_sync(MCPWM_TIMER_1);
  656. }
  657. // need to view its phenomenon in logic analyzer
  658. // set it ignore
  659. TEST_CASE("MCPWM timer2 sync test(logic analyzer)", "[mcpwm][ignore]")
  660. {
  661. test_sync(MCPWM_TIMER_2);
  662. }
  663. TEST_CASE("MCPWM unit0, timer0 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  664. {
  665. capture_test(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_POS_EDGE);
  666. }
  667. TEST_CASE("MCPWM unit0, timer1 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  668. {
  669. capture_test(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_POS_EDGE);
  670. }
  671. TEST_CASE("MCPWM unit0, timer2 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  672. {
  673. capture_test(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_POS_EDGE);
  674. }
  675. TEST_CASE("MCPWM unit1, timer0 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  676. {
  677. capture_test(MCPWM_UNIT_1, MCPWM_TIMER_0, MCPWM_NEG_EDGE);
  678. }
  679. TEST_CASE("MCPWM unit1, timer1 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  680. {
  681. capture_test(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_POS_EDGE);
  682. }
  683. TEST_CASE("MCPWM unit1, timer2 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
  684. {
  685. capture_test(MCPWM_UNIT_1, MCPWM_TIMER_2, MCPWM_POS_EDGE);
  686. }
  687. #endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
  688. #endif // SOC_MCPWM_SUPPORTED