diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index 0495fc66565..516c4e2c446 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -348,23 +348,12 @@ static esp_err_t _node_register_callbacks(twai_node_handle_t node, const twai_ev return ESP_OK; } -static esp_err_t _node_check_timing_valid(twai_onchip_ctx_t *twai_ctx, const twai_timing_advanced_config_t *timing) -{ - if (timing) { - ESP_RETURN_ON_FALSE(twai_hal_check_brp_validation(twai_ctx->hal, timing->brp), ESP_ERR_INVALID_ARG, TAG, "invalid brp"); - ESP_RETURN_ON_FALSE((timing->tseg_1 >= TWAI_LL_TSEG1_MIN) && (timing->tseg_1 <= TWAI_LL_TSEG1_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid tseg1"); - ESP_RETURN_ON_FALSE((timing->tseg_2 >= TWAI_LL_TSEG2_MIN) && (timing->tseg_2 <= TWAI_LL_TSEG2_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid tseg_2"); - ESP_RETURN_ON_FALSE((timing->sjw >= 1) && (timing->sjw <= TWAI_LL_SJW_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid swj"); - } - return ESP_OK; -} - static esp_err_t _node_set_bit_timing(twai_node_handle_t node, const twai_timing_advanced_config_t *timing, const twai_timing_advanced_config_t *timing_fd) { twai_onchip_ctx_t *twai_ctx = __containerof(node, twai_onchip_ctx_t, api_base); ESP_RETURN_ON_FALSE(atomic_load(&twai_ctx->state) == TWAI_ERROR_BUS_OFF, ESP_ERR_INVALID_STATE, TAG, "config timing must when node stopped"); - ESP_RETURN_ON_ERROR(_node_check_timing_valid(twai_ctx, timing), TAG, "invalid param"); - ESP_RETURN_ON_ERROR(_node_check_timing_valid(twai_ctx, timing_fd), TAG, "invalid fd param"); + ESP_RETURN_ON_FALSE(twai_hal_check_timing_valid(twai_ctx->hal, timing, false), ESP_ERR_INVALID_ARG, TAG, "invalid param"); + ESP_RETURN_ON_FALSE(twai_hal_check_timing_valid(twai_ctx->hal, timing_fd, true), ESP_ERR_INVALID_ARG, TAG, "invalid fd param"); if (timing) { twai_hal_configure_timing(twai_ctx->hal, timing); @@ -406,6 +395,10 @@ static esp_err_t _node_calc_set_bit_timing(twai_node_handle_t node, const twai_t #if SOC_HAS(TWAI_FD) twai_timing_advanced_config_t timing_adv_fd = {}; if (timing_fd->bitrate) { + hw_const.brp_max = TWAI_LL_BRP_MAX_FD; + hw_const.tseg1_max = TWAI_LL_TSEG1_MAX_FD; + hw_const.tseg2_max = TWAI_LL_TSEG2_MAX_FD; + hw_const.sjw_max = TWAI_LL_SJW_MAX_FD; real_baud = twai_node_timing_calc_param(twai_ctx->src_freq_hz, timing_fd, &hw_const, &timing_adv_fd); ESP_LOGD(TAG, "timing_fd: src %ld brp %ld prop %d seg1 %d seg2 %d sjw %d ssp %d", twai_ctx->src_freq_hz, timing_adv_fd.brp, timing_adv_fd.prop_seg, timing_adv_fd.tseg_1, timing_adv_fd.tseg_2, timing_adv_fd.sjw, timing_adv_fd.ssp_offset); ESP_RETURN_ON_FALSE(real_baud, ESP_ERR_INVALID_ARG, TAG, "bitrate can't achieve!"); diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp index b41987b5092..d35f4266c3f 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp @@ -165,9 +165,9 @@ TEST_CASE("twai baudrate measurement", "[twai]") uint32_t source_freq = 0; for (size_t i = 0; i < sizeof(twai_available_clk_srcs) / sizeof(twai_available_clk_srcs[0]); i++) { TEST_ESP_OK(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)twai_available_clk_srcs[i], ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &source_freq)); - printf("Test clock source %d frequency: %ld Hz\n", twai_available_clk_srcs[i], source_freq); - test_twai_baudrate_correctness(twai_available_clk_srcs[i], 200000); + printf("\nTest clock source %d frequency: %ld Hz\n", twai_available_clk_srcs[i], source_freq); + test_twai_baudrate_correctness(twai_available_clk_srcs[i], 200000); test_twai_baudrate_correctness(twai_available_clk_srcs[i], 1000000); } } diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp index 47929940ebe..bc2c9da921d 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -159,8 +159,8 @@ TEST_CASE("twai fd transmit time (loopback)", "[twai]") TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame)); TEST_ESP_OK(twai_node_enable(node_hdl)); - printf("%-12s %-14s %-14s %-7s %-15s %s\n", "pkg_len", "frame_len", "frame_num", "brs", "trans_time/ms", "result"); - printf("-------------------------------------------------------------------------\n"); + printf("%-12s %-14s %-14s %-7s %-15s %-15s %s\n", "pkg_len", "frame_len", "frame_num", "brs", "trans_time/ms", "predict/ms", "result"); + printf("-----------------------------------------------------------------------------------------\n"); uint64_t time1, time2; for (uint8_t test_mode = 0; test_mode < 3; test_mode ++) { @@ -182,22 +182,38 @@ TEST_CASE("twai fd transmit time (loopback)", "[twai]") TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 1000)); } + // roughly estimate frame time with fixed frame overhead, ignoring dynamic bit stuffing + // 47: classic standard data frame overhead; + // 70: FD standard data frame overhead with CRC21 + uint32_t arb_bits = frame_len * 8 + ((frame_len == 64) ? 70 : 47); + uint32_t data_bits = 0; + if (test_mode == 2) { + // BRS roughly splits the frame into 30 arbitration bits and payload + 40 FD data phase bits + arb_bits = 30; + data_bits = frame_len * 8 + 40; + } + uint64_t predict_time_ms = (uint64_t)trans_num * arb_bits * 1000 / node_config.bit_timing.bitrate; + predict_time_ms += (uint64_t)trans_num * data_bits * 1000 / node_config.data_timing.bitrate; + predict_time_ms += (trans_num * 10) / 1000; // add about 10 us interrupt overhead per frame + //waiting pkg receive finish TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, -1)); time2 = esp_timer_get_time(); free(tx_msgs); // check if pkg receive correct - printf("%-12d %-14d %-14d %-7d %-15.2f %-s\n", + printf("%-12d %-14d %-14d %-7d %-15.2f %-15llu %-s\n", TEST_TRANS_TIME_BUF_LEN, frame_len, trans_num, (test_mode == 2), (time2 - time1) / 1000.f, + (unsigned long long)predict_time_ms, memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_TIME_BUF_LEN) ? "failed" : "ok"); TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_TIME_BUF_LEN); + TEST_ASSERT_LESS_THAN((predict_time_ms / 10), abs((time2 - time1) / 1000 - predict_time_ms)); } - printf("-------------------------------------------------------------------------\n"); + printf("-----------------------------------------------------------------------------------------\n"); free(send_pkg_ptr); free(recv_pkg_ptr); diff --git a/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h b/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h index 6fdc2ecc869..3baad4e6f7e 100644 --- a/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h +++ b/components/esp_hal_twai/esp32c5/include/hal/twaifd_ll.h @@ -21,9 +21,15 @@ #define TWAI_LL_TSEG1_MIN 0 #define TWAI_LL_TSEG2_MIN 1 #define TWAI_LL_BRP_MAX TWAIFD_BRP +#define TWAI_LL_PROP_MAX TWAIFD_PROP #define TWAI_LL_TSEG1_MAX TWAIFD_PH1 #define TWAI_LL_TSEG2_MAX TWAIFD_PH2 #define TWAI_LL_SJW_MAX TWAIFD_SJW +#define TWAI_LL_BRP_MAX_FD TWAIFD_BRP_FD +#define TWAI_LL_PROP_MAX_FD TWAIFD_PROP_FD +#define TWAI_LL_TSEG1_MAX_FD TWAIFD_PH1_FD +#define TWAI_LL_TSEG2_MAX_FD TWAIFD_PH2_FD +#define TWAI_LL_SJW_MAX_FD TWAIFD_SJW_FD #define TWAI_LL_TIMER_DIV_MAX TWAIFD_TIMER_STEP #define TWAIFD_IDENTIFIER_BASE_S 18 // Start bit of std_id in IDENTIFIER_W of TX buffer or RX buffer @@ -310,17 +316,6 @@ static inline void twaifd_ll_clr_intr_status(twaifd_dev_t *hw, uint32_t intr_mas } /* ------------------------ Bus Timing Registers --------------------------- */ -/** - * @brief Check if the brp value valid - * - * @param brp Bit rate prescaler value - * @return true or False - */ -static inline bool twaifd_ll_check_brp_validation(uint32_t brp) -{ - return (brp >= TWAI_LL_BRP_MIN) && (brp <= TWAI_LL_BRP_MAX); -} - /** * @brief Set bus timing nominal bit rate * diff --git a/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h b/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h index 4adbd01488f..1874ae9fc6d 100644 --- a/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h +++ b/components/esp_hal_twai/esp32h4/include/hal/twaifd_ll.h @@ -21,9 +21,15 @@ #define TWAI_LL_TSEG1_MIN 0 #define TWAI_LL_TSEG2_MIN 1 #define TWAI_LL_BRP_MAX TWAIFD_BRP +#define TWAI_LL_PROP_MAX TWAIFD_PROP #define TWAI_LL_TSEG1_MAX TWAIFD_PH1 #define TWAI_LL_TSEG2_MAX TWAIFD_PH2 #define TWAI_LL_SJW_MAX TWAIFD_SJW +#define TWAI_LL_BRP_MAX_FD TWAIFD_BRP_FD +#define TWAI_LL_PROP_MAX_FD TWAIFD_PROP_FD +#define TWAI_LL_TSEG1_MAX_FD TWAIFD_PH1_FD +#define TWAI_LL_TSEG2_MAX_FD TWAIFD_PH2_FD +#define TWAI_LL_SJW_MAX_FD TWAIFD_SJW_FD #define TWAI_LL_TIMER_DIV_MAX TWAIFD_TIMER_STEP #define TWAIFD_IDENTIFIER_BASE_S 18 // Start bit of std_id in IDENTIFIER_W of TX buffer or RX buffer @@ -309,17 +315,6 @@ static inline void twaifd_ll_clr_intr_status(twaifd_dev_t *hw, uint32_t intr_mas } /* ------------------------ Bus Timing Registers --------------------------- */ -/** - * @brief Check if the brp value valid - * - * @param brp Bit rate prescaler value - * @return true or False - */ -static inline bool twaifd_ll_check_brp_validation(uint32_t brp) -{ - return (brp >= TWAI_LL_BRP_MIN) && (brp <= TWAI_LL_BRP_MAX); -} - /** * @brief Set bus timing nominal bit rate * diff --git a/components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h b/components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h index 7aa359e2002..fff82a564be 100644 --- a/components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h +++ b/components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h @@ -19,9 +19,15 @@ #define TWAI_LL_TSEG1_MIN 0 #define TWAI_LL_TSEG2_MIN 1 #define TWAI_LL_BRP_MAX TWAIFD_BRP +#define TWAI_LL_PROP_MAX TWAIFD_PROP #define TWAI_LL_TSEG1_MAX TWAIFD_PH1 #define TWAI_LL_TSEG2_MAX TWAIFD_PH2 #define TWAI_LL_SJW_MAX TWAIFD_SJW +#define TWAI_LL_BRP_MAX_FD TWAIFD_BRP_FD +#define TWAI_LL_PROP_MAX_FD TWAIFD_PROP_FD +#define TWAI_LL_TSEG1_MAX_FD TWAIFD_PH1_FD +#define TWAI_LL_TSEG2_MAX_FD TWAIFD_PH2_FD +#define TWAI_LL_SJW_MAX_FD TWAIFD_SJW_FD #define TWAI_LL_TIMER_DIV_MAX TWAIFD_TIMER_STEP #define TWAIFD_IDENTIFIER_BASE_S 18 // Start bit of std_id in IDENTIFIER_W of TX buffer or RX buffer @@ -307,17 +313,6 @@ static inline void twaifd_ll_clr_intr_status(twaifd_dev_t *hw, uint32_t intr_mas } /* ------------------------ Bus Timing Registers --------------------------- */ -/** - * @brief Check if the brp value valid - * - * @param brp Bit rate prescaler value - * @return true or False - */ -static inline bool twaifd_ll_check_brp_validation(uint32_t brp) -{ - return (brp >= TWAI_LL_BRP_MIN) && (brp <= TWAI_LL_BRP_MAX); -} - /** * @brief Set bus timing nominal bit rate * diff --git a/components/esp_hal_twai/include/hal/twai_hal.h b/components/esp_hal_twai/include/hal/twai_hal.h index 82798d5bbce..23bf080ab5a 100644 --- a/components/esp_hal_twai/include/hal/twai_hal.h +++ b/components/esp_hal_twai/include/hal/twai_hal.h @@ -121,13 +121,14 @@ void twai_hal_deinit(twai_hal_context_t *hal_ctx); void twai_hal_configure(twai_hal_context_t *hal_ctx, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config, uint32_t clkout_divider); /** - * @brief Check if the brp value valid for hardware register + * @brief Check if the timing value valid for hardware register * * @param hal_ctx Context of the HAL layer - * @param brp Bit rate prescaler value + * @param t_config Pointer to timing configuration structure + * @param is_fd True if the timing is for FD data, false for classic TWAI * @return true or False */ -bool twai_hal_check_brp_validation(twai_hal_context_t *hal_ctx, uint32_t brp); +bool twai_hal_check_timing_valid(twai_hal_context_t *hal_ctx, const twai_timing_advanced_config_t *t_config, bool is_fd); /** * @brief Configure the TWAI timing diff --git a/components/esp_hal_twai/twai_hal_v1.c b/components/esp_hal_twai/twai_hal_v1.c index bf13115bda5..518f5a61c4c 100644 --- a/components/esp_hal_twai/twai_hal_v1.c +++ b/components/esp_hal_twai/twai_hal_v1.c @@ -91,9 +91,17 @@ void twai_hal_configure(twai_hal_context_t *hal_ctx, const twai_timing_config_t twai_ll_set_clkout(hal_ctx->dev, clkout_divider); } -bool twai_hal_check_brp_validation(twai_hal_context_t *hal_ctx, uint32_t brp) +bool twai_hal_check_timing_valid(twai_hal_context_t *hal_ctx, const twai_timing_advanced_config_t *t_config, bool is_fd) { - return twai_ll_check_brp_validation(brp); + (void) is_fd; + bool valid = true; + if (t_config) { + valid &= twai_ll_check_brp_validation(t_config->brp); + valid &= (t_config->sjw >= 1) && (t_config->sjw <= TWAI_LL_SJW_MAX); + valid &= (t_config->tseg_1 >= TWAI_LL_TSEG1_MIN) && (t_config->tseg_1 <= TWAI_LL_TSEG1_MAX); + valid &= (t_config->tseg_2 >= TWAI_LL_TSEG2_MIN) && (t_config->tseg_2 <= TWAI_LL_TSEG2_MAX); + } + return valid; } void twai_hal_configure_timing(twai_hal_context_t *hal_ctx, const twai_timing_advanced_config_t *t_config) diff --git a/components/esp_hal_twai/twai_hal_v2.c b/components/esp_hal_twai/twai_hal_v2.c index acad4dc5df8..cba5b646577 100644 --- a/components/esp_hal_twai/twai_hal_v2.c +++ b/components/esp_hal_twai/twai_hal_v2.c @@ -46,9 +46,25 @@ void twai_hal_deinit(twai_hal_context_t *hal_ctx) memset(hal_ctx, 0, sizeof(twai_hal_context_t)); } -bool twai_hal_check_brp_validation(twai_hal_context_t *hal_ctx, uint32_t brp) +bool twai_hal_check_timing_valid(twai_hal_context_t *hal_ctx, const twai_timing_advanced_config_t *t_config, bool is_fd) { - return twaifd_ll_check_brp_validation(brp); + bool valid = true; + if (t_config) { + if (is_fd) { + valid &= (t_config->brp >= TWAI_LL_BRP_MIN) && (t_config->brp <= TWAI_LL_BRP_MAX_FD); + valid &= (t_config->prop_seg <= TWAI_LL_PROP_MAX_FD); + valid &= (t_config->tseg_1 <= TWAI_LL_TSEG1_MAX_FD); + valid &= (t_config->tseg_2 >= TWAI_LL_TSEG2_MIN) && (t_config->tseg_2 <= TWAI_LL_TSEG2_MAX_FD); + valid &= (t_config->sjw >= 1) && (t_config->sjw <= TWAI_LL_SJW_MAX_FD); + } else { + valid &= (t_config->brp >= TWAI_LL_BRP_MIN) && (t_config->brp <= TWAI_LL_BRP_MAX); + valid &= (t_config->prop_seg <= TWAI_LL_PROP_MAX); + valid &= (t_config->tseg_1 <= TWAI_LL_TSEG1_MAX); + valid &= (t_config->tseg_2 >= TWAI_LL_TSEG2_MIN) && (t_config->tseg_2 <= TWAI_LL_TSEG2_MAX); + valid &= (t_config->sjw >= 1) && (t_config->sjw <= TWAI_LL_SJW_MAX); + } + } + return valid; } void twai_hal_configure_timing(twai_hal_context_t *hal_ctx, const twai_timing_advanced_config_t *t_config)