mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-02 10:00:57 +02:00
Merge branch 'fix/c5_twai_listen_only_workaround' into 'master'
fix(driver_twai): added ctu_official workaround, fixed error count info Closes IDFGH-16314, IDFGH-16278, IDFGH-16364, IDFGH-16383, IDFCI-3106, and IDFCI-3107 See merge request espressif/esp-idf!41570
This commit is contained in:
@@ -43,12 +43,11 @@ uint32_t twai_node_timing_calc_param(const uint32_t source_freq, const twai_timi
|
|||||||
|
|
||||||
uint16_t default_point = (in_param->bitrate >= 800000) ? 750 : ((in_param->bitrate >= 500000) ? 800 : 875);
|
uint16_t default_point = (in_param->bitrate >= 800000) ? 750 : ((in_param->bitrate >= 500000) ? 800 : 875);
|
||||||
uint16_t sample_point = in_param->sp_permill ? in_param->sp_permill : default_point; // default sample point based on bitrate if not configured
|
uint16_t sample_point = in_param->sp_permill ? in_param->sp_permill : default_point; // default sample point based on bitrate if not configured
|
||||||
uint16_t tseg_1 = (tseg * sample_point) / 1000;
|
uint16_t tseg_1 = (tseg * sample_point) / 1000 - 1;
|
||||||
tseg_1 = MAX(hw_limit->tseg1_min, MIN(tseg_1, hw_limit->tseg1_max));
|
tseg_1 = MAX(hw_limit->tseg1_min, MIN(tseg_1, hw_limit->tseg1_max));
|
||||||
uint16_t tseg_2 = tseg - tseg_1 - 1;
|
uint16_t tseg_2 = tseg - tseg_1 - 1;
|
||||||
tseg_2 = MAX(hw_limit->tseg2_min, MIN(tseg_2, hw_limit->tseg2_max));
|
tseg_2 = MAX(hw_limit->tseg2_min, MIN(tseg_2, hw_limit->tseg2_max));
|
||||||
tseg_1 = tseg - tseg_2 - 1;
|
uint16_t prop = MAX(1, tseg_1 / 4); // prop_seg is usually shorter than tseg_1 and at least 1
|
||||||
uint16_t prop = tseg_1 / 2; // distribute tseg1 evenly between prop_seg and tseg_1
|
|
||||||
tseg_1 -= prop;
|
tseg_1 -= prop;
|
||||||
|
|
||||||
out_param->quanta_resolution_hz = 0; // going to deprecated IDF-12725
|
out_param->quanta_resolution_hz = 0; // going to deprecated IDF-12725
|
||||||
|
@@ -79,8 +79,6 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
_Atomic twai_error_state_t state;
|
_Atomic twai_error_state_t state;
|
||||||
uint16_t tx_error_count;
|
|
||||||
uint16_t rx_error_count;
|
|
||||||
twai_node_record_t history;
|
twai_node_record_t history;
|
||||||
|
|
||||||
atomic_bool hw_busy;
|
atomic_bool hw_busy;
|
||||||
@@ -127,8 +125,8 @@ static esp_err_t _node_config_io(twai_onchip_ctx_t *node, const twai_onchip_node
|
|||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(node_config->io_cfg.tx) || (node_config->flags.enable_listen_only && (node_config->io_cfg.tx == -1)), ESP_ERR_INVALID_ARG, TAG, "Invalid tx gpio num");
|
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(node_config->io_cfg.tx) || (node_config->flags.enable_listen_only && (node_config->io_cfg.tx == -1)), ESP_ERR_INVALID_ARG, TAG, "Invalid tx gpio num");
|
||||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(node_config->io_cfg.rx), ESP_ERR_INVALID_ARG, TAG, "Invalid rx gpio num");
|
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(node_config->io_cfg.rx), ESP_ERR_INVALID_ARG, TAG, "Invalid rx gpio num");
|
||||||
ESP_RETURN_ON_FALSE(!(GPIO_IS_VALID_OUTPUT_GPIO(node_config->io_cfg.quanta_clk_out) && (twai_periph_signals[node->ctrlr_id].clk_out_sig < 0)), ESP_ERR_NOT_SUPPORTED, TAG, "quanta_clk_out is not supported");
|
ESP_RETURN_ON_FALSE(!(GPIO_IS_VALID_OUTPUT_GPIO(node_config->io_cfg.quanta_clk_out) && (twai_periph_signals[node->ctrlr_id].clk_out_sig < 0)), ESP_ERR_NOT_SUPPORTED, TAG, "quanta_clk_out gpio is not supported");
|
||||||
ESP_RETURN_ON_FALSE(!(GPIO_IS_VALID_OUTPUT_GPIO(node_config->io_cfg.bus_off_indicator) && (twai_periph_signals[node->ctrlr_id].bus_off_sig < 0)), ESP_ERR_NOT_SUPPORTED, TAG, "bus_off_indicator is not supported");
|
ESP_RETURN_ON_FALSE(!(GPIO_IS_VALID_OUTPUT_GPIO(node_config->io_cfg.bus_off_indicator) && (twai_periph_signals[node->ctrlr_id].bus_off_sig < 0)), ESP_ERR_NOT_SUPPORTED, TAG, "bus_off_indicator gpio is not supported");
|
||||||
|
|
||||||
uint64_t reserve_mask = 0;
|
uint64_t reserve_mask = 0;
|
||||||
// Set RX pin
|
// Set RX pin
|
||||||
@@ -446,7 +444,7 @@ static esp_err_t _node_calc_set_bit_timing(twai_node_handle_t node, twai_clock_s
|
|||||||
.sjw_max = TWAI_LL_SJW_MAX,
|
.sjw_max = TWAI_LL_SJW_MAX,
|
||||||
};
|
};
|
||||||
uint32_t real_baud = twai_node_timing_calc_param(source_freq, timing, &hw_const, &timing_adv);
|
uint32_t real_baud = twai_node_timing_calc_param(source_freq, timing, &hw_const, &timing_adv);
|
||||||
ESP_LOGD(TAG, "norm src %ld, param %ld %d %d %d %d %d", source_freq, timing_adv.brp, timing_adv.prop_seg, timing_adv.tseg_1, timing_adv.tseg_2, timing_adv.sjw, timing_adv.ssp_offset);
|
ESP_LOGD(TAG, "timing: src %ld brp %ld prop %d seg1 %d seg2 %d sjw %d ssp %d", source_freq, 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!");
|
ESP_RETURN_ON_FALSE(real_baud, ESP_ERR_INVALID_ARG, TAG, "bitrate can't achieve!");
|
||||||
if (timing->bitrate != real_baud) {
|
if (timing->bitrate != real_baud) {
|
||||||
ESP_LOGW(TAG, "bitrate precision loss, adjust from %ld to %ld", timing->bitrate, real_baud);
|
ESP_LOGW(TAG, "bitrate precision loss, adjust from %ld to %ld", timing->bitrate, real_baud);
|
||||||
@@ -455,7 +453,7 @@ static esp_err_t _node_calc_set_bit_timing(twai_node_handle_t node, twai_clock_s
|
|||||||
twai_timing_advanced_config_t timing_adv_fd = { .clk_src = root_clock_src, };
|
twai_timing_advanced_config_t timing_adv_fd = { .clk_src = root_clock_src, };
|
||||||
if (timing_fd->bitrate) {
|
if (timing_fd->bitrate) {
|
||||||
real_baud = twai_node_timing_calc_param(source_freq, timing_fd, &hw_const, &timing_adv_fd);
|
real_baud = twai_node_timing_calc_param(source_freq, timing_fd, &hw_const, &timing_adv_fd);
|
||||||
ESP_LOGD(TAG, "fd src %ld, param %ld %d %d %d %d %d", source_freq, 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_LOGD(TAG, "timing_fd: src %ld brp %ld prop %d seg1 %d seg2 %d sjw %d ssp %d", source_freq, 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!");
|
ESP_RETURN_ON_FALSE(real_baud, ESP_ERR_INVALID_ARG, TAG, "bitrate can't achieve!");
|
||||||
if (timing_fd->bitrate != real_baud) {
|
if (timing_fd->bitrate != real_baud) {
|
||||||
ESP_LOGW(TAG, "bitrate precision loss, adjust from %ld to %ld", timing_fd->bitrate, real_baud);
|
ESP_LOGW(TAG, "bitrate precision loss, adjust from %ld to %ld", timing_fd->bitrate, real_baud);
|
||||||
@@ -569,8 +567,8 @@ static esp_err_t _node_get_status(twai_node_handle_t node, twai_node_status_t *s
|
|||||||
|
|
||||||
if (status_ret) {
|
if (status_ret) {
|
||||||
status_ret->state = atomic_load(&twai_ctx->state);
|
status_ret->state = atomic_load(&twai_ctx->state);
|
||||||
status_ret->tx_error_count = twai_ctx->tx_error_count;
|
status_ret->tx_error_count = twai_hal_get_tec(twai_ctx->hal);
|
||||||
status_ret->rx_error_count = twai_ctx->rx_error_count;
|
status_ret->rx_error_count = twai_hal_get_rec(twai_ctx->hal);
|
||||||
}
|
}
|
||||||
if (record_ret) {
|
if (record_ret) {
|
||||||
*record_ret = twai_ctx->history;
|
*record_ret = twai_ctx->history;
|
||||||
@@ -707,13 +705,6 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa
|
|||||||
.enable_self_test = node_config->flags.enable_self_test,
|
.enable_self_test = node_config->flags.enable_self_test,
|
||||||
.enable_loopback = node_config->flags.enable_loopback,
|
.enable_loopback = node_config->flags.enable_loopback,
|
||||||
};
|
};
|
||||||
#if CONFIG_IDF_TARGET_ESP32C5
|
|
||||||
// ESP32C5 has a bug that the listen only mode don't work when there are other nodes sending ACK each other
|
|
||||||
// See IDF-13059 for more details
|
|
||||||
if (node_config->flags.enable_listen_only) {
|
|
||||||
ESP_LOGW(TAG, "Listen only mode for ESP32C5 may not work properly when there are more than 2 nodes on the bus that are sending ACKs to each other");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ESP_GOTO_ON_FALSE(twai_hal_init(node->hal, &hal_config), ESP_ERR_INVALID_STATE, err, TAG, "hardware not in reset state");
|
ESP_GOTO_ON_FALSE(twai_hal_init(node->hal, &hal_config), ESP_ERR_INVALID_STATE, err, TAG, "hardware not in reset state");
|
||||||
// Configure bus timing
|
// Configure bus timing
|
||||||
ESP_GOTO_ON_ERROR(_node_calc_set_bit_timing(&node->api_base, node_config->clk_src, &node_config->bit_timing, &node_config->data_timing), err, TAG, "bitrate error");
|
ESP_GOTO_ON_ERROR(_node_calc_set_bit_timing(&node->api_base, node_config->clk_src, &node_config->bit_timing, &node_config->data_timing), err, TAG, "bitrate error");
|
||||||
|
@@ -57,14 +57,14 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa
|
|||||||
* @brief Helper function to configure a dual 16-bit acceptance filter.
|
* @brief Helper function to configure a dual 16-bit acceptance filter.
|
||||||
* @note For 29bits Extended IDs, ONLY high 16bits id/mask is used for each filter.
|
* @note For 29bits Extended IDs, ONLY high 16bits id/mask is used for each filter.
|
||||||
*
|
*
|
||||||
* @param id1 First ID to filter.
|
* @param id1 First full 11/29 bits ID to filter.
|
||||||
* @param mask1 Mask for first ID.
|
* @param mask1 Mask for first ID.
|
||||||
* @param id2 Second ID to filter.
|
* @param id2 Second full 11/29 bits ID to filter.
|
||||||
* @param mask2 Mask for second ID.
|
* @param mask2 Mask for second ID.
|
||||||
* @param is_ext True if using Extended (29-bit) IDs, false for Standard (11-bit) IDs.
|
* @param is_ext True if using Extended (29-bit) IDs, false for Standard (11-bit) IDs.
|
||||||
* @return twai_mask_filter_config_t A filled filter configuration structure for dual filtering.
|
* @return twai_mask_filter_config_t A filled filter configuration structure for dual filtering.
|
||||||
*/
|
*/
|
||||||
static inline twai_mask_filter_config_t twai_make_dual_filter(uint16_t id1, uint16_t mask1, uint16_t id2, uint16_t mask2, bool is_ext)
|
static inline twai_mask_filter_config_t twai_make_dual_filter(uint32_t id1, uint32_t mask1, uint32_t id2, uint32_t mask2, bool is_ext)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Dual filter is a special mode in hardware,
|
* Dual filter is a special mode in hardware,
|
||||||
@@ -90,6 +90,10 @@ static inline twai_mask_filter_config_t twai_make_dual_filter(uint16_t id1, uint
|
|||||||
.no_fd = false,
|
.no_fd = false,
|
||||||
.dual_filter = true,
|
.dual_filter = true,
|
||||||
};
|
};
|
||||||
|
if ((id1 & mask1 & id2 & mask2) == 0xffffffff) {
|
||||||
|
dual_cfg.id = 0xffffffff; // recover the 'disable' code
|
||||||
|
dual_cfg.mask = 0xffffffff;
|
||||||
|
}
|
||||||
return dual_cfg;
|
return dual_cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -246,7 +246,7 @@ static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t tr
|
|||||||
|
|
||||||
printf("Sending %ld random trans ...\n", trans_num);
|
printf("Sending %ld random trans ...\n", trans_num);
|
||||||
for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) {
|
for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) {
|
||||||
tx_msg.header.id = tx_cnt | 0xf000;
|
tx_msg.header.id = tx_cnt | 0xf000 | (tx_cnt << 16);
|
||||||
tx_msg.header.ide = !!(tx_cnt % 2);
|
tx_msg.header.ide = !!(tx_cnt % 2);
|
||||||
tx_msg.header.rtr = !!(tx_cnt % 3);
|
tx_msg.header.rtr = !!(tx_cnt % 3);
|
||||||
tx_msg.buffer_len = tx_cnt % TWAI_FRAME_MAX_LEN;
|
tx_msg.buffer_len = tx_cnt % TWAI_FRAME_MAX_LEN;
|
||||||
@@ -350,13 +350,17 @@ static IRAM_ATTR bool test_dual_filter_rx_done_cb(twai_node_handle_t handle, con
|
|||||||
rx_frame.buffer_len = TWAI_FRAME_MAX_LEN;
|
rx_frame.buffer_len = TWAI_FRAME_MAX_LEN;
|
||||||
|
|
||||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) {
|
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) {
|
||||||
ESP_EARLY_LOGI("Recv", "RX id 0x%4x len %2d ext %d rmt %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr);
|
ESP_EARLY_LOGI("Recv", "id 0x%8x len %2d ext %d rmt %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr);
|
||||||
switch (test_ctrl[0]) {
|
switch (test_ctrl[0]) {
|
||||||
case 0: // receive something
|
case 0: // receive std id
|
||||||
TEST_ASSERT(!rx_frame.header.ide);
|
TEST_ASSERT(!rx_frame.header.ide);
|
||||||
TEST_ASSERT((rx_frame.header.id >= 0x10) && (rx_frame.header.id <= 0x2f));
|
TEST_ASSERT((rx_frame.header.id >= 0x10) && (rx_frame.header.id <= 0x2f));
|
||||||
break;
|
break;
|
||||||
case 1: break; // receive none
|
case 1: break; // receive none
|
||||||
|
case 2: // receive ext id
|
||||||
|
TEST_ASSERT(rx_frame.header.ide);
|
||||||
|
TEST_ASSERT((rx_frame.header.id >= 0x280000) || (rx_frame.header.id <= 0xfffff));
|
||||||
|
break;
|
||||||
default: TEST_ASSERT(false);
|
default: TEST_ASSERT(false);
|
||||||
}
|
}
|
||||||
test_ctrl[1] ++;
|
test_ctrl[1] ++;
|
||||||
@@ -384,7 +388,7 @@ TEST_CASE("twai dual 16bit mask filter (loopback)", "[twai]")
|
|||||||
user_cbs.on_rx_done = test_dual_filter_rx_done_cb;
|
user_cbs.on_rx_done = test_dual_filter_rx_done_cb;
|
||||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl));
|
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl));
|
||||||
|
|
||||||
printf("Testing dual filter: id1 0x%x mask1 0x%x, id2 0x%x mask2 0x%x\n", 0x020, 0x7f0, 0x013, 0x7f8);
|
printf("Testing dual filter: std id1 0x%x mask1 0x%x, id2 0x%x mask2 0x%x\n", 0x020, 0x7f0, 0x013, 0x7f8);
|
||||||
test_ctrl[0] = 0;
|
test_ctrl[0] = 0;
|
||||||
test_ctrl[1] = 0;
|
test_ctrl[1] = 0;
|
||||||
// filter 1 receive only std id 0x02x
|
// filter 1 receive only std id 0x02x
|
||||||
@@ -395,17 +399,31 @@ TEST_CASE("twai dual 16bit mask filter (loopback)", "[twai]")
|
|||||||
test_random_trans_generator(node_hdl, 50);
|
test_random_trans_generator(node_hdl, 50);
|
||||||
TEST_ASSERT_EQUAL(12, test_ctrl[1]); // must receive 12 of 50 frames under filter config
|
TEST_ASSERT_EQUAL(12, test_ctrl[1]); // must receive 12 of 50 frames under filter config
|
||||||
|
|
||||||
printf("Disable filter\n");
|
dual_config = twai_make_dual_filter(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, false);
|
||||||
|
printf("Testing disable filter by dual_maker, result: id %lx mask %lx\n", dual_config.id, dual_config.mask);
|
||||||
|
TEST_ASSERT_EQUAL(0xffffffff, dual_config.id & dual_config.mask);
|
||||||
|
|
||||||
|
printf("Testing disable filter\n");
|
||||||
test_ctrl[0] = 1;
|
test_ctrl[0] = 1;
|
||||||
test_ctrl[1] = 0;
|
test_ctrl[1] = 0;
|
||||||
dual_config.id = 0xFFFFFFFF;
|
|
||||||
dual_config.mask = 0xFFFFFFFF;
|
|
||||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||||
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &dual_config));
|
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &dual_config));
|
||||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||||
test_random_trans_generator(node_hdl, 40);
|
test_random_trans_generator(node_hdl, 40);
|
||||||
TEST_ASSERT_EQUAL(0, test_ctrl[1]);
|
TEST_ASSERT_EQUAL(0, test_ctrl[1]);
|
||||||
|
|
||||||
|
printf("Testing dual filter: ext id1 0x%x mask1 0x%x, id2 0x%x mask2 0x%x\n", 0x0280000, 0x1ff80000, 0x0000000, 0x1ff00000);
|
||||||
|
test_ctrl[0] = 2;
|
||||||
|
test_ctrl[1] = 0;
|
||||||
|
// filter 1 receive only ext id 0x028xxxxx~0x02fxxxxx
|
||||||
|
// filter 2 receive only ext id 0x000xxxxx
|
||||||
|
dual_config = twai_make_dual_filter(0x0280000, 0x1ff80000, 0x0000000, 0x1ff00000, true);
|
||||||
|
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||||
|
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &dual_config));
|
||||||
|
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||||
|
test_random_trans_generator(node_hdl, 50);
|
||||||
|
TEST_ASSERT_EQUAL(12, test_ctrl[1]); // must receive 12 of 50 frames
|
||||||
|
|
||||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||||
}
|
}
|
||||||
@@ -515,7 +533,7 @@ TEST_CASE("twai bus off recovery (loopback)", "[twai]")
|
|||||||
|
|
||||||
// send frames and trigger error, must become bus off before 50 frames
|
// send frames and trigger error, must become bus off before 50 frames
|
||||||
while ((node_status.state != TWAI_ERROR_BUS_OFF) && (tx_frame.header.id < 50)) {
|
while ((node_status.state != TWAI_ERROR_BUS_OFF) && (tx_frame.header.id < 50)) {
|
||||||
printf("sending frame %ld\n", tx_frame.header.id ++);
|
printf("sending frame %ld last tec %d rec %d\n", tx_frame.header.id ++, node_status.tx_error_count, node_status.rx_error_count);
|
||||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame, 500));
|
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame, 500));
|
||||||
if (tx_frame.header.id > 3) { // trigger error after 3 frames
|
if (tx_frame.header.id > 3) { // trigger error after 3 frames
|
||||||
printf("trigger bit_error now!\n");
|
printf("trigger bit_error now!\n");
|
||||||
@@ -529,6 +547,11 @@ TEST_CASE("twai bus off recovery (loopback)", "[twai]")
|
|||||||
}
|
}
|
||||||
|
|
||||||
// recover node
|
// recover node
|
||||||
|
#if SOC_TWAI_SUPPORT_FD
|
||||||
|
TEST_ASSERT_GREATER_THAN(200, node_status.tx_error_count);
|
||||||
|
#else
|
||||||
|
TEST_ASSERT_EQUAL(128, node_status.tx_error_count); // TEC become 128 when bus off on legacy chips
|
||||||
|
#endif
|
||||||
TEST_ASSERT_EQUAL(TWAI_ERROR_BUS_OFF, node_status.state);
|
TEST_ASSERT_EQUAL(TWAI_ERROR_BUS_OFF, node_status.state);
|
||||||
printf("node offline, start recover ...\n");
|
printf("node offline, start recover ...\n");
|
||||||
TEST_ESP_OK(twai_node_recover(node_hdl));
|
TEST_ESP_OK(twai_node_recover(node_hdl));
|
||||||
@@ -539,7 +562,8 @@ TEST_CASE("twai bus off recovery (loopback)", "[twai]")
|
|||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
twai_node_get_info(node_hdl, &node_status, NULL);
|
twai_node_get_info(node_hdl, &node_status, NULL);
|
||||||
}
|
}
|
||||||
printf("node recovered! continue\n");
|
printf("node recovered! current tec %d rec %d, continue\n", node_status.tx_error_count, node_status.rx_error_count);
|
||||||
|
TEST_ASSERT_LESS_THAN(96, node_status.tx_error_count);
|
||||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame, 500));
|
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame, 500));
|
||||||
|
|
||||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||||
@@ -597,25 +621,25 @@ TEST_CASE("twai tx_wait_all_done thread safe", "[twai]")
|
|||||||
// Test data for ISR send functionality
|
// Test data for ISR send functionality
|
||||||
typedef struct {
|
typedef struct {
|
||||||
twai_node_handle_t node;
|
twai_node_handle_t node;
|
||||||
uint32_t rx_count;
|
uint8_t rx_count;
|
||||||
uint32_t tx_isr_send_count;
|
uint8_t tx_isr_send_count;
|
||||||
uint32_t rx_isr_send_count;
|
uint8_t rx_isr_send_count;
|
||||||
|
twai_frame_t tx_isr_frame;
|
||||||
|
twai_frame_t rx_isr_frame;
|
||||||
bool test_completed;
|
bool test_completed;
|
||||||
} isr_send_test_ctx_t;
|
} isr_send_test_ctx_t;
|
||||||
|
|
||||||
static IRAM_ATTR bool test_tx_isr_send_cb(twai_node_handle_t handle, const twai_tx_done_event_data_t *edata, void *user_ctx)
|
static IRAM_ATTR bool test_tx_isr_send_cb(twai_node_handle_t handle, const twai_tx_done_event_data_t *edata, void *user_ctx)
|
||||||
{
|
{
|
||||||
isr_send_test_ctx_t *ctx = (isr_send_test_ctx_t *)user_ctx;
|
isr_send_test_ctx_t *ctx = (isr_send_test_ctx_t *)user_ctx;
|
||||||
|
twai_frame_t *isr_frame = &ctx->tx_isr_frame;
|
||||||
|
|
||||||
// Test sending from TX ISR context
|
// Test sending from TX ISR context
|
||||||
if (ctx->tx_isr_send_count < 3) {
|
if (ctx->tx_isr_send_count < 3) {
|
||||||
twai_frame_t isr_frame = {};
|
isr_frame->header.id = 0x200 + ctx->tx_isr_send_count;
|
||||||
isr_frame.header.id = 0x200 + ctx->tx_isr_send_count;
|
isr_frame->header.dlc = 1;
|
||||||
isr_frame.header.dlc = 1;
|
|
||||||
isr_frame.buffer = (uint8_t*)(&ctx->tx_isr_send_count);
|
|
||||||
isr_frame.buffer_len = 1;
|
|
||||||
|
|
||||||
esp_err_t err = twai_node_transmit(handle, &isr_frame, 0); // timeout must be 0 in ISR
|
esp_err_t err = twai_node_transmit(handle, isr_frame, 0); // timeout must be 0 in ISR
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
ctx->tx_isr_send_count++;
|
ctx->tx_isr_send_count++;
|
||||||
}
|
}
|
||||||
@@ -627,23 +651,17 @@ static IRAM_ATTR bool test_tx_isr_send_cb(twai_node_handle_t handle, const twai_
|
|||||||
static IRAM_ATTR bool test_rx_isr_send_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
static IRAM_ATTR bool test_rx_isr_send_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||||
{
|
{
|
||||||
isr_send_test_ctx_t *ctx = (isr_send_test_ctx_t *)user_ctx;
|
isr_send_test_ctx_t *ctx = (isr_send_test_ctx_t *)user_ctx;
|
||||||
twai_frame_t rx_frame = {};
|
twai_frame_t *rx_frame = &ctx->rx_isr_frame;
|
||||||
uint8_t buffer[8];
|
|
||||||
rx_frame.buffer = buffer;
|
|
||||||
rx_frame.buffer_len = sizeof(buffer);
|
|
||||||
|
|
||||||
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) {
|
if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) {
|
||||||
ctx->rx_count++;
|
ctx->rx_count++;
|
||||||
|
|
||||||
// Test sending from RX ISR context (response pattern)
|
// Test sending from RX ISR context (response pattern)
|
||||||
if ((rx_frame.header.id >= 0x100) && (rx_frame.header.id < 0x103) && (ctx->rx_isr_send_count < 3)) {
|
if ((rx_frame->header.id >= 0x100) && (rx_frame->header.id < 0x103) && (ctx->rx_isr_send_count < 3)) {
|
||||||
twai_frame_t response_frame = {};
|
rx_frame->header.id = 0x300 + ctx->rx_isr_send_count;
|
||||||
response_frame.header.id = 0x300 + ctx->rx_isr_send_count;
|
rx_frame->header.dlc = 1;
|
||||||
response_frame.header.dlc = 1;
|
|
||||||
response_frame.buffer = (uint8_t*)(&ctx->rx_isr_send_count);
|
|
||||||
response_frame.buffer_len = 1;
|
|
||||||
|
|
||||||
esp_err_t err = twai_node_transmit(handle, &response_frame, 0); // timeout must be 0 in ISR
|
esp_err_t err = twai_node_transmit(handle, rx_frame, 0); // timeout must be 0 in ISR
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
ctx->rx_isr_send_count++;
|
ctx->rx_isr_send_count++;
|
||||||
}
|
}
|
||||||
@@ -660,6 +678,8 @@ static IRAM_ATTR bool test_rx_isr_send_cb(twai_node_handle_t handle, const twai_
|
|||||||
TEST_CASE("twai send from ISR context (loopback)", "[twai]")
|
TEST_CASE("twai send from ISR context (loopback)", "[twai]")
|
||||||
{
|
{
|
||||||
isr_send_test_ctx_t test_ctx = {};
|
isr_send_test_ctx_t test_ctx = {};
|
||||||
|
test_ctx.tx_isr_frame.buffer = &test_ctx.tx_isr_send_count;
|
||||||
|
test_ctx.rx_isr_frame.buffer = &test_ctx.rx_isr_send_count;
|
||||||
|
|
||||||
twai_onchip_node_config_t node_config = {};
|
twai_onchip_node_config_t node_config = {};
|
||||||
node_config.io_cfg.tx = TEST_TX_GPIO;
|
node_config.io_cfg.tx = TEST_TX_GPIO;
|
||||||
@@ -682,13 +702,11 @@ TEST_CASE("twai send from ISR context (loopback)", "[twai]")
|
|||||||
printf("Testing ISR context sending...\n");
|
printf("Testing ISR context sending...\n");
|
||||||
|
|
||||||
// Send initial frames to trigger RX ISR responses
|
// Send initial frames to trigger RX ISR responses
|
||||||
for (int i = 0; i < 3; i++) {
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
twai_frame_t trigger_frame = {};
|
twai_frame_t trigger_frame = {};
|
||||||
trigger_frame.header.id = 0x100 + i;
|
trigger_frame.header.id = 0x100 + i;
|
||||||
trigger_frame.header.dlc = 1;
|
trigger_frame.header.dlc = 1;
|
||||||
trigger_frame.buffer = (uint8_t[]) {
|
trigger_frame.buffer = &i;
|
||||||
(uint8_t)i
|
|
||||||
};
|
|
||||||
trigger_frame.buffer_len = 1;
|
trigger_frame.buffer_len = 1;
|
||||||
|
|
||||||
TEST_ESP_OK(twai_node_transmit(test_ctx.node, &trigger_frame, 500));
|
TEST_ESP_OK(twai_node_transmit(test_ctx.node, &trigger_frame, 500));
|
||||||
@@ -704,9 +722,9 @@ TEST_CASE("twai send from ISR context (loopback)", "[twai]")
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("Test results:\n");
|
printf("Test results:\n");
|
||||||
printf(" RX count: %" PRIu32 "\n", test_ctx.rx_count);
|
printf(" RX count: %d\n", test_ctx.rx_count);
|
||||||
printf(" TX ISR sends: %" PRIu32 "\n", test_ctx.tx_isr_send_count);
|
printf(" TX ISR sends: %d\n", test_ctx.tx_isr_send_count);
|
||||||
printf(" RX ISR sends: %" PRIu32 "\n", test_ctx.rx_isr_send_count);
|
printf(" RX ISR sends: %d\n", test_ctx.rx_isr_send_count);
|
||||||
printf(" Test completed: %s\n", test_ctx.test_completed ? "YES" : "NO");
|
printf(" Test completed: %s\n", test_ctx.test_completed ? "YES" : "NO");
|
||||||
|
|
||||||
// Verify test results
|
// Verify test results
|
||||||
@@ -717,8 +735,6 @@ TEST_CASE("twai send from ISR context (loopback)", "[twai]")
|
|||||||
|
|
||||||
TEST_ESP_OK(twai_node_disable(test_ctx.node));
|
TEST_ESP_OK(twai_node_disable(test_ctx.node));
|
||||||
TEST_ESP_OK(twai_node_delete(test_ctx.node));
|
TEST_ESP_OK(twai_node_delete(test_ctx.node));
|
||||||
|
|
||||||
printf("ISR send test passed!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static IRAM_ATTR bool test_dlc_range_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
static IRAM_ATTR bool test_dlc_range_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
|
||||||
@@ -736,6 +752,8 @@ TEST_CASE("twai dlc range test", "[twai]")
|
|||||||
twai_onchip_node_config_t node_config = {};
|
twai_onchip_node_config_t node_config = {};
|
||||||
node_config.io_cfg.tx = TEST_TX_GPIO;
|
node_config.io_cfg.tx = TEST_TX_GPIO;
|
||||||
node_config.io_cfg.rx = TEST_TX_GPIO; // Using same pin for test without transceiver
|
node_config.io_cfg.rx = TEST_TX_GPIO; // Using same pin for test without transceiver
|
||||||
|
node_config.io_cfg.quanta_clk_out = GPIO_NUM_NC;
|
||||||
|
node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC;
|
||||||
node_config.bit_timing.bitrate = 800000;
|
node_config.bit_timing.bitrate = 800000;
|
||||||
node_config.tx_queue_depth = TEST_FRAME_NUM;
|
node_config.tx_queue_depth = TEST_FRAME_NUM;
|
||||||
node_config.flags.enable_loopback = true;
|
node_config.flags.enable_loopback = true;
|
||||||
|
@@ -36,7 +36,7 @@ def fixture_create_socket_can() -> Bus:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.twai_std
|
@pytest.mark.twai_std
|
||||||
@pytest.mark.temp_skip_ci(targets=['esp32c5', 'esp32h4'], reason='no runner')
|
@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='no runner')
|
||||||
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
||||||
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
||||||
def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None:
|
def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None:
|
||||||
@@ -59,7 +59,7 @@ def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.twai_std
|
@pytest.mark.twai_std
|
||||||
@pytest.mark.temp_skip_ci(targets=['esp32c5', 'esp32h4'], reason='no runner')
|
@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='no runner')
|
||||||
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
||||||
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
||||||
def test_driver_twai_remote_request(dut: Dut, socket_can: Bus) -> None:
|
def test_driver_twai_remote_request(dut: Dut, socket_can: Bus) -> None:
|
||||||
|
@@ -174,7 +174,11 @@ static inline void twaifd_ll_set_mode(twaifd_dev_t *hw, bool listen_only, bool s
|
|||||||
|
|
||||||
twaifd_mode_settings_reg_t opmode = {.val = hw->mode_settings.val};
|
twaifd_mode_settings_reg_t opmode = {.val = hw->mode_settings.val};
|
||||||
opmode.stm = self_test;
|
opmode.stm = self_test;
|
||||||
|
// esp32c5 using `rom` and `acf` together with `bmm` to warkaround the errata 0v2 issue 5
|
||||||
|
// see issue https://github.com/espressif/esp-idf/issues/17461
|
||||||
opmode.bmm = listen_only;
|
opmode.bmm = listen_only;
|
||||||
|
opmode.rom = listen_only;
|
||||||
|
opmode.acf = listen_only;
|
||||||
opmode.ilbp = loopback;
|
opmode.ilbp = loopback;
|
||||||
|
|
||||||
hw->mode_settings.val = opmode.val;
|
hw->mode_settings.val = opmode.val;
|
||||||
|
@@ -180,6 +180,9 @@ static inline void twaifd_ll_set_mode(twaifd_dev_t *hw, bool listen_only, bool s
|
|||||||
twaifd_mode_settings_reg_t opmode = {.val = hw->mode_settings.val};
|
twaifd_mode_settings_reg_t opmode = {.val = hw->mode_settings.val};
|
||||||
opmode.stm = self_test;
|
opmode.stm = self_test;
|
||||||
opmode.bmm = listen_only;
|
opmode.bmm = listen_only;
|
||||||
|
// esp32h4 using `rom` together with `bmm` although errata 0v2 issue 5 is fixed
|
||||||
|
// see detail in https://github.com/espressif/esp-idf/issues/17461
|
||||||
|
opmode.rom = listen_only;
|
||||||
opmode.ilbp = loopback;
|
opmode.ilbp = loopback;
|
||||||
|
|
||||||
hw->mode_settings.val = opmode.val;
|
hw->mode_settings.val = opmode.val;
|
||||||
|
@@ -210,7 +210,7 @@ void twai_hal_start_bus_recovery(twai_hal_context_t *hal_ctx);
|
|||||||
* @param hal_ctx Context of the HAL layer
|
* @param hal_ctx Context of the HAL layer
|
||||||
* @return TX Error Counter Value
|
* @return TX Error Counter Value
|
||||||
*/
|
*/
|
||||||
uint32_t twai_hal_get_tec(twai_hal_context_t *hal_ctx);
|
uint16_t twai_hal_get_tec(twai_hal_context_t *hal_ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the value of the RX Error Counter
|
* @brief Get the value of the RX Error Counter
|
||||||
@@ -218,7 +218,7 @@ uint32_t twai_hal_get_tec(twai_hal_context_t *hal_ctx);
|
|||||||
* @param hal_ctx Context of the HAL layer
|
* @param hal_ctx Context of the HAL layer
|
||||||
* @return RX Error Counter Value
|
* @return RX Error Counter Value
|
||||||
*/
|
*/
|
||||||
uint32_t twai_hal_get_rec(twai_hal_context_t *hal_ctx);
|
uint16_t twai_hal_get_rec(twai_hal_context_t *hal_ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if certain HAL state flags are set
|
* @brief Check if certain HAL state flags are set
|
||||||
|
@@ -113,6 +113,16 @@ void twai_hal_start_bus_recovery(twai_hal_context_t *hal_ctx)
|
|||||||
twaifd_ll_set_operate_cmd(hal_ctx->dev, TWAIFD_LL_HW_CMD_RST_ERR_CNT);
|
twaifd_ll_set_operate_cmd(hal_ctx->dev, TWAIFD_LL_HW_CMD_RST_ERR_CNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t twai_hal_get_tec(twai_hal_context_t *hal_ctx)
|
||||||
|
{
|
||||||
|
return twaifd_ll_get_tec((hal_ctx)->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t twai_hal_get_rec(twai_hal_context_t *hal_ctx)
|
||||||
|
{
|
||||||
|
return twaifd_ll_get_rec((hal_ctx)->dev);
|
||||||
|
}
|
||||||
|
|
||||||
// /* ------------------------------------ IRAM Content ------------------------------------ */
|
// /* ------------------------------------ IRAM Content ------------------------------------ */
|
||||||
|
|
||||||
void twai_hal_format_frame(const twai_hal_trans_desc_t *trans_desc, twai_hal_frame_t *frame)
|
void twai_hal_format_frame(const twai_hal_trans_desc_t *trans_desc, twai_hal_frame_t *frame)
|
||||||
|
@@ -127,12 +127,12 @@ twai_error_state_t twai_hal_get_err_state(twai_hal_context_t *hal_ctx)
|
|||||||
return (hw_state & TWAI_LL_STATUS_BS) ? TWAI_ERROR_BUS_OFF : (hw_state & TWAI_LL_STATUS_ES) ? TWAI_ERROR_PASSIVE : TWAI_ERROR_ACTIVE;
|
return (hw_state & TWAI_LL_STATUS_BS) ? TWAI_ERROR_BUS_OFF : (hw_state & TWAI_LL_STATUS_ES) ? TWAI_ERROR_PASSIVE : TWAI_ERROR_ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t twai_hal_get_tec(twai_hal_context_t *hal_ctx)
|
uint16_t twai_hal_get_tec(twai_hal_context_t *hal_ctx)
|
||||||
{
|
{
|
||||||
return twai_ll_get_tec((hal_ctx)->dev);
|
return twai_ll_get_tec((hal_ctx)->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t twai_hal_get_rec(twai_hal_context_t *hal_ctx)
|
uint16_t twai_hal_get_rec(twai_hal_context_t *hal_ctx)
|
||||||
{
|
{
|
||||||
return twai_ll_get_rec((hal_ctx)->dev);
|
return twai_ll_get_rec((hal_ctx)->dev);
|
||||||
}
|
}
|
||||||
|
@@ -90,12 +90,6 @@ Below are additional configuration fields of the :cpp:type:`twai_onchip_node_con
|
|||||||
- :cpp:member:`twai_onchip_node_config_t::flags::enable_listen_only`: Configures the node in listen-only mode. In this mode, the node only receives and does not transmit any dominant bits, including ACK and error frames.
|
- :cpp:member:`twai_onchip_node_config_t::flags::enable_listen_only`: Configures the node in listen-only mode. In this mode, the node only receives and does not transmit any dominant bits, including ACK and error frames.
|
||||||
- :cpp:member:`twai_onchip_node_config_t::flags::no_receive_rtr`: When using filters, determines whether remote frames matching the ID pattern should be filtered out.
|
- :cpp:member:`twai_onchip_node_config_t::flags::no_receive_rtr`: When using filters, determines whether remote frames matching the ID pattern should be filtered out.
|
||||||
|
|
||||||
.. only:: esp32c5
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Note: The listen-only mode on ESP32C5 can't work properly when there are multiple nodes on the bus that are sending ACKs to each other. An alternative is to use transceiver which supports listen-only mode itself (e.g. TJA1145), and combine it with self-test mode enabled.
|
|
||||||
|
|
||||||
The :cpp:func:`twai_node_enable` function starts the TWAI controller. Once enabled, the controller is connected to the bus and can transmit messages. It also generates events upon receiving messages from other nodes on the bus or when bus errors are detected.
|
The :cpp:func:`twai_node_enable` function starts the TWAI controller. Once enabled, the controller is connected to the bus and can transmit messages. It also generates events upon receiving messages from other nodes on the bus or when bus errors are detected.
|
||||||
|
|
||||||
The corresponding function, :cpp:func:`twai_node_disable`, immediately stops the node and disconnects it from the bus. Any ongoing transmissions will be aborted. When the node is re-enabled later, if there are pending transmissions in the queue, the driver will immediately initiate a new transmission attempt.
|
The corresponding function, :cpp:func:`twai_node_disable`, immediately stops the node and disconnects it from the bus. Any ongoing transmissions will be aborted. When the node is re-enabled later, if there are pending transmissions in the queue, the driver will immediately initiate a new transmission attempt.
|
||||||
|
@@ -90,12 +90,6 @@ TWAI 是一种适用于汽车和工业应用的高可靠性的多主机实时串
|
|||||||
- :cpp:member:`twai_onchip_node_config_t::flags::enable_listen_only` 配置为监听模式,节点只接收,不发送任何显性位,包括 ACK 和错误帧。
|
- :cpp:member:`twai_onchip_node_config_t::flags::enable_listen_only` 配置为监听模式,节点只接收,不发送任何显性位,包括 ACK 和错误帧。
|
||||||
- :cpp:member:`twai_onchip_node_config_t::flags::no_receive_rtr` 使用过滤器时是否同时过滤掉符合 ID 规则的远程帧。
|
- :cpp:member:`twai_onchip_node_config_t::flags::no_receive_rtr` 使用过滤器时是否同时过滤掉符合 ID 规则的远程帧。
|
||||||
|
|
||||||
.. only:: esp32c5
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
注意: ESP32C5 的监听模式在总线上有多个节点相互发送 ACK 信号时无法正常工作。一种替代方案是使用本身支持监听模式的收发器(例如 TJA1145),并结合启用自测模式。
|
|
||||||
|
|
||||||
函数 :cpp:func:`twai_node_enable` 将启动 TWAI 控制器,此时 TWAI 控制器就连接到了总线,可以向总线发送报文。如果收到了总线上其他节点发送的报文,或者检测到了总线错误,也将产生相应事件。
|
函数 :cpp:func:`twai_node_enable` 将启动 TWAI 控制器,此时 TWAI 控制器就连接到了总线,可以向总线发送报文。如果收到了总线上其他节点发送的报文,或者检测到了总线错误,也将产生相应事件。
|
||||||
|
|
||||||
与之对应的函数是 :cpp:func:`twai_node_disable`,该函数将立即停止节点工作并与总线断开,正在进行的传输将被中止。当下次重新启动时,如果发送队列中有未完成的任务,驱动将立即发起新的传输。
|
与之对应的函数是 :cpp:func:`twai_node_disable`,该函数将立即停止节点工作并与总线断开,正在进行的传输将被中止。当下次重新启动时,如果发送队列中有未完成的任务,驱动将立即发起新的传输。
|
||||||
|
@@ -523,9 +523,6 @@ examples/peripherals/twai/twai_error_recovery:
|
|||||||
examples/peripherals/twai/twai_network:
|
examples/peripherals/twai/twai_network:
|
||||||
disable:
|
disable:
|
||||||
- if: SOC_TWAI_SUPPORTED != 1
|
- if: SOC_TWAI_SUPPORTED != 1
|
||||||
disable_test:
|
|
||||||
- if: IDF_TARGET == "esp32"
|
|
||||||
reason: esp32c5,esp32 test has been disabled, because C5 twai don't support listen only in network test, see errata issue 5
|
|
||||||
depends_components:
|
depends_components:
|
||||||
- esp_driver_twai
|
- esp_driver_twai
|
||||||
|
|
||||||
|
@@ -53,9 +53,6 @@ def generate_target_combinations(target_list: list, count: int = 2) -> list:
|
|||||||
],
|
],
|
||||||
indirect=True,
|
indirect=True,
|
||||||
)
|
)
|
||||||
@pytest.mark.temp_skip_ci(
|
|
||||||
targets=['esp32c5,esp32'], reason="C5 twai don't support listen only in network test, see errata issue 5"
|
|
||||||
)
|
|
||||||
def test_twai_network_multi(dut: tuple[IdfDut, IdfDut], socket_can: Bus) -> None:
|
def test_twai_network_multi(dut: tuple[IdfDut, IdfDut], socket_can: Bus) -> None:
|
||||||
"""
|
"""
|
||||||
Test TWAI network communication between two nodes:
|
Test TWAI network communication between two nodes:
|
||||||
|
@@ -644,7 +644,7 @@ def test_twai_range_filters(twai: TwaiTestHelper) -> None:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.twai_std
|
@pytest.mark.twai_std
|
||||||
@pytest.mark.temp_skip_ci(targets=['esp32c5', 'esp32h4'], reason='no runner')
|
@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='no runner')
|
||||||
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
||||||
def test_twai_external_communication(twai: TwaiTestHelper, can_manager: CanBusManager) -> None:
|
def test_twai_external_communication(twai: TwaiTestHelper, can_manager: CanBusManager) -> None:
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user