fix(driver_twai): fixed dual_filter with extid, more accurate sample point

Closes https://github.com/espressif/esp-idf/issues/17504
Closes https://github.com/espressif/esp-idf/issues/17522
This commit is contained in:
wanckl
2025-09-04 16:48:46 +08:00
parent 89578cb372
commit 550e98970b
4 changed files with 36 additions and 15 deletions

View File

@@ -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 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));
uint16_t tseg_2 = tseg - tseg_1 - 1;
tseg_2 = MAX(hw_limit->tseg2_min, MIN(tseg_2, hw_limit->tseg2_max));
tseg_1 = tseg - tseg_2 - 1;
uint16_t prop = tseg_1 / 2; // distribute tseg1 evenly between prop_seg and tseg_1
uint16_t prop = MAX(1, tseg_1 / 4); // prop_seg is usually shorter than tseg_1 and at least 1
tseg_1 -= prop;
out_param->quanta_resolution_hz = 0; // going to deprecated IDF-12725

View File

@@ -444,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,
};
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!");
if (timing->bitrate != real_baud) {
ESP_LOGW(TAG, "bitrate precision loss, adjust from %ld to %ld", timing->bitrate, real_baud);
@@ -453,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, };
if (timing_fd->bitrate) {
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!");
if (timing_fd->bitrate != real_baud) {
ESP_LOGW(TAG, "bitrate precision loss, adjust from %ld to %ld", timing_fd->bitrate, real_baud);

View File

@@ -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.
* @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 id2 Second ID to filter.
* @param id2 Second full 11/29 bits ID to filter.
* @param mask2 Mask for second ID.
* @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.
*/
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,
@@ -90,6 +90,10 @@ static inline twai_mask_filter_config_t twai_make_dual_filter(uint16_t id1, uint
.no_fd = false,
.dual_filter = true,
};
if ((id1 & mask1 & id2 & mask2) == 0xffffffff) {
dual_cfg.id = 0xffffffff; // recover the 'disable' code
dual_cfg.mask = 0xffffffff;
}
return dual_cfg;
}

View File

@@ -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);
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.rtr = !!(tx_cnt % 3);
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;
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]) {
case 0: // receive something
case 0: // receive std id
TEST_ASSERT(!rx_frame.header.ide);
TEST_ASSERT((rx_frame.header.id >= 0x10) && (rx_frame.header.id <= 0x2f));
break;
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);
}
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;
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[1] = 0;
// 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_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[1] = 0;
dual_config.id = 0xFFFFFFFF;
dual_config.mask = 0xFFFFFFFF;
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, 40);
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_delete(node_hdl));
}