mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-07 09:02:08 +00:00
feat(driver_twai): new driver add programming guide
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user