twai: h2 support twai driver

This commit is contained in:
wanlei 2023-02-14 15:25:10 +08:00
parent 76989b504a
commit fdeeced62c
17 changed files with 141 additions and 326 deletions

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
# Enable Socket CAN Device with bitrate 250Kbps

View File

@ -12,6 +12,7 @@ from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.generic
@ -39,6 +40,7 @@ def fixture_create_socket_can() -> Bus:
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.skip(reason='Runner not set up yet')
@ -70,6 +72,7 @@ def test_twai_listen_only(dut: Dut, socket_can: Bus) -> None:
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.skip(reason='Runner not set up yet')

View File

@ -16,6 +16,8 @@
#include "esp_pm.h"
#include "esp_attr.h"
#include "esp_heap_caps.h"
#include "clk_tree.h"
#include "clk_ctrl_os.h"
#include "driver/gpio.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk.h"
@ -426,24 +428,7 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
if (clk_src == 0) {
clk_src = TWAI_CLK_SRC_DEFAULT;
}
switch (clk_src) {
#if SOC_TWAI_CLK_SUPPORT_APB
case TWAI_CLK_SRC_APB:
clock_source_hz = esp_clk_apb_freq();
break;
#endif //SOC_TWAI_CLK_SUPPORT_APB
#if SOC_TWAI_CLK_SUPPORT_XTAL
case TWAI_CLK_SRC_XTAL:
clock_source_hz = esp_clk_xtal_freq();
break;
#endif //SOC_TWAI_CLK_SUPPORT_XTAL
default:
//Invalid clock source
TWAI_CHECK(false, ESP_ERR_INVALID_ARG);
}
clk_tree_src_get_freq_hz(clk_src, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clock_source_hz);
//Check brp validation
uint32_t brp = t_config->brp;
@ -469,8 +454,9 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
p_twai_obj_dummy->alerts_enabled = g_config->alerts_enabled;
p_twai_obj_dummy->module = twai_controller_periph_signals.controllers[controller_id].module;
#if CONFIG_PM_ENABLE && SOC_TWAI_CLK_SUPPORT_APB
#if CONFIG_PM_ENABLE
#if SOC_TWAI_CLK_SUPPORT_APB
// DFS can change APB frequency. So add lock to prevent sleep and APB freq from changing
if (clk_src == TWAI_CLK_SRC_APB) {
// TODO: pm_lock name should also reflect the controller ID
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "twai", &(p_twai_obj_dummy->pm_lock));
@ -478,7 +464,14 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
goto err;
}
}
#endif //CONFIG_PM_ENABLE && SOC_TWAI_CLK_SUPPORT_APB
#else // XTAL
// XTAL freq can be closed in light sleep, so we need to create a lock to prevent light sleep
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "twai", &(p_twai_obj_dummy->pm_lock));
if (ret != ESP_OK) {
goto err;
}
#endif //SOC_TWAI_CLK_SUPPORT_APB
#endif //CONFIG_PM_ENABLE
//Initialize TWAI peripheral registers, and allocate interrupt
TWAI_ENTER_CRITICAL();

View File

@ -24,8 +24,9 @@
#include "hal/twai_types.h"
#include "soc/twai_periph.h"
#include "soc/twai_struct.h"
#include "soc/pcr_struct.h"
#define TWAI_LL_GET_HW(controller_id) ((controller_id == 0) ? (&TWAI) : NULL)
#define TWAI_LL_GET_HW(controller_id) ((controller_id == 0) ? (&TWAI0) : NULL)
#ifdef __cplusplus
extern "C" {
@ -96,7 +97,7 @@ ESP_STATIC_ASSERT(sizeof(twai_ll_frame_buffer_t) == 13, "TX/RX buffer type shoul
__attribute__((always_inline))
static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en)
{
(void)hw;
PCR.twai0_func_clk_conf.twai0_func_clk_en = en;
}
/**
@ -108,8 +109,13 @@ static inline void twai_ll_enable_clock(twai_dev_t *hw, bool en)
__attribute__((always_inline))
static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t clk_src)
{
(void)hw;
HAL_ASSERT(clk_src == TWAI_CLK_SRC_APB);
switch (clk_src) {
case TWAI_CLK_SRC_DEFAULT:
PCR.twai0_func_clk_conf.twai0_func_clk_sel = 0;
break;
default:
HAL_ASSERT(false);
}
}
/* ---------------------------- Mode Register ------------------------------- */
@ -128,7 +134,7 @@ static inline void twai_ll_set_clock_source(twai_dev_t *hw, twai_clock_source_t
__attribute__((always_inline))
static inline void twai_ll_enter_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 1;
hw->mode.reset_mode = 1;
}
/**
@ -145,7 +151,7 @@ static inline void twai_ll_enter_reset_mode(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_exit_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 0;
hw->mode.reset_mode = 0;
}
/**
@ -156,7 +162,7 @@ static inline void twai_ll_exit_reset_mode(twai_dev_t *hw)
__attribute__((always_inline))
static inline bool twai_ll_is_in_reset_mode(twai_dev_t *hw)
{
return hw->mode_reg.rm;
return hw->mode.reset_mode;
}
/**
@ -170,15 +176,15 @@ static inline bool twai_ll_is_in_reset_mode(twai_dev_t *hw)
__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_reg.lom = 0;
hw->mode_reg.stm = 0;
} else if (mode == TWAI_MODE_NO_ACK) { //Self Test Mode (No Ack)
hw->mode_reg.lom = 0;
hw->mode_reg.stm = 1;
} else if (mode == TWAI_MODE_LISTEN_ONLY) { //Listen Only Mode
hw->mode_reg.lom = 1;
hw->mode_reg.stm = 0;
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;
}
}
@ -200,7 +206,7 @@ static inline void twai_ll_set_mode(twai_dev_t *hw, twai_mode_t mode)
__attribute__((always_inline))
static inline void twai_ll_set_cmd_tx(twai_dev_t *hw)
{
hw->command_reg.tr = 1;
hw->cmd.tx_request = 1;
}
/**
@ -218,7 +224,7 @@ static inline void twai_ll_set_cmd_tx(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_set_cmd_tx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x03; //Set command_reg.tr and command_reg.at simultaneously for single shot transmittion request
hw->cmd.val = 0x03; //Set cmd.tx_request and cmd.abort_tx simultaneously for single shot transmitting request
}
/**
@ -238,7 +244,7 @@ static inline void twai_ll_set_cmd_tx_single_shot(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_set_cmd_abort_tx(twai_dev_t *hw)
{
hw->command_reg.at = 1;
hw->cmd.abort_tx = 1;
}
/**
@ -251,7 +257,7 @@ static inline void twai_ll_set_cmd_abort_tx(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_set_cmd_release_rx_buffer(twai_dev_t *hw)
{
hw->command_reg.rrb = 1;
hw->cmd.release_buffer = 1;
}
/**
@ -264,7 +270,7 @@ static inline void twai_ll_set_cmd_release_rx_buffer(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_set_cmd_clear_data_overrun(twai_dev_t *hw)
{
hw->command_reg.cdo = 1;
hw->cmd.clear_data_overrun = 1;
}
/**
@ -284,7 +290,7 @@ static inline void twai_ll_set_cmd_clear_data_overrun(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_set_cmd_self_rx_request(twai_dev_t *hw)
{
hw->command_reg.srr = 1;
hw->cmd.self_rx_request = 1;
}
/**
@ -303,7 +309,7 @@ static inline void twai_ll_set_cmd_self_rx_request(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_set_cmd_self_rx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x12; //Set command_reg.srr and command_reg.at simultaneously for single shot self reception request
hw->cmd.val = 0x12; //Set cmd.self_rx_request and cmd.abort_tx simultaneously for single shot self reception request
}
/* --------------------------- Status Register ------------------------------ */
@ -317,7 +323,7 @@ static inline void twai_ll_set_cmd_self_rx_single_shot(twai_dev_t *hw)
__attribute__((always_inline))
static inline uint32_t twai_ll_get_status(twai_dev_t *hw)
{
return hw->status_reg.val;
return hw->status.val;
}
/**
@ -329,7 +335,7 @@ static inline uint32_t twai_ll_get_status(twai_dev_t *hw)
__attribute__((always_inline))
static inline bool twai_ll_is_fifo_overrun(twai_dev_t *hw)
{
return hw->status_reg.dos;
return hw->status.status_overrun;
}
/**
@ -341,7 +347,7 @@ static inline bool twai_ll_is_fifo_overrun(twai_dev_t *hw)
__attribute__((always_inline))
static inline bool twai_ll_is_last_tx_successful(twai_dev_t *hw)
{
return hw->status_reg.tcs;
return hw->status.status_transmission_complete;
}
/* -------------------------- Interrupt Register ---------------------------- */
@ -358,7 +364,7 @@ static inline bool twai_ll_is_last_tx_successful(twai_dev_t *hw)
__attribute__((always_inline))
static inline uint32_t twai_ll_get_and_clear_intrs(twai_dev_t *hw)
{
return hw->interrupt_reg.val;
return hw->interrupt.val;
}
/* ----------------------- Interrupt Enable Register ------------------------ */
@ -374,7 +380,7 @@ static inline uint32_t twai_ll_get_and_clear_intrs(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask)
{
hw->interrupt_enable_reg.val = intr_mask;
hw->interrupt_enable.val = intr_mask;
}
/* ------------------------ Bus Timing Registers --------------------------- */
@ -405,16 +411,16 @@ static inline bool twai_ll_check_brp_validation(uint32_t brp)
* @param triple_sampling Triple Sampling enable/disable
*
* @note Must be called in reset mode
* @note ESP32H4 brp can be any even number between 2 to 32768
* @note ESP32H2 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_reg.brp = (brp / 2) - 1;
hw->bus_timing_0_reg.sjw = sjw - 1;
hw->bus_timing_1_reg.tseg1 = tseg1 - 1;
hw->bus_timing_1_reg.tseg2 = tseg2 - 1;
hw->bus_timing_1_reg.sam = 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 ------------------------------- */
@ -429,7 +435,7 @@ static inline void twai_ll_set_bus_timing(twai_dev_t *hw, uint32_t brp, uint32_t
__attribute__((always_inline))
static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw)
{
(void)hw->arbitration_lost_captue_reg.val;
(void)hw->arb_lost_cap.val;
}
/* ----------------------------- ECC Register ------------------------------- */
@ -444,7 +450,7 @@ static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw)
__attribute__((always_inline))
static inline void twai_ll_clear_err_code_cap(twai_dev_t *hw)
{
(void)hw->error_code_capture_reg.val;
(void)hw->err_code_cap.val;
}
/* ----------------------------- EWL Register ------------------------------- */
@ -460,7 +466,7 @@ static inline void twai_ll_clear_err_code_cap(twai_dev_t *hw)
__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->error_warning_limit_reg, ewl, ewl);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->err_warning_limit, err_warning_limit, ewl);
}
/**
@ -472,7 +478,7 @@ static inline void twai_ll_set_err_warn_lim(twai_dev_t *hw, uint32_t ewl)
__attribute__((always_inline))
static inline uint32_t twai_ll_get_err_warn_lim(twai_dev_t *hw)
{
return hw->error_warning_limit_reg.val;
return hw->err_warning_limit.val;
}
/* ------------------------ RX Error Count Register ------------------------- */
@ -489,7 +495,7 @@ static inline uint32_t twai_ll_get_err_warn_lim(twai_dev_t *hw)
__attribute__((always_inline))
static inline uint32_t twai_ll_get_rec(twai_dev_t *hw)
{
return hw->rx_error_counter_reg.val;
return hw->rx_err_cnt.val;
}
/**
@ -503,7 +509,7 @@ static inline uint32_t twai_ll_get_rec(twai_dev_t *hw)
__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_error_counter_reg, rxerr, rec);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_err_cnt, rx_err_cnt, rec);
}
/* ------------------------ TX Error Count Register ------------------------- */
@ -519,7 +525,7 @@ static inline void twai_ll_set_rec(twai_dev_t *hw, uint32_t rec)
__attribute__((always_inline))
static inline uint32_t twai_ll_get_tec(twai_dev_t *hw)
{
return hw->tx_error_counter_reg.val;
return hw->tx_err_cnt.val;
}
/**
@ -533,7 +539,7 @@ static inline uint32_t twai_ll_get_tec(twai_dev_t *hw)
__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_error_counter_reg, txerr, tec);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_err_cnt, tx_err_cnt, tec);
}
/* ---------------------- Acceptance Filter Registers ----------------------- */
@ -548,15 +554,15 @@ static inline void twai_ll_set_tec(twai_dev_t *hw, uint32_t tec)
* @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)
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 = __builtin_bswap32(code);
uint32_t mask_swapped = __builtin_bswap32(mask);
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_reg.afm = single_filter;
hw->mode.acceptance_filter_mode = single_filter;
}
/* ------------------------- TX/RX Buffer Registers ------------------------- */
@ -591,7 +597,7 @@ static inline void twai_ll_get_rx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t
{
//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);
rx_frame->bytes[i] = HAL_FORCE_READ_U32_REG_FIELD(hw->tx_rx_buffer[i], byte);
}
}
@ -612,7 +618,7 @@ static inline void twai_ll_get_rx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t
*/
__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)
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;
@ -626,12 +632,12 @@ static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const u
//Set ID. The ID registers are big endian and left aligned, therefore a bswap will be required
if (is_extd) {
uint32_t id_temp = __builtin_bswap32((id & TWAI_EXTD_ID_MASK) << 3); //((id << 3) >> 8*(3-i))
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 = __builtin_bswap16((id & TWAI_STD_ID_MASK) << 5); //((id << 5) >> 8*(1-i))
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;
}
@ -656,7 +662,7 @@ static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const u
*/
__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)
uint8_t *data, uint32_t *flags)
{
//Copy frame information
*dlc = rx_frame->dlc;
@ -672,14 +678,14 @@ static inline void twai_ll_parse_frame_buffer(twai_ll_frame_buffer_t *rx_frame,
for (int i = 0; i < 4; i++) {
id_temp |= rx_frame->extended.id[i] << (8 * i);
}
id_temp = __builtin_bswap32(id_temp) >> 3; //((byte[i] << 8*(3-i)) >> 3)
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 = __builtin_bswap16(id_temp) >> 5; //((byte[i] << 8*(1-i)) >> 5)
id_temp = HAL_SWAP16(id_temp) >> 5; //((byte[i] << 8*(1-i)) >> 5)
*id = id_temp & TWAI_STD_ID_MASK;
}
@ -706,7 +712,7 @@ static inline void twai_ll_parse_frame_buffer(twai_ll_frame_buffer_t *rx_frame,
__attribute__((always_inline))
static inline uint32_t twai_ll_get_rx_msg_count(twai_dev_t *hw)
{
return hw->rx_message_counter_reg.val;
return hw->rx_message_counter.val;
}
/* ------------------------- Clock Divider Register ------------------------- */
@ -714,7 +720,7 @@ static inline uint32_t twai_ll_get_rx_msg_count(twai_dev_t *hw)
/**
* @brief Set CLKOUT Divider and enable/disable
*
* Configure CLKOUT. CLKOUT is a pre-scaled version of APB CLK. Divider can be
* 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
@ -724,15 +730,16 @@ __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_reg.co = 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider_reg, cd, (divider / 2) - 1);
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_reg.co = 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider_reg, cd, 255);
hw->clock_divider.clock_off = 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider, cd, 255);
} else {
hw->clock_divider_reg.co = 1;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider_reg, cd, 0);
hw->clock_divider.clock_off = 1;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clock_divider, cd, 0);
}
}

View File

@ -64,6 +64,17 @@ extern "C" {
#define TWAI_TIMING_CONFIG_20KBITS() {.quanta_resolution_hz = 400000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#endif // (SOC_TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN_FULL >= 200)
#if CONFIG_XTAL_FREQ == 32 // TWAI_CLK_SRC_XTAL = 32M
#define TWAI_TIMING_CONFIG_25KBITS() {.quanta_resolution_hz = 400000, .tseg_1 = 11, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_50KBITS() {.quanta_resolution_hz = 1000000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_100KBITS() {.quanta_resolution_hz = 2000000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_125KBITS() {.quanta_resolution_hz = 4000000, .tseg_1 = 23, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_250KBITS() {.quanta_resolution_hz = 4000000, .tseg_1 = 11, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_500KBITS() {.quanta_resolution_hz = 8000000, .tseg_1 = 11, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_800KBITS() {.quanta_resolution_hz = 16000000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_1MBITS() {.quanta_resolution_hz = 16000000, .tseg_1 = 11, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#elif CONFIG_XTAL_FREQ == 40 // TWAI_CLK_SRC_XTAL = 40M
#define TWAI_TIMING_CONFIG_25KBITS() {.quanta_resolution_hz = 625000, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_50KBITS() {.quanta_resolution_hz = 1000000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_100KBITS() {.quanta_resolution_hz = 2000000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
@ -72,6 +83,7 @@ extern "C" {
#define TWAI_TIMING_CONFIG_500KBITS() {.quanta_resolution_hz = 10000000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_800KBITS() {.quanta_resolution_hz = 20000000, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_1MBITS() {.quanta_resolution_hz = 20000000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#endif //CONFIG_XTAL_FREQ
/**
* @brief Initializer macro for filter configuration to accept all IDs

View File

@ -27,6 +27,10 @@ config SOC_MCPWM_SUPPORTED
bool
default y
config SOC_TWAI_SUPPORTED
bool
default y
config SOC_GPTIMER_SUPPORTED
bool
default y

View File

@ -389,8 +389,8 @@ typedef enum {
* @brief TWAI clock source
*/
typedef enum {
TWAI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */
TWAI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */
} soc_periph_twai_clk_src_t;
//////////////////////////////////////////////////ADC///////////////////////////////////////////////////////////////////

View File

@ -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
*/
@ -135,14 +135,14 @@
#define RMT_SIG_IN1_IDX 72
#define RMT_SIG_OUT1_IDX 72
#define MODEM_DIAG9_IDX 72
#define CAN0_RX_IDX 73
#define CAN0_TX_IDX 73
#define TWAI_RX_IDX 73
#define TWAI_TX_IDX 73
#define MODEM_DIAG10_IDX 73
#define CAN0_BUS_OFF_ON_IDX 74
#define TWAI_BUS_OFF_ON_IDX 74
#define MODEM_DIAG11_IDX 74
#define CAN0_CLKOUT_IDX 75
#define TWAI_CLKOUT_IDX 75
#define MODEM_DIAG12_IDX 75
#define CAN0_STANDBY_IDX 76
#define TWAI_STANDBY_IDX 76
#define MODEM_DIAG13_IDX 76
#define CTE_ANT6_IDX 77
#define CTE_ANT7_IDX 78

View File

@ -32,7 +32,7 @@
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
#define SOC_PCNT_SUPPORTED 1
#define SOC_MCPWM_SUPPORTED 1
// #define SOC_TWAI_SUPPORTED 1 // TODO: IDF-6217
#define SOC_TWAI_SUPPORTED 1
// #define SOC_BT_SUPPORTED 1 // TODO: IDF-6416
// #define SOC_IEEE802154_SUPPORTED 1 // TODO: IDF-6577
#define SOC_GPTIMER_SUPPORTED 1
@ -359,7 +359,6 @@
#define SOC_TIMER_GROUP_TOTAL_TIMERS (2)
#define SOC_TIMER_SUPPORT_ETM (1)
// TODO: IDF-6217 (Copy from esp32c6, need check)
/*-------------------------- TWAI CAPS ---------------------------------------*/
#define SOC_TWAI_CONTROLLER_NUM 1
#define SOC_TWAI_CLK_SUPPORT_XTAL 1

View File

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/twai_periph.h"
#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 = TWAI_TX_IDX,
.rx_sig = TWAI_RX_IDX,
.bus_off_sig = TWAI_BUS_OFF_ON_IDX,
.clk_out_sig = TWAI_CLKOUT_IDX,
.stand_by_sig = TWAI_STANDBY_IDX,
}
}
};

View File

@ -296,21 +296,6 @@ typedef enum {
GLITCH_FILTER_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB 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_MOD_CLK_APB}
/**
* @brief TWAI clock source
*/
typedef enum {
TWAI_CLK_SRC_APB = SOC_MOD_CLK_APB, /*!< Select APB as the source clock */
TWAI_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default clock choice */
} soc_periph_twai_clk_src_t;
//////////////////////////////////////////////////ADC///////////////////////////////////////////////////////////////////
/**

View File

@ -1,209 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* ---------------------------- Register Layout ------------------------------ */
/* The TWAI peripheral's registers are 8bits, however the ESP32-H4 can only access
* peripheral registers every 32bits. Therefore each TWAI register is mapped to
* the least significant byte of every 32bits.
*/
typedef volatile struct twai_dev_s {
//Configuration and Control Registers
union {
struct {
uint32_t rm: 1; /* MOD.0 Reset Mode */
uint32_t lom: 1; /* MOD.1 Listen Only Mode */
uint32_t stm: 1; /* MOD.2 Self Test Mode */
uint32_t afm: 1; /* MOD.3 Acceptance Filter Mode */
uint32_t reserved4: 28; /* Internal Reserved. MOD.4 Sleep Mode not supported */
};
uint32_t val;
} mode_reg; /* Address 0x0000 */
union {
struct {
uint32_t tr: 1; /* CMR.0 Transmission Request */
uint32_t at: 1; /* CMR.1 Abort Transmission */
uint32_t rrb: 1; /* CMR.2 Release Receive Buffer */
uint32_t cdo: 1; /* CMR.3 Clear Data Overrun */
uint32_t srr: 1; /* CMR.4 Self Reception Request */
uint32_t reserved5: 27; /* Internal Reserved */
};
uint32_t val;
} command_reg; /* Address 0x0004 */
union {
struct {
uint32_t rbs: 1; /* SR.0 Receive Buffer Status */
uint32_t dos: 1; /* SR.1 Data Overrun Status */
uint32_t tbs: 1; /* SR.2 Transmit Buffer Status */
uint32_t tcs: 1; /* SR.3 Transmission Complete Status */
uint32_t rs: 1; /* SR.4 Receive Status */
uint32_t ts: 1; /* SR.5 Transmit Status */
uint32_t es: 1; /* SR.6 Error Status */
uint32_t bs: 1; /* SR.7 Bus Status */
uint32_t ms: 1; /* SR.8 Miss Status */
uint32_t reserved9: 23; /* Internal Reserved */
};
uint32_t val;
} status_reg; /* Address 0x0008 */
union {
struct {
uint32_t ri: 1; /* IR.0 Receive Interrupt */
uint32_t ti: 1; /* IR.1 Transmit Interrupt */
uint32_t ei: 1; /* IR.2 Error Interrupt */
uint32_t doi: 1; /* IR.3 Data Overrun Interrupt */
uint32_t reserved4: 1; /* Internal Reserved (Wake-up not supported) */
uint32_t epi: 1; /* IR.5 Error Passive Interrupt */
uint32_t ali: 1; /* IR.6 Arbitration Lost Interrupt */
uint32_t bei: 1; /* IR.7 Bus Error Interrupt */
uint32_t reserved8: 24; /* Internal Reserved */
};
uint32_t val;
} interrupt_reg; /* Address 0x000C */
union {
struct {
uint32_t rie: 1; /* IER.0 Receive Interrupt Enable */
uint32_t tie: 1; /* IER.1 Transmit Interrupt Enable */
uint32_t eie: 1; /* IER.2 Error Interrupt Enable */
uint32_t doie: 1; /* IER.3 Data Overrun Interrupt Enable */
uint32_t reserved4: 1; /* Internal Reserved (Wake-up not supported) */
uint32_t epie: 1; /* IER.5 Error Passive Interrupt Enable */
uint32_t alie: 1; /* IER.6 Arbitration Lost Interrupt Enable */
uint32_t beie: 1; /* IER.7 Bus Error Interrupt Enable */
uint32_t reserved8: 24; /* Internal Reserved */
};
uint32_t val;
} interrupt_enable_reg; /* Address 0x0010 */
uint32_t reserved_14;
union {
struct {
uint32_t brp: 13; /* BTR0[12:0] Baud Rate Prescaler */
uint32_t reserved13: 1; /* Internal Reserved */
uint32_t sjw: 2; /* BTR0[15:14] Synchronization Jump Width*/
uint32_t reserved16: 16; /* Internal Reserved */
};
uint32_t val;
} bus_timing_0_reg; /* Address 0x0018 */
union {
struct {
uint32_t tseg1: 4; /* BTR1[3:0] Timing Segment 1 */
uint32_t tseg2: 3; /* BTR1[6:4] Timing Segment 2 */
uint32_t sam: 1; /* BTR1.7 Sampling*/
uint32_t reserved8: 24; /* Internal Reserved */
};
uint32_t val;
} bus_timing_1_reg; /* Address 0x001C */
uint32_t reserved_20; /* Address 0x0020 (Output control not supported) */
uint32_t reserved_24; /* Address 0x0024 (Test Register not supported) */
uint32_t reserved_28; /* Address 0x0028 */
//Capture and Counter Registers
union {
struct {
uint32_t alc: 5; /* ALC[4:0] Arbitration lost capture */
uint32_t reserved5: 27; /* Internal Reserved */
};
uint32_t val;
} arbitration_lost_captue_reg; /* Address 0x002C */
union {
struct {
uint32_t seg: 5; /* ECC[4:0] Error Code Segment 0 to 5 */
uint32_t dir: 1; /* ECC.5 Error Direction (TX/RX) */
uint32_t errc: 2; /* ECC[7:6] Error Code */
uint32_t reserved8: 24; /* Internal Reserved */
};
uint32_t val;
} error_code_capture_reg; /* Address 0x0030 */
union {
struct {
uint32_t ewl: 8; /* EWL[7:0] Error Warning Limit */
uint32_t reserved8: 24; /* Internal Reserved */
};
uint32_t val;
} error_warning_limit_reg; /* Address 0x0034 */
union {
struct {
uint32_t rxerr: 8; /* RXERR[7:0] Receive Error Counter */
uint32_t reserved8: 24; /* Internal Reserved */
};
uint32_t val;
} rx_error_counter_reg; /* Address 0x0038 */
union {
struct {
uint32_t txerr: 8; /* TXERR[7:0] Receive Error Counter */
uint32_t reserved8: 24; /* Internal Reserved */
};
uint32_t val;
} tx_error_counter_reg; /* Address 0x003C */
//Shared Registers (TX Buff/RX Buff/Acc Filter)
union {
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;
union {
struct {
uint32_t byte: 8; /* TX/RX Byte X [7:0] */
uint32_t reserved24: 24; /* Internal Reserved */
};
uint32_t val;
} tx_rx_buffer[13];
}; /* Address 0x0040 - 0x0070 */
//Misc Registers
union {
struct {
uint32_t rmc: 7; /* RMC[6:0] RX Message Counter */
uint32_t reserved7: 25; /* Internal Reserved */
};
uint32_t val;
} rx_message_counter_reg; /* Address 0x0074 */
uint32_t reserved_78; /* Address 0x0078 (RX Buffer Start Address not supported) */
union {
struct {
uint32_t cd: 8; /* CDR[7:0] CLKOUT frequency selector based of fOSC */
uint32_t co: 1; /* CDR.8 CLKOUT enable/disable */
uint32_t reserved9: 23; /* Internal Reserved */
};
uint32_t val;
} clock_divider_reg; /* Address 0x007C */
} twai_dev_t;
#ifndef __cplusplus
_Static_assert(sizeof(twai_dev_t) == 128, "TWAI registers should be 32 * 4 bytes");
#endif
extern twai_dev_t TWAI;
#ifdef __cplusplus
}
#endif

View File

@ -51,7 +51,6 @@ api-reference/peripherals/sdspi_share
api-reference/peripherals/adc_continuous
api-reference/peripherals/adc_oneshot
api-reference/peripherals/usb_host
api-reference/peripherals/twai
api-reference/peripherals/usb_device
api-reference/peripherals/sdspi_host
api-reference/peripherals/i2s

View File

@ -159,7 +159,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", esp32c3="16384", esp32c6="16384"}
{IDF_TARGET_MAX_BRP:default="128", esp32="128", esp32s2="32768", esp32s3="16384", esp32c3="16384", esp32c6="32768", esp32h2="32768"}
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's useful when you set different clock sources but want the bitrate to keep the same.

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
# TWAI Alert and Recovery Example

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
# TWAI Network Example

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
# TWAI Self Test Example