From d9d6f5a17a6ae19b4d3012d265de8442ec3e3234 Mon Sep 17 00:00:00 2001 From: wanlei Date: Thu, 19 Oct 2023 14:43:17 +0800 Subject: [PATCH] feat(twai): support legacy twai(can) driver for esp32p4 --- components/driver/test_apps/twai/README.md | 4 +- .../test_apps/twai/main/test_app_main.c | 35 +- .../twai/main/test_twai_interactive.c | 32 +- .../driver/test_apps/twai/pytest_twai.py | 6 +- components/driver/twai/twai.c | 14 + components/hal/esp32/include/hal/twai_ll.h | 12 +- components/hal/esp32c3/include/hal/twai_ll.h | 12 +- components/hal/esp32c6/include/hal/twai_ll.h | 12 +- components/hal/esp32h2/include/hal/twai_ll.h | 10 +- .../hal/esp32p4/include/hal/clk_gate_ll.h | 18 - components/hal/esp32p4/include/hal/twai_ll.h | 816 ++++++++++++++++++ components/hal/esp32s2/include/hal/twai_ll.h | 12 +- components/hal/esp32s3/include/hal/twai_ll.h | 12 +- components/hal/twai_hal.c | 14 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 6 +- .../soc/esp32p4/include/soc/clk_tree_defs.h | 15 + .../soc/esp32p4/include/soc/gpio_sig_map.h | 24 +- .../esp32p4/include/soc/hp_sys_clkrst_reg.h | 60 +- .../include/soc/hp_sys_clkrst_struct.h | 24 +- .../soc/esp32p4/include/soc/interrupts.h | 6 +- components/soc/esp32p4/include/soc/soc_caps.h | 4 +- .../soc/esp32p4/include/soc/twai_struct.h | 249 +----- components/soc/esp32p4/interrupts.c | 6 +- components/soc/esp32p4/twai_periph.c | 30 +- docs/docs_not_updated/esp32p4.txt | 1 - docs/en/api-reference/peripherals/twai.rst | 2 +- .../twai/twai_alert_and_recovery/README.md | 4 +- .../twai_alert_and_recovery_example_main.c | 16 +- .../peripherals/twai/twai_network/README.md | 4 +- .../peripherals/twai/twai_self_test/README.md | 4 +- 30 files changed, 1061 insertions(+), 403 deletions(-) create mode 100644 components/hal/esp32p4/include/hal/twai_ll.h diff --git a/components/driver/test_apps/twai/README.md b/components/driver/test_apps/twai/README.md index 2eccd3e551..bf6a3f380d 100644 --- a/components/driver/test_apps/twai/README.md +++ b/components/driver/test_apps/twai/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # Enable Socket CAN Device with bitrate 250Kbps diff --git a/components/driver/test_apps/twai/main/test_app_main.c b/components/driver/test_apps/twai/main/test_app_main.c index 8d0972047f..5743bdfde5 100644 --- a/components/driver/test_apps/twai/main/test_app_main.c +++ b/components/driver/test_apps/twai/main/test_app_main.c @@ -1,38 +1,25 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "unity.h" -#include "unity_test_runner.h" +#include "unity_test_utils.h" #include "esp_heap_caps.h" // Some resources are lazy allocated in the TWAI driver, the threshold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-200) - -static size_t before_free_8bit; -static size_t before_free_32bit; - -static void check_leak(size_t before_free, size_t after_free, const char *type) -{ - ssize_t delta = after_free - before_free; - printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); - TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); -} +#define TEST_MEMORY_LEAK_THRESHOLD (200) void setUp(void) { - before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + unity_utils_record_free_mem(); } void tearDown(void) { - size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); - size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); - check_leak(before_free_8bit, after_free_8bit, "8BIT"); - check_leak(before_free_32bit, after_free_32bit, "32BIT"); + esp_reent_cleanup(); //clean up some of the newlib's lazy allocations + unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD); } void app_main(void) @@ -42,10 +29,10 @@ void app_main(void) // | | \ \ /\ / / _ \ | | | |/ _ \/ __| __| // | | \ V V / ___ \ | | | | __/\__ \ |_ // |_| \_/\_/_/ \_\___| |_|\___||___/\__| - printf(" _______ ___ ___ _____ _\r\n"); - printf("|_ _\\ \\ / / \\ |_ _| |_ _|__ ___| |_\r\n"); - printf(" | | \\ \\ /\\ / / _ \\ | | | |/ _ \\/ __| __|\r\n"); - printf(" | | \\ V V / ___ \\ | | | | __/\\__ \\ |_\r\n"); - printf(" |_| \\_/\\_/_/ \\_\\___| |_|\\___||___/\\__|\r\n"); + printf(" _______ ___ ___ _____ _\n"); + printf("|_ _\\ \\ / / \\ |_ _| |_ _|__ ___| |_\n"); + printf(" | | \\ \\ /\\ / / _ \\ | | | |/ _ \\/ __| __|\n"); + printf(" | | \\ V V / ___ \\ | | | | __/\\__ \\ |_\n"); + printf(" |_| \\_/\\_/_/ \\_\\___| |_|\\___||___/\\__|\n"); unity_run_menu(); } diff --git a/components/driver/test_apps/twai/main/test_twai_interactive.c b/components/driver/test_apps/twai/main/test_twai_interactive.c index d72a0e0847..88b74af55b 100644 --- a/components/driver/test_apps/twai/main/test_twai_interactive.c +++ b/components/driver/test_apps/twai/main/test_twai_interactive.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ #include "unity_test_utils.h" #include "driver/twai.h" #include "soc/soc_caps.h" -#include "esp_attr.h" +#include "esp_log.h" #if CONFIG_TWAI_ISR_IN_IRAM static void IRAM_ATTR test_delay_post_cache_disable(void *args) @@ -37,7 +37,7 @@ TEST_CASE("twai_listen_only", "[twai]") TEST_ESP_OK(twai_start()); #if CONFIG_TWAI_ISR_IN_IRAM - printf("disable flash cache and check if we can still receive the frame\r\n"); + printf("disable flash cache and check if we can still receive the frame\n"); for (int i = 0; i < 100; i++) { unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL); } @@ -48,9 +48,8 @@ TEST_CASE("twai_listen_only", "[twai]") TEST_ESP_OK(twai_receive(&rx_msg, portMAX_DELAY)); TEST_ASSERT_EQUAL(0x123, rx_msg.identifier); - for (int i = 0; i < rx_msg.data_length_code; i++) { - TEST_ASSERT_EQUAL_HEX8(expected_data[i], rx_msg.data[i]); - } + ESP_LOG_BUFFER_HEX("rx", rx_msg.data, rx_msg.data_length_code); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_data, rx_msg.data, rx_msg.data_length_code); TEST_ESP_OK(twai_stop()); TEST_ESP_OK(twai_driver_uninstall()); @@ -58,11 +57,13 @@ TEST_CASE("twai_listen_only", "[twai]") TEST_CASE("twai_remote_request", "[twai]") { + twai_handle_t bus_handle; twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(0, 2, TWAI_MODE_NORMAL); - TEST_ESP_OK(twai_driver_install(&g_config, &t_config, &f_config)); - TEST_ESP_OK(twai_start()); + g_config.controller_id = 2; + TEST_ESP_OK(twai_driver_install_v2(&g_config, &t_config, &f_config, &bus_handle)); + TEST_ESP_OK(twai_start_v2(bus_handle)); twai_message_t req_msg = { .identifier = 0x6688, @@ -70,16 +71,17 @@ TEST_CASE("twai_remote_request", "[twai]") .rtr = true, // remote request .extd = true,// extended ID }; - TEST_ESP_OK(twai_transmit(&req_msg, portMAX_DELAY)); + TEST_ESP_OK(twai_transmit_v2(bus_handle, &req_msg, portMAX_DELAY)); + ESP_LOGI("TWAI", "send remote frame"); uint8_t expected_data[8] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80}; twai_message_t res_msg; - TEST_ESP_OK(twai_receive(&res_msg, portMAX_DELAY)); + TEST_ESP_OK(twai_receive_v2(bus_handle, &res_msg, portMAX_DELAY)); + ESP_LOGI("TWAI", "receive with id %lx\n", res_msg.identifier); TEST_ASSERT_EQUAL(0x6688, res_msg.identifier); - for (int i = 0; i < 8; i++) { - TEST_ASSERT_EQUAL_HEX8(expected_data[i], res_msg.data[i]); - } + ESP_LOG_BUFFER_HEX("rx", res_msg.data, res_msg.data_length_code); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_data, res_msg.data, res_msg.data_length_code); - TEST_ESP_OK(twai_stop()); - TEST_ESP_OK(twai_driver_uninstall()); + TEST_ESP_OK(twai_stop_v2(bus_handle)); + TEST_ESP_OK(twai_driver_uninstall_v2(bus_handle)); } diff --git a/components/driver/test_apps/twai/pytest_twai.py b/components/driver/test_apps/twai/pytest_twai.py index 454511f2a6..d3d8ddeca3 100644 --- a/components/driver/test_apps/twai/pytest_twai.py +++ b/components/driver/test_apps/twai/pytest_twai.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import logging @@ -15,6 +15,7 @@ from pytest_embedded import Dut @pytest.mark.esp32h2 @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.generic @pytest.mark.parametrize( 'config', @@ -41,6 +42,7 @@ def fixture_create_socket_can() -> Bus: @pytest.mark.esp32h2 @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.skip(reason='Runner not set up yet') @pytest.mark.parametrize( 'config', @@ -73,6 +75,7 @@ def test_twai_listen_only(dut: Dut, socket_can: Bus) -> None: @pytest.mark.esp32h2 @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.skip(reason='Runner not set up yet') @pytest.mark.parametrize( 'config', @@ -101,5 +104,6 @@ def test_twai_remote_request(dut: Dut, socket_can: Bus) -> None: data=[0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80], ) socket_can.send(reply, timeout=0.2) + print('send', reply) dut.expect_unity_test_output() diff --git a/components/driver/twai/twai.c b/components/driver/twai/twai.c index 976a4dc336..eb0ebfcd3a 100644 --- a/components/driver/twai/twai.c +++ b/components/driver/twai/twai.c @@ -58,6 +58,12 @@ #define TWAI_RCC_ATOMIC() #endif +#if SOC_PERIPH_CLK_CTRL_SHARED +#define TWAI_PERI_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define TWAI_PERI_ATOMIC() +#endif + /* ------------------ Typedefs, structures, and variables ------------------- */ //Control structure for TWAI driver @@ -453,6 +459,11 @@ esp_err_t twai_driver_install_v2(const twai_general_config_t *g_config, const tw twai_ll_enable_bus_clock(controller_id, true); twai_ll_reset_register(controller_id); } + TWAI_PERI_ATOMIC() { + //Enable functional clock + twai_ll_set_clock_source(p_twai_obj->controller_id, clk_src); + twai_ll_enable_clock(p_twai_obj->controller_id, true); + } //Initialize TWAI HAL layer twai_hal_config_t hal_config = { @@ -514,6 +525,9 @@ esp_err_t twai_driver_uninstall_v2(twai_handle_t handle) //Clear registers by reading twai_hal_deinit(&p_twai_obj->hal); + TWAI_PERI_ATOMIC() { + twai_ll_enable_clock(controller_id, false); + } TWAI_RCC_ATOMIC() { twai_ll_enable_bus_clock(controller_id, false); } diff --git a/components/hal/esp32/include/hal/twai_ll.h b/components/hal/esp32/include/hal/twai_ll.h index 8c35c5e5ba..6fc14529f6 100644 --- a/components/hal/esp32/include/hal/twai_ll.h +++ b/components/hal/esp32/include/hal/twai_ll.h @@ -194,25 +194,25 @@ static inline void twai_ll_reset_register(int group_id) /** * @brief Enable TWAI module clock * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param en true to enable, false to disable */ __attribute__((always_inline)) -static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en) +static inline void twai_ll_enable_clock(int group_id, bool en) { - (void)hw; + (void)group_id; } /** * @brief Set clock source for TWAI module * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param clk_src Clock source */ __attribute__((always_inline)) -static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t clk_src) +static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) { - (void)hw; + (void)group_id; HAL_ASSERT(clk_src == TWAI_CLK_SRC_APB); } diff --git a/components/hal/esp32c3/include/hal/twai_ll.h b/components/hal/esp32c3/include/hal/twai_ll.h index 3283425dfe..d2d713f206 100644 --- a/components/hal/esp32c3/include/hal/twai_ll.h +++ b/components/hal/esp32c3/include/hal/twai_ll.h @@ -124,25 +124,25 @@ static inline void twai_ll_reset_register(int group_id) /** * @brief Enable TWAI module clock * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param en true to enable, false to disable */ __attribute__((always_inline)) -static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en) +static inline void twai_ll_enable_clock(int group_id, bool en) { - (void)hw; + (void)group_id; } /** * @brief Set clock source for TWAI module * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param clk_src Clock source */ __attribute__((always_inline)) -static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t clk_src) +static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) { - (void)hw; + (void)group_id; HAL_ASSERT(clk_src == TWAI_CLK_SRC_APB); } diff --git a/components/hal/esp32c6/include/hal/twai_ll.h b/components/hal/esp32c6/include/hal/twai_ll.h index b70f92d62e..f6a893ea1d 100644 --- a/components/hal/esp32c6/include/hal/twai_ll.h +++ b/components/hal/esp32c6/include/hal/twai_ll.h @@ -123,13 +123,13 @@ static inline void twai_ll_reset_register(int group_id) /** * @brief Enable TWAI module clock * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param en true to enable, false to disable */ __attribute__((always_inline)) -static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en) +static inline void twai_ll_enable_clock(int group_id, bool en) { - if (hw == &TWAI0) { + if (group_id == 0) { PCR.twai0_func_clk_conf.twai0_func_clk_en = en; } else { PCR.twai1_func_clk_conf.twai1_func_clk_en = en; @@ -139,11 +139,11 @@ static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en) /** * @brief Set clock source for TWAI module * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param clk_src Clock source */ __attribute__((always_inline)) -static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t clk_src) +static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) { uint32_t clk_id = 0; bool valid = true; @@ -158,7 +158,7 @@ static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t } if (valid) { - if (hw == &TWAI0) { + if (group_id == 0) { PCR.twai0_func_clk_conf.twai0_func_clk_sel = clk_id; } else { PCR.twai1_func_clk_conf.twai1_func_clk_sel = clk_id; diff --git a/components/hal/esp32h2/include/hal/twai_ll.h b/components/hal/esp32h2/include/hal/twai_ll.h index e66bc0a27a..653404fdb4 100644 --- a/components/hal/esp32h2/include/hal/twai_ll.h +++ b/components/hal/esp32h2/include/hal/twai_ll.h @@ -116,24 +116,26 @@ static inline void twai_ll_reset_register(int group_id) /** * @brief Enable TWAI module clock * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param en true to enable, false to disable */ __attribute__((always_inline)) -static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en) +static inline void twai_ll_enable_clock(int group_id, bool en) { + (void)group_id; PCR.twai0_func_clk_conf.twai0_func_clk_en = en; } /** * @brief Set clock source for TWAI module * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param clk_src Clock source */ __attribute__((always_inline)) -static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t clk_src) +static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) { + (void)group_id; switch (clk_src) { case TWAI_CLK_SRC_DEFAULT: PCR.twai0_func_clk_conf.twai0_func_clk_sel = 0; diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 324e16bbe7..b431dd9186 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -38,12 +38,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return HP_SYS_CLKRST_REG_I2C1_APB_CLK_EN; case PERIPH_LCD_MODULE: return HP_SYS_CLKRST_REG_LCD_CLK_EN; - case PERIPH_TWAI0_MODULE: - return HP_SYS_CLKRST_REG_TWAI0_CLK_EN; - case PERIPH_TWAI1_MODULE: - return HP_SYS_CLKRST_REG_TWAI1_CLK_EN; - case PERIPH_TWAI2_MODULE: - return HP_SYS_CLKRST_REG_TWAI2_CLK_EN; case PERIPH_I3C_MODULE: return HP_SYS_CLKRST_REG_I3C_MST_CLK_EN; case PERIPH_CAM_MODULE: @@ -109,12 +103,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return HP_SYS_CLKRST_REG_RST_EN_I2C0; case PERIPH_I2C1_MODULE: return HP_SYS_CLKRST_REG_RST_EN_I2C1; - case PERIPH_TWAI0_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_CAN0; - case PERIPH_TWAI1_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_CAN1; - case PERIPH_TWAI2_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_CAN2; case PERIPH_LCD_MODULE: return HP_SYS_CLKRST_REG_RST_EN_LCDCAM; case PERIPH_SARADC_MODULE: @@ -174,9 +162,6 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) return HP_SYS_CLKRST_SOC_CLK_CTRL2_REG; case PERIPH_LCD_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL110_REG; - case PERIPH_TWAI0_MODULE: - case PERIPH_TWAI1_MODULE: - case PERIPH_TWAI2_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL116_REG; case PERIPH_I3C_MODULE: case PERIPH_CAM_MODULE: @@ -221,9 +206,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) case PERIPH_I2C0_MODULE: case PERIPH_I2C1_MODULE: return HP_SYS_CLKRST_HP_RST_EN1_REG; - case PERIPH_TWAI0_MODULE: - case PERIPH_TWAI1_MODULE: - case PERIPH_TWAI2_MODULE: case PERIPH_CAM_MODULE: case PERIPH_SARADC_MODULE: case PERIPH_AES_MODULE: diff --git a/components/hal/esp32p4/include/hal/twai_ll.h b/components/hal/esp32p4/include/hal/twai_ll.h new file mode 100644 index 0000000000..7dc878ec0c --- /dev/null +++ b/components/hal/esp32p4/include/hal/twai_ll.h @@ -0,0 +1,816 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for TWAI + +#pragma once + +#include +#include +#include +#include "esp_assert.h" +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/twai_types.h" +#include "soc/twai_struct.h" +#include "soc/hp_sys_clkrst_struct.h" + +#define TWAI_LL_GET_HW(controller_id) ((controller_id == 0) ? (&TWAI0) : \ + (controller_id == 1) ? (&TWAI1) : \ + (&TWAI2)) + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------- Defines and Typedefs --------------------------- */ + +#define TWAI_LL_STATUS_RBS (0x1 << 0) //Receive Buffer Status +#define TWAI_LL_STATUS_DOS (0x1 << 1) //Data Overrun Status +#define TWAI_LL_STATUS_TBS (0x1 << 2) //Transmit Buffer Status +#define TWAI_LL_STATUS_TCS (0x1 << 3) //Transmission Complete Status +#define TWAI_LL_STATUS_RS (0x1 << 4) //Receive Status +#define TWAI_LL_STATUS_TS (0x1 << 5) //Transmit Status +#define TWAI_LL_STATUS_ES (0x1 << 6) //Error Status +#define TWAI_LL_STATUS_BS (0x1 << 7) //Bus Status +#define TWAI_LL_STATUS_MS (0x1 << 8) //Miss Status + +#define TWAI_LL_INTR_RI (0x1 << 0) //Receive Interrupt +#define TWAI_LL_INTR_TI (0x1 << 1) //Transmit Interrupt +#define TWAI_LL_INTR_EI (0x1 << 2) //Error Interrupt +//Data overrun interrupt not supported in SW due to HW peculiarities +#define TWAI_LL_INTR_EPI (0x1 << 5) //Error Passive Interrupt +#define TWAI_LL_INTR_ALI (0x1 << 6) //Arbitration Lost Interrupt +#define TWAI_LL_INTR_BEI (0x1 << 7) //Bus Error Interrupt +#define TWAI_LL_INTR_BISI (0x1 << 8) //Bus Idle Status Interrupt + +/* + * The following frame structure has an NEARLY identical bit field layout to + * each byte of the TX buffer. This allows for formatting and parsing frames to + * be done outside of time critical regions (i.e., ISRs). All the ISR needs to + * do is to copy byte by byte to/from the TX/RX buffer. The two reserved bits in + * TX buffer are used in the frame structure to store the self_reception and + * single_shot flags which in turn indicate the type of transmission to execute. + */ +typedef union { + struct { + struct { + uint8_t dlc: 4; //Data length code (0 to 8) of the frame + uint8_t self_reception: 1; //This frame should be transmitted using self reception command + uint8_t single_shot: 1; //This frame should be transmitted using single shot command + uint8_t rtr: 1; //This frame is a remote transmission request + uint8_t frame_format: 1; //Format of the frame (1 = extended, 0 = standard) + }; + union { + struct { + uint8_t id[2]; //11 bit standard frame identifier + uint8_t data[8]; //Data bytes (0 to 8) + uint8_t reserved8[2]; + } standard; + struct { + uint8_t id[4]; //29 bit extended frame identifier + uint8_t data[8]; //Data bytes (0 to 8) + } extended; + }; + }; + uint8_t bytes[13]; +} __attribute__((packed)) twai_ll_frame_buffer_t; + +ESP_STATIC_ASSERT(sizeof(twai_ll_frame_buffer_t) == 13, "TX/RX buffer type should be 13 bytes"); + +/* ---------------------------- Reset and Clock Control ------------------------------ */ + +/** + * @brief Enable the bus clock for twai module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +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); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define twai_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; twai_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the twai module + * + * @param group_id Group ID + */ +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; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define twai_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; twai_ll_reset_register(__VA_ARGS__) + +/* ---------------------------- Peripheral Control Register ----------------- */ + +/** + * @brief Enable TWAI module clock + * + * @param group_id Group ID + * @param en true to enable, false to disable + */ +__attribute__((always_inline)) +static inline void twai_ll_enable_clock(int group_id, bool en) +{ + switch (group_id) { + case 0: HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai0_clk_en = en; break; + case 1: HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai1_clk_en = en; break; + case 2: HP_SYS_CLKRST.peri_clk_ctrl115.reg_twai2_clk_en = en; break; + default: HAL_ASSERT(false); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define twai_ll_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; twai_ll_enable_clock(__VA_ARGS__) + +/** + * @brief Set clock source for TWAI module + * + * @param group_id Group ID + * @param clk_src Clock source + */ +__attribute__((always_inline)) +static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) +{ + 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); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define twai_ll_set_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; twai_ll_set_clock_source(__VA_ARGS__) + +/* ---------------------------- Mode Register ------------------------------- */ +/** + * @brief Enter reset mode + * + * When in reset mode, the TWAI controller is effectively disconnected from the + * TWAI bus and will not participate in any bus activates. Reset mode is required + * in order to write the majority of configuration registers. + * + * @param hw Start address of the TWAI registers + * + * @note Reset mode is automatically entered on BUS OFF condition + */ +__attribute__((always_inline)) +static inline void twai_ll_enter_reset_mode(twai_dev_t *hw) +{ + hw->mode.reset_mode = 1; +} + +/** + * @brief Exit reset mode + * + * When not in reset mode, the TWAI controller will take part in bus activities + * (e.g., send/receive/acknowledge messages and error frames) depending on the + * operating mode. + * + * @param hw Start address of the TWAI registers + * + * @note Reset mode must be exit to initiate BUS OFF recovery + */ +__attribute__((always_inline)) +static inline void twai_ll_exit_reset_mode(twai_dev_t *hw) +{ + hw->mode.reset_mode = 0; +} + +/** + * @brief Check if in reset mode + * @param hw Start address of the TWAI registers + * @return true if in reset mode + */ +__attribute__((always_inline)) +static inline bool twai_ll_is_in_reset_mode(twai_dev_t *hw) +{ + return hw->mode.reset_mode; +} + +/** + * @brief Set operating mode of TWAI controller + * + * @param hw Start address of the TWAI registers + * @param mode Operating mode + * + * @note Must be called in reset mode + */ +__attribute__((always_inline)) +static inline void twai_ll_set_mode(twai_dev_t *hw, twai_mode_t mode) +{ + if (mode == TWAI_MODE_NORMAL) { //Normal Operating mode + hw->mode.listen_only_mode = 0; + hw->mode.self_test_mode = 0; + } else if (mode == TWAI_MODE_NO_ACK) { //Self Test Mode (No Ack) + hw->mode.listen_only_mode = 0; + hw->mode.self_test_mode = 1; + } else if (mode == TWAI_MODE_LISTEN_ONLY) { //Listen Only Mode + hw->mode.listen_only_mode = 1; + hw->mode.self_test_mode = 0; + } +} + +/* --------------------------- Command Register ----------------------------- */ + +/** + * @brief Set TX 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 + * + * @note Transmit commands should be called last (i.e., after handling buffer + * release and clear data overrun) in order to prevent the other commands + * overwriting this latched TX bit with 0. + */ +__attribute__((always_inline)) +static inline void twai_ll_set_cmd_tx(twai_dev_t *hw) +{ + hw->cmd.tx_request = 1; +} + +/** + * @brief Set single shot TX command + * + * Similar to setting TX command, but the TWAI controller will not automatically + * retry transmission upon an error (e.g., due to an acknowledgement error). + * + * @param hw Start address of the TWAI registers + * + * @note Transmit commands should be called last (i.e., after handling buffer + * release and clear data overrun) in order to prevent the other commands + * overwriting this latched TX bit with 0. + */ +__attribute__((always_inline)) +static inline void twai_ll_set_cmd_tx_single_shot(twai_dev_t *hw) +{ + hw->cmd.val = 0x03; //Set cmd.tx_request and cmd.abort_tx simultaneously for single shot transmitting request +} + +/** + * @brief Aborts TX + * + * Frames awaiting TX will be aborted. Frames already being TX are not aborted. + * Transmission Complete Status bit is automatically set to 1. + * Similar to setting TX command, but the TWAI controller will not automatically + * retry transmission upon an error (e.g., due to acknowledge error). + * + * @param hw Start address of the TWAI registers + * + * @note Transmit commands should be called last (i.e., after handling buffer + * release and clear data overrun) in order to prevent the other commands + * overwriting this latched TX bit with 0. + */ +__attribute__((always_inline)) +static inline void twai_ll_set_cmd_abort_tx(twai_dev_t *hw) +{ + hw->cmd.abort_tx = 1; +} + +/** + * @brief Release RX buffer + * + * Rotates RX buffer to the next frame in the RX FIFO. + * + * @param hw Start address of the TWAI registers + */ +__attribute__((always_inline)) +static inline void twai_ll_set_cmd_release_rx_buffer(twai_dev_t *hw) +{ + hw->cmd.release_buffer = 1; +} + +/** + * @brief Clear data overrun + * + * Clears the data overrun status bit + * + * @param hw Start address of the TWAI registers + */ +__attribute__((always_inline)) +static inline void twai_ll_set_cmd_clear_data_overrun(twai_dev_t *hw) +{ + hw->cmd.clear_data_overrun = 1; +} + +/** + * @brief Set self reception single shot command + * + * Similar to setting TX command, but the TWAI controller also simultaneously + * receive the transmitted frame and is generally used for self testing + * purposes. The TWAI controller will not ACK the received message, so consider + * using the NO_ACK operating mode. + * + * @param hw Start address of the TWAI registers + * + * @note Transmit commands should be called last (i.e., after handling buffer + * release and clear data overrun) in order to prevent the other commands + * overwriting this latched TX bit with 0. + */ +__attribute__((always_inline)) +static inline void twai_ll_set_cmd_self_rx_request(twai_dev_t *hw) +{ + hw->cmd.self_rx_request = 1; +} + +/** + * @brief Set self reception request command + * + * Similar to setting the self reception request, but the TWAI controller will + * not automatically retry transmission upon an error (e.g., due to and + * acknowledgement error). + * + * @param hw Start address of the TWAI registers + * + * @note Transmit commands should be called last (i.e., after handling buffer + * release and clear data overrun) in order to prevent the other commands + * overwriting this latched TX bit with 0. + */ +__attribute__((always_inline)) +static inline void twai_ll_set_cmd_self_rx_single_shot(twai_dev_t *hw) +{ + hw->cmd.val = 0x12; //Set cmd.self_rx_request and cmd.abort_tx simultaneously for single shot self reception request +} + +/* --------------------------- Status Register ------------------------------ */ + +/** + * @brief Get all status bits + * + * @param hw Start address of the TWAI registers + * @return Status bits + */ +__attribute__((always_inline)) +static inline uint32_t twai_ll_get_status(twai_dev_t *hw) +{ + return hw->status.val; +} + +/** + * @brief Check if RX FIFO overrun status bit is set + * + * @param hw Start address of the TWAI registers + * @return Overrun status bit + */ +__attribute__((always_inline)) +static inline bool twai_ll_is_fifo_overrun(twai_dev_t *hw) +{ + return hw->status.status_overrun; +} + +/** + * @brief Check if previously TX was successful + * + * @param hw Start address of the TWAI registers + * @return Whether previous TX was successful + */ +__attribute__((always_inline)) +static inline bool twai_ll_is_last_tx_successful(twai_dev_t *hw) +{ + return hw->status.status_transmission_complete; +} + +/* -------------------------- Interrupt Register ---------------------------- */ + +/** + * @brief Get currently set interrupts + * + * Reading the interrupt registers will automatically clear all interrupts + * except for the Receive Interrupt. + * + * @param hw Start address of the TWAI registers + * @return Bit mask of set interrupts + */ +__attribute__((always_inline)) +static inline uint32_t twai_ll_get_and_clear_intrs(twai_dev_t *hw) +{ + return hw->interrupt_st.val; +} + +/* ----------------------- Interrupt Enable Register ------------------------ */ + +/** + * @brief Set which interrupts are enabled + * + * @param hw Start address of the TWAI registers + * @param Bit mask of interrupts to enable + * + * @note Must be called in reset mode + */ +__attribute__((always_inline)) +static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask) +{ + hw->interrupt_ena.val = intr_mask; +} + +/* ------------------------ Bus Timing Registers --------------------------- */ + +/** + * @brief Check if the brp value valid + * + * @param brp Bit rate prescaler value + * @return true or False + */ +__attribute__((always_inline)) +static inline bool twai_ll_check_brp_validation(uint32_t brp) +{ + bool valid = (brp >= SOC_TWAI_BRP_MIN) && (brp <= SOC_TWAI_BRP_MAX); + // should be an even number + valid = valid && !(brp & 0x01); + return valid; +} + +/** + * @brief Set bus timing + * + * @param hw Start address of the TWAI registers + * @param brp Baud Rate Prescaler + * @param sjw Synchronization Jump Width + * @param tseg1 Timing Segment 1 + * @param tseg2 Timing Segment 2 + * @param triple_sampling Triple Sampling enable/disable + * + * @note Must be called in reset mode + * @note ESP32C6 brp can be any even number between 2 to 32768 + */ +__attribute__((always_inline)) +static inline void twai_ll_set_bus_timing(twai_dev_t *hw, uint32_t brp, uint32_t sjw, uint32_t tseg1, uint32_t tseg2, bool triple_sampling) +{ + hw->bus_timing_0.baud_presc = (brp / 2) - 1; + hw->bus_timing_0.sync_jump_width = sjw - 1; + hw->bus_timing_1.time_segment1 = tseg1 - 1; + hw->bus_timing_1.time_segment2 = tseg2 - 1; + hw->bus_timing_1.time_sampling = triple_sampling; +} + +/* ----------------------------- ALC Register ------------------------------- */ + +/** + * @brief Clear Arbitration Lost Capture Register + * + * Reading the ALC register rearms the Arbitration Lost Interrupt + * + * @param hw Start address of the TWAI registers + */ +__attribute__((always_inline)) +static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw) +{ + (void)hw->arb_lost_cap.val; +} + +/* ----------------------------- ECC Register ------------------------------- */ + +/** + * @brief Clear Error Code Capture register + * + * Reading the ECC register rearms the Bus Error Interrupt + * + * @param hw Start address of the TWAI registers + */ +__attribute__((always_inline)) +static inline void twai_ll_clear_err_code_cap(twai_dev_t *hw) +{ + (void)hw->err_code_cap.val; +} + +/* ----------------------------- EWL Register ------------------------------- */ + +/** + * @brief Set Error Warning Limit + * + * @param hw Start address of the TWAI registers + * @param ewl Error Warning Limit + * + * @note Must be called in reset mode + */ +__attribute__((always_inline)) +static inline void twai_ll_set_err_warn_lim(twai_dev_t *hw, uint32_t ewl) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->err_warning_limit, err_warning_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 twai_ll_get_err_warn_lim(twai_dev_t *hw) +{ + return hw->err_warning_limit.val; +} + +/* ------------------------ RX Error Count Register ------------------------- */ + +/** + * @brief Get RX Error Counter + * + * @param hw Start address of the TWAI registers + * @return REC value + * + * @note REC is not frozen in reset mode. Listen only mode will freeze it. A BUS + * OFF condition automatically sets the REC to 0. + */ +__attribute__((always_inline)) +static inline uint32_t twai_ll_get_rec(twai_dev_t *hw) +{ + return hw->rx_err_cnt.val; +} + +/** + * @brief Set RX Error Counter + * + * @param hw Start address of the TWAI registers + * @param rec REC value + * + * @note Must be called in reset mode + */ +__attribute__((always_inline)) +static inline void twai_ll_set_rec(twai_dev_t *hw, uint32_t rec) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_err_cnt, rx_err_cnt, rec); +} + +/* ------------------------ TX Error Count Register ------------------------- */ + +/** + * @brief Get TX Error Counter + * + * @param hw Start address of the TWAI registers + * @return TEC value + * + * @note A BUS OFF condition will automatically set this to 128 + */ +__attribute__((always_inline)) +static inline uint32_t twai_ll_get_tec(twai_dev_t *hw) +{ + return hw->tx_err_cnt.val; +} + +/** + * @brief Set TX Error Counter + * + * @param hw Start address of the TWAI registers + * @param tec TEC value + * + * @note Must be called in reset mode + */ +__attribute__((always_inline)) +static inline void twai_ll_set_tec(twai_dev_t *hw, uint32_t tec) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_err_cnt, tx_err_cnt, tec); +} + +/* ---------------------- Acceptance Filter Registers ----------------------- */ + +/** + * @brief Set Acceptance Filter + * @param hw Start address of the TWAI registers + * @param code Acceptance Code + * @param mask Acceptance Mask + * @param single_filter Whether to enable single filter mode + * + * @note Must be called in reset mode + */ +__attribute__((always_inline)) +static inline void twai_ll_set_acc_filter(twai_dev_t *hw, uint32_t code, uint32_t mask, bool single_filter) +{ + uint32_t code_swapped = HAL_SWAP32(code); + uint32_t mask_swapped = HAL_SWAP32(mask); + for (int i = 0; i < 4; i++) { + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->acceptance_filter.acr[i], byte, ((code_swapped >> (i * 8)) & 0xFF)); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->acceptance_filter.amr[i], byte, ((mask_swapped >> (i * 8)) & 0xFF)); + } + hw->mode.acceptance_filter_mode = single_filter; +} + +/* ------------------------- TX/RX Buffer Registers ------------------------- */ + +/** + * @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 + * + * @note Call twai_ll_format_frame_buffer() to format a frame + */ +__attribute__((always_inline)) +static inline void twai_ll_set_tx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t *tx_frame) +{ + //Copy formatted frame into TX buffer + for (int i = 0; i < 13; i++) { + hw->tx_rx_buffer[i].val = tx_frame->bytes[i]; + } +} + +/** + * @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 twai_ll_parse_frame_buffer() to parse the formatted frame + */ +__attribute__((always_inline)) +static inline void twai_ll_get_rx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t *rx_frame) +{ + //Copy RX buffer registers into frame + for (int i = 0; i < 13; i++) { + rx_frame->bytes[i] = HAL_FORCE_READ_U32_REG_FIELD(hw->tx_rx_buffer[i], byte); + } +} + +/** + * @brief Format contents of a TWAI frame 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 TX buffer. + * + * @param[in] 11bit or 29bit ID + * @param[in] dlc Data length code + * @param[in] data Pointer to an 8 byte array containing data. NULL if no data + * @param[in] format Type of TWAI frame + * @param[in] single_shot Frame will not be retransmitted on failure + * @param[in] self_rx Frame will also be simultaneously received + * @param[out] tx_frame Pointer to store formatted frame + */ +__attribute__((always_inline)) +static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const uint8_t *data, uint32_t flags, twai_ll_frame_buffer_t *tx_frame) +{ + bool is_extd = flags & TWAI_MSG_FLAG_EXTD; + bool is_rtr = flags & TWAI_MSG_FLAG_RTR; + + //Set frame information + tx_frame->dlc = dlc; + tx_frame->frame_format = is_extd; + tx_frame->rtr = is_rtr; + tx_frame->self_reception = (flags & TWAI_MSG_FLAG_SELF) ? 1 : 0; + tx_frame->single_shot = (flags & TWAI_MSG_FLAG_SS) ? 1 : 0; + + //Set ID. The ID registers are big endian and left aligned, therefore a bswap will be required + if (is_extd) { + uint32_t id_temp = HAL_SWAP32((id & TWAI_EXTD_ID_MASK) << 3); //((id << 3) >> 8*(3-i)) + for (int i = 0; i < 4; i++) { + tx_frame->extended.id[i] = (id_temp >> (8 * i)) & 0xFF; + } + } else { + uint32_t id_temp = HAL_SWAP16((id & TWAI_STD_ID_MASK) << 5); //((id << 5) >> 8*(1-i)) + for (int i = 0; i < 2; i++) { + tx_frame->standard.id[i] = (id_temp >> (8 * i)) & 0xFF; + } + } + + uint8_t *data_buffer = (is_extd) ? tx_frame->extended.data : tx_frame->standard.data; + if (!is_rtr) { //Only copy data if the frame is a data frame (i.e not a remote frame) + for (int i = 0; (i < dlc) && (i < TWAI_FRAME_MAX_DLC); i++) { + data_buffer[i] = data[i]; + } + } +} + +/** + * @brief Parse formatted TWAI frame (RX Buffer Layout) into its constituent contents + * + * @param[in] rx_frame Pointer to formatted frame + * @param[out] id 11 or 29bit ID + * @param[out] dlc Data length code + * @param[out] data Data. Left over bytes set to 0. + * @param[out] format Type of TWAI frame + */ +__attribute__((always_inline)) +static inline void twai_ll_parse_frame_buffer(twai_ll_frame_buffer_t *rx_frame, uint32_t *id, uint8_t *dlc, uint8_t *data, uint32_t *flags) +{ + //Copy frame information + *dlc = rx_frame->dlc; + uint32_t flags_temp = 0; + flags_temp |= (rx_frame->frame_format) ? TWAI_MSG_FLAG_EXTD : 0; + flags_temp |= (rx_frame->rtr) ? TWAI_MSG_FLAG_RTR : 0; + flags_temp |= (rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_MSG_FLAG_DLC_NON_COMP : 0; + *flags = flags_temp; + + //Copy ID. The ID registers are big endian and left aligned, therefore a bswap will be required + if (rx_frame->frame_format) { + uint32_t id_temp = 0; + for (int i = 0; i < 4; i++) { + id_temp |= rx_frame->extended.id[i] << (8 * i); + } + id_temp = HAL_SWAP32(id_temp) >> 3; //((byte[i] << 8*(3-i)) >> 3) + *id = id_temp & TWAI_EXTD_ID_MASK; + } else { + uint32_t id_temp = 0; + for (int i = 0; i < 2; i++) { + id_temp |= rx_frame->standard.id[i] << (8 * i); + } + id_temp = HAL_SWAP16(id_temp) >> 5; //((byte[i] << 8*(1-i)) >> 5) + *id = id_temp & TWAI_STD_ID_MASK; + } + + uint8_t *data_buffer = (rx_frame->frame_format) ? rx_frame->extended.data : rx_frame->standard.data; + //Only copy data if the frame is a data frame (i.e. not a remote frame) + int data_length = (rx_frame->rtr) ? 0 : ((rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_FRAME_MAX_DLC : rx_frame->dlc); + for (int i = 0; i < data_length; i++) { + data[i] = data_buffer[i]; + } + //Set remaining bytes of data to 0 + for (int i = data_length; i < TWAI_FRAME_MAX_DLC; i++) { + data[i] = 0; + } +} + +/* ----------------------- RX Message Count Register ------------------------ */ + +/** + * @brief Get RX Message Counter + * + * @param hw Start address of the TWAI registers + * @return RX Message Counter + */ +__attribute__((always_inline)) +static inline uint32_t twai_ll_get_rx_msg_count(twai_dev_t *hw) +{ + return hw->rx_message_counter.val; +} + +/* ------------------------- Clock Divider Register ------------------------- */ + +/** + * @brief Set CLKOUT Divider and enable/disable + * + * Configure CLKOUT. CLKOUT is a pre-scaled version of peripheral source clock. Divider can be + * 1, or any even number from 2 to 490. Set the divider to 0 to disable CLKOUT. + * + * @param hw Start address of the TWAI registers + * @param divider Divider for CLKOUT (any even number from 2 to 490). Set to 0 to disable CLKOUT + */ +__attribute__((always_inline)) +static inline void twai_ll_set_clkout(twai_dev_t *hw, uint32_t divider) +{ + if (divider >= 2 && divider <= 490) { + hw->clock_divider.clock_off = 0; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider, cd, (divider / 2) - 1); + } else if (divider == 1) { + //Setting the divider reg to max value (255) means a divider of 1 + hw->clock_divider.clock_off = 0; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider, cd, 255); + } else { + hw->clock_divider.clock_off = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider, cd, 0); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/twai_ll.h b/components/hal/esp32s2/include/hal/twai_ll.h index 10d4d8bc4d..3d05c5b0be 100644 --- a/components/hal/esp32s2/include/hal/twai_ll.h +++ b/components/hal/esp32s2/include/hal/twai_ll.h @@ -127,25 +127,25 @@ static inline void twai_ll_reset_register(int group_id) /** * @brief Enable TWAI module clock * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param en true to enable, false to disable */ __attribute__((always_inline)) -static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en) +static inline void twai_ll_enable_clock(int group_id, bool en) { - (void)hw; + (void)group_id; } /** * @brief Set clock source for TWAI module * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param clk_src Clock source */ __attribute__((always_inline)) -static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t clk_src) +static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) { - (void)hw; + (void)group_id; HAL_ASSERT(clk_src == TWAI_CLK_SRC_APB); } diff --git a/components/hal/esp32s3/include/hal/twai_ll.h b/components/hal/esp32s3/include/hal/twai_ll.h index fc23d35485..7f921438fa 100644 --- a/components/hal/esp32s3/include/hal/twai_ll.h +++ b/components/hal/esp32s3/include/hal/twai_ll.h @@ -124,25 +124,25 @@ static inline void twai_ll_reset_register(int group_id) /** * @brief Enable TWAI module clock * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param en true to enable, false to disable */ __attribute__((always_inline)) -static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en) +static inline void twai_ll_enable_clock(int group_id, bool en) { - (void)hw; + (void)group_id; } /** * @brief Set clock source for TWAI module * - * @param hw Start address of the TWAI registers + * @param group_id Group ID * @param clk_src Clock source */ __attribute__((always_inline)) -static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t clk_src) +static inline void twai_ll_set_clock_source(int group_id, twai_clock_source_t clk_src) { - (void)hw; + (void)group_id; HAL_ASSERT(clk_src == TWAI_CLK_SRC_APB); } diff --git a/components/hal/twai_hal.c b/components/hal/twai_hal.c index e0ff94d51a..25d0de61a8 100644 --- a/components/hal/twai_hal.c +++ b/components/hal/twai_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,8 +23,6 @@ bool twai_hal_init(twai_hal_context_t *hal_ctx, const twai_hal_config_t *config) hal_ctx->dev = TWAI_LL_GET_HW(config->controller_id); hal_ctx->state_flags = 0; hal_ctx->clock_source_hz = config->clock_source_hz; - //Enable functional clock - twai_ll_enable_clock(hal_ctx->dev, true); //Initialize TWAI controller, and set default values to registers twai_ll_enter_reset_mode(hal_ctx->dev); if (!twai_ll_is_in_reset_mode(hal_ctx->dev)) { //Must enter reset mode to write to config registers @@ -48,8 +46,6 @@ void twai_hal_deinit(twai_hal_context_t *hal_ctx) twai_ll_set_enabled_intrs(hal_ctx->dev, 0); twai_ll_clear_arb_lost_cap(hal_ctx->dev); twai_ll_clear_err_code_cap(hal_ctx->dev); - //Disable functional clock - twai_ll_enable_clock(hal_ctx->dev, false); hal_ctx->dev = NULL; } @@ -62,14 +58,6 @@ void twai_hal_configure(twai_hal_context_t *hal_ctx, const twai_timing_config_t brp = hal_ctx->clock_source_hz / t_config->quanta_resolution_hz; } - // set clock source - twai_clock_source_t clk_src = t_config->clk_src; - //for backward compatible, zero value means default a default clock source - if (t_config->clk_src == 0) { - clk_src = TWAI_CLK_SRC_DEFAULT; - } - twai_ll_set_clock_source(hal_ctx->dev, clk_src); - //Configure bus timing, acceptance filter, CLKOUT, and interrupts twai_ll_set_bus_timing(hal_ctx->dev, brp, t_config->sjw, t_config->tseg_1, t_config->tseg_2, t_config->triple_sampling); twai_ll_set_acc_filter(hal_ctx->dev, f_config->acceptance_code, f_config->acceptance_mask, f_config->single_filter); diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 37bf739736..bf0195faf9 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -35,6 +35,10 @@ config SOC_MCPWM_SUPPORTED bool default y +config SOC_TWAI_SUPPORTED + bool + default y + config SOC_ETM_SUPPORTED bool default y @@ -1009,7 +1013,7 @@ config SOC_MWDT_SUPPORT_XTAL config SOC_TWAI_CONTROLLER_NUM int - default 2 + default 3 config SOC_TWAI_CLK_SUPPORT_XTAL bool diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index b386fc9d07..c218ff496e 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -464,6 +464,21 @@ typedef enum { } soc_periph_ana_cmpr_clk_src_t; //////////////////////////////////////////////////TWAI////////////////////////////////////////////////////////////////// +/** + * @brief Array initializer for all supported clock sources of TWAI + */ +#define SOC_TWAI_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST} + +/** + * @brief TWAI clock source + */ +typedef enum { + TWAI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ +#if SOC_CLK_TREE_SUPPORTED + TWAI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST /*!< Select RC_FAST as the source clock */ +#endif + TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */ +} soc_periph_twai_clk_src_t; //////////////////////////////////////////////////ADC/////////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32p4/include/soc/gpio_sig_map.h b/components/soc/esp32p4/include/soc/gpio_sig_map.h index 99bd0360b5..d0653170fd 100644 --- a/components/soc/esp32p4/include/soc/gpio_sig_map.h +++ b/components/soc/esp32p4/include/soc/gpio_sig_map.h @@ -159,18 +159,18 @@ #define UART4_SLP_CLK_PAD_IN_IDX 78 #define GPIO_SD6_OUT_IDX 78 #define GPIO_SD7_OUT_IDX 79 -#define CAN0_RX_PAD_IN_IDX 80 -#define CAN0_TX_PAD_OUT_IDX 80 -#define CAN0_BUS_OFF_ON_PAD_OUT_IDX 81 -#define CAN0_CLKOUT_PAD_OUT_IDX 82 -#define CAN1_RX_PAD_IN_IDX 83 -#define CAN1_TX_PAD_OUT_IDX 83 -#define CAN1_BUS_OFF_ON_PAD_OUT_IDX 84 -#define CAN1_CLKOUT_PAD_OUT_IDX 85 -#define CAN2_RX_PAD_IN_IDX 86 -#define CAN2_TX_PAD_OUT_IDX 86 -#define CAN2_BUS_OFF_ON_PAD_OUT_IDX 87 -#define CAN2_CLKOUT_PAD_OUT_IDX 88 +#define TWAI0_RX_PAD_IN_IDX 80 +#define TWAI0_TX_PAD_OUT_IDX 80 +#define TWAI0_BUS_OFF_ON_PAD_OUT_IDX 81 +#define TWAI0_CLKOUT_PAD_OUT_IDX 82 +#define TWAI1_RX_PAD_IN_IDX 83 +#define TWAI1_TX_PAD_OUT_IDX 83 +#define TWAI1_BUS_OFF_ON_PAD_OUT_IDX 84 +#define TWAI1_CLKOUT_PAD_OUT_IDX 85 +#define TWAI2_RX_PAD_IN_IDX 86 +#define TWAI2_TX_PAD_OUT_IDX 86 +#define TWAI2_BUS_OFF_ON_PAD_OUT_IDX 87 +#define TWAI2_CLKOUT_PAD_OUT_IDX 88 #define PWM0_SYNC0_PAD_IN_IDX 89 #define PWM0_CH0_A_PAD_OUT_IDX 89 #define PWM0_SYNC1_PAD_IN_IDX 90 diff --git a/components/soc/esp32p4/include/soc/hp_sys_clkrst_reg.h b/components/soc/esp32p4/include/soc/hp_sys_clkrst_reg.h index 4bfc63fc2e..8a7ad9c6af 100644 --- a/components/soc/esp32p4/include/soc/hp_sys_clkrst_reg.h +++ b/components/soc/esp32p4/include/soc/hp_sys_clkrst_reg.h @@ -3473,27 +3473,27 @@ extern "C" { #define HP_SYS_CLKRST_REG_RST_EN_PWM1_M (HP_SYS_CLKRST_REG_RST_EN_PWM1_V << HP_SYS_CLKRST_REG_RST_EN_PWM1_S) #define HP_SYS_CLKRST_REG_RST_EN_PWM1_V 0x00000001U #define HP_SYS_CLKRST_REG_RST_EN_PWM1_S 25 -/** HP_SYS_CLKRST_REG_RST_EN_CAN0 : R/W; bitpos: [26]; default: 0; +/** HP_SYS_CLKRST_REG_RST_EN_TWAI0 : R/W; bitpos: [26]; default: 0; * Reserved */ -#define HP_SYS_CLKRST_REG_RST_EN_CAN0 (BIT(26)) -#define HP_SYS_CLKRST_REG_RST_EN_CAN0_M (HP_SYS_CLKRST_REG_RST_EN_CAN0_V << HP_SYS_CLKRST_REG_RST_EN_CAN0_S) -#define HP_SYS_CLKRST_REG_RST_EN_CAN0_V 0x00000001U -#define HP_SYS_CLKRST_REG_RST_EN_CAN0_S 26 -/** HP_SYS_CLKRST_REG_RST_EN_CAN1 : R/W; bitpos: [27]; default: 0; +#define HP_SYS_CLKRST_REG_RST_EN_TWAI0 (BIT(26)) +#define HP_SYS_CLKRST_REG_RST_EN_TWAI0_M (HP_SYS_CLKRST_REG_RST_EN_TWAI0_V << HP_SYS_CLKRST_REG_RST_EN_TWAI0_S) +#define HP_SYS_CLKRST_REG_RST_EN_TWAI0_V 0x00000001U +#define HP_SYS_CLKRST_REG_RST_EN_TWAI0_S 26 +/** HP_SYS_CLKRST_REG_RST_EN_TWAI1 : R/W; bitpos: [27]; default: 0; * Reserved */ -#define HP_SYS_CLKRST_REG_RST_EN_CAN1 (BIT(27)) -#define HP_SYS_CLKRST_REG_RST_EN_CAN1_M (HP_SYS_CLKRST_REG_RST_EN_CAN1_V << HP_SYS_CLKRST_REG_RST_EN_CAN1_S) -#define HP_SYS_CLKRST_REG_RST_EN_CAN1_V 0x00000001U -#define HP_SYS_CLKRST_REG_RST_EN_CAN1_S 27 -/** HP_SYS_CLKRST_REG_RST_EN_CAN2 : R/W; bitpos: [28]; default: 0; +#define HP_SYS_CLKRST_REG_RST_EN_TWAI1 (BIT(27)) +#define HP_SYS_CLKRST_REG_RST_EN_TWAI1_M (HP_SYS_CLKRST_REG_RST_EN_TWAI1_V << HP_SYS_CLKRST_REG_RST_EN_TWAI1_S) +#define HP_SYS_CLKRST_REG_RST_EN_TWAI1_V 0x00000001U +#define HP_SYS_CLKRST_REG_RST_EN_TWAI1_S 27 +/** HP_SYS_CLKRST_REG_RST_EN_TWAI2 : R/W; bitpos: [28]; default: 0; * Reserved */ -#define HP_SYS_CLKRST_REG_RST_EN_CAN2 (BIT(28)) -#define HP_SYS_CLKRST_REG_RST_EN_CAN2_M (HP_SYS_CLKRST_REG_RST_EN_CAN2_V << HP_SYS_CLKRST_REG_RST_EN_CAN2_S) -#define HP_SYS_CLKRST_REG_RST_EN_CAN2_V 0x00000001U -#define HP_SYS_CLKRST_REG_RST_EN_CAN2_S 28 +#define HP_SYS_CLKRST_REG_RST_EN_TWAI2 (BIT(28)) +#define HP_SYS_CLKRST_REG_RST_EN_TWAI2_M (HP_SYS_CLKRST_REG_RST_EN_TWAI2_V << HP_SYS_CLKRST_REG_RST_EN_TWAI2_S) +#define HP_SYS_CLKRST_REG_RST_EN_TWAI2_V 0x00000001U +#define HP_SYS_CLKRST_REG_RST_EN_TWAI2_S 28 /** HP_SYS_CLKRST_REG_RST_EN_LEDC : R/W; bitpos: [29]; default: 0; * Reserved */ @@ -3971,27 +3971,27 @@ extern "C" { #define HP_SYS_CLKRST_REG_FORCE_NORST_PWM1_M (HP_SYS_CLKRST_REG_FORCE_NORST_PWM1_V << HP_SYS_CLKRST_REG_FORCE_NORST_PWM1_S) #define HP_SYS_CLKRST_REG_FORCE_NORST_PWM1_V 0x00000001U #define HP_SYS_CLKRST_REG_FORCE_NORST_PWM1_S 5 -/** HP_SYS_CLKRST_REG_FORCE_NORST_CAN0 : R/W; bitpos: [6]; default: 0; +/** HP_SYS_CLKRST_REG_FORCE_NORST_TWAI0 : R/W; bitpos: [6]; default: 0; * Reserved */ -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN0 (BIT(6)) -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN0_M (HP_SYS_CLKRST_REG_FORCE_NORST_CAN0_V << HP_SYS_CLKRST_REG_FORCE_NORST_CAN0_S) -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN0_V 0x00000001U -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN0_S 6 -/** HP_SYS_CLKRST_REG_FORCE_NORST_CAN1 : R/W; bitpos: [7]; default: 0; +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI0 (BIT(6)) +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI0_M (HP_SYS_CLKRST_REG_FORCE_NORST_TWAI0_V << HP_SYS_CLKRST_REG_FORCE_NORST_TWAI0_S) +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI0_V 0x00000001U +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI0_S 6 +/** HP_SYS_CLKRST_REG_FORCE_NORST_TWAI1 : R/W; bitpos: [7]; default: 0; * Reserved */ -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN1 (BIT(7)) -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN1_M (HP_SYS_CLKRST_REG_FORCE_NORST_CAN1_V << HP_SYS_CLKRST_REG_FORCE_NORST_CAN1_S) -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN1_V 0x00000001U -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN1_S 7 -/** HP_SYS_CLKRST_REG_FORCE_NORST_CAN2 : R/W; bitpos: [8]; default: 0; +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI1 (BIT(7)) +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI1_M (HP_SYS_CLKRST_REG_FORCE_NORST_TWAI1_V << HP_SYS_CLKRST_REG_FORCE_NORST_TWAI1_S) +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI1_V 0x00000001U +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI1_S 7 +/** HP_SYS_CLKRST_REG_FORCE_NORST_TWAI2 : R/W; bitpos: [8]; default: 0; * Reserved */ -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN2 (BIT(8)) -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN2_M (HP_SYS_CLKRST_REG_FORCE_NORST_CAN2_V << HP_SYS_CLKRST_REG_FORCE_NORST_CAN2_S) -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN2_V 0x00000001U -#define HP_SYS_CLKRST_REG_FORCE_NORST_CAN2_S 8 +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI2 (BIT(8)) +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI2_M (HP_SYS_CLKRST_REG_FORCE_NORST_TWAI2_V << HP_SYS_CLKRST_REG_FORCE_NORST_TWAI2_S) +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI2_V 0x00000001U +#define HP_SYS_CLKRST_REG_FORCE_NORST_TWAI2_S 8 /** HP_SYS_CLKRST_REG_FORCE_NORST_LEDC : R/W; bitpos: [9]; default: 0; * Reserved */ diff --git a/components/soc/esp32p4/include/soc/hp_sys_clkrst_struct.h b/components/soc/esp32p4/include/soc/hp_sys_clkrst_struct.h index d672ecc629..2837628cd6 100644 --- a/components/soc/esp32p4/include/soc/hp_sys_clkrst_struct.h +++ b/components/soc/esp32p4/include/soc/hp_sys_clkrst_struct.h @@ -2350,18 +2350,18 @@ typedef union { * Reserved */ uint32_t reg_rst_en_pwm1:1; - /** reg_rst_en_can0 : R/W; bitpos: [26]; default: 0; + /** reg_rst_en_twai0 : R/W; bitpos: [26]; default: 0; * Reserved */ - uint32_t reg_rst_en_can0:1; - /** reg_rst_en_can1 : R/W; bitpos: [27]; default: 0; + uint32_t reg_rst_en_twai0:1; + /** reg_rst_en_twai1 : R/W; bitpos: [27]; default: 0; * Reserved */ - uint32_t reg_rst_en_can1:1; - /** reg_rst_en_can2 : R/W; bitpos: [28]; default: 0; + uint32_t reg_rst_en_twai1:1; + /** reg_rst_en_twai2 : R/W; bitpos: [28]; default: 0; * Reserved */ - uint32_t reg_rst_en_can2:1; + uint32_t reg_rst_en_twai2:1; /** reg_rst_en_ledc : R/W; bitpos: [29]; default: 0; * Reserved */ @@ -2656,18 +2656,18 @@ typedef union { * Reserved */ uint32_t reg_force_norst_pwm1:1; - /** reg_force_norst_can0 : R/W; bitpos: [6]; default: 0; + /** reg_force_norst_twai0 : R/W; bitpos: [6]; default: 0; * Reserved */ - uint32_t reg_force_norst_can0:1; - /** reg_force_norst_can1 : R/W; bitpos: [7]; default: 0; + uint32_t reg_force_norst_twai0:1; + /** reg_force_norst_twai1 : R/W; bitpos: [7]; default: 0; * Reserved */ - uint32_t reg_force_norst_can1:1; - /** reg_force_norst_can2 : R/W; bitpos: [8]; default: 0; + uint32_t reg_force_norst_twai1:1; + /** reg_force_norst_twai2 : R/W; bitpos: [8]; default: 0; * Reserved */ - uint32_t reg_force_norst_can2:1; + uint32_t reg_force_norst_twai2:1; /** reg_force_norst_ledc : R/W; bitpos: [9]; default: 0; * Reserved */ diff --git a/components/soc/esp32p4/include/soc/interrupts.h b/components/soc/esp32p4/include/soc/interrupts.h index 881aee4519..685da9861d 100644 --- a/components/soc/esp32p4/include/soc/interrupts.h +++ b/components/soc/esp32p4/include/soc/interrupts.h @@ -55,9 +55,9 @@ typedef enum { ETS_ADC_INTR_SOURCE, ETS_PWM0_INTR_SOURCE, ETS_PWM1_INTR_SOURCE, - ETS_CAN0_INTR_SOURCE, - ETS_CAN1_INTR_SOURCE, - ETS_CAN2_INTR_SOURCE, + ETS_TWAI0_INTR_SOURCE, + ETS_TWAI1_INTR_SOURCE, + ETS_TWAI2_INTR_SOURCE, ETS_RMT_INTR_SOURCE, ETS_I2C0_INTR_SOURCE, ETS_I2C1_INTR_SOURCE, diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 35685464f6..5d3c438216 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -35,7 +35,7 @@ #define SOC_GPTIMER_SUPPORTED 1 #define SOC_PCNT_SUPPORTED 1 #define SOC_MCPWM_SUPPORTED 1 -// #define SOC_TWAI_SUPPORTED 1 //TODO: IDF-7470 +#define SOC_TWAI_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 #define SOC_PARLIO_SUPPORTED 1 //TODO: IDF-7471 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 @@ -458,7 +458,7 @@ #define SOC_MWDT_SUPPORT_XTAL (1) /*-------------------------- TWAI CAPS ---------------------------------------*/ -#define SOC_TWAI_CONTROLLER_NUM 2 +#define SOC_TWAI_CONTROLLER_NUM 3 #define SOC_TWAI_CLK_SUPPORT_XTAL 1 #define SOC_TWAI_BRP_MIN 2 #define SOC_TWAI_BRP_MAX 32768 diff --git a/components/soc/esp32p4/include/soc/twai_struct.h b/components/soc/esp32p4/include/soc/twai_struct.h index 758d6462fc..9029051309 100644 --- a/components/soc/esp32p4/include/soc/twai_struct.h +++ b/components/soc/esp32p4/include/soc/twai_struct.h @@ -434,7 +434,7 @@ typedef union { uint32_t reserved_9:23; }; uint32_t val; -} twai_interrupt_reg_t; +} twai_interrupt_status_reg_t; /** Type of interrupt_enable register * Interrupt enable register. @@ -493,214 +493,43 @@ typedef union { /** Group: Data Registers */ -/** Type of data_0 register - * Data register 0. +/** Type of buffer register + * TX RX Buffer. */ typedef union { struct { - /** data_0 : R/W; bitpos: [7:0]; default: 0; + /** byte : R/W; bitpos: [7:0]; default: 0; * In reset mode, it is acceptance code register 0 with R/W Permission. In operation * mode, when software initiate write operation, it is tx data register 0 and when * software initiate read operation, it is rx data register 0. */ - uint32_t data_0:8; + uint32_t byte:8; uint32_t reserved_8:24; }; uint32_t val; -} twai_data_0_reg_t; - -/** Type of data_1 register - * Data register 1. - */ -typedef union { - struct { - /** data_1 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, it is acceptance code register 1 with R/W Permission. In operation - * mode, when software initiate write operation, it is tx data register 1 and when - * software initiate read operation, it is rx data register 1. - */ - uint32_t data_1:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_1_reg_t; - -/** Type of data_2 register - * Data register 2. - */ -typedef union { - struct { - /** data_2 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, it is acceptance code register 2 with R/W Permission. In operation - * mode, when software initiate write operation, it is tx data register 2 and when - * software initiate read operation, it is rx data register 2. - */ - uint32_t data_2:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_2_reg_t; - -/** Type of data_3 register - * Data register 3. - */ -typedef union { - struct { - /** data_3 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, it is acceptance code register 3 with R/W Permission. In operation - * mode, when software initiate write operation, it is tx data register 3 and when - * software initiate read operation, it is rx data register 3. - */ - uint32_t data_3:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_3_reg_t; - -/** Type of data_4 register - * Data register 4. - */ -typedef union { - struct { - /** data_4 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, it is acceptance mask register 0 with R/W Permission. In operation - * mode, when software initiate write operation, it is tx data register 4 and when - * software initiate read operation, it is rx data register 4. - */ - uint32_t data_4:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_4_reg_t; - -/** Type of data_5 register - * Data register 5. - */ -typedef union { - struct { - /** data_5 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, it is acceptance mask register 1 with R/W Permission. In operation - * mode, when software initiate write operation, it is tx data register 5 and when - * software initiate read operation, it is rx data register 5. - */ - uint32_t data_5:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_5_reg_t; - -/** Type of data_6 register - * Data register 6. - */ -typedef union { - struct { - /** data_6 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, it is acceptance mask register 2 with R/W Permission. In operation - * mode, when software initiate write operation, it is tx data register 6 and when - * software initiate read operation, it is rx data register 6. - */ - uint32_t data_6:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_6_reg_t; - -/** Type of data_7 register - * Data register 7. - */ -typedef union { - struct { - /** data_7 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, it is acceptance mask register 3 with R/W Permission. In operation - * mode, when software initiate write operation, it is tx data register 7 and when - * software initiate read operation, it is rx data register 7. - */ - uint32_t data_7:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_7_reg_t; - -/** Type of data_8 register - * Data register 8. - */ -typedef union { - struct { - /** data_8 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, reserved with RO. In operation mode, when software initiate write - * operation, it is tx data register 8 and when software initiate read operation, it - * is rx data register 8. - */ - uint32_t data_8:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_8_reg_t; - -/** Type of data_9 register - * Data register 9. - */ -typedef union { - struct { - /** data_9 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, reserved with RO. In operation mode, when software initiate write - * operation, it is tx data register 9 and when software initiate read operation, it - * is rx data register 9. - */ - uint32_t data_9:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_9_reg_t; - -/** Type of data_10 register - * Data register 10. - */ -typedef union { - struct { - /** data_10 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, reserved with RO. In operation mode, when software initiate write - * operation, it is tx data register 10 and when software initiate read operation, it - * is rx data register 10. - */ - uint32_t data_10:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_10_reg_t; - -/** Type of data_11 register - * Data register 11. - */ -typedef union { - struct { - /** data_11 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, reserved with RO. In operation mode, when software initiate write - * operation, it is tx data register 11 and when software initiate read operation, it - * is rx data register 11. - */ - uint32_t data_11:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_11_reg_t; - -/** Type of data_12 register - * Data register 12. - */ -typedef union { - struct { - /** data_12 : R/W; bitpos: [7:0]; default: 0; - * In reset mode, reserved with RO. In operation mode, when software initiate write - * operation, it is tx data register 12 and when software initiate read operation, it - * is rx data register 12. - */ - uint32_t data_12:8; - uint32_t reserved_8:24; - }; - uint32_t val; -} twai_data_12_reg_t; +} twai_tx_rx_buffer_reg_t; +typedef struct { + union { + struct { + uint32_t byte: 8; /* ACRx[7:0] Acceptance Code */ + uint32_t reserved8: 24; /* Internal Reserved */ + }; + uint32_t val; + } acr[4]; + union { + struct { + uint32_t byte: 8; /* AMRx[7:0] Acceptance Mask */ + uint32_t reserved8: 24; /* Internal Reserved */ + }; + uint32_t val; + } amr[4]; + uint32_t reserved_60; + uint32_t reserved_64; + uint32_t reserved_68; + uint32_t reserved_6c; + uint32_t reserved_70; +} acceptance_filter_reg_t; /** Group: Timestamp Register */ /** Type of timestamp_data register @@ -749,8 +578,8 @@ typedef struct { volatile twai_mode_reg_t mode; volatile twai_cmd_reg_t cmd; volatile twai_status_reg_t status; - volatile twai_interrupt_reg_t interrupt; - volatile twai_interrupt_enable_reg_t interrupt_enable; + volatile twai_interrupt_status_reg_t interrupt_st; + volatile twai_interrupt_enable_reg_t interrupt_ena; uint32_t reserved_014; volatile twai_bus_timing_0_reg_t bus_timing_0; volatile twai_bus_timing_1_reg_t bus_timing_1; @@ -760,19 +589,10 @@ typedef struct { volatile twai_err_warning_limit_reg_t err_warning_limit; volatile twai_rx_err_cnt_reg_t rx_err_cnt; volatile twai_tx_err_cnt_reg_t tx_err_cnt; - volatile twai_data_0_reg_t data_0; - volatile twai_data_1_reg_t data_1; - volatile twai_data_2_reg_t data_2; - volatile twai_data_3_reg_t data_3; - volatile twai_data_4_reg_t data_4; - volatile twai_data_5_reg_t data_5; - volatile twai_data_6_reg_t data_6; - volatile twai_data_7_reg_t data_7; - volatile twai_data_8_reg_t data_8; - volatile twai_data_9_reg_t data_9; - volatile twai_data_10_reg_t data_10; - volatile twai_data_11_reg_t data_11; - volatile twai_data_12_reg_t data_12; + volatile union { + acceptance_filter_reg_t acceptance_filter; + twai_tx_rx_buffer_reg_t tx_rx_buffer[13]; + }; volatile twai_rx_message_counter_reg_t rx_message_counter; uint32_t reserved_078; volatile twai_clock_divider_reg_t clock_divider; @@ -786,6 +606,9 @@ typedef struct { volatile twai_timestamp_cfg_reg_t timestamp_cfg; } twai_dev_t; +extern twai_dev_t TWAI0; +extern twai_dev_t TWAI1; +extern twai_dev_t TWAI2; #ifndef __cplusplus _Static_assert(sizeof(twai_dev_t) == 0xa0, "Invalid size of twai_dev_t structure"); diff --git a/components/soc/esp32p4/interrupts.c b/components/soc/esp32p4/interrupts.c index be8694e6b9..6d76d073e5 100644 --- a/components/soc/esp32p4/interrupts.c +++ b/components/soc/esp32p4/interrupts.c @@ -47,9 +47,9 @@ const char *const esp_isr_names[] = { [ETS_ADC_INTR_SOURCE] = "ADC", [ETS_PWM0_INTR_SOURCE] = "PWM0", [ETS_PWM1_INTR_SOURCE] = "PWM1", - [ETS_CAN0_INTR_SOURCE] = "CAN0", - [ETS_CAN1_INTR_SOURCE] = "CAN1", - [ETS_CAN2_INTR_SOURCE] = "CAN2", + [ETS_TWAI0_INTR_SOURCE] = "TWAI0", + [ETS_TWAI1_INTR_SOURCE] = "TWAI1", + [ETS_TWAI2_INTR_SOURCE] = "TWAI2", [ETS_RMT_INTR_SOURCE] = "RMT", [ETS_I2C0_INTR_SOURCE] = "I2C0", [ETS_I2C1_INTR_SOURCE] = "I2C1", diff --git a/components/soc/esp32p4/twai_periph.c b/components/soc/esp32p4/twai_periph.c index 061cd4a4d7..67b016fa0d 100644 --- a/components/soc/esp32p4/twai_periph.c +++ b/components/soc/esp32p4/twai_periph.c @@ -8,5 +8,33 @@ #include "soc/gpio_sig_map.h" const twai_controller_signal_conn_t twai_controller_periph_signals = { - + .controllers = { + [0] = { + .module = PERIPH_TWAI0_MODULE, + .irq_id = ETS_TWAI0_INTR_SOURCE, + .tx_sig = TWAI0_TX_PAD_OUT_IDX, + .rx_sig = TWAI0_RX_PAD_IN_IDX, + .bus_off_sig = TWAI0_BUS_OFF_ON_PAD_OUT_IDX, + .clk_out_sig = TWAI0_CLKOUT_PAD_OUT_IDX, + .stand_by_sig = TWAI0_STANDBY_PAD_OUT_IDX, + }, + [1] = { + .module = PERIPH_TWAI1_MODULE, + .irq_id = ETS_TWAI1_INTR_SOURCE, + .tx_sig = TWAI1_TX_PAD_OUT_IDX, + .rx_sig = TWAI1_RX_PAD_IN_IDX, + .bus_off_sig = TWAI1_BUS_OFF_ON_PAD_OUT_IDX, + .clk_out_sig = TWAI1_CLKOUT_PAD_OUT_IDX, + .stand_by_sig = TWAI1_STANDBY_PAD_OUT_IDX, + }, + [2] = { + .module = PERIPH_TWAI2_MODULE, + .irq_id = ETS_TWAI2_INTR_SOURCE, + .tx_sig = TWAI2_TX_PAD_OUT_IDX, + .rx_sig = TWAI2_RX_PAD_IN_IDX, + .bus_off_sig = TWAI2_BUS_OFF_ON_PAD_OUT_IDX, + .clk_out_sig = TWAI2_CLKOUT_PAD_OUT_IDX, + .stand_by_sig = TWAI2_STANDBY_PAD_OUT_IDX, + } + } }; diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 2f190dd544..64aa2b98fe 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -82,7 +82,6 @@ api-reference/peripherals/gpio/esp32p4.inc api-reference/peripherals/adc_continuous.rst api-reference/peripherals/adc_oneshot.rst api-reference/peripherals/usb_host.rst -api-reference/peripherals/twai.rst api-reference/peripherals/usb_host/usb_host_notes_arch.rst api-reference/peripherals/usb_host/usb_host_notes_index.rst api-reference/peripherals/usb_host/usb_host_notes_dwc_otg.rst diff --git a/docs/en/api-reference/peripherals/twai.rst b/docs/en/api-reference/peripherals/twai.rst index f55f76efd2..3a19a7f03a 100644 --- a/docs/en/api-reference/peripherals/twai.rst +++ b/docs/en/api-reference/peripherals/twai.rst @@ -164,7 +164,7 @@ The operating bit rate of the TWAI driver is configured using the :cpp:type:`twa 2. **Timing Segment 1** consists of 1 to 16 time quanta before sample point 3. **Timing Segment 2** consists of 1 to 8 time quanta after sample point -{IDF_TARGET_MAX_BRP:default="128", esp32="128", esp32s2="32768", esp32s3="16384", esp32c3="16384", esp32c6="32768", esp32h2="32768"} +{IDF_TARGET_MAX_BRP:default="32768", esp32="128", esp32s3="16384", esp32c3="16384"} The **Baudrate Prescaler** is used to determine the period of each time quantum by dividing the TWAI controller's source clock. On the {IDF_TARGET_NAME}, the ``brp`` can be **any even number from 2 to {IDF_TARGET_MAX_BRP}**. Alternatively, you can decide the resolution of each quantum, by setting :cpp:member:`twai_timing_config_t::quanta_resolution_hz` to a non-zero value. In this way, the driver can calculate the underlying ``brp`` value for you. It is useful when you set different clock sources but want the bitrate to keep the same. diff --git a/examples/peripherals/twai/twai_alert_and_recovery/README.md b/examples/peripherals/twai/twai_alert_and_recovery/README.md index 0c8b1c9a96..860c76d494 100644 --- a/examples/peripherals/twai/twai_alert_and_recovery/README.md +++ b/examples/peripherals/twai/twai_alert_and_recovery/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # TWAI Alert and Recovery Example diff --git a/examples/peripherals/twai/twai_alert_and_recovery/main/twai_alert_and_recovery_example_main.c b/examples/peripherals/twai/twai_alert_and_recovery/main/twai_alert_and_recovery_example_main.c index fa740a8ce0..ac138733cf 100644 --- a/examples/peripherals/twai/twai_alert_and_recovery/main/twai_alert_and_recovery_example_main.c +++ b/examples/peripherals/twai/twai_alert_and_recovery/main/twai_alert_and_recovery_example_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ @@ -26,7 +26,7 @@ #include "driver/twai.h" #include "esp_rom_gpio.h" #include "esp_rom_sys.h" -#include "soc/gpio_sig_map.h" // For GPIO matrix signal index +#include "soc/twai_periph.h" // For GPIO matrix signal index /* --------------------- Definitions and static variables ------------------ */ //Example Configuration @@ -38,12 +38,6 @@ #define ERR_PERIOD_US 80 //Approximate time for two bits at 25KBPS #define EXAMPLE_TAG "TWAI Alert and Recovery" -#if CONFIG_IDF_TARGET_ESP32C6 -#define TWAI_TX_SIGNAL_IDX TWAI0_TX_IDX -#else -#define TWAI_TX_SIGNAL_IDX TWAI_TX_IDX -#endif - static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS(); static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NO_ACK); @@ -54,15 +48,15 @@ static SemaphoreHandle_t ctrl_task_sem; static bool trigger_tx_error = false; /* --------------------------- Tasks and Functions -------------------------- */ - +extern const twai_controller_signal_conn_t twai_controller_periph_signals; static void invert_tx_bits(bool enable) { if (enable) { //Inverts output of TX to trigger errors - esp_rom_gpio_connect_out_signal(TX_GPIO_NUM, TWAI_TX_SIGNAL_IDX, true, false); + esp_rom_gpio_connect_out_signal(TX_GPIO_NUM, twai_controller_periph_signals.controllers[0].tx_sig, true, false); } else { //Returns TX to default settings - esp_rom_gpio_connect_out_signal(TX_GPIO_NUM, TWAI_TX_SIGNAL_IDX, false, false); + esp_rom_gpio_connect_out_signal(TX_GPIO_NUM, twai_controller_periph_signals.controllers[0].tx_sig, false, false); } } diff --git a/examples/peripherals/twai/twai_network/README.md b/examples/peripherals/twai/twai_network/README.md index dd0fd36ccf..a10d4ca76f 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-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # TWAI Network Example diff --git a/examples/peripherals/twai/twai_self_test/README.md b/examples/peripherals/twai/twai_self_test/README.md index 38902161dd..ae75e83231 100644 --- a/examples/peripherals/twai/twai_self_test/README.md +++ b/examples/peripherals/twai/twai_self_test/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # TWAI Self Test Example