diff --git a/components/esp_driver_twai/esp_twai.c b/components/esp_driver_twai/esp_twai.c index 26d86a5174b..69515cde732 100644 --- a/components/esp_driver_twai/esp_twai.c +++ b/components/esp_driver_twai/esp_twai.c @@ -23,12 +23,12 @@ * | tseg2/2 ^ ^ * sjw sample_point */ -uint32_t twai_node_timing_calc_param(const uint32_t source_freq, const twai_timing_basic_config_t *in_param, const twai_timing_constraint_t *hw_limit, twai_timing_advanced_config_t *out_param) +uint32_t twai_node_timing_calc_param(const uint32_t source_freq, const twai_timing_basic_config_t *in_param, const twai_timing_limits_t *hw_limit, twai_timing_advanced_config_t *out_param) { uint32_t total_div = (source_freq + in_param->bitrate / 2) / in_param->bitrate; uint32_t pre_div = hw_limit->brp_min; uint16_t tseg = 0; - for (; pre_div <= hw_limit->brp_max; pre_div ++) { + for (; pre_div <= hw_limit->brp_max; pre_div += hw_limit->brp_inc) { tseg = total_div / pre_div; if (total_div != tseg * pre_div) { continue; // no integer tseg diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index ae528af92a4..08bbaf4b491 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -436,19 +436,11 @@ static esp_err_t _node_calc_set_bit_timing(twai_node_handle_t node, const twai_t ESP_RETURN_ON_FALSE((!timing_fd->bitrate) || (timing_fd->bitrate == timing->bitrate), ESP_ERR_INVALID_ARG, TAG, "FD stage bitrate is not supported"); #endif - twai_timing_constraint_t hw_const = { - .brp_min = TWAI_LL_BRP_MIN, - .brp_max = TWAI_LL_BRP_MAX, - .prop_max = TWAI_LL_PROP_MAX, - .tseg1_min = TWAI_LL_TSEG1_MIN, - .tseg1_max = TWAI_LL_TSEG1_MAX, - .tseg2_min = TWAI_LL_TSEG2_MIN, - .tseg2_max = TWAI_LL_TSEG2_MAX, - .sjw_max = TWAI_LL_SJW_MAX, - }; + twai_timing_limits_t hw_limits = {}; + twai_hal_get_timing_limits(&hw_limits); twai_timing_advanced_config_t timing_adv = {}, *timing_fd_ptr = NULL; - uint32_t real_baud = twai_node_timing_calc_param(twai_ctx->src_freq_hz, timing, &hw_const, &timing_adv); + uint32_t real_baud = twai_node_timing_calc_param(twai_ctx->src_freq_hz, timing, &hw_limits, &timing_adv); ESP_LOGD(TAG, "timing: src %ld brp %ld prop %d seg1 %d seg2 %d sjw %d ssp %d", twai_ctx->src_freq_hz, timing_adv.brp, timing_adv.prop_seg, timing_adv.tseg_1, timing_adv.tseg_2, timing_adv.sjw, timing_adv.ssp_offset); ESP_RETURN_ON_FALSE(real_baud, ESP_ERR_INVALID_ARG, TAG, "bitrate can't achieve!"); if (timing->bitrate != real_baud) { @@ -457,12 +449,8 @@ 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.prop_max = TWAI_LL_PROP_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); + twai_hal_get_timing_limits_fd(&hw_limits); + real_baud = twai_node_timing_calc_param(twai_ctx->src_freq_hz, timing_fd, &hw_limits, &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!"); if (timing_fd->bitrate != real_baud) { @@ -843,3 +831,19 @@ err: _node_destroy(node); return ret; } + +esp_err_t twai_node_onchip_get_timing_limits(bool is_fd, twai_timing_limits_t *timing_limits) +{ + ESP_RETURN_ON_FALSE(timing_limits, ESP_ERR_INVALID_ARG, TAG, "Invalid argument: null"); + + if (is_fd) { +#if SOC_HAS(TWAI_FD) + twai_hal_get_timing_limits_fd(timing_limits); +#else + ESP_RETURN_ON_ERROR(ESP_ERR_NOT_SUPPORTED, TAG, "FD is not supported"); +#endif + } else { + twai_hal_get_timing_limits(timing_limits); + } + return ESP_OK; +} diff --git a/components/esp_driver_twai/include/esp_private/twai_utils.h b/components/esp_driver_twai/include/esp_private/twai_utils.h index 587fc8a45f6..81239f8bd24 100644 --- a/components/esp_driver_twai/include/esp_private/twai_utils.h +++ b/components/esp_driver_twai/include/esp_private/twai_utils.h @@ -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 */ @@ -11,22 +11,6 @@ extern "C" { #endif -/** - * @brief TWAI hardware-dependent bit-timing constant - * - * Used for calculating and checking bit-timing parameters - */ -typedef struct { - uint32_t brp_min; /* Bit-rate prescaler */ - uint32_t brp_max; - uint8_t prop_max; /* Propagation segment */ - uint8_t tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */ - uint8_t tseg1_max; - uint8_t tseg2_min; /* Time segment 2 = phase_seg2 */ - uint8_t tseg2_max; - uint8_t sjw_max; /* Synchronisation jump width */ -} twai_timing_constraint_t; - /** * @brief Calculate TWAI timing parameters for a given source frequency and baud rate. * @@ -40,7 +24,7 @@ typedef struct { * @param out_param Pointer to the output structure where the calculated timing parameters will be stored. * @return the actual hardware adopted baudrate. */ -uint32_t twai_node_timing_calc_param(const uint32_t source_freq, const twai_timing_basic_config_t *in_param, const twai_timing_constraint_t *hw_limit, twai_timing_advanced_config_t *out_param); +uint32_t twai_node_timing_calc_param(const uint32_t source_freq, const twai_timing_basic_config_t *in_param, const twai_timing_limits_t *hw_limit, twai_timing_advanced_config_t *out_param); #ifdef __cplusplus } diff --git a/components/esp_driver_twai/include/esp_twai_onchip.h b/components/esp_driver_twai/include/esp_twai_onchip.h index a5773868e55..ce95a8997c5 100644 --- a/components/esp_driver_twai/include/esp_twai_onchip.h +++ b/components/esp_driver_twai/include/esp_twai_onchip.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -101,6 +101,15 @@ static inline twai_mask_filter_config_t twai_make_dual_filter(uint32_t id1, uint return dual_cfg; } +/** + * @brief Get the hardware-dependent timing limits + * + * @param[in] is_fd True for FD data timing, false for classic timing + * @param[out] timing_limits Pointer to timing limits structure + * @return ESP_OK if successful, ESP_ERR_INVALID_ARG if invalid argument + */ +esp_err_t twai_node_onchip_get_timing_limits(bool is_fd, twai_timing_limits_t *timing_limits); + #ifdef __cplusplus } #endif diff --git a/components/esp_hal_twai/include/hal/twai_hal.h b/components/esp_hal_twai/include/hal/twai_hal.h index c3cec1b68e0..f6d204fc1c0 100644 --- a/components/esp_hal_twai/include/hal/twai_hal.h +++ b/components/esp_hal_twai/include/hal/twai_hal.h @@ -132,6 +132,20 @@ bool twai_hal_init(twai_hal_context_t *hal_ctx, const twai_hal_config_t *config) */ void twai_hal_deinit(twai_hal_context_t *hal_ctx); +/** + * @brief Get the hardware-dependent timing limits const + * + * @param t_const Pointer to timing limits const structure + */ +void twai_hal_get_timing_limits(twai_timing_limits_t *t_const); + +/** + * @brief Get the hardware-dependent timing limits const for FD data timing + * + * @param t_const_fd Pointer to timing limits const structure for FD data + */ +void twai_hal_get_timing_limits_fd(twai_timing_limits_t *t_const_fd); + /** * @brief Configure the TWAI peripheral for legacy driver (deprecated) * diff --git a/components/esp_hal_twai/include/hal/twai_types.h b/components/esp_hal_twai/include/hal/twai_types.h index 5577c147ee7..224a3e81b66 100644 --- a/components/esp_hal_twai/include/hal/twai_types.h +++ b/components/esp_hal_twai/include/hal/twai_types.h @@ -74,6 +74,24 @@ typedef struct { uint8_t ssp_offset; /**< Secondary sample point offset refet to Sync seg, in quanta time, set 0 to disable ssp */ } twai_timing_advanced_config_t; +/** + * @brief TWAI hardware-dependent timing limits const + * + * Used for calculating and checking bit-timing parameters + */ +typedef struct { + uint32_t brp_min; /**< Bit-rate prescaler minimum value */ + uint32_t brp_max; /**< Bit-rate prescaler maximum value */ + uint32_t brp_inc; /**< Bit-rate prescaler increment step */ + uint32_t prop_min; /**< Propagation segment minimum value */ + uint32_t prop_max; /**< Propagation segment maximum value */ + uint32_t tseg1_min; /**< Time segment 1 (phase_seg1) minimum value */ + uint32_t tseg1_max; /**< Time segment 1 (phase_seg1) maximum value */ + uint32_t tseg2_min; /**< Time segment 2 (phase_seg2) minimum value */ + uint32_t tseg2_max; /**< Time segment 2 (phase_seg2) maximum value */ + uint32_t sjw_max; /**< Synchronisation jump width maximum value */ +} twai_timing_limits_t; + /** * @brief Configuration for TWAI mask filter */ diff --git a/components/esp_hal_twai/twai_hal_v1.c b/components/esp_hal_twai/twai_hal_v1.c index 8db40957686..4ea5990daa1 100644 --- a/components/esp_hal_twai/twai_hal_v1.c +++ b/components/esp_hal_twai/twai_hal_v1.c @@ -92,14 +92,29 @@ void twai_hal_configure(twai_hal_context_t *hal_ctx, const twai_timing_config_t twai_ll_set_clkout(hal_ctx->dev, clkout_divider); } +void twai_hal_get_timing_limits(twai_timing_limits_t *t_const) +{ + t_const->brp_min = TWAI_LL_BRP_MIN; + t_const->brp_max = TWAI_LL_BRP_MAX; + t_const->brp_inc = 2; // see `twai_ll_check_brp_validation()` + t_const->prop_min = 0; // hardware don't support prop_seg + t_const->prop_max = TWAI_LL_PROP_MAX; + t_const->tseg1_min = TWAI_LL_TSEG1_MIN; + t_const->tseg1_max = TWAI_LL_TSEG1_MAX; + t_const->tseg2_min = TWAI_LL_TSEG2_MIN; + t_const->tseg2_max = TWAI_LL_TSEG2_MAX; + t_const->sjw_max = TWAI_LL_SJW_MAX; +} + bool twai_hal_check_timing_valid(twai_hal_context_t *hal_ctx, const twai_timing_advanced_config_t *t_config, bool is_fd) { (void) is_fd; bool valid = true; if (t_config) { + int hw_seg1 = t_config->tseg_1 + t_config->prop_seg; 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 &= (hw_seg1 >= TWAI_LL_TSEG1_MIN) && (hw_seg1 <= TWAI_LL_TSEG1_MAX); valid &= (t_config->tseg_2 >= TWAI_LL_TSEG2_MIN) && (t_config->tseg_2 <= TWAI_LL_TSEG2_MAX); } return valid; diff --git a/components/esp_hal_twai/twai_hal_v2.c b/components/esp_hal_twai/twai_hal_v2.c index 2b5c46966d3..cfceb8715c2 100644 --- a/components/esp_hal_twai/twai_hal_v2.c +++ b/components/esp_hal_twai/twai_hal_v2.c @@ -48,6 +48,34 @@ void twai_hal_deinit(twai_hal_context_t *hal_ctx) memset(hal_ctx, 0, sizeof(twai_hal_context_t)); } +void twai_hal_get_timing_limits(twai_timing_limits_t *t_const) +{ + t_const->brp_min = TWAI_LL_BRP_MIN; + t_const->brp_max = TWAI_LL_BRP_MAX; + t_const->brp_inc = 1; + t_const->prop_min = 1; + t_const->prop_max = TWAI_LL_PROP_MAX; + t_const->tseg1_min = TWAI_LL_TSEG1_MIN; + t_const->tseg1_max = TWAI_LL_TSEG1_MAX; + t_const->tseg2_min = TWAI_LL_TSEG2_MIN; + t_const->tseg2_max = TWAI_LL_TSEG2_MAX; + t_const->sjw_max = TWAI_LL_SJW_MAX; +} + +void twai_hal_get_timing_limits_fd(twai_timing_limits_t *t_const_fd) +{ + t_const_fd->brp_min = TWAI_LL_BRP_MIN; + t_const_fd->brp_max = TWAI_LL_BRP_MAX_FD; + t_const_fd->brp_inc = 1; + t_const_fd->prop_min = 1; + t_const_fd->prop_max = TWAI_LL_PROP_MAX_FD; + t_const_fd->tseg1_min = TWAI_LL_TSEG1_MIN; + t_const_fd->tseg1_max = TWAI_LL_TSEG1_MAX_FD; + t_const_fd->tseg2_min = TWAI_LL_TSEG2_MIN; + t_const_fd->tseg2_max = TWAI_LL_TSEG2_MAX_FD; + t_const_fd->sjw_max = TWAI_LL_SJW_MAX_FD; +} + bool twai_hal_check_timing_valid(twai_hal_context_t *hal_ctx, const twai_timing_advanced_config_t *t_config, bool is_fd) { bool valid = true;