mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-03 10:30:58 +02:00
fix(driver_twai): update example using wait_tx_done api
This commit is contained in:
@@ -45,17 +45,17 @@ idf.py -p PORT flash monitor
|
|||||||
install twai success
|
install twai success
|
||||||
node started
|
node started
|
||||||
|
|
||||||
sending frame 0
|
sending frame 0, please trigger error during sending
|
||||||
sending frame 1
|
sending frame 1, please trigger error during sending
|
||||||
|
|
||||||
...
|
...
|
||||||
sending frame 4
|
sending frame 4, please trigger error during sending
|
||||||
// Manually trigger error here (disconnect TX/RX or short H/L)
|
// Manually trigger error here (disconnect TX/RX or short H/L)
|
||||||
bus error: 0x2
|
bus error: 0x2
|
||||||
state changed: error_active -> error_warning
|
state changed: error_active -> error_warning
|
||||||
|
|
||||||
...
|
...
|
||||||
sending frame 9
|
sending frame 9, please trigger error during sending
|
||||||
// Trigger error again
|
// Trigger error again
|
||||||
bus error: 0x2
|
bus error: 0x2
|
||||||
state changed: error_passive -> bus_off
|
state changed: error_passive -> bus_off
|
||||||
@@ -66,7 +66,7 @@ waiting ... 0
|
|||||||
state changed: bus_off -> error_active
|
state changed: bus_off -> error_active
|
||||||
node recovered! continue
|
node recovered! continue
|
||||||
|
|
||||||
sending frame 0
|
sending frame 0, please trigger error during sending
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
@@ -89,7 +89,7 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG, "sending frame %d", i);
|
ESP_LOGI(TAG, "sending frame %d, please trigger error during sending", i);
|
||||||
tx_frame.header.id = i;
|
tx_frame.header.id = i;
|
||||||
ESP_ERROR_CHECK(twai_node_transmit(node_hdl, &tx_frame, 500));
|
ESP_ERROR_CHECK(twai_node_transmit(node_hdl, &tx_frame, 500));
|
||||||
}
|
}
|
||||||
|
@@ -34,13 +34,10 @@ typedef struct {
|
|||||||
// Transmission completion callback
|
// Transmission completion callback
|
||||||
static IRAM_ATTR bool twai_sender_tx_done_callback(twai_node_handle_t handle, const twai_tx_done_event_data_t *edata, void *user_ctx)
|
static IRAM_ATTR bool twai_sender_tx_done_callback(twai_node_handle_t handle, const twai_tx_done_event_data_t *edata, void *user_ctx)
|
||||||
{
|
{
|
||||||
BaseType_t woken;
|
|
||||||
SemaphoreHandle_t *tx_semaphore = (SemaphoreHandle_t *)user_ctx;
|
|
||||||
if (!edata->is_tx_success) {
|
if (!edata->is_tx_success) {
|
||||||
ESP_EARLY_LOGW(TAG, "Failed to transmit message, ID: 0x%X", edata->done_tx_frame->header.id);
|
ESP_EARLY_LOGW(TAG, "Failed to transmit message, ID: 0x%X", edata->done_tx_frame->header.id);
|
||||||
}
|
}
|
||||||
xSemaphoreGiveFromISR(*tx_semaphore, &woken);
|
return false; // No task wake required
|
||||||
return (woken == pdTRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bus error callback
|
// Bus error callback
|
||||||
@@ -53,7 +50,6 @@ static IRAM_ATTR bool twai_sender_on_error_callback(twai_node_handle_t handle, c
|
|||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
twai_node_handle_t sender_node = NULL;
|
twai_node_handle_t sender_node = NULL;
|
||||||
SemaphoreHandle_t tx_semaphore = NULL;
|
|
||||||
printf("===================TWAI Sender Example Starting...===================\n");
|
printf("===================TWAI Sender Example Starting...===================\n");
|
||||||
|
|
||||||
// Configure TWAI node
|
// Configure TWAI node
|
||||||
@@ -79,15 +75,10 @@ void app_main(void)
|
|||||||
.on_tx_done = twai_sender_tx_done_callback,
|
.on_tx_done = twai_sender_tx_done_callback,
|
||||||
.on_error = twai_sender_on_error_callback,
|
.on_error = twai_sender_on_error_callback,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(twai_node_register_event_callbacks(sender_node, &callbacks, &tx_semaphore));
|
ESP_ERROR_CHECK(twai_node_register_event_callbacks(sender_node, &callbacks, NULL));
|
||||||
|
|
||||||
// Enable TWAI node
|
// Enable TWAI node
|
||||||
ESP_ERROR_CHECK(twai_node_enable(sender_node));
|
ESP_ERROR_CHECK(twai_node_enable(sender_node));
|
||||||
|
|
||||||
// Create semaphore for transmission completion
|
|
||||||
tx_semaphore = xSemaphoreCreateCounting(howmany(TWAI_DATA_LEN, TWAI_FRAME_MAX_LEN), 0);
|
|
||||||
assert(tx_semaphore != NULL);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "TWAI Sender started successfully");
|
ESP_LOGI(TAG, "TWAI Sender started successfully");
|
||||||
ESP_LOGI(TAG, "Sending messages with IDs: 0x%03X (data), 0x%03X (heartbeat)", TWAI_DATA_ID, TWAI_HEARTBEAT_ID);
|
ESP_LOGI(TAG, "Sending messages with IDs: 0x%03X (data), 0x%03X (heartbeat)", TWAI_DATA_ID, TWAI_HEARTBEAT_ID);
|
||||||
|
|
||||||
@@ -101,7 +92,7 @@ void app_main(void)
|
|||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(twai_node_transmit(sender_node, &tx_frame, 500));
|
ESP_ERROR_CHECK(twai_node_transmit(sender_node, &tx_frame, 500));
|
||||||
ESP_LOGI(TAG, "Sending heartbeat message: %lld", timestamp);
|
ESP_LOGI(TAG, "Sending heartbeat message: %lld", timestamp);
|
||||||
xSemaphoreTake(tx_semaphore, portMAX_DELAY);
|
ESP_ERROR_CHECK(twai_node_transmit_wait_all_done(sender_node, -1)); // -1 means wait forever
|
||||||
|
|
||||||
// Send burst data messages every 10 seconds
|
// Send burst data messages every 10 seconds
|
||||||
if ((timestamp / 1000000) % 10 == 0) {
|
if ((timestamp / 1000000) % 10 == 0) {
|
||||||
@@ -118,9 +109,7 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Frames mounted, wait for all frames to be transmitted
|
// Frames mounted, wait for all frames to be transmitted
|
||||||
for (int i = 0; i < num_frames; i++) {
|
ESP_ERROR_CHECK(twai_node_transmit_wait_all_done(sender_node, -1));
|
||||||
xSemaphoreTake(tx_semaphore, portMAX_DELAY);
|
|
||||||
}
|
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +122,6 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vSemaphoreDelete(tx_semaphore);
|
|
||||||
ESP_ERROR_CHECK(twai_node_disable(sender_node));
|
ESP_ERROR_CHECK(twai_node_disable(sender_node));
|
||||||
ESP_ERROR_CHECK(twai_node_delete(sender_node));
|
ESP_ERROR_CHECK(twai_node_delete(sender_node));
|
||||||
}
|
}
|
||||||
|
@@ -42,66 +42,13 @@ static struct {
|
|||||||
static bool twai_send_tx_done_cb(twai_node_handle_t handle, const twai_tx_done_event_data_t *event_data, void *user_ctx)
|
static bool twai_send_tx_done_cb(twai_node_handle_t handle, const twai_tx_done_event_data_t *event_data, void *user_ctx)
|
||||||
{
|
{
|
||||||
ESP_UNUSED(handle);
|
ESP_UNUSED(handle);
|
||||||
ESP_UNUSED(event_data);
|
|
||||||
twai_controller_ctx_t *controller = (twai_controller_ctx_t *)user_ctx;
|
twai_controller_ctx_t *controller = (twai_controller_ctx_t *)user_ctx;
|
||||||
|
|
||||||
/* Signal TX completion */
|
|
||||||
if (atomic_load(&controller->send_ctx.is_tx_pending)) {
|
|
||||||
atomic_store(&controller->send_ctx.is_tx_pending, false);
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
xSemaphoreGiveFromISR(controller->send_ctx.tx_done_sem, &xHigherPriorityTaskWoken);
|
|
||||||
return xHigherPriorityTaskWoken == pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize the send module for a controller
|
|
||||||
*
|
|
||||||
* @param[in] controller Pointer to the controller context
|
|
||||||
*
|
|
||||||
* @return @c ESP_OK on success, error code on failure
|
|
||||||
*/
|
|
||||||
static esp_err_t twai_send_init_controller(twai_controller_ctx_t *controller)
|
|
||||||
{
|
|
||||||
int controller_id = controller - &g_twai_controller_ctx[0];
|
int controller_id = controller - &g_twai_controller_ctx[0];
|
||||||
|
|
||||||
/* Create TX completion semaphore */
|
if (!event_data->is_tx_success) {
|
||||||
controller->send_ctx.tx_done_sem = xSemaphoreCreateBinary();
|
ESP_EARLY_LOGW(TAG, "Node %d: Bus error when sending frame with ID: 0x%X", controller_id, event_data->done_tx_frame->header.id);
|
||||||
if (controller->send_ctx.tx_done_sem == NULL) {
|
|
||||||
ESP_LOGE(TAG, "Failed to create TX semaphore for controller %d", controller_id);
|
|
||||||
return ESP_ERR_NO_MEM;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
/* Initialize TX pending flag */
|
|
||||||
atomic_init(&controller->send_ctx.is_tx_pending, false);
|
|
||||||
|
|
||||||
/* Register TX done callback */
|
|
||||||
twai_core_ctx_t *core_ctx = &controller->core_ctx;
|
|
||||||
core_ctx->driver_cbs.on_tx_done = twai_send_tx_done_cb;
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Deinitialize the send module for a controller
|
|
||||||
*
|
|
||||||
* @param[in] controller Pointer to the controller context
|
|
||||||
*/
|
|
||||||
static void twai_send_deinit_controller(twai_controller_ctx_t *controller)
|
|
||||||
{
|
|
||||||
/* Clear pending flag */
|
|
||||||
atomic_store(&controller->send_ctx.is_tx_pending, false);
|
|
||||||
|
|
||||||
/* Delete TX completion semaphore */
|
|
||||||
if (controller->send_ctx.tx_done_sem) {
|
|
||||||
vSemaphoreDelete(controller->send_ctx.tx_done_sem);
|
|
||||||
controller->send_ctx.tx_done_sem = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear callback */
|
|
||||||
controller->core_ctx.driver_cbs.on_tx_done = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,33 +62,21 @@ static void twai_send_deinit_controller(twai_controller_ctx_t *controller)
|
|||||||
*/
|
*/
|
||||||
static esp_err_t send_frame_sync(twai_controller_ctx_t *controller, const twai_frame_t *frame, uint32_t timeout_ms)
|
static esp_err_t send_frame_sync(twai_controller_ctx_t *controller, const twai_frame_t *frame, uint32_t timeout_ms)
|
||||||
{
|
{
|
||||||
if (!controller) {
|
ESP_RETURN_ON_FALSE(controller, ESP_ERR_INVALID_ARG, TAG, "Invalid controller pointer");
|
||||||
ESP_LOGE(TAG, "Invalid controller pointer");
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
int controller_id = controller - &g_twai_controller_ctx[0];
|
int controller_id = controller - &g_twai_controller_ctx[0];
|
||||||
esp_err_t ret = ESP_OK;
|
|
||||||
twai_core_ctx_t *ctx = &controller->core_ctx;
|
twai_core_ctx_t *ctx = &controller->core_ctx;
|
||||||
|
|
||||||
/* Check if TWAI driver is running */
|
/* Check if TWAI driver is running */
|
||||||
ESP_RETURN_ON_FALSE(atomic_load(&ctx->is_initialized), ESP_ERR_INVALID_STATE, TAG, "TWAI%d not initialized", controller_id);
|
ESP_RETURN_ON_FALSE(atomic_load(&ctx->is_initialized), ESP_ERR_INVALID_STATE, TAG, "TWAI%d not initialized", controller_id);
|
||||||
|
|
||||||
/* Mark TX as pending */
|
|
||||||
atomic_store(&controller->send_ctx.is_tx_pending, true);
|
|
||||||
|
|
||||||
/* Transmit the frame */
|
/* Transmit the frame */
|
||||||
ret = twai_node_transmit(controller->node_handle, frame, timeout_ms);
|
ESP_RETURN_ON_ERROR(twai_node_transmit(controller->node_handle, frame, timeout_ms), TAG, "Node %d: Failed to queue TX frame", controller_id);
|
||||||
ESP_GOTO_ON_ERROR(ret, err, TAG, "Node %d: Failed to queue TX frame: %s", controller_id, esp_err_to_name(ret));
|
|
||||||
|
|
||||||
/* Wait for TX completion or timeout */
|
/* Wait for TX completion or timeout */
|
||||||
ESP_GOTO_ON_FALSE(xSemaphoreTake(controller->send_ctx.tx_done_sem, pdMS_TO_TICKS(timeout_ms)) == pdTRUE, ESP_ERR_TIMEOUT, err, TAG,
|
ESP_RETURN_ON_ERROR(twai_node_transmit_wait_all_done(controller->node_handle, timeout_ms), TAG, "Node %d: TX not completed after %"PRIu32" ms", controller_id, timeout_ms);
|
||||||
"Node %d: TX timed out after %"PRIu32" ms", controller_id, timeout_ms);
|
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
err:
|
|
||||||
atomic_store(&controller->send_ctx.is_tx_pending, false);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -228,10 +163,7 @@ void register_twai_send_commands(void)
|
|||||||
/* Initialize send context for all controllers */
|
/* Initialize send context for all controllers */
|
||||||
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||||
twai_controller_ctx_t *controller = &g_twai_controller_ctx[i];
|
twai_controller_ctx_t *controller = &g_twai_controller_ctx[i];
|
||||||
esp_err_t ret = twai_send_init_controller(controller);
|
controller->core_ctx.driver_cbs.on_tx_done = twai_send_tx_done_cb;
|
||||||
if (ret != ESP_OK) {
|
|
||||||
ESP_LOGW(TAG, "Failed to initialize send module for TWAI%d: %s", i, esp_err_to_name(ret));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register command arguments */
|
/* Register command arguments */
|
||||||
@@ -270,6 +202,6 @@ void unregister_twai_send_commands(void)
|
|||||||
/* Cleanup all controller send modules */
|
/* Cleanup all controller send modules */
|
||||||
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
for (int i = 0; i < SOC_TWAI_CONTROLLER_NUM; i++) {
|
||||||
twai_controller_ctx_t *controller = &g_twai_controller_ctx[i];
|
twai_controller_ctx_t *controller = &g_twai_controller_ctx[i];
|
||||||
twai_send_deinit_controller(controller);
|
controller->core_ctx.driver_cbs.on_tx_done = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user