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 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

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, .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);
@@ -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, }; 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);

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. * @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;
} }

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); 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));
} }