From 2a50dd8a8f909d2087481b2c45a9e654caeefde3 Mon Sep 17 00:00:00 2001 From: morris Date: Sun, 9 Oct 2022 11:17:45 +0800 Subject: [PATCH 1/3] mcpwm: default clock cource is PLL160M On esp32, the default clock source is also PLL160M --- components/soc/esp32/include/soc/clk_tree_defs.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/soc/esp32/include/soc/clk_tree_defs.h b/components/soc/esp32/include/soc/clk_tree_defs.h index 9e2541bd6e..89e8b06c6b 100644 --- a/components/soc/esp32/include/soc/clk_tree_defs.h +++ b/components/soc/esp32/include/soc/clk_tree_defs.h @@ -108,6 +108,7 @@ typedef enum { // For digital domain: peripherals, WIFI, BLE SOC_MOD_CLK_APB, /*!< APB_CLK is highly dependent on the CPU_CLK source */ SOC_MOD_CLK_PLL_D2, /*!< PLL_D2_CLK is derived from PLL, it has a fixed divider of 2 */ + SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from PLL, and has a fixed frequency of 160MHz */ SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 8MHz rc oscillator, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST_D256, /*!< RC_FAST_D256_CLK comes from the internal 8MHz rc oscillator, divided by 256, and passing a clock gating to the peripherals */ @@ -207,14 +208,14 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of MCPWM Timer */ -#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_D2} +#define SOC_MCPWM_TIMER_CLKS {SOC_MOD_CLK_PLL_F160M} /** * @brief Type of MCPWM timer clock source */ typedef enum { - MCPWM_TIMER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_D2, /*!< Select PLL_D2 (160MHz) as the source clock */ - MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_D2, /*!< Select PLL_D2 as the default clock choice */ + MCPWM_TIMER_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ + MCPWM_TIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ } soc_periph_mcpwm_timer_clk_src_t; /** From 1af428dff3b3e7f2e0c9830f3b1ede6ac05d9949 Mon Sep 17 00:00:00 2001 From: morris Date: Sun, 9 Oct 2022 11:10:19 +0800 Subject: [PATCH 2/3] mcpwm: fix wrong return value in the legacy driver For APIs that not return esp_err_t value, we can't use macros like ESP_RETURN_ON_xxx --- components/driver/deprecated/driver/mcpwm.h | 2 +- components/driver/deprecated/mcpwm_legacy.c | 25 +++++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/components/driver/deprecated/driver/mcpwm.h b/components/driver/deprecated/driver/mcpwm.h index a85c1951bb..58c9520811 100644 --- a/components/driver/deprecated/driver/mcpwm.h +++ b/components/driver/deprecated/driver/mcpwm.h @@ -470,7 +470,7 @@ uint32_t mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_si * @param cap_sig capture channel of whose edge is to be determined * * @return - * Capture signal edge: 1 - positive edge, 2 - negtive edge + * Capture signal edge: 1 - positive edge, 2 - negative edge, 0 - Invalid */ uint32_t mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig); diff --git a/components/driver/deprecated/mcpwm_legacy.c b/components/driver/deprecated/mcpwm_legacy.c index 1d9577b8c0..3d384a4f47 100644 --- a/components/driver/deprecated/mcpwm_legacy.c +++ b/components/driver/deprecated/mcpwm_legacy.c @@ -425,7 +425,10 @@ esp_err_t mcpwm_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpw uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) { - MCPWM_TIMER_CHECK(mcpwm_num, timer_num); + if (mcpwm_num >= MCPWM_UNIT_MAX || timer_num >= MCPWM_TIMER_MAX) { + ESP_LOGE(TAG, "Invalid MCPWM timer instance"); + return 0; + } mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; mcpwm_critical_enter(mcpwm_num); int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev); @@ -439,9 +442,12 @@ uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num) float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen) { + if (mcpwm_num >= MCPWM_UNIT_MAX || timer_num >= MCPWM_TIMER_MAX || gen >= MCPWM_GEN_MAX) { + ESP_LOGE(TAG, "Invalid MCPWM generator instance"); + return 0; + } //the driver currently always use the timer x for operator x const int op = timer_num; - MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen); mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; mcpwm_critical_enter(mcpwm_num); float duty = 100.0 * mcpwm_ll_operator_get_compare_value(hal->dev, op, gen) / mcpwm_ll_timer_get_peak(hal->dev, timer_num, false); @@ -451,9 +457,12 @@ float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_gene uint32_t mcpwm_get_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen) { + if (mcpwm_num >= MCPWM_UNIT_MAX || timer_num >= MCPWM_TIMER_MAX || gen >= MCPWM_GEN_MAX) { + ESP_LOGE(TAG, "Invalid MCPWM generator instance"); + return 0; + } //the driver currently always use the timer x for operator x const int op = timer_num; - MCPWM_GEN_CHECK(mcpwm_num, timer_num, gen); mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; mcpwm_critical_enter(mcpwm_num); int real_group_prescale = mcpwm_ll_group_get_clock_prescale(hal->dev); @@ -849,16 +858,18 @@ esp_err_t mcpwm_capture_disable_channel(mcpwm_unit_t mcpwm_num, mcpwm_capture_ch uint32_t MCPWM_ISR_ATTR mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig) { - ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR); - ESP_RETURN_ON_FALSE(cap_sig < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR); + if (mcpwm_num >= MCPWM_UNIT_MAX || cap_sig >= SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER) { + return 0; + } mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; return mcpwm_ll_capture_get_value(hal->dev, cap_sig); } uint32_t MCPWM_ISR_ATTR mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig) { - ESP_RETURN_ON_FALSE(mcpwm_num < SOC_MCPWM_GROUPS, ESP_ERR_INVALID_ARG, TAG, MCPWM_GROUP_NUM_ERROR); - ESP_RETURN_ON_FALSE(cap_sig < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER, ESP_ERR_INVALID_ARG, TAG, MCPWM_CAPTURE_ERROR); + if (mcpwm_num >= MCPWM_UNIT_MAX || cap_sig >= SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER) { + return 0; + } mcpwm_hal_context_t *hal = &context[mcpwm_num].hal; return mcpwm_ll_capture_get_edge(hal->dev, cap_sig) == MCPWM_CAP_EDGE_NEG ? 2 : 1; } From 0db5909b47b23bb9166dbe7889a865c26291d19c Mon Sep 17 00:00:00 2001 From: morris Date: Sun, 9 Oct 2022 11:14:44 +0800 Subject: [PATCH 3/3] mcpwm: new function to fetch capture resolution --- components/driver/include/driver/mcpwm_cap.h | 12 ++++++++++++ components/driver/mcpwm/mcpwm_cap.c | 7 +++++++ .../driver/test_apps/mcpwm/main/test_mcpwm_cap.c | 10 +++++----- docs/en/api-reference/peripherals/mcpwm.rst | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/components/driver/include/driver/mcpwm_cap.h b/components/driver/include/driver/mcpwm_cap.h index d40ef2fd1a..f1bb030720 100644 --- a/components/driver/include/driver/mcpwm_cap.h +++ b/components/driver/include/driver/mcpwm_cap.h @@ -94,6 +94,18 @@ esp_err_t mcpwm_capture_timer_start(mcpwm_cap_timer_handle_t cap_timer); */ esp_err_t mcpwm_capture_timer_stop(mcpwm_cap_timer_handle_t cap_timer); +/** + * @brief Get MCPWM capture timer resolution, in Hz + * + * @param[in] cap_timer MCPWM capture timer, allocated by `mcpwm_new_capture_timer()` + * @param[out] out_resolution Returned capture timer resolution, in Hz + * @return + * - ESP_OK: Get capture timer resolution successfully + * - ESP_ERR_INVALID_ARG: Get capture timer resolution failed because of invalid argument + * - ESP_FAIL: Get capture timer resolution failed because of other error + */ +esp_err_t mcpwm_capture_timer_get_resolution(mcpwm_cap_timer_handle_t cap_timer, uint32_t *out_resolution); + /** * @brief MCPWM Capture timer sync phase configuration */ diff --git a/components/driver/mcpwm/mcpwm_cap.c b/components/driver/mcpwm/mcpwm_cap.c index ef6e3b2c2a..7a80545c54 100644 --- a/components/driver/mcpwm/mcpwm_cap.c +++ b/components/driver/mcpwm/mcpwm_cap.c @@ -185,6 +185,13 @@ esp_err_t mcpwm_capture_timer_stop(mcpwm_cap_timer_handle_t cap_timer) return ESP_OK; } +esp_err_t mcpwm_capture_timer_get_resolution(mcpwm_cap_timer_handle_t cap_timer, uint32_t *out_resolution) +{ + ESP_RETURN_ON_FALSE(cap_timer && out_resolution, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + *out_resolution = cap_timer->resolution_hz; + return ESP_OK; +} + static esp_err_t mcpwm_capture_channel_register_to_timer(mcpwm_cap_channel_t *cap_channel, mcpwm_cap_timer_t *cap_timer) { int cap_chan_id = -1; diff --git a/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c b/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c index 911f2e8dcc..7da9603480 100644 --- a/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c +++ b/components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c @@ -74,7 +74,7 @@ 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 = { - .clk_src = MCPWM_CAPTURE_CLK_SRC_APB, + .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT, .group_id = 0, }; TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer)); @@ -115,8 +115,8 @@ TEST_CASE("mcpwm_capture_ext_gpio", "[mcpwm]") gpio_set_level(cap_gpio, 0); vTaskDelay(pdMS_TO_TICKS(100)); printf("capture value: Pos=%"PRIu32", Neg=%"PRIu32"\r\n", cap_value[0], cap_value[1]); - // Capture timer is clocked from APB by default - uint32_t clk_src_res = esp_clk_apb_freq(); + uint32_t clk_src_res; + mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res); TEST_ASSERT_UINT_WITHIN(100000, clk_src_res / 10, cap_value[1] - cap_value[0]); printf("uninstall capture channel and timer\r\n"); @@ -183,8 +183,8 @@ TEST_CASE("mcpwm_capture_software_catch", "[mcpwm]") 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); - // Capture timer is clocked from APB by default - uint32_t clk_src_res = esp_clk_apb_freq(); + uint32_t clk_src_res; + mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res); TEST_ASSERT_UINT_WITHIN(80000, clk_src_res / 100, delta); printf("uninstall capture channel and timer\r\n"); diff --git a/docs/en/api-reference/peripherals/mcpwm.rst b/docs/en/api-reference/peripherals/mcpwm.rst index 4760534731..d9e5032f7d 100644 --- a/docs/en/api-reference/peripherals/mcpwm.rst +++ b/docs/en/api-reference/peripherals/mcpwm.rst @@ -806,7 +806,7 @@ The MCPWM capture channel can inform the user when there's a valid edge detected - :cpp:member:`mcpwm_capture_event_callbacks_t::on_cap` sets callback function for the capture channel when a valid edge is detected. -The callback function will provide event specific data of type :cpp:type:`mcpwm_capture_event_data_t`, so that you can get the the edge of the capture signal in :cpp:member:`mcpwm_capture_event_data_t::cap_edge` and the count value of that moment in :cpp:member:`mcpwm_capture_event_data_t::cap_value`. +The callback function will provide event specific data of type :cpp:type:`mcpwm_capture_event_data_t`, so that you can get the edge of the capture signal in :cpp:member:`mcpwm_capture_event_data_t::cap_edge` and the count value of that moment in :cpp:member:`mcpwm_capture_event_data_t::cap_value`. To convert the capture count into timestamp, you need to know the resolution of the capture timer by calling :cpp:func:`mcpwm_capture_timer_get_resolution`. The callback function is called within the ISR context, so is should **not** attempt to block (e.g., make sure that only FreeRTOS APIs with ``ISR`` suffix is called within the function).