feat(driver_twai): add api to get onchip hardware timing limit

This commit is contained in:
wanckl
2026-07-09 15:11:39 +08:00
parent 124edb2243
commit 21c1c30db5
8 changed files with 111 additions and 39 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)
*

View File

@@ -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
*/

View File

@@ -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;

View File

@@ -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;