Merge branch 'feature/c3_twai_bringup' into 'master'

TWAI: bringup for S3 & C3

Closes IDF-2109 and IDF-1770

See merge request espressif/esp-idf!11984
This commit is contained in:
Michael (XIAO Xufeng)
2021-01-15 13:46:21 +08:00
18 changed files with 341 additions and 191 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for TWAI
@@ -33,22 +33,22 @@ extern "C" {
/* ------------------------- Defines and Typedefs --------------------------- */
#define TWAI_LL_STATUS_RBS (0x1 << 0)
#define TWAI_LL_STATUS_DOS (0x1 << 1)
#define TWAI_LL_STATUS_TBS (0x1 << 2)
#define TWAI_LL_STATUS_TCS (0x1 << 3)
#define TWAI_LL_STATUS_RS (0x1 << 4)
#define TWAI_LL_STATUS_TS (0x1 << 5)
#define TWAI_LL_STATUS_ES (0x1 << 6)
#define TWAI_LL_STATUS_BS (0x1 << 7)
#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_INTR_RI (0x1 << 0)
#define TWAI_LL_INTR_TI (0x1 << 1)
#define TWAI_LL_INTR_EI (0x1 << 2)
#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)
#define TWAI_LL_INTR_ALI (0x1 << 6)
#define TWAI_LL_INTR_BEI (0x1 << 7)
#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
/*
* The following frame structure has an NEARLY identical bit field layout to
@@ -82,6 +82,8 @@ typedef union {
uint8_t bytes[13];
} __attribute__((packed)) twai_ll_frame_buffer_t;
_Static_assert(sizeof(twai_ll_frame_buffer_t) == 13, "TX/RX buffer type should be 13 bytes");
/* ---------------------------- Mode Register ------------------------------- */
/**
@@ -92,14 +94,12 @@ typedef union {
* in order to write the majority of configuration registers.
*
* @param hw Start address of the TWAI registers
* @return true if reset mode was entered successfully
*
* @note Reset mode is automatically entered on BUS OFF condition
*/
static inline bool twai_ll_enter_reset_mode(twai_dev_t *hw)
static inline void twai_ll_enter_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 1;
return hw->mode_reg.rm;
}
/**
@@ -110,14 +110,12 @@ static inline bool twai_ll_enter_reset_mode(twai_dev_t *hw)
* operating mode.
*
* @param hw Start address of the TWAI registers
* @return true if reset mode was exit successfully
*
* @note Reset mode must be exit to initiate BUS OFF recovery
*/
static inline bool twai_ll_exit_reset_mode(twai_dev_t *hw)
static inline void twai_ll_exit_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 0;
return !(hw->mode_reg.rm);
}
/**
@@ -186,7 +184,7 @@ static inline void twai_ll_set_cmd_tx(twai_dev_t *hw)
*/
static inline void twai_ll_set_cmd_tx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x03; //Writing to TR and AT simultaneously
hw->command_reg.val = 0x03; //Set command_reg.tr and command_reg.at simultaneously for single shot transmittion request
}
/**
@@ -266,7 +264,7 @@ static inline void twai_ll_set_cmd_self_rx_request(twai_dev_t *hw)
*/
static inline void twai_ll_set_cmd_self_rx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x12;
hw->command_reg.val = 0x12; //Set command_reg.srr and command_reg.at simultaneously for single shot self reception request
}
/* --------------------------- Status Register ------------------------------ */
@@ -304,8 +302,6 @@ static inline bool twai_ll_is_last_tx_successful(twai_dev_t *hw)
return hw->status_reg.tcs;
}
//Todo: Add stand alone status bit check functions when necessary
/* -------------------------- Interrupt Register ---------------------------- */
/**
@@ -334,12 +330,7 @@ static inline uint32_t twai_ll_get_and_clear_intrs(twai_dev_t *hw)
*/
static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask)
{
#ifdef TWAI_BRP_DIV_SUPPORTED
//ESP32 Rev 2 has brp div. Need to mask when setting
hw->interrupt_enable_reg.val = (hw->interrupt_enable_reg.val & 0x10) | intr_mask;
#else
hw->interrupt_enable_reg.val = intr_mask;
#endif
}
/* ------------------------ Bus Timing Registers --------------------------- */
@@ -355,18 +346,10 @@ static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask)
* @param triple_sampling Triple Sampling enable/disable
*
* @note Must be called in reset mode
* @note ESP32 rev 2 or later can support a x2 brp by setting a brp_div bit,
* allowing the brp to go from a maximum of 128 to 256.
* @note ESP32C3 brp can be any even number between 2 to 32768
*/
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)
{
#ifdef TWAI_BRP_DIV_SUPPORTED
if (brp > TWAI_BRP_DIV_THRESH) {
//Need to set brp_div bit
hw->interrupt_enable_reg.brp_div = 1;
brp /= 2;
}
#endif
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;
@@ -386,7 +369,6 @@ static inline void twai_ll_set_bus_timing(twai_dev_t *hw, uint32_t brp, uint32_t
static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw)
{
(void)hw->arbitration_lost_captue_reg.val;
//Todo: Decode ALC register
}
/* ----------------------------- ECC Register ------------------------------- */
@@ -401,7 +383,6 @@ static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw)
static inline void twai_ll_clear_err_code_cap(twai_dev_t *hw)
{
(void)hw->error_code_capture_reg.val;
//Todo: Decode error code capture
}
/* ----------------------------- EWL Register ------------------------------- */
@@ -546,7 +527,11 @@ static inline void twai_ll_get_rx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t
/**
* @brief Format contents of a TWAI frame into layout of TX Buffer
*
* @param[in] id 11 or 29bit ID
* 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
@@ -557,9 +542,6 @@ static inline void twai_ll_get_rx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t
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)
{
/* 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. */
bool is_extd = flags & TWAI_MSG_FLAG_EXTD;
bool is_rtr = flags & TWAI_MSG_FLAG_RTR;
@@ -570,7 +552,7 @@ static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const u
tx_frame->self_reception = (flags & TWAI_MSG_FLAG_SELF) ? 1 : 0;
tx_frame->single_shot = (flags & TWAI_MSG_FLAG_SS) ? 1 : 0;
//Set ID
//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))
for (int i = 0; i < 4; i++) {
@@ -583,9 +565,8 @@ static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const u
}
}
//Set Data
uint8_t *data_buffer = (is_extd) ? tx_frame->extended.data : tx_frame->standard.data;
if (!is_rtr) {
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];
}
@@ -593,7 +574,7 @@ static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const u
}
/**
* @brief Parse formatted TWAI frame (RX Buffer Layout) into its contents
* @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
@@ -604,8 +585,6 @@ static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const u
static inline void twai_ll_prase_frame_buffer(twai_ll_frame_buffer_t *rx_frame, uint32_t *id, uint8_t *dlc,
uint8_t *data, uint32_t *flags)
{
//This function decodes a frame structure into it's constituent components.
//Copy frame information
*dlc = rx_frame->dlc;
uint32_t flags_temp = 0;
@@ -614,7 +593,7 @@ static inline void twai_ll_prase_frame_buffer(twai_ll_frame_buffer_t *rx_frame,
flags_temp |= (rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_MSG_FLAG_DLC_NON_COMP : 0;
*flags = flags_temp;
//Copy ID
//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++) {
@@ -631,8 +610,8 @@ static inline void twai_ll_prase_frame_buffer(twai_ll_frame_buffer_t *rx_frame,
*id = id_temp & TWAI_STD_ID_MASK;
}
//Copy data
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];
@@ -661,43 +640,27 @@ 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
* 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. Set to 0 to disable CLKOUT
* @param divider Divider for CLKOUT (any even number from 2 to 490). Set to 0 to disable CLKOUT
*/
static inline void twai_ll_set_clkout(twai_dev_t *hw, uint32_t divider)
{
/* Configure CLKOUT. CLKOUT is a pre-scaled version of APB CLK. Divider can be
1, or any even number from 2 to 14. Set to out of range value (0) to disable
CLKOUT. */
if (divider >= 2 && divider <= 14) {
TWAI.clock_divider_reg.co = 0;
TWAI.clock_divider_reg.cd = (divider / 2) - 1;
if (divider >= 2 && divider <= 490) {
hw->clock_divider_reg.co = 0;
hw->clock_divider_reg.cd = (divider / 2) - 1;
} else if (divider == 1) {
TWAI.clock_divider_reg.co = 0;
TWAI.clock_divider_reg.cd = 7;
//Setting the divider reg to max value (255) means a divider of 1
hw->clock_divider_reg.co = 0;
hw->clock_divider_reg.cd = 255;
} else {
TWAI.clock_divider_reg.co = 1;
TWAI.clock_divider_reg.cd = 0;
hw->clock_divider_reg.co = 1;
hw->clock_divider_reg.cd = 0;
}
}
/**
* @brief Set register address mapping to extended mode
*
* Extended mode register address mapping consists of more registers and extra
* features.
*
* @param hw Start address of the TWAI registers
*
* @note Must be called before setting any configuration
* @note Must be called in reset mode
*/
static inline void twai_ll_enable_extended_reg_layout(twai_dev_t *hw)
{
hw->clock_divider_reg.cm = 1;
}
#ifdef __cplusplus
}
#endif