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