mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
feat(driver_twai): add api to get onchip hardware timing limit
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user