From c54562ab72236e1efd8e0b296ae75fdc039bbc31 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 21 Aug 2025 18:42:04 +0800 Subject: [PATCH 1/2] feat(twai): add driver support on esp32h4 --- .../test_apps/legacy_twai/pytest_twai.py | 10 +- .../test_apps/test_twai/README.md | 4 +- .../test_twai/main/test_twai_common.cpp | 2 +- .../test_apps/test_twai/pytest_driver_twai.py | 8 +- .../hal/esp32c5/include/hal/twaifd_ll.h | 11 +- .../hal/esp32h4/include/hal/twaifd_ll.h | 967 ++++++++++++++++++ components/hal/esp32p4/include/hal/twai_ll.h | 74 +- .../esp32h4/include/soc/Kconfig.soc_caps.in | 40 + .../soc/esp32h4/include/soc/clk_tree_defs.h | 16 + components/soc/esp32h4/include/soc/soc_caps.h | 16 +- .../soc/esp32h4/register/soc/twaifd_struct.h | 171 ++-- components/soc/esp32h4/twai_periph.c | 21 + .../soc/esp32p4/include/soc/clk_tree_defs.h | 1 - docs/docs_not_updated/esp32h4.txt | 1 - .../twai/twai_error_recovery/README.md | 4 +- .../peripherals/twai/twai_network/README.md | 4 +- .../peripherals/twai/twai_utils/README.md | 4 +- .../twai/twai_utils/pytest_twai_utils.py | 2 +- 18 files changed, 1203 insertions(+), 153 deletions(-) create mode 100644 components/hal/esp32h4/include/hal/twaifd_ll.h create mode 100644 components/soc/esp32h4/twai_periph.c diff --git a/components/driver/test_apps/legacy_twai/pytest_twai.py b/components/driver/test_apps/legacy_twai/pytest_twai.py index 5d6bd65bfc..ae59da9786 100644 --- a/components/driver/test_apps/legacy_twai/pytest_twai.py +++ b/components/driver/test_apps/legacy_twai/pytest_twai.py @@ -22,7 +22,7 @@ from pytest_embedded_idf.utils import idf_parametrize @idf_parametrize( 'target', ['esp32', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32s2', 'esp32s3', 'esp32p4'], indirect=['target'] ) -def test_twai_self(dut: Dut) -> None: +def test_legacy_twai_self(dut: Dut) -> None: dut.run_all_single_board_cases(group='twai-loop-back') @@ -31,11 +31,11 @@ def fixture_create_socket_can() -> Bus: # Set up the socket CAN with the bitrate start_command = 'sudo ip link set can0 up type can bitrate 250000 restart-ms 100' stop_command = 'sudo ip link set can0 down' - subprocess.run(start_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + subprocess.run(start_command, shell=True, capture_output=True, text=True) bus = Bus(interface='socketcan', channel='can0', bitrate=250000) yield bus # test invoked here bus.shutdown() - subprocess.run(stop_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + subprocess.run(stop_command, shell=True, capture_output=True, text=True) @pytest.mark.twai_std @@ -49,7 +49,7 @@ def fixture_create_socket_can() -> Bus: @idf_parametrize( 'target', ['esp32', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32s2', 'esp32s3', 'esp32p4'], indirect=['target'] ) -def test_twai_listen_only(dut: Dut, socket_can: Bus) -> None: +def test_legacy_twai_listen_only(dut: Dut, socket_can: Bus) -> None: dut.serial.hard_reset() dut.expect_exact('Press ENTER to see the list of tests') @@ -79,7 +79,7 @@ def test_twai_listen_only(dut: Dut, socket_can: Bus) -> None: @idf_parametrize( 'target', ['esp32', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32s2', 'esp32s3', 'esp32p4'], indirect=['target'] ) -def test_twai_remote_request(dut: Dut, socket_can: Bus) -> None: +def test_legacy_twai_remote_request(dut: Dut, socket_can: Bus) -> None: dut.serial.hard_reset() dut.expect_exact('Press ENTER to see the list of tests') diff --git a/components/esp_driver_twai/test_apps/test_twai/README.md b/components/esp_driver_twai/test_apps/test_twai/README.md index f921835020..c3221d0779 100644 --- a/components/esp_driver_twai/test_apps/test_twai/README.md +++ b/components/esp_driver_twai/test_apps/test_twai/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp index d13b287ad5..a42d0e4ed6 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp @@ -33,7 +33,7 @@ static IRAM_ATTR bool test_driver_install_rx_cb(twai_node_handle_t handle, const twai_frame_t rx_frame = {}; if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) { - ESP_EARLY_LOGI("Recv ", "id 0x%lx rtr %d", rx_frame.header.id, rx_frame.header.rtr); + esp_rom_printf("Recv id 0x%lx rtr %d", rx_frame.header.id, rx_frame.header.rtr); } if (rx_frame.header.id != 0x100) { TEST_FAIL(); //callback is unregistered, should not run here diff --git a/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py b/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py index 12a28fe91f..cfd61082d8 100644 --- a/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py +++ b/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py @@ -26,17 +26,17 @@ def fixture_create_socket_can() -> Bus: start_command = 'sudo ip link set can0 up type can bitrate 250000' stop_command = 'sudo ip link set can0 down' try: - subprocess.run(start_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + subprocess.run(start_command, shell=True, capture_output=True, text=True) except Exception as e: print(f'Open bus Error: {e}') bus = Bus(interface='socketcan', channel='can0', bitrate=250000) yield bus # test invoked here bus.shutdown() - subprocess.run(stop_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + subprocess.run(stop_command, shell=True, capture_output=True, text=True) @pytest.mark.twai_std -@pytest.mark.temp_skip_ci(targets=['esp32c5'], reason='no runner') +@pytest.mark.temp_skip_ci(targets=['esp32c5', 'esp32h4'], reason='no runner') @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: @@ -59,7 +59,7 @@ def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None: @pytest.mark.twai_std -@pytest.mark.temp_skip_ci(targets=['esp32c5'], reason='no runner') +@pytest.mark.temp_skip_ci(targets=['esp32c5', 'esp32h4'], reason='no runner') @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: diff --git a/components/hal/esp32c5/include/hal/twaifd_ll.h b/components/hal/esp32c5/include/hal/twaifd_ll.h index 9f015cfffb..59b72699b0 100644 --- a/components/hal/esp32c5/include/hal/twaifd_ll.h +++ b/components/hal/esp32c5/include/hal/twaifd_ll.h @@ -98,7 +98,16 @@ static inline void twaifd_ll_reset_register(uint8_t twai_id) */ static inline void twaifd_ll_set_clock_source(uint8_t twai_id, twai_clock_source_t clk_src) { - PCR.twai[twai_id].twai_func_clk_conf.twai_func_clk_sel = (clk_src == TWAI_CLK_SRC_XTAL) ? 0 : 1; + switch (clk_src) { + case TWAI_CLK_SRC_PLL_F80M: + PCR.twai[twai_id].twai_func_clk_conf.twai_func_clk_sel = 1; + break; + case TWAI_CLK_SRC_XTAL: + PCR.twai[twai_id].twai_func_clk_conf.twai_func_clk_sel = 0; + break; + default: + HAL_ASSERT(false); + } } /** diff --git a/components/hal/esp32h4/include/hal/twaifd_ll.h b/components/hal/esp32h4/include/hal/twaifd_ll.h new file mode 100644 index 0000000000..3bb3871102 --- /dev/null +++ b/components/hal/esp32h4/include/hal/twaifd_ll.h @@ -0,0 +1,967 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The Lowlevel layer for TWAI is not public api, don't use in application code. + ******************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "soc/pcr_reg.h" +#include "soc/pcr_struct.h" +#include "soc/twaifd_reg.h" +#include "soc/twaifd_struct.h" +#include "hal/twai_types.h" +#include "hal/assert.h" +#include "hal/misc.h" + +#define TWAIFD_LL_GET_HW(num) (((num) == 0) ? (&TWAI0) : NULL) + +#define TWAI_LL_BRP_MIN 1 +#define TWAI_LL_BRP_MAX 255 +#define TWAI_LL_TSEG1_MIN 0 +#define TWAI_LL_TSEG2_MIN 1 +#define TWAI_LL_TSEG1_MAX TWAIFD_PH1 +#define TWAI_LL_TSEG2_MAX TWAIFD_PH2 +#define TWAI_LL_SJW_MAX TWAIFD_SJW + +#define TWAIFD_IDENTIFIER_BASE_S 18 // Start bit of std_id in IDENTIFIER_W of TX buffer or RX buffer + +#define TWAIFD_LL_ERR_BIT_ERR 0x0 // Bit Error +#define TWAIFD_LL_ERR_CRC_ERR 0x1 // CRC Error +#define TWAIFD_LL_ERR_FRM_ERR 0x2 // Form Error +#define TWAIFD_LL_ERR_ACK_ERR 0x3 // Acknowledge Error +#define TWAIFD_LL_ERR_STUF_ERR 0x4 // Stuff Error + +#define TWAIFD_LL_SSP_SRC_MEAS_OFFSET 0x0 // Using Measured Transmitter delay + SSP_OFFSET +#define TWAIFD_LL_SSP_SRC_NO_SSP 0x1 // SSP is disabled +#define TWAIFD_LL_SSP_SRC_OFFSET_ONLY 0x2 // Using SSP_OFFSET only + +#define TWAIFD_LL_TX_CMD_EMPTY TWAIFD_TXCE // Set tx buffer to "Empty" state +#define TWAIFD_LL_TX_CMD_READY TWAIFD_TXCR // Set tx buffer to "Ready" state +#define TWAIFD_LL_TX_CMD_ABORT TWAIFD_TXCA // Set tx buffer to "Aborted" state + +#define TWAIFD_LL_HW_CMD_RST_ERR_CNT TWAIFD_ERCRST // Error Counters Reset +#define TWAIFD_LL_HW_CMD_RST_RX_CNT TWAIFD_RXFCRST // Clear RX bus traffic counter +#define TWAIFD_LL_HW_CMD_RST_TX_CNT TWAIFD_TXFCRST // Clear TX bus traffic counter + +#define TWAIFD_LL_INTR_TX_DONE TWAIFD_TXBHCI_INT_ST// Transmit finish (ok or error) +#define TWAIFD_LL_INTR_TX_SUCCESS TWAIFD_TXI_INT_ST // Transmit success without error +#define TWAIFD_LL_INTR_RX_NOT_EMPTY TWAIFD_RBNEI_INT_ST // RX buffer not empty interrupt +#define TWAIFD_LL_INTR_RX_FULL TWAIFD_RXFI_INT_ST // RX buffer full interrupt +#define TWAIFD_LL_INTR_ERR_WARN TWAIFD_EWLI_INT_ST // Error Interrupt +#define TWAIFD_LL_INTR_BUS_ERR TWAIFD_BEI_INT_ST // Bus error interrupt +#define TWAIFD_LL_INTR_FSM_CHANGE TWAIFD_FCSI_INT_ST // Fault confinement state changed interrupt +#define TWAIFD_LL_INTR_ARBI_LOST TWAIFD_ALI_INT_ST // Arbitration Lost Interrupt +#define TWAIFD_LL_INTR_DATA_OVERRUN TWAIFD_DOI_INT_ST // Data Overrun Interrupt + +#define TWAI_LL_DRIVER_INTERRUPTS (TWAIFD_LL_INTR_TX_DONE | TWAIFD_LL_INTR_RX_NOT_EMPTY | TWAIFD_LL_INTR_RX_FULL | \ + TWAIFD_LL_INTR_ERR_WARN | TWAIFD_LL_INTR_BUS_ERR | TWAIFD_LL_INTR_FSM_CHANGE | \ + TWAIFD_LL_INTR_ARBI_LOST | TWAIFD_LL_INTR_DATA_OVERRUN) + +/** + * @brief Enable the bus clock and module clock for twai module + * + * @param twai_id Hardware ID + * @param enable true to enable, false to disable + */ +static inline void twaifd_ll_enable_bus_clock(uint8_t twai_id, bool enable) +{ + PCR.twai0_conf.twai0_clk_en = enable; +} + +/** + * @brief Reset the twai module + * + * @param twai_id Hardware ID + */ +static inline void twaifd_ll_reset_register(uint8_t twai_id) +{ + PCR.twai0_conf.twai0_rst_en = 1; + PCR.twai0_conf.twai0_rst_en = 0; +} + +/** + * @brief Set clock source for TWAI module + * + * @param twai_id Hardware ID + * @param clk_src Clock source + */ +static inline void twaifd_ll_set_clock_source(uint8_t twai_id, twai_clock_source_t clk_src) +{ + switch (clk_src) { + case TWAI_CLK_SRC_XTAL: + PCR.twai0_func_clk_conf.twai0_func_clk_sel = 0; + break; + case TWAI_CLK_SRC_PLL_F96M: + PCR.twai0_func_clk_conf.twai0_func_clk_sel = 2; + break; + // We do not plan to support the TWAI_CLK_SRC_RC_FAST clock source, + // as the accuracy of this clock does not meet the requirements for the baud rate + // case TWAI_CLK_SRC_RC_FAST: + // PCR.twai0_func_clk_conf.twai0_func_clk_sel = 1; + // break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Enable TWAI module clock source + * + * @param twai_id Hardware ID + * @param enable true to enable, false to disable + */ +static inline void twaifd_ll_enable_clock(uint8_t twai_id, bool enable) +{ + PCR.twai0_func_clk_conf.twai0_func_clk_en = enable; + if (enable) { + while (!PCR.twai0_conf.twai0_ready); + } +} + +/** + * @brief Waits for pending changes to take effect in the hardware. + * + * @param hw Pointer to the hardware structure. + */ +static inline void twaifd_ll_waiting_state_change(twaifd_dev_t *hw) +{ + while (!hw->int_stat.fcsi_int_st); // Wait until the change is applied +} + + +/* ---------------------------- Mode Register ------------------------------- */ +// WARNING!! Following 'mode_settings' should in same spin_lock` !!! + +/** + * @brief Reset hardware. + * + * @param hw Pointer to hardware structure. + */ +static inline void twaifd_ll_reset(twaifd_dev_t *hw) +{ + hw->mode_settings.rst = 1; +} + +/** + * @brief Enable or disable hardware. + * + * @param hw Pointer to hardware structure. + * @param enable Boolean flag to enable (true) or disable (false). + */ +static inline void twaifd_ll_enable_hw(twaifd_dev_t *hw, bool enable) +{ + hw->mode_settings.ena = enable; +} + +/** + * @brief Set operating mode of TWAI controller + * + * @param hw Start address of the TWAI registers + * @param listen_only Listen only mode (a.k.a. bus monitoring mode) + * @param self_test Self test mode + * @param loopback Loopback mode + */ +static inline void twaifd_ll_set_mode(twaifd_dev_t *hw, bool listen_only, bool self_test, bool loopback) +{ + //mode should be changed under disabled + HAL_ASSERT(hw->mode_settings.ena == 0); + + twaifd_mode_settings_reg_t opmode = {.val = hw->mode_settings.val}; + opmode.stm = self_test; + opmode.bmm = listen_only; + opmode.ilbp = loopback; + + hw->mode_settings.val = opmode.val; +} + +/** + * @brief Set the TX retransmission limit. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param limit Retransmission limit (0-15, or negative for infinite). + */ +static inline void twaifd_ll_set_tx_retrans_limit(twaifd_dev_t *hw, int8_t limit) +{ + HAL_ASSERT(limit <= (int8_t)TWAIFD_RTRTH_V); // Check the limit is valid + hw->mode_settings.rtrle = (limit >= 0); // Enable/disable retransmissions + hw->mode_settings.rtrth = limit; // Set the limit +} + +/** + * set bit rate flexible between nominal field and data field + * when set this bit, all frame will be regarded as CANFD frame, even though nominal bit rate and data bit rate are the same + */ +static inline void twaifd_ll_enable_fd_mode(twaifd_dev_t *hw, bool ena) +{ + hw->mode_settings.fde = ena; +} + +/** + * @brief Enable or disable the RX fifo automatic increase when read to register + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param ena Set to true to enable RX automatic mode, false to disable. + */ +static inline void twaifd_ll_enable_rxfifo_auto_incrase(twaifd_dev_t *hw, bool ena) +{ + hw->mode_settings.rxbam = ena; +} + +/** + * @brief Enable or disable the filter. + * + * @param hw Pointer to hardware structure. + * @param enable `true` to enable, `false` to disable. + */ +static inline void twaifd_ll_enable_filter_mode(twaifd_dev_t* hw, bool enable) +{ + // Must be called when hardware is disabled. + HAL_ASSERT(hw->mode_settings.ena == 0); + hw->mode_settings.afm = enable; +} + +/** + * @brief Set remote frame filtering behaviour. + * + * @param hw Pointer to hardware structure. + * @param en True to drop, false to Receive to next filter + */ +static inline void twaifd_ll_filter_block_rtr(twaifd_dev_t* hw, bool en) +{ + hw->mode_settings.fdrf = en; +} + +/** + * @brief Enable or disable the time-triggered transmission mode for the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param enable Set to true to enable time-triggered transmission mode, false to disable. + */ +static inline void twaifd_ll_enable_time_trig_trans_mode(twaifd_dev_t* hw, bool enable) +{ + hw->mode_settings.tttm = enable; +} + +/* --------------------------- Command Register ----------------------------- */ +/** + * @brief Set command to TWAIFD hardware + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param commands command code refer to `TWAIFD_LL_HW_CMD_`. + */ +static inline void twaifd_ll_set_operate_cmd(twaifd_dev_t *hw, uint32_t commands) +{ + hw->command.val = commands; + while (hw->command.val & commands); +} + +/* -------------------------- Interrupt Register ---------------------------- */ + +/** + * @brief Set which interrupts are enabled + * + * @param hw Start address of the TWAI registers + * @param intr_mask mask of interrupts to enable + */ +static inline void twaifd_ll_enable_intr(twaifd_dev_t *hw, uint32_t intr_mask) +{ + hw->int_ena_set.val = intr_mask; + hw->int_ena_clr.val = ~intr_mask; +} + +/** + * @brief Get the interrupt status of the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The current interrupt status as a 32-bit value, used with `TWAIFD_LL_INTR_`. + */ +__attribute__((always_inline)) +static inline uint32_t twaifd_ll_get_intr_status(twaifd_dev_t *hw) +{ + return hw->int_stat.val; +} + +/** + * @brief Clear the specified interrupt status of the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param intr_mask The interrupt mask specifying which interrupts to clear. + */ +__attribute__((always_inline)) +static inline void twaifd_ll_clr_intr_status(twaifd_dev_t *hw, uint32_t intr_mask) +{ + // this register is write to clear + hw->int_stat.val = intr_mask; +} + +/* ------------------------ Bus Timing Registers --------------------------- */ +/** + * @brief Check if the brp value valid + * + * @param brp Bit rate prescaler value + * @return true or False + */ +static inline bool twaifd_ll_check_brp_validation(uint32_t brp) +{ + return (brp >= TWAI_LL_BRP_MIN) && (brp <= TWAI_LL_BRP_MAX); +} + +/** + * @brief Set bus timing nominal bit rate + * + * @param hw Start address of the TWAI registers + * @param timing_param timing params + */ +static inline void twaifd_ll_set_nominal_bitrate(twaifd_dev_t *hw, const twai_timing_advanced_config_t *timing_param) +{ + twaifd_btr_reg_t reg_w = {.val = 0}; + HAL_FORCE_MODIFY_U32_REG_FIELD(reg_w, brp, timing_param->brp); + reg_w.prop = timing_param->prop_seg; + reg_w.ph1 = timing_param->tseg_1; + reg_w.ph2 = timing_param->tseg_2; + reg_w.sjw = timing_param->sjw; + + hw->btr.val = reg_w.val; +} + +/** + * @brief Set bus timing for FD data section bit rate + * + * @param hw Start address of the TWAI registers + * @param timing_param_fd FD timing params + */ +static inline void twaifd_ll_set_fd_bitrate(twaifd_dev_t *hw, const twai_timing_advanced_config_t *timing_param_fd) +{ + twaifd_btr_fd_reg_t reg_w = {.val = 0}; + HAL_FORCE_MODIFY_U32_REG_FIELD(reg_w, brp_fd, timing_param_fd->brp); + reg_w.prop_fd = timing_param_fd->prop_seg; + reg_w.ph1_fd = timing_param_fd->tseg_1; + reg_w.ph2_fd = timing_param_fd->tseg_2; + reg_w.sjw_fd = timing_param_fd->sjw; + + hw->btr_fd.val = reg_w.val; +} + +/** + * @brief Secondary Sample Point (SSP) config for data bitrate + * + * @param hw Start address of the TWAI registers + * @param ssp_src_code Secondary point mode config, see TWAIFD_LL_SSP_SRC_xxx. + * @param offset_val Secondary sampling point position is configured as delay from Sync_Seg in multiples of System clock + */ +static inline void twaifd_ll_config_secondary_sample_point(twaifd_dev_t *hw, uint8_t ssp_src_code, uint8_t offset_val) +{ + hw->trv_delay_ssp_cfg.ssp_src = ssp_src_code; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->trv_delay_ssp_cfg, ssp_offset, offset_val); +} + +/* ----------------------------- ERR Capt Register ------------------------------- */ + +/** + * @brief Get the error reason flags from the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The error reasons, see `twai_error_flags_t` + */ +__attribute__((always_inline)) +static inline twai_error_flags_t twaifd_ll_get_err_reason(twaifd_dev_t *hw) +{ + uint8_t error_code = hw->err_capt_retr_ctr_alc_ts_info.err_type; + twai_error_flags_t errors = { + .bit_err = error_code == TWAIFD_LL_ERR_BIT_ERR, + .form_err = error_code == TWAIFD_LL_ERR_FRM_ERR, + .stuff_err = error_code == TWAIFD_LL_ERR_STUF_ERR, + .ack_err = error_code == TWAIFD_LL_ERR_ACK_ERR + }; + return errors; +} + +/* ----------------------------- EWL Register ------------------------------- */ + +// this func can only use in TWAIFD_MODE_TEST, and 'mode_settings.ena' must be zero +static inline void twaifd_ll_set_err_warn_limit(twaifd_dev_t *hw, uint32_t ewl) +{ + HAL_ASSERT(hw->mode_settings.tstm); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->ewl_erp_fault_state, ew_limit, ewl); +} + +/** + * @brief Get Error Warning Limit + * + * @param hw Start address of the TWAI registers + * @return Error Warning Limit + */ +__attribute__((always_inline)) +static inline uint32_t twaifd_ll_get_err_warn_limit(twaifd_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->ewl_erp_fault_state, ew_limit); +} + +/** + * @brief Get the current fault state of the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Fault state (bus-off, error passive, or active state). + */ +__attribute__((always_inline)) +static inline twai_error_state_t twaifd_ll_get_fault_state(twaifd_dev_t *hw) +{ + if (hw->ewl_erp_fault_state.bof) { + return TWAI_ERROR_BUS_OFF; + } + if (hw->ewl_erp_fault_state.erp) { + return TWAI_ERROR_PASSIVE; + } + return TWAI_ERROR_ACTIVE; +} + +/** + * @brief Get the error count in normal mode for the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Error count in normal mode. + */ +static inline uint32_t twaifd_ll_get_err_count_norm(twaifd_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->err_norm_err_fd, err_norm_val); +} + +/** + * @brief Get the error count in FD mode for the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Error count in FD mode. + */ +static inline uint32_t twaifd_ll_get_err_count_fd(twaifd_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->err_norm_err_fd, err_fd_val); +} + +/* ------------------------ RX Error Count Register ------------------------- */ +/** + * @brief Get RX Error Counter + * + * @param hw Start address of the TWAI registers + * @return REC value + */ +__attribute__((always_inline)) +static inline uint32_t twaifd_ll_get_rec(twaifd_dev_t *hw) +{ + return hw->rec_tec.rec_val; +} + +/* ------------------------ TX Error Count Register ------------------------- */ +/** + * @brief Get TX Error Counter + * + * @param hw Start address of the TWAI registers + * @return TEC value + */ +__attribute__((always_inline)) +static inline uint32_t twaifd_ll_get_tec(twaifd_dev_t *hw) +{ + return hw->rec_tec.tec_val; +} + +/* ---------------------- Acceptance Filter Registers ----------------------- */ +/** + * @brief Enable or disable filter to receive basic frame with std id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the filter to configure + * @param is_range Setting for range filter or mask filter + * @param en True to receive, False to drop + */ +static inline void twaifd_ll_filter_enable_basic_std(twaifd_dev_t* hw, uint8_t filter_id, bool is_range, bool en) +{ + HAL_ASSERT(filter_id < (is_range ? SOC_TWAI_RANGE_FILTER_NUM : SOC_TWAI_MASK_FILTER_NUM)); + // The hw_filter_id of range_filter is indexed after mask_filter + uint8_t hw_filter_id = is_range ? filter_id + SOC_TWAI_MASK_FILTER_NUM : filter_id; + if (en) { + hw->filter_control_filter_status.val |= TWAIFD_FANB << (hw_filter_id * TWAIFD_FBNB_S); + } else { + hw->filter_control_filter_status.val &= ~(TWAIFD_FANB << (hw_filter_id * TWAIFD_FBNB_S)); + } +} + +/** + * @brief Enable or disable filter to receive basic frame with ext id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the filter to configure + * @param is_range Setting for range filter or mask filter + * @param en True to receive, False to drop + */ +static inline void twaifd_ll_filter_enable_basic_ext(twaifd_dev_t* hw, uint8_t filter_id, bool is_range, bool en) +{ + HAL_ASSERT(filter_id < (is_range ? SOC_TWAI_RANGE_FILTER_NUM : SOC_TWAI_MASK_FILTER_NUM)); + // The hw_filter_id of range_filter is indexed after mask_filter + uint8_t hw_filter_id = is_range ? filter_id + SOC_TWAI_MASK_FILTER_NUM : filter_id; + if (en) { + hw->filter_control_filter_status.val |= TWAIFD_FANE << (hw_filter_id * TWAIFD_FBNB_S); + } else { + hw->filter_control_filter_status.val &= ~(TWAIFD_FANE << (hw_filter_id * TWAIFD_FBNB_S)); + } +} + +/** + * @brief Enable or disable filter to receive fd frame with std id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the filter to configure + * @param is_range Setting for range filter or mask filter + * @param en True to receive, False to drop + */ +static inline void twaifd_ll_filter_enable_fd_std(twaifd_dev_t* hw, uint8_t filter_id, bool is_range, bool en) +{ + HAL_ASSERT(filter_id < (is_range ? SOC_TWAI_RANGE_FILTER_NUM : SOC_TWAI_MASK_FILTER_NUM)); + // The hw_filter_id of range_filter is indexed after mask_filter + uint8_t hw_filter_id = is_range ? filter_id + SOC_TWAI_MASK_FILTER_NUM : filter_id; + if (en) { + hw->filter_control_filter_status.val |= TWAIFD_FAFB << (hw_filter_id * TWAIFD_FBNB_S); + } else { + hw->filter_control_filter_status.val &= ~(TWAIFD_FAFB << (hw_filter_id * TWAIFD_FBNB_S)); + } +} + +/** + * @brief Enable or disable filter to receive fd frame with ext id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the filter to configure + * @param is_range Setting for range filter or mask filter + * @param en True to receive, False to drop + */ +static inline void twaifd_ll_filter_enable_fd_ext(twaifd_dev_t* hw, uint8_t filter_id, bool is_range, bool en) +{ + HAL_ASSERT(filter_id < (is_range ? SOC_TWAI_RANGE_FILTER_NUM : SOC_TWAI_MASK_FILTER_NUM)); + // The hw_filter_id of range_filter is indexed after mask_filter + uint8_t hw_filter_id = is_range ? filter_id + SOC_TWAI_MASK_FILTER_NUM : filter_id; + if (en) { + hw->filter_control_filter_status.val |= TWAIFD_FAFE << (hw_filter_id * TWAIFD_FBNB_S); + } else { + hw->filter_control_filter_status.val &= ~(TWAIFD_FAFE << (hw_filter_id * TWAIFD_FBNB_S)); + } +} + +/** + * @brief Set Bit Acceptance Filter + * @param hw Start address of the TWAI registers + * @param filter_id Filter number id + * @param is_ext Filter for ext_id or std_id + * @param code Acceptance Code + * @param mask Acceptance Mask + */ +static inline void twaifd_ll_filter_set_id_mask(twaifd_dev_t* hw, uint8_t filter_id, bool is_ext, uint32_t code, uint32_t mask) +{ + hw->mask_filters[filter_id].filter_mask.bit_mask_val = is_ext ? mask : (mask << TWAIFD_IDENTIFIER_BASE_S); + hw->mask_filters[filter_id].filter_val.bit_val = is_ext ? code : (code << TWAIFD_IDENTIFIER_BASE_S); +} + +/** + * @brief Set Range Acceptance Filter + * @param hw Start address of the TWAI registers + * @param filter_id Filter number id + * @param is_ext Filter for ext_id or std_id + * @param high The id range high limit + * @param low The id range low limit + */ +static inline void twaifd_ll_filter_set_range(twaifd_dev_t* hw, uint8_t filter_id, bool is_ext, uint32_t high, uint32_t low) +{ + hw->range_filters[filter_id].ran_low.bit_ran_low_val = is_ext ? low : (low << TWAIFD_IDENTIFIER_BASE_S); + hw->range_filters[filter_id].ran_high.bit_ran_high_val = is_ext ? high : (high << TWAIFD_IDENTIFIER_BASE_S); +} + +/* ------------------------- TX Buffer Registers ------------------------- */ + +/** + * @brief Get the number of TX buffers available. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return The number of TX buffers available. + */ +static inline uint32_t twaifd_ll_get_tx_buffer_quantity(twaifd_dev_t *hw) +{ + return hw->tx_command_txtb_info.txt_buffer_count; +} + +/** + * @brief Get the status of a specific TX buffer. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param buffer_idx Index of the TX buffer (0-7). + * @return The status of the selected TX buffer. + */ +static inline uint32_t twaifd_ll_get_tx_buffer_status(twaifd_dev_t *hw, uint8_t buffer_idx) +{ + HAL_ASSERT(buffer_idx < twaifd_ll_get_tx_buffer_quantity(hw)); // Ensure buffer index is valid + uint32_t reg_val = hw->tx_status.val; + return reg_val & (TWAIFD_TX2S_V << (TWAIFD_TX2S_S * buffer_idx)); // Get status for buffer +} + +/** + * @brief Set TX Buffer command + * + * Setting the TX command will cause the TWAI controller to attempt to transmit + * the frame stored in the TX buffer. The TX buffer will be occupied (i.e., + * locked) until TX completes. + * + * @param hw Start address of the TWAI registers + * @param buffer_idx + * @param cmd The command want to set, see `TWAIFD_LL_TX_CMD_` + */ +__attribute__((always_inline)) +static inline void twaifd_ll_set_tx_cmd(twaifd_dev_t *hw, uint8_t buffer_idx, uint32_t cmd) +{ + hw->tx_command_txtb_info.val = (cmd | BIT(buffer_idx + TWAIFD_TXB1_S)); +} + +/** + * @brief Set the priority for a specific TX buffer. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param buffer_idx Index of the TX buffer (0-7). + * @param priority The priority level to set for the buffer. + */ +static inline void twaifd_ll_set_tx_buffer_priority(twaifd_dev_t *hw, uint8_t buffer_idx, uint32_t priority) +{ + HAL_ASSERT(buffer_idx < twaifd_ll_get_tx_buffer_quantity(hw)); // Ensure buffer index is valid + uint32_t reg_val = hw->tx_priority.val; + reg_val &= ~(TWAIFD_TXT1P_V << (TWAIFD_TXT2P_S * buffer_idx)); // Clear old priority + reg_val |= priority << (TWAIFD_TXT2P_S * buffer_idx); // Set new priority + hw->tx_priority.val = reg_val; +} + +/** + * @brief Copy a formatted TWAI frame into TX buffer for transmission + * + * @param hw Start address of the TWAI registers + * @param tx_frame Pointer to formatted frame + * @param buffer_idx The tx buffer index to copy in + * + * @note Call twaifd_ll_format_frame_header() and twaifd_ll_format_frame_data() to format a frame + */ +__attribute__((always_inline)) +static inline void twaifd_ll_mount_tx_buffer(twaifd_dev_t *hw, twaifd_frame_buffer_t *tx_frame, uint8_t buffer_idx) +{ + //Copy formatted frame into TX buffer + for (int i = 0; i < sizeof(twaifd_frame_buffer_t) / sizeof(uint32_t); i++) { + hw->txt_mem_cell[buffer_idx].txt_buffer.words[i] = tx_frame->words[i]; + } +} + +/* ------------------------- RX Buffer Registers ------------------------- */ + +/** + * @brief Get the size of the RX buffer. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Size of the RX buffer. + */ +static inline uint32_t twaifd_ll_get_rx_buffer_size(twaifd_dev_t *hw) +{ + return hw->rx_mem_info.rx_buff_size; +} + +/** + * @brief Get the number of frames in the RX buffer. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Number of frames in the RX buffer. + */ +__attribute__((always_inline)) +static inline uint32_t twaifd_ll_get_rx_frame_count(twaifd_dev_t *hw) +{ + return hw->rx_status_rx_settings.rxfrc; +} + +/** + * @brief Check if the RX FIFO is empty. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return 1 if RX FIFO is empty, 0 otherwise. + */ +static inline uint32_t twaifd_ll_is_rx_buffer_empty(twaifd_dev_t *hw) +{ + return hw->rx_status_rx_settings.rxe; +} + +/** + * @brief Copy a received frame from the RX buffer for parsing + * + * @param hw Start address of the TWAI registers + * @param rx_frame Pointer to store formatted frame + * + * @note Call twaifd_ll_parse_frame_header() and twaifd_ll_parse_frame_data() to parse the formatted frame + */ +__attribute__((always_inline)) +static inline void twaifd_ll_get_rx_frame(twaifd_dev_t *hw, twaifd_frame_buffer_t *rx_frame) +{ + // If rx_automatic_mode enabled, hw->rx_data.rx_data should 32bit access + rx_frame->words[0] = hw->rx_data.rx_data; + for (uint8_t i = 1; i <= rx_frame->format.rwcnt; i++) { + rx_frame->words[i] = hw->rx_data.rx_data; + } + HAL_ASSERT(!hw->rx_status_rx_settings.rxmof); +} + +/* ------------------------- TWAIFD frame ------------------------- */ +/** + * @brief Format contents of a TWAI frame header into layout of TX Buffer + * + * This function encodes a message into a frame structure. The frame structure + * has an identical layout to the TX buffer, allowing the frame structure to be + * directly copied into hardware. + * + * @param[in] header Including DLC, ID, Format, etc. + * @param[in] final_dlc data length code of frame. + * @param[out] tx_frame Pointer to store formatted frame + */ +__attribute__((always_inline)) +static inline void twaifd_ll_format_frame_header(const twai_frame_header_t *header, uint8_t final_dlc, twaifd_frame_buffer_t *tx_frame) +{ + HAL_ASSERT(final_dlc <= TWAIFD_FRAME_MAX_DLC); + + //Set frame information + tx_frame->format.ide = header->ide; + tx_frame->format.rtr = header->rtr; + tx_frame->format.fdf = header->fdf; + tx_frame->format.brs = header->brs; + tx_frame->format.dlc = final_dlc; + + tx_frame->timestamp_low = header->timestamp; + tx_frame->timestamp_high = header->timestamp >> 32; + + if (tx_frame->format.ide) { + tx_frame->identifier.val = (header->id & TWAI_EXT_ID_MASK); + } else { + tx_frame->identifier.identifier_base = (header->id & TWAI_STD_ID_MASK); + } +} + +/** + * @brief Format contents of a TWAI data into layout of TX Buffer + * + * This function encodes a message into a frame structure. The frame structure + * has an identical layout to the TX buffer, allowing the frame structure to be + * directly copied into hardware. + * + * @param[in] buffer Pointer to an 8 byte array containing data. + * @param[in] len data length of data buffer. + * @param[out] tx_frame Pointer to store formatted frame + */ +__attribute__((always_inline)) +static inline void twaifd_ll_format_frame_data(const uint8_t *buffer, uint32_t len, twaifd_frame_buffer_t *tx_frame) +{ + HAL_ASSERT(len <= TWAIFD_FRAME_MAX_LEN); + memcpy(tx_frame->data, buffer, len); +} + +/** + * @brief Parse formatted TWAI frame header (RX Buffer Layout) into its constituent contents + * + * @param[in] rx_frame Pointer to formatted frame + * @param[out] p_frame_header Including DLC, ID, Format, etc. + */ +__attribute__((always_inline)) +static inline void twaifd_ll_parse_frame_header(const twaifd_frame_buffer_t *rx_frame, twai_frame_header_t *p_frame_header) +{ + //Copy frame information + p_frame_header->ide = rx_frame->format.ide; + p_frame_header->rtr = rx_frame->format.rtr; + p_frame_header->fdf = rx_frame->format.fdf; + p_frame_header->brs = rx_frame->format.brs; + p_frame_header->esi = rx_frame->format.esi; + p_frame_header->dlc = rx_frame->format.dlc; + + p_frame_header->timestamp = rx_frame->timestamp_high; + p_frame_header->timestamp <<= 32; + p_frame_header->timestamp |= rx_frame->timestamp_low; + + if (p_frame_header->ide) { + p_frame_header->id = (rx_frame->identifier.val & TWAI_EXT_ID_MASK); + } else { + // No check with 'TWAI_STD_ID_MASK' again due to register `identifier_base` already 11 bits len + p_frame_header->id = rx_frame->identifier.identifier_base; + } +} + +/** + * @brief Parse formatted TWAI data (RX Buffer Layout) into data buffer + * + * @param[in] rx_frame Pointer to formatted frame + * @param[out] buffer Pointer to an 8 byte array to save data + * @param[in] buffer_len_limit The buffer length limit, If less then frame data length, over length data will dropped + */ +__attribute__((always_inline)) +static inline void twaifd_ll_parse_frame_data(const twaifd_frame_buffer_t *rx_frame, uint8_t *buffer, int len_limit) +{ + memcpy(buffer, rx_frame->data, len_limit); +} + +/* ------------------------- Tx Rx traffic counters Register ------------------------- */ +/** + * @brief Get RX Message Counter + * + * @param hw Start address of the TWAI registers + * @return RX Message Counter + */ +static inline uint32_t twaifd_ll_get_rx_traffic_counter(twaifd_dev_t *hw) +{ + return hw->rx_fr_ctr.val; +} + +/** + * @brief Get TX Message Counter + * + * @param hw Start address of the TWAI registers + * @return TX Message Counter + */ +static inline uint32_t twaifd_ll_get_tx_traffic_counter(twaifd_dev_t *hw) +{ + return hw->tx_fr_ctr.val; +} + +/* ------------------------- Timestamp Register ------------------------- */ + +/** + * @brief Enable or disable the timer clock. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param enable True to enable, false to disable. + */ +static inline void twaifd_ll_timer_enable_clock(twaifd_dev_t *hw, bool enable) +{ + hw->timer_clk_en.clk_en = enable; +} + +/** + * @brief Enable or disable timer power. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param enable True to enable, false to disable. + */ +static inline void twaifd_ll_timer_enable(twaifd_dev_t *hw, bool enable) +{ + hw->timer_cfg.timer_ce = enable; +} + +/** + * @brief Set the timer step value. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param step Step value to set (actual step = step - 1). + */ +static inline void twaifd_ll_timer_set_step(twaifd_dev_t *hw, uint32_t step) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->timer_cfg, timer_step, (step - 1)); +} + +/** + * @brief Set timer mode to up or down counter. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param up True for up counter, false for down counter. + */ +static inline void twaifd_ll_timer_set_direction(twaifd_dev_t *hw, bool up) +{ + hw->timer_cfg.timer_up_dn = up; +} + +/** + * @brief Clear or reset the timer count. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param clear True to clear count, false to set count. + */ +static inline void twaifd_ll_timer_clr_count(twaifd_dev_t *hw, bool clear) +{ + hw->timer_cfg.timer_clr = clear; +} + +/** + * @brief Set the timer preload value. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param load_value 64-bit load value. + */ +static inline void twaifd_ll_timer_set_preload_value(twaifd_dev_t *hw, uint64_t load_value) +{ + hw->timer_ld_val_h.val = (uint32_t)(load_value >> 32); + hw->timer_ld_val_l.val = (uint32_t) load_value; +} + +/** + * @brief Apply preload value + * + * @param hw Pointer to the TWAI-FD device hardware. + */ +static inline void twaifd_ll_timer_apply_preload_value(twaifd_dev_t *hw) +{ + hw->timer_cfg.timer_set = 1; +} + +/** + * @brief Set the timer alarm value. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param alarm_value 64-bit alarm value. + */ +static inline void twaifd_ll_timer_set_alarm_value(twaifd_dev_t *hw, uint64_t alarm_value) +{ + hw->timer_ct_val_h.val = (uint32_t)(alarm_value >> 32); + hw->timer_ct_val_l.val = (uint32_t) alarm_value; +} + +/** + * @brief Enable or disable timer interrupt by mask. + * + * @param hw Timer Group register base address + * @param mask Mask of interrupt events + * @param en True: enable interrupt + * False: disable interrupt + */ +static inline void twaifd_ll_timer_enable_intr(twaifd_dev_t *hw, uint32_t mask, bool en) +{ + if (en) { + hw->timer_int_ena.val |= mask; + } else { + hw->timer_int_ena.val &= ~mask; + } +} + +/** + * @brief Get the current timer interrupt status. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Current interrupt status. + */ +static inline uint32_t twaifd_ll_timer_get_intr_status(twaifd_dev_t *hw, uint32_t mask) +{ + return hw->timer_int_st.val & mask; +} + +/** + * @brief Clear specific timer interrupts. + * + * @param hw Pointer to the TWAI-FD device hardware. + */ +static inline void twaifd_ll_timer_clr_intr_status(twaifd_dev_t *hw, uint32_t mask) +{ + hw->timer_int_clr.val = mask; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/twai_ll.h b/components/hal/esp32p4/include/hal/twai_ll.h index fb68f9a761..2eb02c75fc 100644 --- a/components/hal/esp32p4/include/hal/twai_ll.h +++ b/components/hal/esp32p4/include/hal/twai_ll.h @@ -149,12 +149,18 @@ ESP_STATIC_ASSERT(sizeof(twai_ll_frame_buffer_t) == 13, "TX/RX buffer type shoul */ static inline void twai_ll_enable_bus_clock(int group_id, bool enable) { - switch (group_id) - { - case 0: HP_SYS_CLKRST.soc_clk_ctrl2.reg_twai0_apb_clk_en = enable; break; - case 1: HP_SYS_CLKRST.soc_clk_ctrl2.reg_twai1_apb_clk_en = enable; break; - case 2: HP_SYS_CLKRST.soc_clk_ctrl2.reg_twai2_apb_clk_en = enable; break; - default: HAL_ASSERT(false); + switch (group_id) { + case 0: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_twai0_apb_clk_en = enable; + break; + case 1: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_twai1_apb_clk_en = enable; + break; + case 2: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_twai2_apb_clk_en = enable; + break; + default: + HAL_ASSERT(false); } } @@ -172,17 +178,19 @@ static inline void twai_ll_enable_bus_clock(int group_id, bool enable) */ static inline void twai_ll_reset_register(int group_id) { - switch (group_id) - { - case 0: HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai0 = 1; - HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai0 = 0; - break; - case 1: HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai1 = 1; - HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai1 = 0; - break; - case 2: HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai2 = 1; - HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai2 = 0; - break; + switch (group_id) { + case 0: + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai0 = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai0 = 0; + break; + case 1: + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai1 = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai1 = 0; + break; + case 2: + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai2 = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_twai2 = 0; + break; default: HAL_ASSERT(false); } } @@ -229,21 +237,23 @@ static inline void twai_ll_enable_clock(int group_id, bool en) __attribute__((always_inline)) static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) { + // We do not plan to support the TWAI_CLK_SRC_RC_FAST clock source, + // as the accuracy of this clock does not meet the requirements for the baud rate + HAL_ASSERT(clk_src == TWAI_CLK_SRC_XTAL); uint32_t clk_id = 0; - switch (clk_src) { - case TWAI_CLK_SRC_XTAL: clk_id = 0; break; -#if SOC_CLK_TREE_SUPPORTED - case TWAI_CLK_SRC_RC_FAST: clk_id = 1; break; -#endif - default: HAL_ASSERT(false); - } - switch (group_id) { - case 0: HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai0_clk_src_sel = clk_id; break; - case 1: HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai1_clk_src_sel = clk_id; break; - case 2: HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai2_clk_src_sel = clk_id; break; - default: HAL_ASSERT(false); + case 0: + HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai0_clk_src_sel = clk_id; + break; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai1_clk_src_sel = clk_id; + break; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai2_clk_src_sel = clk_id; + break; + default: + HAL_ASSERT(false); } } @@ -554,9 +564,9 @@ __attribute__((always_inline)) static inline void twai_ll_parse_err_code_cap(twai_dev_t *hw, twai_ll_err_type_t *type, twai_ll_err_dir_t *dir, twai_ll_err_seg_t *seg) { uint32_t ecc = hw->err_code_cap.val; - *type = (twai_ll_err_type_t) ((ecc >> 6) & 0x3); - *dir = (twai_ll_err_dir_t) ((ecc >> 5) & 0x1); - *seg = (twai_ll_err_seg_t) (ecc & 0x1F); + *type = (twai_ll_err_type_t)((ecc >> 6) & 0x3); + *dir = (twai_ll_err_dir_t)((ecc >> 5) & 0x1); + *seg = (twai_ll_err_seg_t)(ecc & 0x1F); } /* ----------------------------- EWL Register ------------------------------- */ diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index efd9d3a9e8..400d76c99e 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -19,6 +19,10 @@ config SOC_GPTIMER_SUPPORTED bool default y +config SOC_TWAI_SUPPORTED + bool + default y + config SOC_ETM_SUPPORTED bool default y @@ -695,6 +699,42 @@ config SOC_MWDT_SUPPORT_XTAL bool default y +config SOC_TWAI_CONTROLLER_NUM + int + default 1 + +config SOC_TWAI_MASK_FILTER_NUM + int + default 3 + +config SOC_TWAI_RANGE_FILTER_NUM + int + default 1 + +config SOC_TWAI_BRP_MIN + int + default 1 + +config SOC_TWAI_BRP_MAX + int + default 255 + +config SOC_TWAI_CLK_SUPPORT_XTAL + bool + default y + +config SOC_TWAI_SUPPORTS_RX_STATUS + bool + default y + +config SOC_TWAI_SUPPORT_FD + bool + default y + +config SOC_TWAI_SUPPORT_TIMESTAMP + bool + default y + config SOC_EFUSE_DIS_DOWNLOAD_ICACHE bool default n diff --git a/components/soc/esp32h4/include/soc/clk_tree_defs.h b/components/soc/esp32h4/include/soc/clk_tree_defs.h index c2403cf339..8bd291b5bf 100644 --- a/components/soc/esp32h4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h4/include/soc/clk_tree_defs.h @@ -355,6 +355,22 @@ typedef enum { SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the default clock choice */ } soc_periph_sdm_clk_src_t; +//////////////////////////////////////////////////TWAI////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of TWAI + */ +#define SOC_TWAI_CLKS {(soc_periph_twai_clk_src_t)SOC_MOD_CLK_XTAL, (soc_periph_twai_clk_src_t)SOC_MOD_CLK_PLL_F96M} + +/** + * @brief TWAI clock source + */ +typedef enum { + TWAI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + TWAI_CLK_SRC_PLL_F96M = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_96M as the source clock */ + TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_96M as the default clock choice */ +} soc_periph_twai_clk_src_t; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index adcb3c3017..7901c6d2d1 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -40,7 +40,7 @@ #define SOC_GPTIMER_SUPPORTED 1 // #define SOC_PCNT_SUPPORTED 1 // TODO: [ESP32H4] IDF-12338 // #define SOC_MCPWM_SUPPORTED 1 // TODO: [ESP32H4] IDF-12380 -// #define SOC_TWAI_SUPPORTED 1 // TODO: [ESP32H4] IDF-12352 +#define SOC_TWAI_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 // #define SOC_PARLIO_SUPPORTED 1 // TODO: [ESP32H4] IDF-12345 IDF-12347 // #define SOC_BT_SUPPORTED 1 @@ -450,11 +450,15 @@ #define SOC_MWDT_SUPPORT_XTAL (1) /*-------------------------- TWAI CAPS ---------------------------------------*/ -// #define SOC_TWAI_CONTROLLER_NUM 2 -// #define SOC_TWAI_CLK_SUPPORT_XTAL 1 -// #define SOC_TWAI_BRP_MIN 2 -// #define SOC_TWAI_BRP_MAX 32768 -// #define SOC_TWAI_SUPPORTS_RX_STATUS 1 +#define SOC_TWAI_CONTROLLER_NUM 1U +#define SOC_TWAI_MASK_FILTER_NUM 3 +#define SOC_TWAI_RANGE_FILTER_NUM 1U +#define SOC_TWAI_BRP_MIN 1U +#define SOC_TWAI_BRP_MAX 255 +#define SOC_TWAI_CLK_SUPPORT_XTAL 1 +#define SOC_TWAI_SUPPORTS_RX_STATUS 1 +#define SOC_TWAI_SUPPORT_FD 1 +#define SOC_TWAI_SUPPORT_TIMESTAMP 1 /*-------------------------- eFuse CAPS----------------------------*/ #define SOC_EFUSE_DIS_DOWNLOAD_ICACHE 0 diff --git a/components/soc/esp32h4/register/soc/twaifd_struct.h b/components/soc/esp32h4/register/soc/twaifd_struct.h index 8c19a3f288..dbdeb40c3a 100644 --- a/components/soc/esp32h4/register/soc/twaifd_struct.h +++ b/components/soc/esp32h4/register/soc/twaifd_struct.h @@ -1299,107 +1299,39 @@ typedef union { /** Group: filter register */ -/** Type of filter_a_mask register - * TWAI FD filter A mask value register +/** Type of filter_mask register + * TWAI FD filter mask value register */ typedef union { struct { - /** bit_mask_a_val : R/W; bitpos: [28:0]; default: 0; - * Filter A mask. The identifier format is the same as in IDENTIFIER_W of TXT buffer + /** bit_mask_val : R/W; bitpos: [28:0]; default: 0; + * Filter mask. The identifier format is the same as in IDENTIFIER_W of TXT buffer * or RX - * buffer. If filter A is not present, writes to this register have no effect and read + * buffer. If filter is not present, writes to this register have no effect and read * will return all zeroes. */ - uint32_t bit_mask_a_val:29; + uint32_t bit_mask_val:29; uint32_t reserved_29:3; }; uint32_t val; -} twaifd_filter_a_mask_reg_t; +} twaifd_filter_mask_reg_t; -/** Type of filter_a_val register - * TWAI FD filter A bit value register +/** Type of filter_val register + * TWAI FD filter bit value register */ typedef union { struct { - /** bit_val_a_val : R/W; bitpos: [28:0]; default: 0; - * Filter A value. The identifier format is the same as in IDENTIFIER_W of TXT buffer + /** bit_val : R/W; bitpos: [28:0]; default: 0; + * Filter value. The identifier format is the same as in IDENTIFIER_W of TXT buffer * or RX buffer. - * If filter A is not present, writes to this register have no effect and read will + * If filter is not present, writes to this register have no effect and read will * return all zeroes. */ - uint32_t bit_val_a_val:29; + uint32_t bit_val:29; uint32_t reserved_29:3; }; uint32_t val; -} twaifd_filter_a_val_reg_t; - -/** Type of filter_b_mask register - * TWAI FD filter B mask value register - */ -typedef union { - struct { - /** bit_mask_b_val : R/W; bitpos: [28:0]; default: 0; - * Filter B mask. The identifier format is the same as in IDENTIFIER_W of TXT buffer - * or RX - * buffer. If filter A is not present, writes to this register have no effect and read - * will return all zeroes. - */ - uint32_t bit_mask_b_val:29; - uint32_t reserved_29:3; - }; - uint32_t val; -} twaifd_filter_b_mask_reg_t; - -/** Type of filter_b_val register - * TWAI FD filter B bit value register - */ -typedef union { - struct { - /** bit_val_b_val : R/W; bitpos: [28:0]; default: 0; - * Filter B value. The identifier format is the same as in IDENTIFIER_W of TXT buffer - * or RX buffer. - * If filter A is not present, writes to this register have no effect and read will - * return all zeroes. - */ - uint32_t bit_val_b_val:29; - uint32_t reserved_29:3; - }; - uint32_t val; -} twaifd_filter_b_val_reg_t; - -/** Type of filter_c_mask register - * TWAI FD filter C mask value register - */ -typedef union { - struct { - /** bit_mask_c_val : R/W; bitpos: [28:0]; default: 0; - * Filter C mask. The identifier format is the same as in IDENTIFIER_W of TXT buffer - * or RX - * buffer. If filter A is not present, writes to this register have no effect and read - * will return all zeroes. - */ - uint32_t bit_mask_c_val:29; - uint32_t reserved_29:3; - }; - uint32_t val; -} twaifd_filter_c_mask_reg_t; - -/** Type of filter_c_val register - * TWAI FD filter C bit value register - */ -typedef union { - struct { - /** bit_val_c_val : R/W; bitpos: [28:0]; default: 0; - * Filter C value. The identifier format is the same as in IDENTIFIER_W of TXT buffer - * or RX buffer. - * If filter A is not present, writes to this register have no effect and read will - * return all zeroes. - */ - uint32_t bit_val_c_val:29; - uint32_t reserved_29:3; - }; - uint32_t val; -} twaifd_filter_c_val_reg_t; +} twaifd_filter_val_reg_t; /** Type of filter_ran_low register * TWAI FD filter range low value register @@ -1806,8 +1738,65 @@ typedef union { uint32_t val; } twaifd_date_ver_reg_t; - +/** TWAI bits filter register + */ typedef struct { + volatile twaifd_filter_mask_reg_t filter_mask; + volatile twaifd_filter_val_reg_t filter_val; +} twaifd_mask_filter_reg_t; + +/** TWAI range filter register + */ +typedef struct { + volatile twaifd_filter_ran_low_reg_t ran_low; + volatile twaifd_filter_ran_high_reg_t ran_high; +} twaifd_range_filter_reg_t; + +/** + * @brief TWAI frame buffer register types + */ +typedef union twaifd_frame_buffer_t { + struct { + union { + struct { + uint32_t dlc: 4; // Data length code (0-15) + uint32_t reserved4: 1; // Reserved bit + uint32_t rtr: 1; // Remote transmission request + uint32_t ide: 1; // Identifier extension bit + uint32_t fdf: 1; // Flexible data-rate format bit + uint32_t reserved8: 1; // Reserved bit + uint32_t brs: 1; // Bit rate switch flag + uint32_t esi: 1; // Error state indicator + uint32_t rwcnt: 5; // Re-transmission counter + uint32_t reserved16: 16; // Reserved bits + }; + uint32_t val; // Complete 32-bit register value for format + } format; + + union { + struct { + uint32_t identifier_ext: 18; // Extended identifier (18 bits) + uint32_t identifier_base: 11; // Base identifier (11 bits) + uint32_t reserved29: 3; // Reserved bits + }; + uint32_t val; // Complete 32-bit register value for identifier + } identifier; + + uint32_t timestamp_low; // Lower 32 bits of timestamp + uint32_t timestamp_high; // Upper 32 bits of timestamp + uint32_t data[16]; // Data payload (16 words) + }; + uint32_t words[20]; // Raw 32-bit words for direct access +} twaifd_frame_buffer_t; + +/** TWAI frame txt buffer registers + */ +typedef struct { + volatile twaifd_frame_buffer_t txt_buffer; + uint32_t reserved_50[44]; +} twaifd_frame_mem_t; + +typedef struct twaifd_dev_t { volatile twaifd_device_id_version_reg_t device_id_version; volatile twaifd_mode_settings_reg_t mode_settings; volatile twaifd_status_reg_t status; @@ -1823,14 +1812,8 @@ typedef struct { volatile twaifd_rec_tec_reg_t rec_tec; volatile twaifd_err_norm_err_fd_reg_t err_norm_err_fd; volatile twaifd_ctr_pres_reg_t ctr_pres; - volatile twaifd_filter_a_mask_reg_t filter_a_mask; - volatile twaifd_filter_a_val_reg_t filter_a_val; - volatile twaifd_filter_b_mask_reg_t filter_b_mask; - volatile twaifd_filter_b_val_reg_t filter_b_val; - volatile twaifd_filter_c_mask_reg_t filter_c_mask; - volatile twaifd_filter_c_val_reg_t filter_c_val; - volatile twaifd_filter_ran_low_reg_t filter_ran_low; - volatile twaifd_filter_ran_high_reg_t filter_ran_high; + volatile twaifd_mask_filter_reg_t mask_filters[3]; + volatile twaifd_range_filter_reg_t range_filters[1]; volatile twaifd_filter_control_filter_status_reg_t filter_control_filter_status; volatile twaifd_rx_mem_info_reg_t rx_mem_info; volatile twaifd_rx_pointers_reg_t rx_pointers; @@ -1847,7 +1830,9 @@ typedef struct { volatile twaifd_yolo_reg_t yolo; volatile twaifd_timestamp_low_reg_t timestamp_low; volatile twaifd_timestamp_high_reg_t timestamp_high; - uint32_t reserved_09c[974]; + uint32_t reserved_09c[25]; + volatile twaifd_frame_mem_t txt_mem_cell[8]; + uint32_t reserved_900[437]; volatile twaifd_timer_clk_en_reg_t timer_clk_en; volatile twaifd_timer_int_raw_reg_t timer_int_raw; volatile twaifd_timer_int_st_reg_t timer_int_st; @@ -1861,7 +1846,7 @@ typedef struct { volatile twaifd_date_ver_reg_t date_ver; } twaifd_dev_t; -extern twaifd_dev_t TWAIFD; +extern twaifd_dev_t TWAI0; #ifndef __cplusplus _Static_assert(sizeof(twaifd_dev_t) == 0x1000, "Invalid size of twaifd_dev_t structure"); diff --git a/components/soc/esp32h4/twai_periph.c b/components/soc/esp32h4/twai_periph.c new file mode 100644 index 0000000000..e819c61255 --- /dev/null +++ b/components/soc/esp32h4/twai_periph.c @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/twai_periph.h" +#include "soc/gpio_sig_map.h" + +const twai_signal_conn_t twai_periph_signals[1] = { + [0] = { + .module_name = "TWAI0", + .irq_id = ETS_TWAI0_INTR_SOURCE, + .timer_irq_id = ETS_TWAI0_TIMER_INTR_SOURCE, + .tx_sig = TWAI0_TX_IDX, + .rx_sig = TWAI0_RX_IDX, + .bus_off_sig = -1, + .clk_out_sig = -1, + .stand_by_sig = -1, + } +}; diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 8dd4f0604a..c1a0edeb89 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -605,7 +605,6 @@ typedef enum { */ typedef enum { TWAI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - TWAI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */ } soc_periph_twai_clk_src_t; diff --git a/docs/docs_not_updated/esp32h4.txt b/docs/docs_not_updated/esp32h4.txt index ea29f01fc1..f03124356c 100644 --- a/docs/docs_not_updated/esp32h4.txt +++ b/docs/docs_not_updated/esp32h4.txt @@ -145,7 +145,6 @@ api-reference/peripherals/mcpwm.rst api-reference/peripherals/usb_host.rst api-reference/peripherals/camera_driver.rst api-reference/peripherals/adc_oneshot.rst -api-reference/peripherals/twai.rst api-reference/peripherals/sdspi_share.rst api-reference/peripherals/ana_cmpr.rst api-reference/peripherals/adc_continuous.rst diff --git a/examples/peripherals/twai/twai_error_recovery/README.md b/examples/peripherals/twai/twai_error_recovery/README.md index 672f6dfffd..a311512382 100644 --- a/examples/peripherals/twai/twai_error_recovery/README.md +++ b/examples/peripherals/twai/twai_error_recovery/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # TWAI Bus-Off Recovery Example This example demonstrates how to recover a TWAI node from a Bus-Off error condition and resume communication. The recovery is triggered by physically inducing bus errors and handled using the ESP TWAI on-chip driver with callback support. diff --git a/examples/peripherals/twai/twai_network/README.md b/examples/peripherals/twai/twai_network/README.md index a0c7f8a64f..13cb153169 100644 --- a/examples/peripherals/twai/twai_network/README.md +++ b/examples/peripherals/twai/twai_network/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # TWAI Network Example diff --git a/examples/peripherals/twai/twai_utils/README.md b/examples/peripherals/twai/twai_utils/README.md index 4dc7b8145f..56c702b8cc 100644 --- a/examples/peripherals/twai/twai_utils/README.md +++ b/examples/peripherals/twai/twai_utils/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # TWAI Console Example diff --git a/examples/peripherals/twai/twai_utils/pytest_twai_utils.py b/examples/peripherals/twai/twai_utils/pytest_twai_utils.py index cfbf496c88..a641a0986a 100644 --- a/examples/peripherals/twai/twai_utils/pytest_twai_utils.py +++ b/examples/peripherals/twai/twai_utils/pytest_twai_utils.py @@ -644,7 +644,7 @@ def test_twai_range_filters(twai: TwaiTestHelper) -> None: @pytest.mark.twai_std -@pytest.mark.temp_skip_ci(targets=['esp32c5'], reason='no runner') +@pytest.mark.temp_skip_ci(targets=['esp32c5', 'esp32h4'], reason='no runner') @idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target']) def test_twai_external_communication(twai: TwaiTestHelper, can_manager: CanBusManager) -> None: """ From 921e62b81fe3d44da13ab0ab6ac332d29da58963 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 22 Aug 2025 14:32:08 +0800 Subject: [PATCH 2/2] fix(twai): busoff and clkout may not available in SOC return ESP_ERR_NOT_SUPPORTED if these signals are required from user but not available in SOC --- components/esp_driver_twai/esp_twai_onchip.c | 4 +++- .../test_twai/main/test_twai_common.cpp | 16 ++++++++++++++++ .../test_apps/test_twai/main/test_twai_fd.cpp | 4 ++++ .../test_twai/main/test_twai_network.cpp | 4 ++++ components/soc/esp32c5/twai_periph.c | 14 +++++++------- .../main/twai_recovery_main.c | 8 ++++++-- .../twai_listen_only/main/twai_listen_only.c | 4 ++-- .../twai_network/twai_sender/main/twai_sender.c | 4 ++-- 8 files changed, 44 insertions(+), 14 deletions(-) diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index 2046d2b3c5..7b95a5420c 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -127,8 +127,10 @@ 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_GPIO(node_config->io_cfg.rx), ESP_ERR_INVALID_ARG, TAG, "Invalid rx gpio num"); - uint64_t reserve_mask = 0; + 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.bus_off_indicator) && (twai_periph_signals[node->ctrlr_id].bus_off_sig < 0)), ESP_ERR_NOT_SUPPORTED, TAG, "bus_off_indicator is not supported"); + uint64_t reserve_mask = 0; // Set RX pin gpio_set_pull_mode(node_config->io_cfg.rx, GPIO_PULLUP_ONLY); // pullup to avoid noise if no connection to transceiver gpio_matrix_input(node_config->io_cfg.rx, twai_periph_signals[node->ctrlr_id].rx_sig, false); diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp index a42d0e4ed6..ee94a8bcd5 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.cpp @@ -48,6 +48,8 @@ TEST_CASE("twai install uninstall (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 1000000; node_config.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH; node_config.flags.enable_self_test = true; @@ -111,6 +113,8 @@ static void test_twai_baudrate_correctness(twai_clock_source_t clk_src, uint32_t 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.clk_src = clk_src; node_config.bit_timing.bitrate = test_bitrate; node_config.tx_queue_depth = 1; @@ -183,6 +187,8 @@ TEST_CASE("twai transmit stop resume (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 200000; node_config.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH; node_config.flags.enable_self_test = true; @@ -280,6 +286,8 @@ TEST_CASE("twai mask filter (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 1000000; node_config.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH; node_config.flags.enable_self_test = true; @@ -363,6 +371,8 @@ TEST_CASE("twai dual 16bit mask filter (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 1000000; node_config.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH; node_config.flags.enable_self_test = true; @@ -436,6 +446,8 @@ TEST_CASE("twai driver cache safe (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 50000; //slow bitrate to ensure cache disabled before tx_queue finish node_config.tx_queue_depth = TEST_FRAME_NUM; node_config.flags.enable_loopback = true; @@ -487,6 +499,8 @@ TEST_CASE("twai bus off recovery (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 50000; //slow bitrate to ensure soft error trigger node_config.tx_queue_depth = 1; node_config.flags.enable_self_test = true; @@ -558,6 +572,8 @@ TEST_CASE("twai tx_wait_all_done thread safe", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 100000; //slow bitrate to ensure transmite finish during wait_all_done node_config.tx_queue_depth = TEST_FRAME_NUM; node_config.flags.enable_self_test = true; diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp index 59e3861e1e..47929940eb 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.cpp @@ -66,6 +66,8 @@ TEST_CASE("twai range filter (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 1000000; node_config.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH; node_config.flags.enable_self_test = true; @@ -139,6 +141,8 @@ TEST_CASE("twai fd transmit time (loopback)", "[twai]") twai_onchip_node_config_t node_config = {}; 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.quanta_clk_out = GPIO_NUM_NC; + node_config.io_cfg.bus_off_indicator = GPIO_NUM_NC; node_config.bit_timing.bitrate = 1000000; node_config.data_timing.bitrate = 4000000; node_config.data_timing.ssp_permill = 700; // ssp 70.0% diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp index 043154ddb7..5b4ad1ee85 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_network.cpp @@ -31,6 +31,8 @@ TEST_CASE("twai_listen_only", "[twai_net]") twai_onchip_node_config_t node_config = {}; node_config.io_cfg.tx = TEST_TX_GPIO; node_config.io_cfg.rx = TEST_RX_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 = 250000; node_config.tx_queue_depth = 3; node_config.flags.enable_listen_only = true; @@ -71,6 +73,8 @@ TEST_CASE("twai_remote_request", "[twai_net]") twai_onchip_node_config_t node_config = {}; node_config.io_cfg.tx = TEST_TX_GPIO; node_config.io_cfg.rx = TEST_RX_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 = 250000; node_config.tx_queue_depth = 3; node_config.fail_retry_cnt = -1; // retry forever if send remote frame failed diff --git a/components/soc/esp32c5/twai_periph.c b/components/soc/esp32c5/twai_periph.c index 80e627a0b2..b8e19aeab2 100644 --- a/components/soc/esp32c5/twai_periph.c +++ b/components/soc/esp32c5/twai_periph.c @@ -7,16 +7,16 @@ #include "soc/twai_periph.h" #include "soc/gpio_sig_map.h" -const twai_signal_conn_t twai_periph_signals[SOC_TWAI_CONTROLLER_NUM] = { +const twai_signal_conn_t twai_periph_signals[2] = { [0] = { .module_name = "TWAI0", .irq_id = ETS_TWAI0_INTR_SOURCE, .timer_irq_id = ETS_TWAI0_TIMER_INTR_SOURCE, .tx_sig = TWAI0_TX_IDX, .rx_sig = TWAI0_RX_IDX, - .bus_off_sig = TWAI0_BUS_OFF_ON_IDX, - .clk_out_sig = TWAI0_CLKOUT_IDX, - .stand_by_sig = TWAI0_STANDBY_IDX, + .bus_off_sig = -1, + .clk_out_sig = -1, + .stand_by_sig = -1, }, [1] = { .module_name = "TWAI1", @@ -24,8 +24,8 @@ const twai_signal_conn_t twai_periph_signals[SOC_TWAI_CONTROLLER_NUM] = { .timer_irq_id = ETS_TWAI1_TIMER_INTR_SOURCE, .tx_sig = TWAI1_TX_IDX, .rx_sig = TWAI1_RX_IDX, - .bus_off_sig = TWAI1_BUS_OFF_ON_IDX, - .clk_out_sig = TWAI1_CLKOUT_IDX, - .stand_by_sig = TWAI1_STANDBY_IDX, + .bus_off_sig = -1, + .clk_out_sig = -1, + .stand_by_sig = -1, }, }; diff --git a/examples/peripherals/twai/twai_error_recovery/main/twai_recovery_main.c b/examples/peripherals/twai/twai_error_recovery/main/twai_recovery_main.c index 8e0bf10713..201b1472bd 100644 --- a/examples/peripherals/twai/twai_error_recovery/main/twai_recovery_main.c +++ b/examples/peripherals/twai/twai_error_recovery/main/twai_recovery_main.c @@ -49,8 +49,12 @@ void app_main(void) { twai_node_handle_t node_hdl; twai_onchip_node_config_t node_config = { - .io_cfg.tx = TX_GPIO_NUM, - .io_cfg.rx = RX_GPIO_NUM, + .io_cfg = { + .tx = TX_GPIO_NUM, + .rx = RX_GPIO_NUM, + .quanta_clk_out = GPIO_NUM_NC, + .bus_off_indicator = GPIO_NUM_NC, + }, .bit_timing.bitrate = TWAI_BITRATE, .tx_queue_depth = 1, .flags.enable_self_test = true, diff --git a/examples/peripherals/twai/twai_network/twai_listen_only/main/twai_listen_only.c b/examples/peripherals/twai/twai_network/twai_listen_only/main/twai_listen_only.c index fa53395bbb..1851281f18 100644 --- a/examples/peripherals/twai/twai_network/twai_listen_only/main/twai_listen_only.c +++ b/examples/peripherals/twai/twai_network/twai_listen_only/main/twai_listen_only.c @@ -94,8 +94,8 @@ void app_main(void) .io_cfg = { .tx = TWAI_LISTENER_TX_GPIO, .rx = TWAI_LISTENER_RX_GPIO, - .quanta_clk_out = -1, - .bus_off_indicator = -1, + .quanta_clk_out = GPIO_NUM_NC, + .bus_off_indicator = GPIO_NUM_NC, }, .bit_timing.bitrate = TWAI_BITRATE, .flags.enable_listen_only = true, diff --git a/examples/peripherals/twai/twai_network/twai_sender/main/twai_sender.c b/examples/peripherals/twai/twai_network/twai_sender/main/twai_sender.c index 2c9c037c7c..a8255752bc 100644 --- a/examples/peripherals/twai/twai_network/twai_sender/main/twai_sender.c +++ b/examples/peripherals/twai/twai_network/twai_sender/main/twai_sender.c @@ -57,8 +57,8 @@ void app_main(void) .io_cfg = { .tx = TWAI_SENDER_TX_GPIO, .rx = TWAI_SENDER_RX_GPIO, - .quanta_clk_out = -1, - .bus_off_indicator = -1, + .quanta_clk_out = GPIO_NUM_NC, + .bus_off_indicator = GPIO_NUM_NC, }, .bit_timing = { .bitrate = TWAI_BITRATE,