From aea648dbd2f1fe125c353fb79f6f2260aa068940 Mon Sep 17 00:00:00 2001 From: wanckl Date: Tue, 14 Apr 2026 17:41:04 +0800 Subject: [PATCH] feat(driver_twai): bringup s31 twaifd driver support --- components/esp_driver_twai/esp_twai_onchip.c | 4 + .../test_apps/test_twai/README.md | 4 +- .../test_twai/main/test_twai_common.cpp | 2 +- .../test_apps/test_twai/pytest_driver_twai.py | 4 +- .../esp32s31/include/hal/twai_ll.h | 211 ++++ .../esp32s31/include/hal/twaifd_ll.h | 1097 +++++++++++++++++ .../esp_hal_twai/esp32s31/twai_periph.c | 105 ++ .../esp32s31/include/soc/Kconfig.soc_caps.in | 24 + .../soc/esp32s31/include/soc/clk_tree_defs.h | 16 + .../soc/esp32s31/include/soc/soc_caps.h | 9 +- .../soc/esp32s31/register/soc/twaifd_reg.h | 108 +- .../soc/esp32s31/register/soc/twaifd_struct.h | 175 ++- examples/peripherals/.build-test-rules.yml | 8 + examples/peripherals/twai/cybergear/README.md | 4 +- .../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 | 1 + .../twai_utils/sdkconfig.defaults.esp32s31 | 1 + 19 files changed, 1626 insertions(+), 159 deletions(-) create mode 100644 components/esp_hal_twai/esp32s31/include/hal/twai_ll.h create mode 100644 components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h create mode 100644 components/esp_hal_twai/esp32s31/twai_periph.c create mode 100644 examples/peripherals/twai/twai_utils/sdkconfig.defaults.esp32s31 diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index deb2b097e4..0495fc6656 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -25,6 +25,10 @@ static void _twai_rcc_clock_ctrl(uint8_t ctrlr_id, bool enable) PERIPH_RCC_ATOMIC() { twai_ll_enable_clock(ctrlr_id, enable); } +#if TWAI_LL_SUPPORT(MEM_LP) + twai_ll_mem_power_by_pmu(ctrlr_id); + twai_ll_mem_lp_mode_sel(ctrlr_id, TWAI_LL_MEM_LP_MODE_SHUT_DOWN); +#endif } static void _twai_rcc_clock_sel(uint8_t ctrlr_id, twai_clock_source_t clock) { 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 c3221d0779..2ce6f477ac 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-H4 | 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 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | 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 f23bae4ce2..b41987b509 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 @@ -57,7 +57,7 @@ TEST_CASE("twai install uninstall (loopback)", "[twai]") 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.bit_timing.bitrate = 500000; node_config.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH; node_config.flags.enable_self_test = true; node_config.flags.enable_loopback = true; 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 c25a08ea4f..0c350e9bc0 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 @@ -78,7 +78,7 @@ def fixture_create_socket_can() -> Bus: # Interactive Tests # --------------------------------------------------------------------------- @pytest.mark.twai_std -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='no runner') +@pytest.mark.temp_skip_ci(targets=['esp32h4', 'esp32s31'], 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: @@ -99,7 +99,7 @@ def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None: @pytest.mark.twai_std -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='no runner') +@pytest.mark.temp_skip_ci(targets=['esp32h4', 'esp32s31'], 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/esp_hal_twai/esp32s31/include/hal/twai_ll.h b/components/esp_hal_twai/esp32s31/include/hal/twai_ll.h new file mode 100644 index 0000000000..541f75a3d1 --- /dev/null +++ b/components/esp_hal_twai/esp32s31/include/hal/twai_ll.h @@ -0,0 +1,211 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "hal/twai_types.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_system_struct.h" + +#define TWAI_LL_GET(_attr) TWAI_LL_ ## _attr +#define TWAI_LL_SUPPORT(_feat) TWAI_LL_SUPPORT_ ## _feat + +#define TWAI_LL_SUPPORT_TIMESTAMP 1 +#define TWAI_LL_SUPPORT_RX_STATUS 1 +#define TWAI_LL_SUPPORT_MEM_LP 1 // support memory low power mode + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + TWAI_LL_MEM_LP_MODE_DEEP_SLEEP, // memory will enter deep sleep during low power stage, keep memory data + TWAI_LL_MEM_LP_MODE_LIGHT_SLEEP, // memory will enter light sleep during low power stage, keep memory data + TWAI_LL_MEM_LP_MODE_SHUT_DOWN, // memory will be powered down during low power stage + TWAI_LL_MEM_LP_MODE_DISABLE, // disable the low power stage +} twai_ll_mem_lp_mode_sel_t; + +/** + * @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 twai_ll_enable_bus_clock(uint8_t twai_id, bool enable) +{ + switch (twai_id) { + case 0: + HP_SYS_CLKRST.twai0_ctrl0.reg_twai0_apb_clk_en = enable; + break; + case 1: + HP_SYS_CLKRST.twai1_ctrl0.reg_twai1_apb_clk_en = enable; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Select the power control mode for the TWAI memory block + * + * @param twai_id Hardware ID + */ +static inline void twai_ll_mem_power_by_pmu(uint8_t twai_id) +{ + switch (twai_id) { + case 0: + HP_SYSTEM.sys_can0_mem_lp_ctrl.sys_can0_mem_force_ctrl = 0; + HP_SYSTEM.sys_can0_mem_lp_ctrl.sys_can0_mem_lp_en = 0; + break; + case 1: + HP_SYSTEM.sys_can1_mem_lp_ctrl.sys_can1_mem_force_ctrl = 0; + HP_SYSTEM.sys_can1_mem_lp_ctrl.sys_can1_mem_lp_en = 0; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Select the low power mode for the TWAI memory block + * + * @param twai_id Hardware ID + * @param mode Low power mode + */ +static inline void twai_ll_mem_lp_mode_sel(uint8_t twai_id, twai_ll_mem_lp_mode_sel_t mode) +{ + switch (twai_id) { + case 0: + HP_SYSTEM.sys_can0_mem_lp_ctrl.sys_can0_mem_lp_mode = mode; + break; + case 1: + HP_SYSTEM.sys_can1_mem_lp_ctrl.sys_can1_mem_lp_mode = mode; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Force the TWAI memory block to power on + * + * @param twai_id Hardware ID + */ +static inline void twai_ll_mem_force_power_on(uint8_t twai_id) +{ + switch (twai_id) { + case 0: + HP_SYSTEM.sys_can0_mem_lp_ctrl.sys_can0_mem_force_ctrl = 1; + HP_SYSTEM.sys_can0_mem_lp_ctrl.sys_can0_mem_lp_en = 0; + break; + case 1: + HP_SYSTEM.sys_can1_mem_lp_ctrl.sys_can1_mem_force_ctrl = 1; + HP_SYSTEM.sys_can1_mem_lp_ctrl.sys_can1_mem_lp_en = 0; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Force the TWAI memory block to enter low power mode + * + * @param twai_id Hardware ID + */ +static inline void twai_ll_mem_force_low_power(uint8_t twai_id) +{ + switch (twai_id) { + case 0: + HP_SYSTEM.sys_can0_mem_lp_ctrl.sys_can0_mem_force_ctrl = 1; + HP_SYSTEM.sys_can0_mem_lp_ctrl.sys_can0_mem_lp_en = 1; + break; + case 1: + HP_SYSTEM.sys_can1_mem_lp_ctrl.sys_can1_mem_force_ctrl = 1; + HP_SYSTEM.sys_can1_mem_lp_ctrl.sys_can1_mem_lp_en = 1; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Reset the TWAI module + * + * @param twai_id Hardware ID + */ +static inline void twai_ll_reset_register(uint8_t twai_id) +{ + switch (twai_id) { + case 0: + HP_SYS_CLKRST.twai0_ctrl0.reg_twai0_rst_en = 1; + HP_SYS_CLKRST.twai0_ctrl0.reg_twai0_rst_en = 0; + break; + case 1: + HP_SYS_CLKRST.twai1_ctrl0.reg_twai1_rst_en = 1; + HP_SYS_CLKRST.twai1_ctrl0.reg_twai1_rst_en = 0; + break; + default: + HAL_ASSERT(false); + } +} + +/** + * @brief Set clock source for TWAI module + * + * @param twai_id Hardware ID + * @param clk_src Clock source + */ +static inline void twai_ll_set_clock_source(uint8_t twai_id, twai_clock_source_t clk_src) +{ + uint32_t clk_sel = 0; + + switch (clk_src) { + case TWAI_CLK_SRC_XTAL: + clk_sel = 0; + break; + case TWAI_CLK_SRC_PLL_F80M: + clk_sel = 2; + break; + default: + HAL_ASSERT(false); + } + + switch (twai_id) { + case 0: + HP_SYS_CLKRST.twai0_ctrl0.reg_twai0_clk_src_sel = clk_sel; + break; + case 1: + HP_SYS_CLKRST.twai1_ctrl0.reg_twai1_clk_src_sel = clk_sel; + 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 twai_ll_enable_clock(uint8_t twai_id, bool enable) +{ + switch (twai_id) { + case 0: + HP_SYS_CLKRST.twai0_ctrl0.reg_twai0_clk_en = enable; + break; + case 1: + HP_SYS_CLKRST.twai1_ctrl0.reg_twai1_clk_en = enable; + break; + default: + HAL_ASSERT(false); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h b/components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h new file mode 100644 index 0000000000..7aa359e200 --- /dev/null +++ b/components/esp_hal_twai/esp32s31/include/hal/twaifd_ll.h @@ -0,0 +1,1097 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#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) ? (&TWAIFD0) : (((num) == 1) ? (&TWAIFD1) : NULL)) + +#define TWAI_LL_BRP_MIN 1 +#define TWAI_LL_TSEG1_MIN 0 +#define TWAI_LL_TSEG2_MIN 1 +#define TWAI_LL_BRP_MAX TWAIFD_BRP +#define TWAI_LL_TSEG1_MAX TWAIFD_PH1 +#define TWAI_LL_TSEG2_MAX TWAIFD_PH2 +#define TWAI_LL_SJW_MAX TWAIFD_SJW +#define TWAI_LL_TIMER_DIV_MAX TWAIFD_TIMER_STEP + +#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_HW_CMD_CLR_OVERRUN TWAIFD_CDO // Clear RX buffer overrun flag +#define TWAIFD_LL_HW_CMD_RX_FLUSH TWAIFD_RRB // Flush RX buffer (read and write pointers are set to 0 and the frame counter is set to 0) + +#define TWAIFD_LL_INTR_TX_DONE TWAIFD_TXBHCI_INT_ST// Transmit finish (ok or error) +#define TWAIFD_LL_INTR_TX_FRAME TWAIFD_TXI_INT_ST // A frame is transmitted +#define TWAIFD_LL_INTR_RX_FRAME TWAIFD_RXI_INT_ST // A frame is received +#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_OVERLOAD TWAIFD_OFI_INT_ST // Overload Frame Interrupt +#define TWAIFD_LL_INTR_ERR_WARN TWAIFD_EWLI_INT_ST // Error warning limit 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_ARBIT_LOST TWAIFD_ALI_INT_ST // Arbitration Lost Interrupt +#define TWAIFD_LL_INTR_DATA_OVERRUN TWAIFD_DOI_INT_ST // Data Overrun Interrupt + +#define TWAIFD_LL_INTR_TIMER_OVERFLOW TWAIFD_TIMER_OVERFLOW_INT_ST // Timer overflow 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_ARBIT_LOST | TWAIFD_LL_INTR_DATA_OVERRUN) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + TWAIFD_LL_TS_POINT_EOF = 0, // in 6th bit of end of frame (moment when the received frame is considered valid) + TWAIFD_LL_TS_POINT_SOF = 1, // start of frame bit +} twaifd_ll_timestamp_point_t; + +/** + * @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. + * + * @note After enable, the node will join the bus after receiving 11 consecutive recessive bits + * @note If disable, the node becomes "bus-off", all TX buffers goes to "empty" state without resetting the memories, RX buffer is flushed. + * + * @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; + // esp32s31 using `rom` together with `bmm` although errata 0v2 issue 5 is fixed + // see detail in https://github.com/espressif/esp-idf/issues/17461 + opmode.rom = listen_only; + opmode.ilbp = loopback; + + hw->mode_settings.val = opmode.val; +} + +/** + * @brief Set the TX retransmission limit. + * + * @note First attempt to transmit TWAI frames does not count as retransmission. + * + * @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 TWAI FD 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 Whether to enable protocol exception handling + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param ena Set to true to enable PEX, false to disable. + */ +static inline void twaifd_ll_enable_pex(twaifd_dev_t *hw, bool ena) +{ + hw->mode_settings.pex = 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_increase(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 Enable or disable the test mode for the TWAI-FD peripheral. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param enable Set to true to enable test mode, false to disable. + */ +static inline void twaifd_ll_enable_test_mode(twaifd_dev_t* hw, bool enable) +{ + hw->mode_settings.tstm = enable; +} + +/** + * @brief Enable or disable the parity error detection for the RX and TX buffers. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param enable Set to true to enable parity error detection, false to disable. + */ +static inline void twaifd_ll_enable_parity_error_detection(twaifd_dev_t* hw, bool enable) +{ + // Must be called when hardware is disabled. + HAL_ASSERT(hw->mode_settings.ena == 0); + hw->mode_settings.pchke = enable; +} + +/** + * @brief Whether to drop the RTR frames in filter. + * + * @param hw Pointer to hardware structure. + * @param en True to drop, false to pass it to the next filter + */ +static inline void twaifd_ll_filter_drop_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. + * + * @note Time triggered transmission is always considered only from the highest priority TX buffer in “ready” state. + * + * @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; +} + +/** + * @brief Whether to treat bus-off as TX failure + * + * @note Disable it, it allows going bus-off and re-integrating without the need of software interaction with TX buffers. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param enable Set to true to enable, false to disable. + */ +static inline void twaifd_ll_enable_bus_off_tx_fail_mode(twaifd_dev_t* hw, bool enable) +{ + hw->mode_settings.tbfbo = 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); +} + +/** + * @brief Get measured transmitter delay + * + * @param hw Start address of the TWAI registers + * @return Transmitter Delay Value in clock source cycles, include the input delay of TWAI FD (2 cycles) + */ +static inline uint32_t twaifd_ll_get_transmitter_delay(twaifd_dev_t *hw) +{ + return hw->trv_delay_ssp_cfg.trv_delay_value; +} + +/* ----------------------------- 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 nominal bit rate stage. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Error count in nominal bit rate stage. + */ +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 data bit rate stage. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Error count in FD data bit rate stage. + */ +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 mask filter to receive classic frame with std id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the mask filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_mask_filter_accept_classic_std(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + if (accept) { + hw->filter_control_filter_status.val |= 0x01 << (filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x01 << (filter_id * 4)); + } +} + +/** + * @brief Enable or disable mask filter to receive classic frame with ext id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the mask filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_mask_filter_accept_classic_ext(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + if (accept) { + hw->filter_control_filter_status.val |= 0x02 << (filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x02 << (filter_id * 4)); + } +} + +/** + * @brief Enable or disable mask 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 mask filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_mask_filter_accept_fd_std(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + if (accept) { + hw->filter_control_filter_status.val |= 0x04 << (filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x04 << (filter_id * 4)); + } +} + +/** + * @brief Enable or disable mask 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 mask filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_mask_filter_accept_fd_ext(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + if (accept) { + hw->filter_control_filter_status.val |= 0x08 << (filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x08 << (filter_id * 4)); + } +} + +/** + * @brief Enable or disable range filter to receive classic frame with std id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the range filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_range_filter_accept_classic_std(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + uint8_t hw_filter_id = filter_id + 3; + if (accept) { + hw->filter_control_filter_status.val |= 0x01 << (hw_filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x01 << (hw_filter_id * 4)); + } +} + +/** + * @brief Enable or disable range filter to receive classic frame with ext id + * + * @param hw Pointer to the TWAI FD hardware instance + * @param filter_id The unique ID of the range filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_range_filter_accept_classic_ext(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + uint8_t hw_filter_id = filter_id + 3; + if (accept) { + hw->filter_control_filter_status.val |= 0x02 << (hw_filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x02 << (hw_filter_id * 4)); + } +} + +/** + * @brief Enable or disable range 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 range filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_range_filter_accept_fd_std(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + uint8_t hw_filter_id = filter_id + 3; + if (accept) { + hw->filter_control_filter_status.val |= 0x04 << (hw_filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x04 << (hw_filter_id * 4)); + } +} + +/** + * @brief Enable or disable range 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 range filter to configure + * @param accept True to accept the frame, False to drop the frame + */ +static inline void twaifd_ll_range_filter_accept_fd_ext(twaifd_dev_t* hw, uint8_t filter_id, bool accept) +{ + uint8_t hw_filter_id = filter_id + 3; + if (accept) { + hw->filter_control_filter_status.val |= 0x08 << (hw_filter_id * 4); + } else { + hw->filter_control_filter_status.val &= ~(0x08 << (hw_filter_id * 4)); + } +} + +/** + * @brief Set the ID and mask for mask 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_mask_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 the ID range for range 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_range_filter_set_id_thres(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) | 0x3FFFF; +} + +/* ------------------------- TX Buffer Registers ------------------------- */ + +/** + * @brief Get the number of TX buffers that are preset in the hardware. + * + * @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_total(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_total(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 The tx buffer index to set the command + * @param cmd The command want to set, see `TWAIFD_LL_TX_CMD_` + */ +__attribute__((always_inline)) +static inline void twaifd_ll_set_tx_buffer_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. + * + * @note If two TX buffers have equal priority, TX buffer with the lower index has precedence. + * + * @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. Higher values indicate higher priority. + */ +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_total(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. + * + * @note It contains a single RX buffer where received frames are stored. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Size of the RX buffer, in multiple of 32-bit words. + */ +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 free space in the RX buffer. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Free space in the RX buffer, in multiple of 32-bit words. + */ +static inline uint32_t twaifd_ll_get_rx_free_space(twaifd_dev_t *hw) +{ + return hw->rx_mem_info.rx_free; +} + +/** + * @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 true if RX FIFO is empty, false otherwise. + */ +static inline bool twaifd_ll_is_rx_buffer_empty(twaifd_dev_t *hw) +{ + return hw->rx_status_rx_settings.rxe; +} + +/** + * @brief Check if the RX FIFO is full. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return true if RX FIFO is full, false otherwise. + */ +static inline bool twaifd_ll_is_rx_buffer_full(twaifd_dev_t *hw) +{ + return hw->rx_status_rx_settings.rxf; +} + +/** + * @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 Set the sample point for the timestamp. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param sample_point Sample point for the timestamp. + */ +static inline void twaifd_ll_ts_set_sample_point(twaifd_dev_t *hw, twaifd_ll_timestamp_point_t sample_point) +{ + hw->rx_status_rx_settings.rtsop = sample_point; +} + +/** + * @brief Whether to force enable the register config clock of the timer + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param enable True to enable, false to disable. + */ +static inline void twaifd_ll_timer_force_enable_cfg_clock(twaifd_dev_t *hw, bool enable) +{ + hw->timer_clk_en.clk_en = enable; +} + +/** + * @brief Enable or disable the timer. + * + * @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 Get the bit width of the timer. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Bit width of the timer. + */ +__attribute__((always_inline)) +static inline uint8_t twaifd_ll_timer_get_bitwidth(twaifd_dev_t *hw) +{ + return hw->err_capt_retr_ctr_alc_ts_info.ts_bits + 1; +} + +/** + * @brief Get the current timer count. + * @note The frame time is recorded by hardware, so this function is not required, can be used for independent test + * + * @param hw Pointer to the TWAI-FD device hardware. + * @return Current timer count as a 64-bit value. + */ +static inline uint64_t twaifd_ll_timer_get_count(twaifd_dev_t *hw) +{ + uint64_t count = ((uint64_t)hw->timestamp_high.val << 32) | hw->timestamp_low.val; + return count; +} + +/** + * @brief Set the timer clock divider value. + * + * @note This is to determine the resolution of the timer. We can also treat it as a prescaler. + * + * @param hw Pointer to the TWAI-FD device hardware. + * @param div Clock divider value to set. + */ +static inline void twaifd_ll_timer_set_clkdiv(twaifd_dev_t *hw, uint32_t div) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->timer_cfg, timer_step, (div - 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 when overflow. + * + * @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. + */ +__attribute__((always_inline)) +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. + */ +__attribute__((always_inline)) +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/esp_hal_twai/esp32s31/twai_periph.c b/components/esp_hal_twai/esp32s31/twai_periph.c new file mode 100644 index 0000000000..bd6e12ef4a --- /dev/null +++ b/components/esp_hal_twai/esp32s31/twai_periph.c @@ -0,0 +1,105 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/twai_periph.h" +#include "soc/gpio_sig_map.h" +#include "soc/interrupts.h" +#include "soc/twaifd_reg.h" + +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 = -1, + .clk_out_sig = -1, + .stand_by_sig = -1, + }, + [1] = { + .module_name = "TWAI1", + .irq_id = ETS_TWAI1_INTR_SOURCE, + .timer_irq_id = ETS_TWAI1_TIMER_INTR_SOURCE, + .tx_sig = TWAI1_TX_IDX, + .rx_sig = TWAI1_RX_IDX, + .bus_off_sig = -1, + .clk_out_sig = -1, + .stand_by_sig = -1, + }, +}; + +/** + * TWAI Registers to be saved during sleep retention + * - TWAIFD_MODE_SETTINGS_REG + * - TWAIFD_STATUS_REG + * - TWAIFD_COMMAND_REG + * - TWAIFD_INT_ENA_SET_REG + * - TWAIFD_INT_ENA_CLR_REG + * - TWAIFD_BTR_REG + * - TWAIFD_BTR_FD_REG + * - TWAIFD_EWL_ERP_FAULT_STATE_REG + * - TWAIFD_REC_TEC_REG + * - TWAIFD_ERR_NORM_ERR_FD_REG + * - TWAIFD_FILTER_A_MASK_REG + * - TWAIFD_FILTER_A_VAL_REG + * - TWAIFD_FILTER_B_MASK_REG + * - TWAIFD_FILTER_B_VAL_REG + * - TWAIFD_FILTER_C_MASK_REG + * - TWAIFD_FILTER_C_VAL_REG + * - TWAIFD_FILTER_RAN_LOW_REG + * - TWAIFD_FILTER_RAN_HIGH_REG + * - TWAIFD_FILTER_CONTROL_FILTER_STATUS_REG + * - TWAIFD_RX_STATUS_RX_SETTINGS_REG + * - TWAIFD_TX_COMMAND_TXTB_INFO_REG + * - TWAIFD_TX_PRIORITY_REG + * - TWAIFD_TRV_DELAY_SSP_CFG_REG + * - TWAIFD_RX_FR_CTR_REG + * - TWAIFD_TX_FR_CTR_REG + */ +#define TWAI_RETENTION_REGS_CNT 25 +#define TWAI_RETENTION_REGS_BASE(i) REG_TWAIFD_BASE(i) +static const uint32_t twai_regs_map[4] = {0xb27fdf37, 0x3, 0x0, 0x0}; + +// twai timer registers is far away from twai registers, so we need a separate link +// - TWAIFD_TIMER_INT_ENA_REG +// - TWAIFD_TIMER_CFG_REG +#define TWAI_TIMER_RETENTION_REGS_CNT 2 +#define TWAI_TIMER_RETENTION_REGS_BASE(i) (REG_TWAIFD_BASE(i) + 0xfe0) +static const uint32_t twai_timer_regs_map[4] = {0x5, 0x0, 0x0, 0x0}; + +#define TWAI_SLEEP_RETENTION_ENTRIES(id) { \ + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_TWAI_LINK(0x00), \ + TWAI_RETENTION_REGS_BASE(id), TWAI_RETENTION_REGS_BASE(id), \ + TWAI_RETENTION_REGS_CNT, 0, 0, \ + twai_regs_map[0], twai_regs_map[1], \ + twai_regs_map[2], twai_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT( \ + REGDMA_TWAI_LINK(0x01), \ + TWAI_TIMER_RETENTION_REGS_BASE(id), TWAI_TIMER_RETENTION_REGS_BASE(id), \ + TWAI_TIMER_RETENTION_REGS_CNT, 0, 0, \ + twai_timer_regs_map[0], twai_timer_regs_map[1], \ + twai_timer_regs_map[2], twai_timer_regs_map[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t twai0_regs_retention[] = TWAI_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t twai1_regs_retention[] = TWAI_SLEEP_RETENTION_ENTRIES(1); + +const twai_reg_retention_info_t twai_reg_retention_info[2] = { + [0] = { + .module_id = SLEEP_RETENTION_MODULE_TWAI0, + .entry_array = twai0_regs_retention, + .array_size = ARRAY_SIZE(twai0_regs_retention) + }, + [1] = { + .module_id = SLEEP_RETENTION_MODULE_TWAI1, + .entry_array = twai1_regs_retention, + .array_size = ARRAY_SIZE(twai1_regs_retention) + }, +}; diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 348b966141..75e93135e6 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -39,6 +39,14 @@ config SOC_MCPWM_SUPPORTED bool default y +config SOC_TWAI_SUPPORTED + bool + default y + +config SOC_TWAI_FD_SUPPORTED + bool + default y + config SOC_ETM_SUPPORTED bool default y @@ -527,6 +535,22 @@ config SOC_MWDT_SUPPORT_XTAL bool default y +config SOC_TWAI_CONTROLLER_NUM + int + default 2 + +config SOC_TWAI_MASK_FILTER_NUM + int + default 3 + +config SOC_TWAI_RANGE_FILTER_NUM + int + default 1 + +config SOC_TWAI_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_AES_GDMA bool default y diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index b557e83b31..015ff77cbc 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -350,6 +350,22 @@ typedef enum { GLITCH_FILTER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the default clock choice */ } soc_periph_glitch_filter_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_F80M} + +/** + * @brief TWAI clock source + */ +typedef enum { + TWAI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + TWAI_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ + TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default clock choice */ +} soc_periph_twai_clk_src_t; + //////////////////////////////////////////////////MCPWM///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 8cfeb48e98..7cec669bd4 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -40,7 +40,8 @@ // #define SOC_LCDCAM_I80_LCD_SUPPORTED 1 // TODO: [ESP32S31] IDF-14722 // #define SOC_LCDCAM_RGB_LCD_SUPPORTED 1 // TODO: [ESP32S31] IDF-14722 #define SOC_MCPWM_SUPPORTED 1 -// #define SOC_TWAI_SUPPORTED 1 // TODO: [ESP32S31] IDF-14719 +#define SOC_TWAI_SUPPORTED 1 +#define SOC_TWAI_FD_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 // #define SOC_PARLIO_SUPPORTED 1 // TODO: [ESP32S31] IDF-14711 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 @@ -267,6 +268,12 @@ #define SOC_MWDT_SUPPORT_XTAL (1) // #define SOC_MWDT_SUPPORT_SLEEP_RETENTION (1) +/*-------------------------- TWAI CAPS ---------------------------------------*/ +#define SOC_TWAI_CONTROLLER_NUM 2U +#define SOC_TWAI_MASK_FILTER_NUM 3U +#define SOC_TWAI_RANGE_FILTER_NUM 1U +#define SOC_TWAI_SUPPORT_SLEEP_RETENTION 1 + /*-------------------------- AES CAPS ----------------------------------------*/ #define SOC_AES_GDMA (1) #define SOC_AES_SUPPORT_DMA (1) diff --git a/components/soc/esp32s31/register/soc/twaifd_reg.h b/components/soc/esp32s31/register/soc/twaifd_reg.h index 0930ed7431..bae02607a7 100644 --- a/components/soc/esp32s31/register/soc/twaifd_reg.h +++ b/components/soc/esp32s31/register/soc/twaifd_reg.h @@ -1,19 +1,23 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ #pragma once -#include "soc/soc.h" +#include "esp_bit_defs.h" +#include "soc/reg_base.h" + #ifdef __cplusplus extern "C" { #endif +#define REG_TWAIFD_BASE(i) (DR_REG_TWAIFD0_BASE + (i) * 0x1000) // TWAIFD0 and TWAIFD1 + /** TWAIFD_DEVICE_ID_VERSION_REG register * TWAI FD device id status register */ -#define TWAIFD_DEVICE_ID_VERSION_REG (DR_REG_TWAIFD_BASE + 0x0) +#define TWAIFD_DEVICE_ID_VERSION_REG(i) (REG_TWAIFD_BASE(i) + 0x0) /** TWAIFD_DEVICE_ID : RO; bitpos: [15:0]; default: 51965; * Represents whether CAN IP function is mapped correctly on its base address. */ @@ -39,7 +43,7 @@ extern "C" { /** TWAIFD_MODE_SETTINGS_REG register * TWAI FD mode setting register */ -#define TWAIFD_MODE_SETTINGS_REG (DR_REG_TWAIFD_BASE + 0x4) +#define TWAIFD_MODE_SETTINGS_REG(i) (REG_TWAIFD_BASE(i) + 0x4) /** TWAIFD_RST : WO; bitpos: [0]; default: 0; * Soft reset. Writing logic 1 resets CTU CAN FD. After writing logic 1, logic 0 does * not need to be written, this bit @@ -260,7 +264,7 @@ extern "C" { /** TWAIFD_STATUS_REG register * TWAI FD status register */ -#define TWAIFD_STATUS_REG (DR_REG_TWAIFD_BASE + 0x8) +#define TWAIFD_STATUS_REG(i) (REG_TWAIFD_BASE(i) + 0x8) /** TWAIFD_RXNE : RO; bitpos: [0]; default: 0; * RX buffer not empty. This bit is 1 when least one frame is stored in RX buffer. * 0: empty @@ -396,7 +400,7 @@ extern "C" { /** TWAIFD_COMMAND_REG register * TWAI FD command register */ -#define TWAIFD_COMMAND_REG (DR_REG_TWAIFD_BASE + 0xc) +#define TWAIFD_COMMAND_REG(i) (REG_TWAIFD_BASE(i) + 0xc) /** TWAIFD_RXRPMV : WO; bitpos: [1]; default: 0; * RX Buffer read pointer move. */ @@ -481,7 +485,7 @@ extern "C" { /** TWAIFD_INT_STAT_REG register * TWAI FD command register */ -#define TWAIFD_INT_STAT_REG (DR_REG_TWAIFD_BASE + 0x10) +#define TWAIFD_INT_STAT_REG(i) (REG_TWAIFD_BASE(i) + 0x10) /** TWAIFD_RXI_INT_ST : R/W1C; bitpos: [0]; default: 0; * The masked interrupt status of TWAIFD_RXI_INT. * Frame received interrupt. @@ -597,7 +601,7 @@ extern "C" { /** TWAIFD_INT_ENA_SET_REG register * TWAI FD interrupt enable register */ -#define TWAIFD_INT_ENA_SET_REG (DR_REG_TWAIFD_BASE + 0x14) +#define TWAIFD_INT_ENA_SET_REG(i) (REG_TWAIFD_BASE(i) + 0x14) /** TWAIFD_RXI_INT_ENA_MASK : R/W1S; bitpos: [0]; default: 0; * Write 1 to enable TWAIFD_RXI_INT. */ @@ -686,7 +690,7 @@ extern "C" { /** TWAIFD_INT_ENA_CLR_REG register * TWAI FD interrupt enable clear register */ -#define TWAIFD_INT_ENA_CLR_REG (DR_REG_TWAIFD_BASE + 0x18) +#define TWAIFD_INT_ENA_CLR_REG(i) (REG_TWAIFD_BASE(i) + 0x18) /** TWAIFD_RXI_INT_ENA_CLR : WO; bitpos: [0]; default: 0; * Write 1 to clear TWAIFD_RXI_INT_ENA . */ @@ -775,7 +779,7 @@ extern "C" { /** TWAIFD_INT_MASK_SET_REG register * TWAI FD interrupt mask register */ -#define TWAIFD_INT_MASK_SET_REG (DR_REG_TWAIFD_BASE + 0x1c) +#define TWAIFD_INT_MASK_SET_REG(i) (REG_TWAIFD_BASE(i) + 0x1c) /** TWAIFD_RXI_INT_MASK_SET : R/W1S; bitpos: [0]; default: 0; * Write 1 to mask TWAIFD_RXI_INT. */ @@ -864,7 +868,7 @@ extern "C" { /** TWAIFD_INT_MASK_CLR_REG register * TWAI FD interrupt mask clear register */ -#define TWAIFD_INT_MASK_CLR_REG (DR_REG_TWAIFD_BASE + 0x20) +#define TWAIFD_INT_MASK_CLR_REG(i) (REG_TWAIFD_BASE(i) + 0x20) /** TWAIFD_RXI_INT_MASK_CLR : WO; bitpos: [0]; default: 0; * Write 1 to clear TWAIFD_RXI_INT_MASK_CLR . */ @@ -953,7 +957,7 @@ extern "C" { /** TWAIFD_BTR_REG register * TWAI FD bit-timing register */ -#define TWAIFD_BTR_REG (DR_REG_TWAIFD_BASE + 0x24) +#define TWAIFD_BTR_REG(i) (REG_TWAIFD_BASE(i) + 0x24) /** TWAIFD_PROP : R/W; bitpos: [6:0]; default: 5; * Configures the propagation segment of nominal bit rate. * Measurement unit: time quanta @@ -998,7 +1002,7 @@ extern "C" { /** TWAIFD_BTR_FD_REG register * TWAI FD bit-timing of FD register */ -#define TWAIFD_BTR_FD_REG (DR_REG_TWAIFD_BASE + 0x28) +#define TWAIFD_BTR_FD_REG(i) (REG_TWAIFD_BASE(i) + 0x28) /** TWAIFD_PROP_FD : R/W; bitpos: [5:0]; default: 3; * Configures the propagation segment of data bit rate. * Measurement unit: time quanta @@ -1043,7 +1047,7 @@ extern "C" { /** TWAIFD_EWL_ERP_FAULT_STATE_REG register * TWAI FD error threshold and status register */ -#define TWAIFD_EWL_ERP_FAULT_STATE_REG (DR_REG_TWAIFD_BASE + 0x2c) +#define TWAIFD_EWL_ERP_FAULT_STATE_REG(i) (REG_TWAIFD_BASE(i) + 0x2c) /** TWAIFD_EW_LIMIT : R/W; bitpos: [7:0]; default: 96; * Error warning limit. If error warning limit is reached interrupt can be generated. * Error warning limit @@ -1087,7 +1091,7 @@ extern "C" { /** TWAIFD_REC_TEC_REG register * TWAI FD error counters status register */ -#define TWAIFD_REC_TEC_REG (DR_REG_TWAIFD_BASE + 0x30) +#define TWAIFD_REC_TEC_REG(i) (REG_TWAIFD_BASE(i) + 0x30) /** TWAIFD_REC_VAL : RO; bitpos: [8:0]; default: 0; * Represents the receiver error counter value. */ @@ -1106,7 +1110,7 @@ extern "C" { /** TWAIFD_ERR_NORM_ERR_FD_REG register * TWAI FD special error counters status register */ -#define TWAIFD_ERR_NORM_ERR_FD_REG (DR_REG_TWAIFD_BASE + 0x34) +#define TWAIFD_ERR_NORM_ERR_FD_REG(i) (REG_TWAIFD_BASE(i) + 0x34) /** TWAIFD_ERR_NORM_VAL : RO; bitpos: [15:0]; default: 0; * Represents the number of error in the nominal bit time. */ @@ -1125,7 +1129,7 @@ extern "C" { /** TWAIFD_CTR_PRES_REG register * TWAI FD error counters pre-define configuration register */ -#define TWAIFD_CTR_PRES_REG (DR_REG_TWAIFD_BASE + 0x38) +#define TWAIFD_CTR_PRES_REG(i) (REG_TWAIFD_BASE(i) + 0x38) /** TWAIFD_CTPV : WO; bitpos: [8:0]; default: 0; * Configures the pre-defined value to set the error counter. */ @@ -1175,7 +1179,7 @@ extern "C" { /** TWAIFD_FILTER_A_MASK_REG register * TWAI FD filter A mask value register */ -#define TWAIFD_FILTER_A_MASK_REG (DR_REG_TWAIFD_BASE + 0x3c) +#define TWAIFD_FILTER_A_MASK_REG(i) (REG_TWAIFD_BASE(i) + 0x3c) /** TWAIFD_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 * or RX @@ -1190,7 +1194,7 @@ extern "C" { /** TWAIFD_FILTER_A_VAL_REG register * TWAI FD filter A bit value register */ -#define TWAIFD_FILTER_A_VAL_REG (DR_REG_TWAIFD_BASE + 0x40) +#define TWAIFD_FILTER_A_VAL_REG(i) (REG_TWAIFD_BASE(i) + 0x40) /** TWAIFD_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 * or RX buffer. @@ -1205,7 +1209,7 @@ extern "C" { /** TWAIFD_FILTER_B_MASK_REG register * TWAI FD filter B mask value register */ -#define TWAIFD_FILTER_B_MASK_REG (DR_REG_TWAIFD_BASE + 0x44) +#define TWAIFD_FILTER_B_MASK_REG(i) (REG_TWAIFD_BASE(i) + 0x44) /** TWAIFD_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 @@ -1220,7 +1224,7 @@ extern "C" { /** TWAIFD_FILTER_B_VAL_REG register * TWAI FD filter B bit value register */ -#define TWAIFD_FILTER_B_VAL_REG (DR_REG_TWAIFD_BASE + 0x48) +#define TWAIFD_FILTER_B_VAL_REG(i) (REG_TWAIFD_BASE(i) + 0x48) /** TWAIFD_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. @@ -1235,7 +1239,7 @@ extern "C" { /** TWAIFD_FILTER_C_MASK_REG register * TWAI FD filter C mask value register */ -#define TWAIFD_FILTER_C_MASK_REG (DR_REG_TWAIFD_BASE + 0x4c) +#define TWAIFD_FILTER_C_MASK_REG(i) (REG_TWAIFD_BASE(i) + 0x4c) /** TWAIFD_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 @@ -1250,7 +1254,7 @@ extern "C" { /** TWAIFD_FILTER_C_VAL_REG register * TWAI FD filter C bit value register */ -#define TWAIFD_FILTER_C_VAL_REG (DR_REG_TWAIFD_BASE + 0x50) +#define TWAIFD_FILTER_C_VAL_REG(i) (REG_TWAIFD_BASE(i) + 0x50) /** TWAIFD_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. @@ -1265,7 +1269,7 @@ extern "C" { /** TWAIFD_FILTER_RAN_LOW_REG register * TWAI FD filter range low value register */ -#define TWAIFD_FILTER_RAN_LOW_REG (DR_REG_TWAIFD_BASE + 0x54) +#define TWAIFD_FILTER_RAN_LOW_REG(i) (REG_TWAIFD_BASE(i) + 0x54) /** TWAIFD_BIT_RAN_LOW_VAL : R/W; bitpos: [28:0]; default: 0; * Filter Range Low threshold. The identifier format is the same as in IDENTIFIER_W of * TXT @@ -1281,7 +1285,7 @@ extern "C" { /** TWAIFD_FILTER_RAN_HIGH_REG register * TWAI FD filter range high value register */ -#define TWAIFD_FILTER_RAN_HIGH_REG (DR_REG_TWAIFD_BASE + 0x58) +#define TWAIFD_FILTER_RAN_HIGH_REG(i) (REG_TWAIFD_BASE(i) + 0x58) /** TWAIFD_BIT_RAN_HIGH_VAL : R/W; bitpos: [28:0]; default: 0; * Range filter High threshold. The identifier format is the same as in IDENTIFIER_W * of TXT @@ -1297,7 +1301,7 @@ extern "C" { /** TWAIFD_FILTER_CONTROL_FILTER_STATUS_REG register * TWAI FD filter control register */ -#define TWAIFD_FILTER_CONTROL_FILTER_STATUS_REG (DR_REG_TWAIFD_BASE + 0x5c) +#define TWAIFD_FILTER_CONTROL_FILTER_STATUS_REG(i) (REG_TWAIFD_BASE(i) + 0x5c) /** TWAIFD_FANB : R/W; bitpos: [0]; default: 1; * CAN Basic Frame is accepted by filter A. */ @@ -1442,7 +1446,7 @@ extern "C" { /** TWAIFD_RX_MEM_INFO_REG register * TWAI FD rx memory information register */ -#define TWAIFD_RX_MEM_INFO_REG (DR_REG_TWAIFD_BASE + 0x60) +#define TWAIFD_RX_MEM_INFO_REG(i) (REG_TWAIFD_BASE(i) + 0x60) /** TWAIFD_RX_BUFF_SIZE : RO; bitpos: [12:0]; default: 128; * Size of RX buffer in 32-bit words. */ @@ -1461,7 +1465,7 @@ extern "C" { /** TWAIFD_RX_POINTERS_REG register * TWAI FD rx memory pointer information register */ -#define TWAIFD_RX_POINTERS_REG (DR_REG_TWAIFD_BASE + 0x64) +#define TWAIFD_RX_POINTERS_REG(i) (REG_TWAIFD_BASE(i) + 0x64) /** TWAIFD_RX_WPP : RO; bitpos: [11:0]; default: 0; * Write pointer position in RX buffer. Upon store of received frame write pointer is * updated. @@ -1482,7 +1486,7 @@ extern "C" { /** TWAIFD_RX_STATUS_RX_SETTINGS_REG register * TWAI FD rx status & setting register */ -#define TWAIFD_RX_STATUS_RX_SETTINGS_REG (DR_REG_TWAIFD_BASE + 0x68) +#define TWAIFD_RX_STATUS_RX_SETTINGS_REG(i) (REG_TWAIFD_BASE(i) + 0x68) /** TWAIFD_RXE : RO; bitpos: [0]; default: 1; * Represents whether or not the RX buffer is empty. RX buffer is empty. There is no * CAN Frame stored in it. @@ -1535,7 +1539,7 @@ extern "C" { /** TWAIFD_RX_DATA_REG register * TWAI FD received data register */ -#define TWAIFD_RX_DATA_REG (DR_REG_TWAIFD_BASE + 0x6c) +#define TWAIFD_RX_DATA_REG(i) (REG_TWAIFD_BASE(i) + 0x6c) /** TWAIFD_RX_DATA : RO; bitpos: [31:0]; default: 0; * RX buffer data at read pointer position in FIFO. By reading from this register, * read pointer is auto- @@ -1551,7 +1555,7 @@ extern "C" { /** TWAIFD_TX_STATUS_REG register * TWAI FD TX buffer status register */ -#define TWAIFD_TX_STATUS_REG (DR_REG_TWAIFD_BASE + 0x70) +#define TWAIFD_TX_STATUS_REG(i) (REG_TWAIFD_BASE(i) + 0x70) /** TWAIFD_TXTB0_STATE : RO; bitpos: [3:0]; default: 8; * Status of TXT buffer 1. * 0b0000 - TXT_NOT_EXIST - TXT buffer does not exist in the core (applies only to TXT @@ -1624,7 +1628,7 @@ extern "C" { /** TWAIFD_TX_COMMAND_TXTB_INFO_REG register * TWAI FD TXT buffer command & information register */ -#define TWAIFD_TX_COMMAND_TXTB_INFO_REG (DR_REG_TWAIFD_BASE + 0x74) +#define TWAIFD_TX_COMMAND_TXTB_INFO_REG(i) (REG_TWAIFD_BASE(i) + 0x74) /** TWAIFD_TXCE : WO; bitpos: [0]; default: 0; * Issues "set empty" command. */ @@ -1727,7 +1731,7 @@ extern "C" { /** TWAIFD_TX_PRIORITY_REG register * TWAI FD TXT buffer command & information register */ -#define TWAIFD_TX_PRIORITY_REG (DR_REG_TWAIFD_BASE + 0x78) +#define TWAIFD_TX_PRIORITY_REG(i) (REG_TWAIFD_BASE(i) + 0x78) /** TWAIFD_TXT1P : R/W; bitpos: [2:0]; default: 1; * Priority of TXT buffer 1. */ @@ -1795,7 +1799,7 @@ extern "C" { * TWAI FD error capture & retransmit counter & arbitration lost & timestamp * integration information register */ -#define TWAIFD_ERR_CAPT_RETR_CTR_ALC_TS_INFO_REG (DR_REG_TWAIFD_BASE + 0x7c) +#define TWAIFD_ERR_CAPT_RETR_CTR_ALC_TS_INFO_REG(i) (REG_TWAIFD_BASE(i) + 0x7c) /** TWAIFD_ERR_POS : RO; bitpos: [4:0]; default: 31; * 0b00000 - ERC_POS_SOF - Error in Start of Frame * 0b00001 - ERC_POS_ARB - Error in Arbitration Filed @@ -1870,7 +1874,7 @@ extern "C" { /** TWAIFD_TRV_DELAY_SSP_CFG_REG register * TWAI FD transmit delay & secondary sample point configuration register */ -#define TWAIFD_TRV_DELAY_SSP_CFG_REG (DR_REG_TWAIFD_BASE + 0x80) +#define TWAIFD_TRV_DELAY_SSP_CFG_REG(i) (REG_TWAIFD_BASE(i) + 0x80) /** TWAIFD_TRV_DELAY_VALUE : RO; bitpos: [6:0]; default: 0; * Measured Transmitter delay in multiple of minimal Time quanta. */ @@ -1902,7 +1906,7 @@ extern "C" { /** TWAIFD_RX_FR_CTR_REG register * TWAI FD received frame counter register */ -#define TWAIFD_RX_FR_CTR_REG (DR_REG_TWAIFD_BASE + 0x84) +#define TWAIFD_RX_FR_CTR_REG(i) (REG_TWAIFD_BASE(i) + 0x84) /** TWAIFD_RX_FR_CTR_VAL : RO; bitpos: [31:0]; default: 0; * Number of received frames by CTU CAN FD. */ @@ -1914,7 +1918,7 @@ extern "C" { /** TWAIFD_TX_FR_CTR_REG register * TWAI FD transmitted frame counter register */ -#define TWAIFD_TX_FR_CTR_REG (DR_REG_TWAIFD_BASE + 0x88) +#define TWAIFD_TX_FR_CTR_REG(i) (REG_TWAIFD_BASE(i) + 0x88) /** TWAIFD_TX_CTR_VAL : RO; bitpos: [31:0]; default: 0; * Number of transmitted frames by CTU CAN FD. */ @@ -1926,7 +1930,7 @@ extern "C" { /** TWAIFD_DEBUG_REG register * TWAI FD debug register */ -#define TWAIFD_DEBUG_REG (DR_REG_TWAIFD_BASE + 0x8c) +#define TWAIFD_DEBUG_REG(i) (REG_TWAIFD_BASE(i) + 0x8c) /** TWAIFD_STUFF_COUNT : RO; bitpos: [2:0]; default: 0; * Actual stuff count modulo 8 as defined in ISO FD protocol. Stuff count is erased * in the beginning @@ -2053,7 +2057,7 @@ extern "C" { /** TWAIFD_YOLO_REG register * TWAI FD transmitted frame counter register */ -#define TWAIFD_YOLO_REG (DR_REG_TWAIFD_BASE + 0x90) +#define TWAIFD_YOLO_REG(i) (REG_TWAIFD_BASE(i) + 0x90) /** TWAIFD_YOLO_VAL : RO; bitpos: [31:0]; default: 3735928559; * What else could be in this register?? */ @@ -2065,7 +2069,7 @@ extern "C" { /** TWAIFD_TIMESTAMP_LOW_REG register * TWAI FD transmitted frame counter register */ -#define TWAIFD_TIMESTAMP_LOW_REG (DR_REG_TWAIFD_BASE + 0x94) +#define TWAIFD_TIMESTAMP_LOW_REG(i) (REG_TWAIFD_BASE(i) + 0x94) /** TWAIFD_TIMESTAMP_LOW : RO; bitpos: [31:0]; default: 0; * Bits 31:0 of time base. */ @@ -2077,7 +2081,7 @@ extern "C" { /** TWAIFD_TIMESTAMP_HIGH_REG register * TWAI FD transmitted frame counter register */ -#define TWAIFD_TIMESTAMP_HIGH_REG (DR_REG_TWAIFD_BASE + 0x98) +#define TWAIFD_TIMESTAMP_HIGH_REG(i) (REG_TWAIFD_BASE(i) + 0x98) /** TWAIFD_TIMESTAMP_HIGH : RO; bitpos: [31:0]; default: 0; * Bits 63:32 of time base. */ @@ -2089,7 +2093,7 @@ extern "C" { /** TWAIFD_TIMER_CLK_EN_REG register * TWAIFD timer clock force enable register. */ -#define TWAIFD_TIMER_CLK_EN_REG (DR_REG_TWAIFD_BASE + 0xfd4) +#define TWAIFD_TIMER_CLK_EN_REG(i) (REG_TWAIFD_BASE(i) + 0xfd4) /** TWAIFD_CLK_EN : R/W; bitpos: [0]; default: 0; * Set this bit to force enable TWAIFD register configuration clock signal. */ @@ -2108,7 +2112,7 @@ extern "C" { /** TWAIFD_TIMER_INT_RAW_REG register * TWAIFD raw interrupt register. */ -#define TWAIFD_TIMER_INT_RAW_REG (DR_REG_TWAIFD_BASE + 0xfd8) +#define TWAIFD_TIMER_INT_RAW_REG(i) (REG_TWAIFD_BASE(i) + 0xfd8) /** TWAIFD_TIMER_OVERFLOW_INT_RAW : R/SS/WTC; bitpos: [0]; default: 0; * The raw bit signal for read_done interrupt. */ @@ -2120,7 +2124,7 @@ extern "C" { /** TWAIFD_TIMER_INT_ST_REG register * TWAIFD interrupt status register. */ -#define TWAIFD_TIMER_INT_ST_REG (DR_REG_TWAIFD_BASE + 0xfdc) +#define TWAIFD_TIMER_INT_ST_REG(i) (REG_TWAIFD_BASE(i) + 0xfdc) /** TWAIFD_TIMER_OVERFLOW_INT_ST : RO; bitpos: [0]; default: 0; * The status signal for read_done interrupt. */ @@ -2132,7 +2136,7 @@ extern "C" { /** TWAIFD_TIMER_INT_ENA_REG register * TWAIFD interrupt enable register. */ -#define TWAIFD_TIMER_INT_ENA_REG (DR_REG_TWAIFD_BASE + 0xfe0) +#define TWAIFD_TIMER_INT_ENA_REG(i) (REG_TWAIFD_BASE(i) + 0xfe0) /** TWAIFD_TIMER_OVERFLOW_INT_ENA : R/W; bitpos: [0]; default: 0; * The enable signal for read_done interrupt. */ @@ -2144,7 +2148,7 @@ extern "C" { /** TWAIFD_TIMER_INT_CLR_REG register * TWAIFD interrupt clear register. */ -#define TWAIFD_TIMER_INT_CLR_REG (DR_REG_TWAIFD_BASE + 0xfe4) +#define TWAIFD_TIMER_INT_CLR_REG(i) (REG_TWAIFD_BASE(i) + 0xfe4) /** TWAIFD_TIMER_OVERFLOW_INT_CLR : WT; bitpos: [0]; default: 0; * The clear signal for read_done interrupt. */ @@ -2156,7 +2160,7 @@ extern "C" { /** TWAIFD_TIMER_CFG_REG register * TWAI FD timer configure register. */ -#define TWAIFD_TIMER_CFG_REG (DR_REG_TWAIFD_BASE + 0xfe8) +#define TWAIFD_TIMER_CFG_REG(i) (REG_TWAIFD_BASE(i) + 0xfe8) /** TWAIFD_TIMER_CE : R/W; bitpos: [0]; default: 0; * TWAI FD timer enable register. * 1b0: Not enable @@ -2204,7 +2208,7 @@ extern "C" { /** TWAIFD_TIMER_LD_VAL_L_REG register * TWAI FD timer pre-load value low register. */ -#define TWAIFD_TIMER_LD_VAL_L_REG (DR_REG_TWAIFD_BASE + 0xfec) +#define TWAIFD_TIMER_LD_VAL_L_REG(i) (REG_TWAIFD_BASE(i) + 0xfec) /** TWAIFD_TIMER_LD_VAL_L : R/W; bitpos: [31:0]; default: 0; * TWAI FD timer count pre-load value register, low part. */ @@ -2216,7 +2220,7 @@ extern "C" { /** TWAIFD_TIMER_LD_VAL_H_REG register * TWAI FD timer pre-load value high register. */ -#define TWAIFD_TIMER_LD_VAL_H_REG (DR_REG_TWAIFD_BASE + 0xff0) +#define TWAIFD_TIMER_LD_VAL_H_REG(i) (REG_TWAIFD_BASE(i) + 0xff0) /** TWAIFD_TIMER_LD_VAL_H : R/W; bitpos: [31:0]; default: 0; * TWAI FD timer pre-load value register, high part. * If timestamp valid bit-width less than 33, this field is ignored. @@ -2229,7 +2233,7 @@ extern "C" { /** TWAIFD_TIMER_CT_VAL_L_REG register * TWAI FD timer count-to value low register. */ -#define TWAIFD_TIMER_CT_VAL_L_REG (DR_REG_TWAIFD_BASE + 0xff4) +#define TWAIFD_TIMER_CT_VAL_L_REG(i) (REG_TWAIFD_BASE(i) + 0xff4) /** TWAIFD_TIMER_CT_VAL_L : R/W; bitpos: [31:0]; default: 4294967295; * TWAI FD timer count-to value register, low part. */ @@ -2241,7 +2245,7 @@ extern "C" { /** TWAIFD_TIMER_CT_VAL_H_REG register * TWAI FD timer count-to value high register. */ -#define TWAIFD_TIMER_CT_VAL_H_REG (DR_REG_TWAIFD_BASE + 0xff8) +#define TWAIFD_TIMER_CT_VAL_H_REG(i) (REG_TWAIFD_BASE(i) + 0xff8) /** TWAIFD_TIMER_CT_VAL_H : R/W; bitpos: [31:0]; default: 4294967295; * TWAI FD timer count-to value register, high part. * If timestamp valid bit-width less than 33, this field is ignored. @@ -2254,7 +2258,7 @@ extern "C" { /** TWAIFD_DATE_VER_REG register * TWAI FD date version */ -#define TWAIFD_DATE_VER_REG (DR_REG_TWAIFD_BASE + 0xffc) +#define TWAIFD_DATE_VER_REG(i) (REG_TWAIFD_BASE(i) + 0xffc) /** TWAIFD_DATE_VER : R/W; bitpos: [31:0]; default: 37823088; * TWAI FD version */ diff --git a/components/soc/esp32s31/register/soc/twaifd_struct.h b/components/soc/esp32s31/register/soc/twaifd_struct.h index 420c6b66e1..5d19d167f4 100644 --- a/components/soc/esp32s31/register/soc/twaifd_struct.h +++ b/components/soc/esp32s31/register/soc/twaifd_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -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,66 @@ 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. Note there are no remote frames in CAN FD protocol + 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 +1813,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 +1831,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]; // only 4 are actively used + 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,6 +1847,9 @@ typedef struct { volatile twaifd_date_ver_reg_t date_ver; } twaifd_dev_t; +extern twaifd_dev_t TWAIFD0; +extern twaifd_dev_t TWAIFD1; + #ifndef __cplusplus _Static_assert(sizeof(twaifd_dev_t) == 0x1000, "Invalid size of twaifd_dev_t structure"); diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index a712d5d59e..db9a8147cc 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -736,6 +736,10 @@ examples/peripherals/twai/twai_error_recovery: examples/peripherals/twai/twai_network/twai_listen_only: disable: - if: SOC_TWAI_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET in ["esp32s31"] + temporary: true + reason: no runner depends_components: - esp_driver_twai - esp_hal_twai @@ -744,6 +748,10 @@ examples/peripherals/twai/twai_network/twai_listen_only: examples/peripherals/twai/twai_network/twai_sender: disable: - if: SOC_TWAI_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET in ["esp32s31"] + temporary: true + reason: no runner depends_components: - esp_driver_twai - esp_hal_twai diff --git a/examples/peripherals/twai/cybergear/README.md b/examples/peripherals/twai/cybergear/README.md index 73216922b8..a81072b268 100644 --- a/examples/peripherals/twai/cybergear/README.md +++ b/examples/peripherals/twai/cybergear/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | 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 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # CyberGear Motor Control Example diff --git a/examples/peripherals/twai/twai_error_recovery/README.md b/examples/peripherals/twai/twai_error_recovery/README.md index a311512382..d9f6abecf4 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-H4 | 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 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # 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 13cb153169..4354ce25ee 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-H4 | 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 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # TWAI Network Example diff --git a/examples/peripherals/twai/twai_utils/README.md b/examples/peripherals/twai/twai_utils/README.md index 059b9a5273..45277b242a 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-H4 | 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 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # 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 8b5288062a..be3bc70a8b 100644 --- a/examples/peripherals/twai/twai_utils/pytest_twai_utils.py +++ b/examples/peripherals/twai/twai_utils/pytest_twai_utils.py @@ -595,6 +595,7 @@ def test_twai_utils_range_filters(twai: TwaiTestHelper) -> None: @pytest.mark.twai_std @pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='no runner') +@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='no runner') @idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target']) def test_twai_utils_external_communication(twai: TwaiTestHelper, usb_can: CanBusManager) -> None: test_frames = [ diff --git a/examples/peripherals/twai/twai_utils/sdkconfig.defaults.esp32s31 b/examples/peripherals/twai/twai_utils/sdkconfig.defaults.esp32s31 new file mode 100644 index 0000000000..daff3b9a4d --- /dev/null +++ b/examples/peripherals/twai/twai_utils/sdkconfig.defaults.esp32s31 @@ -0,0 +1 @@ +CONFIG_EXAMPLE_ENABLE_TWAI_FD=y