mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
Merge branch 'fix/twai_ci_job_pollution_v5.5' into 'release/v5.5'
fix(ci): twai test close board to fixed ci jobs pullotion (v5.5) See merge request espressif/esp-idf!49921
This commit is contained in:
@@ -77,6 +77,7 @@ typedef struct {
|
||||
uint32_t src_freq_hz;
|
||||
uint32_t timestamp_freq_hz;
|
||||
uint32_t valid_fd_timing;
|
||||
bool enable_scheduled_tx;
|
||||
twai_event_callbacks_t cbs;
|
||||
void *user_data;
|
||||
esp_pm_lock_handle_t pm_lock;
|
||||
@@ -623,7 +624,7 @@ static esp_err_t _node_queue_tx(twai_node_handle_t node, const twai_frame_t *fra
|
||||
ESP_RETURN_ON_FALSE_ISR(!frame->header.fdf || frame->buffer_len <= TWAI_FRAME_MAX_LEN, ESP_ERR_INVALID_ARG, TAG, "fdf flag or buffer_len not supported");
|
||||
#endif
|
||||
ESP_RETURN_ON_FALSE_ISR((frame->header.dlc <= TWAIFD_FRAME_MAX_DLC) && \
|
||||
(frame->buffer_len <= (frame->header.fdf ? TWAIFD_FRAME_MAX_LEN : TWAI_FRAME_MAX_LEN)), ESP_ERR_INVALID_ARG, TAG, "illegal transfer length (buffer_len %ld)", frame->buffer_len);
|
||||
(frame->buffer_len <= (frame->header.fdf ? TWAIFD_FRAME_MAX_LEN : TWAI_FRAME_MAX_LEN)), ESP_ERR_INVALID_ARG, TAG, "illegal transfer length (buffer_len %ld, dlc %d)", frame->buffer_len, frame->header.dlc);
|
||||
ESP_RETURN_ON_FALSE_ISR((!frame->header.brs) || (twai_ctx->valid_fd_timing), ESP_ERR_INVALID_ARG, TAG, "brs can't be used without config data_timing");
|
||||
ESP_RETURN_ON_FALSE_ISR(!twai_ctx->hal->enable_listen_only, ESP_ERR_NOT_SUPPORTED, TAG, "node is config as listen only");
|
||||
ESP_RETURN_ON_FALSE_ISR(atomic_load(&twai_ctx->state) != TWAI_ERROR_BUS_OFF, ESP_ERR_INVALID_STATE, TAG, "node is bus off");
|
||||
@@ -700,6 +701,11 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa
|
||||
ESP_RETURN_ON_FALSE(!node_config->intr_priority || (BIT(node_config->intr_priority) & ESP_INTR_FLAG_LOWMED), ESP_ERR_INVALID_ARG, TAG, "Invalid intr_priority level");
|
||||
#if !SOC_TWAI_SUPPORT_SLEEP_RETENTION
|
||||
ESP_RETURN_ON_FALSE(!node_config->flags.sleep_allow_pd, ESP_ERR_NOT_SUPPORTED, TAG, "sleep retention is not supported on this target");
|
||||
#endif
|
||||
#if SOC_TWAI_SUPPORT_TIMESTAMP
|
||||
ESP_RETURN_ON_FALSE(!node_config->flags.enable_scheduled_tx || node_config->timestamp_resolution_hz, ESP_ERR_INVALID_ARG, TAG, "enable_scheduled_tx requires timestamp_resolution_hz");
|
||||
#else
|
||||
ESP_RETURN_ON_FALSE(!node_config->flags.enable_scheduled_tx, ESP_ERR_NOT_SUPPORTED, TAG, "enable_scheduled_tx is not supported on this chip");
|
||||
#endif
|
||||
// Allocate TWAI node from internal memory because it contains atomic variable
|
||||
twai_onchip_ctx_t *node = heap_caps_calloc(1, sizeof(twai_onchip_ctx_t) + twai_hal_get_mem_requirment(), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
@@ -711,6 +717,7 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa
|
||||
node->ctrlr_id = ctrlr_id;
|
||||
node->hal = (twai_hal_context_t *)(node + 1); //hal context is place at end of driver context
|
||||
node->curr_clk_src = node_config->clk_src ? node_config->clk_src : TWAI_CLK_SRC_DEFAULT;
|
||||
node->enable_scheduled_tx = node_config->flags.enable_scheduled_tx;
|
||||
ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(node->curr_clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &node->src_freq_hz), err, TAG, "get clock source frequency failed");
|
||||
|
||||
// state is in bus_off before enabled
|
||||
@@ -791,6 +798,7 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa
|
||||
.enable_listen_only = node_config->flags.enable_listen_only,
|
||||
.enable_self_test = node_config->flags.enable_self_test,
|
||||
.enable_loopback = node_config->flags.enable_loopback,
|
||||
.enable_time_trigger_tx = node->enable_scheduled_tx,
|
||||
};
|
||||
ESP_GOTO_ON_FALSE(twai_hal_init(node->hal, &hal_config), ESP_ERR_INVALID_STATE, err, TAG, "hardware not in reset state");
|
||||
node->tx_slot_num = twai_hal_get_tx_slot_num(node->hal);
|
||||
|
||||
@@ -26,7 +26,7 @@ typedef struct {
|
||||
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 */
|
||||
uint32_t timestamp_resolution_hz; /**< Timebase frequency (in Hz), used for recording the timestamp of RX frame, set 0 to disable the timestamp feature */
|
||||
uint32_t timestamp_resolution_hz; /**< Timebase frequency (in Hz), used for RX frame timestamps and scheduled TX trigger times, set 0 to disable the timestamp feature */
|
||||
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] */
|
||||
@@ -36,6 +36,8 @@ typedef struct {
|
||||
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 */
|
||||
uint32_t sleep_allow_pd: 1; /**< Allow power down during sleep to save power, driver will backup/restore the TWAI registers to guarantee the peripheral features. */
|
||||
uint32_t enable_scheduled_tx: 1; /**< Schedule TX mode, if enabled, the tx frame will actually send until `twai_frame_t::header.trigger_time` is reached,
|
||||
Feature depends on hardware support, and `timestamp_resolution_hz` must be set. */
|
||||
} flags; /**< Misc configuration flags */
|
||||
} twai_onchip_node_config_t;
|
||||
|
||||
|
||||
@@ -932,3 +932,79 @@ TEST_CASE("twai rx timestamp", "[twai]")
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("twai schedule transmit", "[twai]")
|
||||
{
|
||||
twai_node_handle_t node_hdl;
|
||||
twai_onchip_node_config_t node_config = {};
|
||||
node_config.io_cfg.tx = TEST_TX_GPIO;
|
||||
node_config.io_cfg.rx = TEST_TX_GPIO;
|
||||
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 = 100000;
|
||||
node_config.tx_queue_depth = 10;
|
||||
node_config.flags.enable_loopback = true;
|
||||
node_config.flags.enable_self_test = true;
|
||||
node_config.flags.enable_scheduled_tx = true;
|
||||
|
||||
printf("Testing schedule feature check\n");
|
||||
#if !SOC_TWAI_SUPPORT_TIMESTAMP
|
||||
TEST_ESP_ERR(twai_new_node_onchip(&node_config, &node_hdl), ESP_ERR_NOT_SUPPORTED);
|
||||
return;
|
||||
#endif
|
||||
TEST_ESP_ERR(twai_new_node_onchip(&node_config, &node_hdl), ESP_ERR_INVALID_ARG);
|
||||
node_config.timestamp_resolution_hz = 1000000;
|
||||
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
|
||||
|
||||
twai_frame_t rx_frame = {};
|
||||
twai_event_callbacks_t user_cbs = {};
|
||||
user_cbs.on_rx_done = test_dlc_range_cb;
|
||||
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame));
|
||||
TEST_ESP_OK(twai_node_enable(node_hdl));
|
||||
|
||||
twai_frame_t tx_frame[6] = {};
|
||||
uint64_t time_now = esp_timer_get_time();
|
||||
printf("time_now = %llu\n", time_now);
|
||||
|
||||
printf("Testing schedule frame 1 blocks immediate frame 2\n");
|
||||
tx_frame[0].header.id = 1;
|
||||
tx_frame[0].header.trigger_time = time_now + 1000000;
|
||||
tx_frame[1].header.id = 2;
|
||||
tx_frame[1].header.trigger_time = 0; // set 0 to send immediately but will be blocked by 1st frame
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame[0], 100));
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame[1], 100));
|
||||
TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, -1));
|
||||
// should receive 2nd frame in same time
|
||||
TEST_ASSERT_EQUAL(tx_frame[1].header.id, rx_frame.header.id);
|
||||
TEST_ASSERT_INT32_WITHIN(1000000 / 100, 1000000, rx_frame.header.timestamp - time_now);
|
||||
|
||||
printf("\nTesting schedule time sequence\n");
|
||||
time_now = esp_timer_get_time();
|
||||
tx_frame[0].header.trigger_time = time_now + 1000000;
|
||||
for (int i = 1; i < 6; i++) {
|
||||
tx_frame[i].header.id = i;
|
||||
tx_frame[i].header.trigger_time = tx_frame[i - 1].header.trigger_time + i * 1000000;
|
||||
printf("Schedule frame %d after %lld s\n", i, (tx_frame[i].header.trigger_time - time_now) / 1000000);
|
||||
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame[i], 0));
|
||||
}
|
||||
|
||||
printf("\nWaiting for checking result\n");
|
||||
uint64_t last_time = rx_frame.header.timestamp;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
time_now = esp_timer_get_time();
|
||||
int second_cnt = 0;
|
||||
while (rx_frame.header.timestamp == last_time) {
|
||||
vTaskDelay(1);
|
||||
second_cnt++;
|
||||
if (second_cnt % 1000 == 0) { // print time every 1 second
|
||||
esp_rom_printf("%d ", second_cnt / 1000);
|
||||
}
|
||||
}
|
||||
last_time = rx_frame.header.timestamp;
|
||||
printf("\nFrame %d received after %d s\n", i, second_cnt / 1000);
|
||||
TEST_ASSERT_INT32_WITHIN(1000000 / 100, second_cnt * 1000, rx_frame.header.timestamp - time_now);
|
||||
}
|
||||
|
||||
TEST_ESP_OK(twai_node_disable(node_hdl));
|
||||
TEST_ESP_OK(twai_node_delete(node_hdl));
|
||||
}
|
||||
|
||||
@@ -88,51 +88,52 @@ def fixture_create_socket_can() -> Bus:
|
||||
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
||||
def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None:
|
||||
esp_reset_and_wait_ready(dut)
|
||||
try:
|
||||
esp_reset_and_wait_ready(dut)
|
||||
|
||||
dut.write('"twai_listen_only"')
|
||||
dut.write('"twai_listen_only"')
|
||||
# wait the DUT to finish initialize
|
||||
time.sleep(0.1)
|
||||
|
||||
# wait the DUT to finish initialize
|
||||
time.sleep(0.1)
|
||||
|
||||
message = Message(
|
||||
arbitration_id=0x6688,
|
||||
is_extended_id=True,
|
||||
data=[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
|
||||
)
|
||||
print('USB Socket CAN Send:', message, 'Return:', socket_can.send(message))
|
||||
dut.expect_unity_test_output(timeout=10)
|
||||
esp_enter_flash_mode(dut)
|
||||
message = Message(
|
||||
arbitration_id=0x6688,
|
||||
is_extended_id=True,
|
||||
data=[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
|
||||
)
|
||||
print('USB Socket CAN Send:', message, 'Return:', socket_can.send(message))
|
||||
dut.expect_unity_test_output(timeout=10)
|
||||
finally:
|
||||
esp_enter_flash_mode(dut)
|
||||
|
||||
|
||||
@pytest.mark.twai_adapter
|
||||
@pytest.mark.parametrize('config', ['release'], indirect=True)
|
||||
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
|
||||
def test_driver_twai_remote_request(dut: Dut, socket_can: Bus) -> None:
|
||||
esp_reset_and_wait_ready(dut)
|
||||
try:
|
||||
esp_reset_and_wait_ready(dut)
|
||||
|
||||
dut.write('"twai_remote_request"')
|
||||
dut.write('"twai_remote_request"')
|
||||
print('Waiting remote frame ...')
|
||||
deadline = time.time() + 5.0
|
||||
req = None
|
||||
while time.time() < deadline:
|
||||
req = socket_can.recv(timeout=0.2)
|
||||
if req is not None and req.is_remote_frame:
|
||||
break
|
||||
|
||||
print('Waiting remote frame ...')
|
||||
deadline = time.time() + 5.0
|
||||
req = None
|
||||
while time.time() < deadline:
|
||||
req = socket_can.recv(timeout=0.2)
|
||||
if req is not None and req.is_remote_frame:
|
||||
break
|
||||
if req is None:
|
||||
raise Exception('Remote frame not received')
|
||||
print(f'USB Socket CAN Received: {req}')
|
||||
|
||||
if req is None:
|
||||
raise Exception('Remote frame not received')
|
||||
reply = Message(
|
||||
arbitration_id=req.arbitration_id,
|
||||
is_extended_id=req.is_extended_id,
|
||||
data=[0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10],
|
||||
)
|
||||
socket_can.send(reply, timeout=0.2)
|
||||
print('USB Socket CAN Replied:', reply)
|
||||
|
||||
print(f'USB Socket CAN Received: {req}')
|
||||
|
||||
reply = Message(
|
||||
arbitration_id=req.arbitration_id,
|
||||
is_extended_id=req.is_extended_id,
|
||||
data=[0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10],
|
||||
)
|
||||
socket_can.send(reply, timeout=0.2)
|
||||
print('USB Socket CAN Replied:', reply)
|
||||
|
||||
dut.expect_unity_test_output(timeout=10)
|
||||
esp_enter_flash_mode(dut)
|
||||
dut.expect_unity_test_output(timeout=10)
|
||||
finally:
|
||||
esp_enter_flash_mode(dut)
|
||||
|
||||
Reference in New Issue
Block a user