feat(driver_twai): new driver add programming guide

This commit is contained in:
wanckl
2025-05-09 20:22:02 +08:00
parent a952037d82
commit 77277b59fc
25 changed files with 1009 additions and 1339 deletions

View File

@@ -247,10 +247,13 @@ static void twai_intr_handler_main(void *arg)
//Handle events that only require alerting (i.e. no handler)
if (events & TWAI_HAL_EVENT_BUS_OFF) {
twai_ll_set_mode(p_twai_obj->hal->dev, true, false, false); //Freeze TEC/REC by entering LOM
p_twai_obj->state = TWAI_STATE_BUS_OFF;
twai_alert_handler(p_twai_obj, TWAI_ALERT_BUS_OFF, &alert_req);
}
if (events & TWAI_HAL_EVENT_BUS_RECOV_CPLT) {
//Back to STOPPED state after recovered, for cautious engineering strategy
twai_ll_enter_reset_mode(p_twai_obj->hal->dev);
p_twai_obj->state = TWAI_STATE_STOPPED;
twai_alert_handler(p_twai_obj, TWAI_ALERT_BUS_RECOVERED, &alert_req);
}

View File

@@ -234,6 +234,15 @@ static void _node_isr_main(void *arg)
if (twai_ctx->cbs.on_state_change) {
do_yield |= twai_ctx->cbs.on_state_change(&twai_ctx->api_base, &e_data, twai_ctx->user_data);
}
// node recover from busoff, restart remain tx transaction
if ((e_data.old_sta == TWAI_ERROR_BUS_OFF) && (e_data.new_sta == TWAI_ERROR_ACTIVE)) {
if (xQueueReceiveFromISR(twai_ctx->tx_mount_queue, &twai_ctx->p_curr_tx, &do_yield)) {
atomic_store(&twai_ctx->hw_busy, true);
_node_start_trans(twai_ctx);
} else {
atomic_store(&twai_ctx->hw_busy, false);
}
}
}
// deal RX event, then TX later, TODO: DIG-620
@@ -263,9 +272,9 @@ static void _node_isr_main(void *arg)
// deal TX event
if (events & TWAI_HAL_EVENT_TX_BUFF_FREE) {
// only call tx_done_cb when tx without error, otherwise on_error_cb should triggered if it is registered
if (twai_ctx->cbs.on_tx_done && (events & TWAI_HAL_EVENT_TX_SUCCESS)) {
if (twai_ctx->cbs.on_tx_done) {
twai_tx_done_event_data_t tx_ev = {
.is_tx_success = (events & TWAI_HAL_EVENT_TX_SUCCESS), // find 'on_error_cb' if not success
.done_tx_frame = twai_ctx->p_curr_tx,
};
do_yield |= twai_ctx->cbs.on_tx_done(&twai_ctx->api_base, &tx_ev, twai_ctx->user_data);
@@ -482,6 +491,9 @@ static esp_err_t _node_config_mask_filter(twai_node_handle_t node, uint8_t filte
twai_onchip_ctx_t *twai_ctx = __containerof(node, twai_onchip_ctx_t, api_base);
ESP_RETURN_ON_FALSE(filter_id < SOC_TWAI_MASK_FILTER_NUM, ESP_ERR_INVALID_ARG, TAG, "Invalid mask filter id %d", filter_id);
ESP_RETURN_ON_FALSE(mask_cfg->num_of_ids <= 1, ESP_ERR_INVALID_ARG, TAG, "Invalid num_of_ids");
uint32_t id = mask_cfg->num_of_ids ? mask_cfg->id_list[0] : mask_cfg->id;
bool full_close = (mask_cfg->mask == UINT32_MAX) && (id == UINT32_MAX);
ESP_RETURN_ON_FALSE(full_close || mask_cfg->dual_filter || mask_cfg->is_ext || !((mask_cfg->mask | id) & ~TWAI_STD_ID_MASK), ESP_ERR_INVALID_ARG, TAG, "std_id only (is_ext=0) but valid id/mask larger than 11 bits");
#if SOC_TWAI_SUPPORT_FD
// FD targets don't support Dual filter
ESP_RETURN_ON_FALSE(!mask_cfg->dual_filter, ESP_ERR_NOT_SUPPORTED, TAG, "The target don't support Dual Filter");
@@ -497,6 +509,8 @@ static esp_err_t _node_config_range_filter(twai_node_handle_t node, uint8_t filt
{
twai_onchip_ctx_t *twai_ctx = __containerof(node, twai_onchip_ctx_t, api_base);
ESP_RETURN_ON_FALSE(filter_id < SOC_TWAI_RANGE_FILTER_NUM, ESP_ERR_INVALID_ARG, TAG, "Invalid range filter id %d", filter_id);
ESP_RETURN_ON_FALSE((range_cfg->range_low > range_cfg->range_high) || range_cfg->is_ext || !(range_cfg->range_high & ~TWAI_STD_ID_MASK), \
ESP_ERR_INVALID_ARG, TAG, "std_id only (is_ext=0) but valid low/high id larger than 11 bits");
ESP_RETURN_ON_FALSE(atomic_load(&twai_ctx->state) == TWAI_ERROR_BUS_OFF, ESP_ERR_INVALID_STATE, TAG, "config filter must when node stopped");
twai_hal_configure_range_filter(twai_ctx->hal, filter_id, range_cfg);

View File

@@ -13,6 +13,46 @@
extern "C" {
#endif
/**
* @brief TWAI on-chip node initialization configuration structure
*/
typedef struct {
struct {
gpio_num_t tx; /**< GPIO pin for twai TX */
gpio_num_t rx; /**< GPIO pin for twai RX */
gpio_num_t quanta_clk_out; /**< GPIO pin for quanta clock output, Set -1 to not use */
gpio_num_t bus_off_indicator; /**< GPIO pin for bus-off indicator, Set -1 to not use */
} io_cfg; /**< I/O configuration */
twai_clock_source_t clk_src; /**< Optional, clock source, remain 0 to using TWAI_CLK_SRC_DEFAULT by default */
twai_timing_basic_config_t bit_timing; /**< Timing configuration for classic twai and FD arbitration stage */
twai_timing_basic_config_t data_timing; /**< Optional, timing configuration for FD data stage */
int8_t fail_retry_cnt; /**< Hardware retry limit if failed, range [-1:15], -1 for re-trans forever */
uint32_t tx_queue_depth; /**< Depth of the transmit queue */
int intr_priority; /**< Interrupt priority, [0:3] */
struct {
uint32_t enable_self_test: 1; /**< Transmission does not require acknowledgment. Use this mode for self testing */
uint32_t enable_loopback: 1; /**< The TWAI controller receive back frames what it send out */
uint32_t enable_listen_only: 1; /**< The TWAI controller will not influence the bus (No transmissions or acknowledgments) but can receive messages */
uint32_t no_receive_rtr: 1; /**< Don't receive remote frames */
} flags; /**< Misc configuration flags */
} twai_onchip_node_config_t;
/**
* @brief Allocate a TWAI hardware node by specific init config structure
* To delete/free the TWAI, call `twai_node_delete()`
*
* @param[in] node_config Init config structure
* @param[out] node_ret Return driver handle
*
* @return ESP_OK Allocate success
* ESP_ERR_NO_MEM No enough free memory
* ESP_ERR_NOT_FOUND No free hardware controller
* ESP_ERR_INVALID_ARG Config argument not available
* ESP_ERR_INVALID_STATE State error, including hardware state error and driver state error
* ESP_FAIL Other reasons
*/
esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twai_node_handle_t *node_ret);
/**
* @brief Helper function to configure a dual 16-bit acceptance filter.
* @note For 29bits Extended IDs, ONLY high 16bits id/mask is used for eache filter.
@@ -51,46 +91,6 @@ static inline twai_mask_filter_config_t twai_make_dual_filter(uint16_t id1, uint
return dual_cfg;
}
/**
* @brief TWAI on-chip node initialization configuration structure
*/
typedef struct {
struct {
gpio_num_t tx; /**< GPIO pin for twai TX */
gpio_num_t rx; /**< GPIO pin for twai RX */
gpio_num_t quanta_clk_out; /**< GPIO pin for quanta clock output, Set -1 to not use */
gpio_num_t bus_off_indicator; /**< GPIO pin for bus-off indicator, Set -1 to not use */
} io_cfg; /**< I/O configuration */
twai_clock_source_t clk_src; /**< Optional, clock source, remain 0 to using TWAI_CLK_SRC_DEFAULT by default */
twai_timing_basic_config_t bit_timing; /**< Timing configuration for classic twai and FD arbitration stage */
twai_timing_basic_config_t data_timing; /**< Optional, timing configuration for FD data stage */
int8_t fail_retry_cnt; /**< Hardware retry limit if failed, range [-1:15], -1 for re-trans forever */
uint32_t tx_queue_depth; /**< Depth of the transmit queue */
int intr_priority; /**< Interrupt priority, [0:3] */
struct {
uint32_t enable_self_test: 1; /**< Transmission does not require acknowledgment. Use this mode for self testing */
uint32_t enable_loopback: 1; /**< The TWAI controller receive back frames what it send out */
uint32_t enable_listen_only: 1; /**< The TWAI controller will not influence the bus (No transmissions or acknowledgments) but can receive messages */
uint32_t no_receive_rtr: 1; /**< Don't receive remote frames */
} flags;
} twai_onchip_node_config_t;
/**
* @brief Allocate a TWAI hardware node by specific init config structure
* To delete/free the TWAI, call `twai_node_delete()`
*
* @param[in] node_config Init config structure
* @param[out] node_ret Return driver handle
*
* @return ESP_OK Allocate success
* ESP_ERR_NO_MEM No enough free memory
* ESP_ERR_NOT_FOUND No free hardware controller
* ESP_ERR_INVALID_ARG Config argument not available
* ESP_ERR_INVALID_STATE State error, including hardware state error and driver state error
* ESP_FAIL Other reasons
*/
esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twai_node_handle_t *node_ret);
#ifdef __cplusplus
}
#endif

View File

@@ -29,7 +29,7 @@ typedef struct {
/**
* @brief TWAI transaction frame param type
*/
typedef struct twai_frame_t {
typedef struct {
twai_frame_header_t header; /**< message attribute/metadata, exclude data buffer*/
uint8_t *buffer; /**< buffer address for tx and rx message data*/
size_t buffer_len; /**< buffer length of provided data buffer pointer, in bytes.*/
@@ -57,6 +57,7 @@ typedef struct {
* @brief TWAI "TX done" event data
*/
typedef struct {
bool is_tx_success; /**< Indicate if frame send successful, refer `on_error` callback for fail reason if send failed */
const twai_frame_t *done_tx_frame; /**< Pointer to the frame that has been transmitted */
} twai_tx_done_event_data_t;

View File

@@ -17,8 +17,8 @@ extern "C" {
#endif
/* valid bits in TWAI ID for frame formats */
#define TWAI_STD_ID_MASK 0x000007FFU /* Mask of the ID fields in a standard frame */
#define TWAI_EXT_ID_MASK 0x1FFFFFFFU /* Mask of the ID fields in an extended frame */
#define TWAI_STD_ID_MASK 0x000007FFU /**< Mask of the ID fields in a standard frame */
#define TWAI_EXT_ID_MASK 0x1FFFFFFFU /**< Mask of the ID fields in an extended frame */
/* TWAI payload length and DLC definitions */
#define TWAI_FRAME_MAX_DLC 8
@@ -32,10 +32,10 @@ extern "C" {
* @brief TWAI node error fsm states
*/
typedef enum {
TWAI_ERROR_ACTIVE, /**< Error active state: TEC/REC < 96 */
TWAI_ERROR_WARNING, /**< Error warning state: TEC/REC >= 96 and < 128 */
TWAI_ERROR_PASSIVE, /**< Error passive state: TEC/REC >= 128 and < 256 */
TWAI_ERROR_BUS_OFF, /**< Bus-off state: TEC >= 256 (node offline) */
TWAI_ERROR_ACTIVE, /**< Error active state: TEC/REC < 96 */
TWAI_ERROR_WARNING, /**< Error warning state: TEC/REC >= 96 and < 128 */
TWAI_ERROR_PASSIVE, /**< Error passive state: TEC/REC >= 128 and < 256 */
TWAI_ERROR_BUS_OFF, /**< Bus-off state: TEC >= 256 (node offline) */
} twai_error_state_t;
/**

View File

@@ -216,8 +216,8 @@ static inline uint32_t twai_hal_decode_interrupt(twai_hal_context_t *hal_ctx)
TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ERROR_WARNING);
TWAI_HAL_SET_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_WARN);
} else if (hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_RECOVERING) {
//Previously undergoing bus recovery. Thus means bus recovery complete
TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_RECOV_CPLT);
//Previously undergoing bus recovery. Thus means bus recovery complete, hardware back to error_active
TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_RECOV_CPLT | TWAI_HAL_EVENT_ERROR_ACTIVE);
TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_RECOVERING | TWAI_HAL_STATE_FLAG_BUS_OFF);
} else { //Just went below EWL
TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BELOW_EWL);
@@ -269,7 +269,6 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
//Handle low latency events
if (events & TWAI_HAL_EVENT_BUS_OFF) {
twai_ll_set_mode(hal_ctx->dev, true, false, false); //Freeze TEC/REC by entering LOM
#ifdef CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC
//Errata workaround: Force REC to 0 by re-triggering bus-off (by setting TEC to 0 then 255)
twai_ll_set_tec(hal_ctx->dev, 0);
@@ -277,9 +276,6 @@ uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
(void) twai_ll_get_and_clear_intrs(hal_ctx->dev); //Clear the re-triggered bus-off interrupt
#endif
}
if (events & TWAI_HAL_EVENT_BUS_RECOV_CPLT) {
twai_ll_enter_reset_mode(hal_ctx->dev); //Enter reset mode to stop the controller
}
if (events & TWAI_HAL_EVENT_BUS_ERR) {
twai_ll_err_type_t type;
twai_ll_err_dir_t dir;