| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2022-08-04 13:08:48 +08:00
										 |  |  | #include <inttypes.h>
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | #include "freertos/FreeRTOS.h"
 | 
					
						
							|  |  |  | #include "freertos/task.h"
 | 
					
						
							|  |  |  | #include "freertos/event_groups.h"
 | 
					
						
							|  |  |  | #include "unity.h"
 | 
					
						
							|  |  |  | #include "soc/soc_caps.h"
 | 
					
						
							|  |  |  | #include "esp_private/esp_clk.h"
 | 
					
						
							|  |  |  | #include "driver/mcpwm_cap.h"
 | 
					
						
							|  |  |  | #include "driver/mcpwm_sync.h"
 | 
					
						
							|  |  |  | #include "driver/gpio.h"
 | 
					
						
							|  |  |  | #include "test_mcpwm_utils.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("mcpwm_capture_install_uninstall", "[mcpwm]") | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     printf("install mcpwm capture timers\r\n"); | 
					
						
							|  |  |  |     mcpwm_capture_timer_config_t cap_timer_config = { | 
					
						
							|  |  |  |         .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     int total_cap_timers = SOC_MCPWM_GROUPS * SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP; | 
					
						
							|  |  |  |     mcpwm_cap_timer_handle_t cap_timers[total_cap_timers]; | 
					
						
							|  |  |  |     int k = 0; | 
					
						
							|  |  |  |     for (int i = 0; i < SOC_MCPWM_GROUPS; i++) { | 
					
						
							|  |  |  |         cap_timer_config.group_id = i; | 
					
						
							|  |  |  |         for (int j = 0; j < SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP; j++) { | 
					
						
							|  |  |  |             TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timers[k++])); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_capture_timer(&cap_timer_config, &cap_timers[0])); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("install mcpwm capture channels\r\n"); | 
					
						
							|  |  |  |     mcpwm_capture_channel_config_t cap_chan_config = { | 
					
						
							|  |  |  |         .gpio_num = 0, | 
					
						
							|  |  |  |         .prescale = 2, | 
					
						
							|  |  |  |         .flags.pos_edge = true, | 
					
						
							|  |  |  |         .flags.pull_up = true, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     mcpwm_cap_channel_handle_t cap_channels[total_cap_timers][SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER]; | 
					
						
							|  |  |  |     for (int i = 0; i < total_cap_timers; i++) { | 
					
						
							|  |  |  |         for (int j = 0; j < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER; j++) { | 
					
						
							|  |  |  |             TEST_ESP_OK(mcpwm_new_capture_channel(cap_timers[i], &cap_chan_config, &cap_channels[i][j])); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_capture_channel(cap_timers[i], &cap_chan_config, &cap_channels[i][0])); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("uninstall mcpwm capture channels and timers\r\n"); | 
					
						
							|  |  |  |     for (int i = 0; i < total_cap_timers; i++) { | 
					
						
							|  |  |  |         for (int j = 0; j < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER; j++) { | 
					
						
							|  |  |  |             TEST_ESP_OK(mcpwm_del_capture_channel(cap_channels[i][j])); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         TEST_ESP_OK(mcpwm_del_capture_timer(cap_timers[i])); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_MCPWM_CALLBACK_ATTR | 
					
						
							|  |  |  | static bool test_capture_callback(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *edata, void *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t *cap_value = (uint32_t *)user_data; | 
					
						
							|  |  |  |     if (edata->cap_edge == MCPWM_CAP_EDGE_NEG) { | 
					
						
							|  |  |  |         cap_value[1] = edata->cap_value; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         cap_value[0] = edata->cap_value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("mcpwm_capture_ext_gpio", "[mcpwm]") | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     printf("install mcpwm capture timer\r\n"); | 
					
						
							|  |  |  |     mcpwm_cap_timer_handle_t cap_timer = NULL; | 
					
						
							|  |  |  |     mcpwm_capture_timer_config_t cap_timer_config = { | 
					
						
							| 
									
										
										
										
											2022-10-09 11:14:44 +08:00
										 |  |  |         .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |         .group_id = 0, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int cap_gpio = 0; | 
					
						
							|  |  |  |     // put the GPIO into a preset state
 | 
					
						
							|  |  |  |     gpio_set_level(cap_gpio, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("install mcpwm capture channel\r\n"); | 
					
						
							|  |  |  |     mcpwm_cap_channel_handle_t pps_channel; | 
					
						
							|  |  |  |     mcpwm_capture_channel_config_t cap_chan_config = { | 
					
						
							|  |  |  |         .gpio_num = cap_gpio, | 
					
						
							|  |  |  |         .prescale = 1, | 
					
						
							|  |  |  |         .flags.pos_edge = true, | 
					
						
							|  |  |  |         .flags.neg_edge = true, | 
					
						
							|  |  |  |         .flags.io_loop_back = true, // so we can use GPIO functions to simulate the external capture signal
 | 
					
						
							|  |  |  |         .flags.pull_up = true, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &pps_channel)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("install callback for capture channel\r\n"); | 
					
						
							|  |  |  |     mcpwm_capture_event_callbacks_t cbs = { | 
					
						
							|  |  |  |         .on_cap = test_capture_callback, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     uint32_t cap_value[2] = {0}; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(pps_channel, &cbs, cap_value)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  |     printf("enable capture channel\r\n"); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_enable(pps_channel)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     printf("enable and start capture timer\r\n"); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("simulate GPIO capture signal\r\n"); | 
					
						
							|  |  |  |     gpio_set_level(cap_gpio, 1); | 
					
						
							| 
									
										
										
										
											2022-12-21 18:38:07 +08:00
										 |  |  |     vTaskDelay(pdMS_TO_TICKS(10)); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     gpio_set_level(cap_gpio, 0); | 
					
						
							| 
									
										
										
										
											2022-12-21 18:38:07 +08:00
										 |  |  |     vTaskDelay(pdMS_TO_TICKS(10)); | 
					
						
							| 
									
										
										
										
											2022-08-04 13:08:48 +08:00
										 |  |  |     printf("capture value: Pos=%"PRIu32", Neg=%"PRIu32"\r\n", cap_value[0], cap_value[1]); | 
					
						
							| 
									
										
										
										
											2022-10-09 11:14:44 +08:00
										 |  |  |     uint32_t clk_src_res; | 
					
						
							| 
									
										
										
										
											2022-12-21 18:38:07 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res)); | 
					
						
							|  |  |  |     clk_src_res /= 1000; // convert to kHz
 | 
					
						
							|  |  |  |     TEST_ASSERT_UINT_WITHIN(1000, 10000, (cap_value[1] - cap_value[0]) * 1000 / clk_src_res); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     printf("uninstall capture channel and timer\r\n"); | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_capture_channel_disable(pps_channel)); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_del_capture_channel(pps_channel)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     uint32_t cap_data[2]; | 
					
						
							|  |  |  |     int cap_data_index; | 
					
						
							|  |  |  | } test_soft_catch_user_data_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_MCPWM_CALLBACK_ATTR | 
					
						
							|  |  |  | static bool soft_cap_callback(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *data, void *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     test_soft_catch_user_data_t *cbdata = (test_soft_catch_user_data_t *)user_data; | 
					
						
							|  |  |  |     cbdata->cap_data[cbdata->cap_data_index++] = data->cap_value; | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("mcpwm_capture_software_catch", "[mcpwm]") | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     printf("install mcpwm capture timer\r\n"); | 
					
						
							|  |  |  |     mcpwm_cap_timer_handle_t cap_timer = NULL; | 
					
						
							|  |  |  |     mcpwm_capture_timer_config_t cap_timer_config = { | 
					
						
							|  |  |  |         .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, | 
					
						
							|  |  |  |         .group_id = 0, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("install mcpwm capture channel\r\n"); | 
					
						
							|  |  |  |     mcpwm_cap_channel_handle_t cap_channel = NULL; | 
					
						
							|  |  |  |     mcpwm_capture_channel_config_t cap_chan_config = { | 
					
						
							|  |  |  |         .gpio_num = -1, // don't need any GPIO, we use software to trigger a catch
 | 
					
						
							|  |  |  |         .prescale = 2, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     test_soft_catch_user_data_t test_callback_data = {}; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  |     TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_capture_channel_trigger_soft_catch(cap_channel)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     printf("register event callback for capture channel\r\n"); | 
					
						
							|  |  |  |     mcpwm_capture_event_callbacks_t cbs = { | 
					
						
							|  |  |  |         .on_cap = soft_cap_callback, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &test_callback_data)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  |     printf("enable capture channel\r\n"); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_enable(cap_channel)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     printf("enable and start capture timer\r\n"); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("trigger software catch\r\n"); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel)); | 
					
						
							|  |  |  |     vTaskDelay(pdMS_TO_TICKS(10)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel)); | 
					
						
							|  |  |  |     vTaskDelay(pdMS_TO_TICKS(10)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // check user data
 | 
					
						
							|  |  |  |     TEST_ASSERT_EQUAL(2, test_callback_data.cap_data_index); | 
					
						
							|  |  |  |     uint32_t delta = test_callback_data.cap_data[1] - test_callback_data.cap_data[0]; | 
					
						
							|  |  |  |     esp_rom_printf("duration=%u ticks\r\n", delta); | 
					
						
							| 
									
										
										
										
											2022-10-09 11:14:44 +08:00
										 |  |  |     uint32_t clk_src_res; | 
					
						
							| 
									
										
										
										
											2022-12-21 18:38:07 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res)); | 
					
						
							|  |  |  |     clk_src_res /= 1000; // convert to kHz
 | 
					
						
							|  |  |  |     TEST_ASSERT_UINT_WITHIN(1000, 10000, delta * 1000 / clk_src_res); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     printf("uninstall capture channel and timer\r\n"); | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel)); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_MCPWM_CALLBACK_ATTR | 
					
						
							|  |  |  | static bool test_capture_after_sync_callback(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *data, void *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t *cap_data = (uint32_t *)user_data; | 
					
						
							|  |  |  |     *cap_data = data->cap_value; | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST_CASE("mcpwm_capture_timer_sync_phase_lock", "[mcpwm]") | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     mcpwm_capture_timer_config_t cap_timer_config = { | 
					
						
							|  |  |  |         .group_id = 0, | 
					
						
							|  |  |  |         .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     mcpwm_cap_timer_handle_t cap_timer = NULL; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mcpwm_sync_handle_t soft_sync = NULL; | 
					
						
							|  |  |  |     mcpwm_soft_sync_config_t soft_sync_config = {}; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_new_soft_sync_src(&soft_sync_config, &soft_sync)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mcpwm_capture_timer_sync_phase_config_t sync_config = { | 
					
						
							|  |  |  |         .count_value = 1000, | 
					
						
							|  |  |  |         .direction = MCPWM_TIMER_DIRECTION_UP, | 
					
						
							|  |  |  |         .sync_src = soft_sync, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_timer_set_phase_on_sync(cap_timer, &sync_config)); | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     mcpwm_cap_channel_handle_t cap_channel = NULL; | 
					
						
							|  |  |  |     mcpwm_capture_channel_config_t cap_chan_config = { | 
					
						
							|  |  |  |         .gpio_num = -1, // don't need any GPIO, we use software to trigger a catch
 | 
					
						
							|  |  |  |         .prescale = 1, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mcpwm_capture_event_callbacks_t cbs = { | 
					
						
							|  |  |  |         .on_cap = test_capture_after_sync_callback, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     uint32_t cap_data; | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &cap_data)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  |     printf("enable capture channel\r\n"); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_enable(cap_channel)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel)); | 
					
						
							|  |  |  |     vTaskDelay(pdMS_TO_TICKS(10)); | 
					
						
							| 
									
										
										
										
											2022-08-04 13:08:48 +08:00
										 |  |  |     printf("capture data before sync: %"PRIu32"\r\n", cap_data); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_soft_sync_activate(soft_sync)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel)); | 
					
						
							|  |  |  |     vTaskDelay(pdMS_TO_TICKS(10)); | 
					
						
							| 
									
										
										
										
											2022-08-04 13:08:48 +08:00
										 |  |  |     printf("capture data after sync: %"PRIu32"\r\n", cap_data); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     TEST_ASSERT_EQUAL(1000, cap_data); | 
					
						
							| 
									
										
										
										
											2022-08-09 13:51:56 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel)); | 
					
						
							| 
									
										
										
										
											2022-05-28 17:03:05 +08:00
										 |  |  |     TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer)); | 
					
						
							|  |  |  |     TEST_ESP_OK(mcpwm_del_sync_src(soft_sync)); | 
					
						
							|  |  |  | } |