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