test_pwm.c 30 KB

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