mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/twai_backport_accumulated_fixes_v4.2' into 'release/v4.2'
TWAI backport accumulated fixes (backport v4.2) See merge request espressif/esp-idf!11459
This commit is contained in:
commit
7dc03f16e7
@ -71,6 +71,29 @@ menu "Driver configurations"
|
||||
|
||||
endmenu # SPI Configuration
|
||||
|
||||
menu "TWAI configuration"
|
||||
|
||||
config TWAI_ISR_IN_IRAM
|
||||
bool "Place TWAI ISR function into IRAM"
|
||||
default n
|
||||
select FREERTOS_SUPPORT_STATIC_ALLOCATION
|
||||
# We need to enable FREERTOS_SUPPORT_STATIC_ALLOCATION because the
|
||||
# TWAI driver requires the use of FreeRTOS Queues and Semaphores from
|
||||
# the driver ISR. These Queues and Semaphores need to be placed in
|
||||
# DRAM thus FreeRTOS static allocation API is required.
|
||||
help
|
||||
Place the TWAI ISR in to IRAM. This will allow the ISR to avoid
|
||||
cache misses, and also be able to run whilst the cache is disabled
|
||||
(such as when writing to SPI Flash).
|
||||
Note that if this option is enabled:
|
||||
- Users should also set the ESP_INTR_FLAG_IRAM in the driver
|
||||
configuration structure when installing the driver (see docs for
|
||||
specifics).
|
||||
- Alert logging (i.e., setting of the TWAI_ALERT_AND_LOG flag)
|
||||
will have no effect.
|
||||
|
||||
endmenu # TWAI Configuration
|
||||
|
||||
menu "UART configuration"
|
||||
|
||||
config UART_ISR_IN_IRAM
|
||||
|
@ -43,7 +43,8 @@ extern "C" {
|
||||
#define TWAI_GENERAL_CONFIG_DEFAULT(tx_io_num, rx_io_num, op_mode) {.mode = op_mode, .tx_io = tx_io_num, .rx_io = rx_io_num, \
|
||||
.clkout_io = TWAI_IO_UNUSED, .bus_off_io = TWAI_IO_UNUSED, \
|
||||
.tx_queue_len = 5, .rx_queue_len = 5, \
|
||||
.alerts_enabled = TWAI_ALERT_NONE, .clkout_divider = 0, }
|
||||
.alerts_enabled = TWAI_ALERT_NONE, .clkout_divider = 0, \
|
||||
.intr_flags = ESP_INTR_FLAG_LEVEL1}
|
||||
|
||||
/**
|
||||
* @brief Alert flags
|
||||
@ -70,7 +71,7 @@ extern "C" {
|
||||
#define TWAI_ALERT_BUS_OFF 0x1000 /**< Alert(4096): Bus-off condition occurred. TWAI controller can no longer influence bus */
|
||||
#define TWAI_ALERT_ALL 0x1FFF /**< Bit mask to enable all alerts during configuration */
|
||||
#define TWAI_ALERT_NONE 0x0000 /**< Bit mask to disable all alerts during configuration */
|
||||
#define TWAI_ALERT_AND_LOG 0x2000 /**< Bit mask to enable alerts to also be logged when they occur */
|
||||
#define TWAI_ALERT_AND_LOG 0x2000 /**< Bit mask to enable alerts to also be logged when they occur. Note that logging from the ISR is disabled if CONFIG_TWAI_ISR_IN_IRAM is enabled (see docs). */
|
||||
|
||||
/** @endcond */
|
||||
|
||||
@ -103,6 +104,7 @@ typedef struct {
|
||||
uint32_t rx_queue_len; /**< Number of messages RX queue can hold */
|
||||
uint32_t alerts_enabled; /**< Bit field of alerts to enable (see documentation) */
|
||||
uint32_t clkout_divider; /**< CLKOUT divider. Can be 1 or any even number from 2 to 14 (optional, set to 0 if unused) */
|
||||
int intr_flags; /**< Interrupt flags to set the priority of the driver's ISR. Note that to use the ESP_INTR_FLAG_IRAM, the CONFIG_TWAI_ISR_IN_IRAM option should be enabled first. */
|
||||
} twai_general_config_t;
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_pm.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "driver/twai.h"
|
||||
@ -44,7 +46,14 @@
|
||||
})
|
||||
#define TWAI_SET_FLAG(var, mask) ((var) |= (mask))
|
||||
#define TWAI_RESET_FLAG(var, mask) ((var) &= ~(mask))
|
||||
#ifdef CONFIG_TWAI_ISR_IN_IRAM
|
||||
#define TWAI_ISR_ATTR IRAM_ATTR
|
||||
#define TWAI_MALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#else
|
||||
#define TWAI_TAG "TWAI"
|
||||
#define TWAI_ISR_ATTR
|
||||
#define TWAI_MALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||
#endif //CONFIG_TWAI_ISR_IN_IRAM
|
||||
|
||||
#define DRIVER_DEFAULT_INTERRUPTS 0xE7 //Exclude data overrun (bit[3]) and brp_div (bit[4])
|
||||
|
||||
@ -72,6 +81,13 @@ typedef struct {
|
||||
uint32_t bus_error_count;
|
||||
intr_handle_t isr_handle;
|
||||
//TX and RX
|
||||
#ifdef CONFIG_TWAI_ISR_IN_IRAM
|
||||
void *tx_queue_buff;
|
||||
void *tx_queue_struct;
|
||||
void *rx_queue_buff;
|
||||
void *rx_queue_struct;
|
||||
void *semphr_struct;
|
||||
#endif
|
||||
QueueHandle_t tx_queue;
|
||||
QueueHandle_t rx_queue;
|
||||
int tx_msg_count;
|
||||
@ -97,12 +113,13 @@ static twai_hal_context_t twai_context;
|
||||
|
||||
/* -------------------- Interrupt and Alert Handlers ------------------------ */
|
||||
|
||||
static void twai_alert_handler(uint32_t alert_code, int *alert_req)
|
||||
TWAI_ISR_ATTR static void twai_alert_handler(uint32_t alert_code, int *alert_req)
|
||||
{
|
||||
if (p_twai_obj->alerts_enabled & alert_code) {
|
||||
//Signify alert has occurred
|
||||
TWAI_SET_FLAG(p_twai_obj->alerts_triggered, alert_code);
|
||||
*alert_req = 1;
|
||||
#ifndef CONFIG_TWAI_ISR_IN_IRAM //Only log if ISR is not in IRAM
|
||||
if (p_twai_obj->alerts_enabled & TWAI_ALERT_AND_LOG) {
|
||||
if (alert_code >= ALERT_LOG_LEVEL_ERROR) {
|
||||
ESP_EARLY_LOGE(TWAI_TAG, "Alert %d", alert_code);
|
||||
@ -112,6 +129,7 @@ static void twai_alert_handler(uint32_t alert_code, int *alert_req)
|
||||
ESP_EARLY_LOGI(TWAI_TAG, "Alert %d", alert_code);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +257,7 @@ static inline void twai_handle_tx_buffer_frame(BaseType_t *task_woken, int *aler
|
||||
}
|
||||
}
|
||||
|
||||
static void twai_intr_handler_main(void *arg)
|
||||
TWAI_ISR_ATTR static void twai_intr_handler_main(void *arg)
|
||||
{
|
||||
BaseType_t task_woken = pdFALSE;
|
||||
int alert_req = 0;
|
||||
@ -297,7 +315,7 @@ static void twai_intr_handler_main(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------- GPIO functions ------------------------------ */
|
||||
/* -------------------------- Helper functions ----------------------------- */
|
||||
|
||||
static void twai_configure_gpio(gpio_num_t tx, gpio_num_t rx, gpio_num_t clkout, gpio_num_t bus_status)
|
||||
{
|
||||
@ -327,6 +345,94 @@ static void twai_configure_gpio(gpio_num_t tx, gpio_num_t rx, gpio_num_t clkout,
|
||||
}
|
||||
}
|
||||
|
||||
static void twai_free_driver_obj(twai_obj_t *p_obj)
|
||||
{
|
||||
//Free driver object and any dependent SW resources it uses (queues, semaphores etc)
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (p_obj->pm_lock != NULL) {
|
||||
ESP_ERROR_CHECK(esp_pm_lock_delete(p_obj->pm_lock));
|
||||
}
|
||||
#endif
|
||||
//Delete queues and semaphores
|
||||
if (p_obj->tx_queue != NULL) {
|
||||
vQueueDelete(p_obj->tx_queue);
|
||||
}
|
||||
if (p_obj->rx_queue != NULL) {
|
||||
vQueueDelete(p_obj->rx_queue);
|
||||
}
|
||||
if (p_obj->alert_semphr != NULL) {
|
||||
vSemaphoreDelete(p_obj->alert_semphr);
|
||||
}
|
||||
#ifdef CONFIG_TWAI_ISR_IN_IRAM
|
||||
//Free memory used by static queues and semaphores. free() allows freeing NULL pointers
|
||||
free(p_obj->tx_queue_buff);
|
||||
free(p_obj->tx_queue_struct);
|
||||
free(p_obj->rx_queue_buff);
|
||||
free(p_obj->rx_queue_struct);
|
||||
free(p_obj->semphr_struct);
|
||||
#endif //CONFIG_TWAI_ISR_IN_IRAM
|
||||
free(p_obj);
|
||||
}
|
||||
|
||||
static twai_obj_t *twai_alloc_driver_obj(uint32_t tx_queue_len, uint32_t rx_queue_len)
|
||||
{
|
||||
//Allocates driver object and any dependent SW resources it uses (queues, semaphores etc)
|
||||
//Create a TWAI driver object
|
||||
twai_obj_t *p_obj = heap_caps_calloc(1, sizeof(twai_obj_t), TWAI_MALLOC_CAPS);
|
||||
if (p_obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#ifdef CONFIG_TWAI_ISR_IN_IRAM
|
||||
//Allocate memory for queues and semaphores in DRAM
|
||||
if (tx_queue_len > 0) {
|
||||
p_obj->tx_queue_buff = heap_caps_calloc(tx_queue_len, sizeof(twai_hal_frame_t), TWAI_MALLOC_CAPS);
|
||||
p_obj->tx_queue_struct = heap_caps_calloc(1, sizeof(StaticQueue_t), TWAI_MALLOC_CAPS);
|
||||
if (p_obj->tx_queue_buff == NULL || p_obj->tx_queue_struct == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
p_obj->rx_queue_buff = heap_caps_calloc(rx_queue_len, sizeof(twai_hal_frame_t), TWAI_MALLOC_CAPS);
|
||||
p_obj->rx_queue_struct = heap_caps_calloc(1, sizeof(StaticQueue_t), TWAI_MALLOC_CAPS);
|
||||
p_obj->semphr_struct = heap_caps_calloc(1, sizeof(StaticSemaphore_t), TWAI_MALLOC_CAPS);
|
||||
if (p_obj->rx_queue_buff == NULL || p_obj->rx_queue_struct == NULL || p_obj->semphr_struct == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
//Create static queues and semaphores
|
||||
if (tx_queue_len > 0) {
|
||||
p_obj->tx_queue = xQueueCreateStatic(tx_queue_len, sizeof(twai_hal_frame_t), p_obj->tx_queue_buff, p_obj->tx_queue_struct);
|
||||
if (p_obj->tx_queue == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
p_obj->rx_queue = xQueueCreateStatic(rx_queue_len, sizeof(twai_hal_frame_t), p_obj->rx_queue_buff, p_obj->rx_queue_struct);
|
||||
p_obj->alert_semphr = xSemaphoreCreateBinaryStatic(p_obj->semphr_struct);
|
||||
if (p_obj->rx_queue == NULL || p_obj->alert_semphr == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
#else //CONFIG_TWAI_ISR_IN_IRAM
|
||||
if (tx_queue_len > 0) {
|
||||
p_obj->tx_queue = xQueueCreate(tx_queue_len, sizeof(twai_hal_frame_t));
|
||||
}
|
||||
p_obj->rx_queue = xQueueCreate(rx_queue_len, sizeof(twai_hal_frame_t));
|
||||
p_obj->alert_semphr = xSemaphoreCreateBinary();
|
||||
if ((tx_queue_len > 0 && p_obj->tx_queue == NULL) || p_obj->rx_queue == NULL || p_obj->alert_semphr == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
#endif //CONFIG_TWAI_ISR_IN_IRAM
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_err_t pm_err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "twai", &(p_obj->pm_lock));
|
||||
if (pm_err != ESP_OK ) {
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
return p_obj;
|
||||
|
||||
cleanup:
|
||||
twai_free_driver_obj(p_obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ---------------------------- Public Functions ---------------------------- */
|
||||
|
||||
esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config)
|
||||
@ -338,33 +444,26 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
|
||||
TWAI_CHECK(g_config->rx_queue_len > 0, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(g_config->tx_io >= 0 && g_config->tx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(g_config->rx_io >= 0 && g_config->rx_io < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG);
|
||||
TWAI_CHECK(TWAI_BRP_IS_VALID(t_config->brp), ESP_ERR_INVALID_ARG);
|
||||
#if (CONFIG_ESP32_REV_MIN >= 2)
|
||||
TWAI_CHECK(t_config->brp >= TWAI_BRP_MIN && t_config->brp <= TWAI_BRP_MAX_ECO, ESP_ERR_INVALID_ARG);
|
||||
#else
|
||||
TWAI_CHECK(t_config->brp >= TWAI_BRP_MIN && t_config->brp <= TWAI_BRP_MAX, ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
#ifndef CONFIG_TWAI_ISR_IN_IRAM
|
||||
TWAI_CHECK(!(g_config->intr_flags & ESP_INTR_FLAG_IRAM), ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
TWAI_ENTER_CRITICAL();
|
||||
TWAI_CHECK_FROM_CRIT(p_twai_obj == NULL, ESP_ERR_INVALID_STATE);
|
||||
TWAI_EXIT_CRITICAL();
|
||||
|
||||
esp_err_t ret;
|
||||
twai_obj_t *p_twai_obj_dummy;
|
||||
|
||||
//Create a TWAI object
|
||||
p_twai_obj_dummy = calloc(1, sizeof(twai_obj_t));
|
||||
//Create a TWAI object (including queues and semaphores)
|
||||
p_twai_obj_dummy = twai_alloc_driver_obj(g_config->tx_queue_len, g_config->rx_queue_len);
|
||||
TWAI_CHECK(p_twai_obj_dummy != NULL, ESP_ERR_NO_MEM);
|
||||
|
||||
//Initialize queues, semaphores, and power management locks
|
||||
p_twai_obj_dummy->tx_queue = (g_config->tx_queue_len > 0) ? xQueueCreate(g_config->tx_queue_len, sizeof(twai_hal_frame_t)) : NULL;
|
||||
p_twai_obj_dummy->rx_queue = xQueueCreate(g_config->rx_queue_len, sizeof(twai_hal_frame_t));
|
||||
p_twai_obj_dummy->alert_semphr = xSemaphoreCreateBinary();
|
||||
if ((g_config->tx_queue_len > 0 && p_twai_obj_dummy->tx_queue == NULL) ||
|
||||
p_twai_obj_dummy->rx_queue == NULL || p_twai_obj_dummy->alert_semphr == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto err;
|
||||
}
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_err_t pm_err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "twai", &(p_twai_obj_dummy->pm_lock));
|
||||
if (pm_err != ESP_OK ) {
|
||||
ret = pm_err;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
//Initialize flags and variables. All other members are 0 initialized by calloc()
|
||||
//Initialize flags and variables. All other members are already set to zero by twai_alloc_driver_obj()
|
||||
p_twai_obj_dummy->control_flags = CTRL_FLAG_STOPPED;
|
||||
p_twai_obj_dummy->mode = g_config->mode;
|
||||
p_twai_obj_dummy->alerts_enabled = g_config->alerts_enabled;
|
||||
@ -389,35 +488,16 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
|
||||
|
||||
//Allocate GPIO and Interrupts
|
||||
twai_configure_gpio(g_config->tx_io, g_config->rx_io, g_config->clkout_io, g_config->bus_off_io);
|
||||
ESP_ERROR_CHECK(esp_intr_alloc(ETS_TWAI_INTR_SOURCE, 0, twai_intr_handler_main, NULL, &p_twai_obj->isr_handle));
|
||||
ESP_ERROR_CHECK(esp_intr_alloc(ETS_TWAI_INTR_SOURCE, g_config->intr_flags, twai_intr_handler_main, NULL, &p_twai_obj->isr_handle));
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
ESP_ERROR_CHECK(esp_pm_lock_acquire(p_twai_obj->pm_lock)); //Acquire pm_lock to keep APB clock at 80MHz
|
||||
#endif
|
||||
return ESP_OK; //TWAI module is still in reset mode, users need to call twai_start() afterwards
|
||||
|
||||
err:
|
||||
//Cleanup TWAI object and return error
|
||||
if (p_twai_obj_dummy != NULL) {
|
||||
if (p_twai_obj_dummy->tx_queue != NULL) {
|
||||
vQueueDelete(p_twai_obj_dummy->tx_queue);
|
||||
p_twai_obj_dummy->tx_queue = NULL;
|
||||
}
|
||||
if (p_twai_obj_dummy->rx_queue != NULL) {
|
||||
vQueueDelete(p_twai_obj_dummy->rx_queue);
|
||||
p_twai_obj_dummy->rx_queue = NULL;
|
||||
}
|
||||
if (p_twai_obj_dummy->alert_semphr != NULL) {
|
||||
vSemaphoreDelete(p_twai_obj_dummy->alert_semphr);
|
||||
p_twai_obj_dummy->alert_semphr = NULL;
|
||||
}
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
if (p_twai_obj_dummy->pm_lock != NULL) {
|
||||
ESP_ERROR_CHECK(esp_pm_lock_delete(p_twai_obj_dummy->pm_lock));
|
||||
}
|
||||
#endif
|
||||
free(p_twai_obj_dummy);
|
||||
}
|
||||
err:
|
||||
//Free can driver object
|
||||
twai_free_driver_obj(p_twai_obj_dummy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -439,19 +519,12 @@ esp_err_t twai_driver_uninstall(void)
|
||||
|
||||
ESP_ERROR_CHECK(esp_intr_free(p_twai_obj_dummy->isr_handle)); //Free interrupt
|
||||
|
||||
//Delete queues, semaphores, and power management locks
|
||||
if (p_twai_obj_dummy->tx_queue != NULL) {
|
||||
vQueueDelete(p_twai_obj_dummy->tx_queue);
|
||||
}
|
||||
vQueueDelete(p_twai_obj_dummy->rx_queue);
|
||||
vSemaphoreDelete(p_twai_obj_dummy->alert_semphr);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
//Release and delete power management lock
|
||||
ESP_ERROR_CHECK(esp_pm_lock_release(p_twai_obj_dummy->pm_lock));
|
||||
ESP_ERROR_CHECK(esp_pm_lock_delete(p_twai_obj_dummy->pm_lock));
|
||||
#endif
|
||||
free(p_twai_obj_dummy); //Free can driver object
|
||||
|
||||
//Free can driver object
|
||||
twai_free_driver_obj(p_twai_obj_dummy);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ idf_component_register(SRCS "src/cpu_util.c"
|
||||
"src/hal/wdt_hal_iram.c"
|
||||
"src/compare_set.c"
|
||||
"src/hal/twai_hal.c"
|
||||
"src/hal/twai_hal_iram.c"
|
||||
PRIV_REQUIRES ${target}
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
|
@ -20,6 +20,7 @@ extern "C" {
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**
|
||||
* @brief TWAI Constants
|
||||
@ -59,7 +60,7 @@ extern "C" {
|
||||
#define TWAI_TIMING_CONFIG_5KBITS() {.brp = 800, .tseg_1 = 15, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
|
||||
#define TWAI_TIMING_CONFIG_10KBITS() {.brp = 400, .tseg_1 = 15, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
|
||||
#endif
|
||||
#if (TWAI_BRP_MAX > 128)
|
||||
#if (TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN >= 2)
|
||||
#define TWAI_TIMING_CONFIG_12_5KBITS() {.brp = 256, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
|
||||
#define TWAI_TIMING_CONFIG_16KBITS() {.brp = 200, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
|
||||
#define TWAI_TIMING_CONFIG_20KBITS() {.brp = 200, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
|
||||
|
@ -25,3 +25,7 @@ entries:
|
||||
soc_hal (noflash)
|
||||
wdt_hal_iram (noflash)
|
||||
systimer_hal (noflash)
|
||||
if TWAI_ISR_IN_IRAM = y:
|
||||
twai_hal_iram (noflash)
|
||||
else:
|
||||
twai_hal_iram (default)
|
||||
|
@ -20,20 +20,12 @@ extern "C" {
|
||||
|
||||
#warning soc/can_caps.h is deprecated, please use soc/twai_caps.h instead
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/* ---------------------------- Compatibility ------------------------------- */
|
||||
|
||||
#if (CONFIG_ESP32_REV_MIN >= 2)
|
||||
#define CAN_BRP_DIV_SUPPORTED 1
|
||||
#define CAN_BRP_DIV_THRESH 128
|
||||
#define CAN_BRP_IS_VALID(brp) (((brp) >= 2 && (brp) <= 128 && ((brp) & 0x1) == 0) || ((brp) >= 132 && (brp) <= 256 && ((brp) & 0x3) == 0))
|
||||
#define CAN_BRP_MAX 256
|
||||
#else
|
||||
#define CAN_BRP_IS_VALID(brp) ((brp) >= 2 && (brp) <= 128 && ((brp) & 0x1) == 0)
|
||||
#define CAN_BRP_MAX 128
|
||||
#endif
|
||||
|
||||
#define CAN_BRP_MIN 2
|
||||
#define CAN_BRP_MAX 128
|
||||
#define CAN_BRP_MAX_ECO 256
|
||||
#define CAN_BRP_DIV_THRESH 128
|
||||
#define CAN_SUPPORT_MULTI_ADDRESS_LAYOUT 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -18,22 +18,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
//Chip specific TWAI related macros
|
||||
#if __DOXYGEN__ || (CONFIG_ESP32_REV_MIN >= 2)
|
||||
#define TWAI_BRP_DIV_SUPPORTED 1
|
||||
#define TWAI_BRP_DIV_THRESH 128
|
||||
//Any even number from 2 to 128, or multiples of 4 from 132 to 256
|
||||
#define TWAI_BRP_IS_VALID(brp) (((brp) >= 2 && (brp) <= 128 && ((brp) & 0x1) == 0) || ((brp) >= 132 && (brp) <= 256 && ((brp) & 0x3) == 0))
|
||||
#define TWAI_BRP_MAX 256
|
||||
#else
|
||||
//Any even number from 2 to 128
|
||||
#define TWAI_BRP_IS_VALID(brp) ((brp) >= 2 && (brp) <= 128 && ((brp) & 0x1) == 0)
|
||||
#define TWAI_BRP_MAX 128
|
||||
#endif
|
||||
|
||||
//Chip specific TWAI capabilities
|
||||
#define TWAI_BRP_MIN 2
|
||||
#define TWAI_BRP_MAX 128
|
||||
#define TWAI_BRP_MAX_ECO 256
|
||||
#define TWAI_BRP_DIV_THRESH 128
|
||||
#define TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -18,10 +18,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//Chip specific TWAI related macros
|
||||
//Any even number from 2 to 32768
|
||||
#define TWAI_BRP_IS_VALID(brp) ((brp) >= 2 && (brp) <= 32768 && ((brp) & 0x1) == 0)
|
||||
#define TWAI_BRP_MAX 32768
|
||||
#define TWAI_BRP_MIN 2
|
||||
#define TWAI_BRP_MAX 32768
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ typedef volatile struct twai_dev_s {
|
||||
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 reserved24: 23; /* Internal Reserved */
|
||||
uint32_t reserved23: 23; /* Internal Reserved */
|
||||
};
|
||||
uint32_t val;
|
||||
} status_reg; /* Address 2 */
|
||||
|
@ -38,7 +38,7 @@ extern "C" {
|
||||
#define CAN_MSG_FLAG_SELF TWAI_MSG_FLAG_SELF
|
||||
#define CAN_MSG_FLAG_DLC_NON_COMP TWAI_MSG_FLAG_DLC_NON_COMP
|
||||
|
||||
#if (TWAI_BRP_MAX > 128)
|
||||
#if (TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN >= 2)
|
||||
#define CAN_TIMING_CONFIG_12_5KBITS() TWAI_TIMING_CONFIG_12_5KBITS()
|
||||
#define CAN_TIMING_CONFIG_16KBITS() TWAI_TIMING_CONFIG_16KBITS()
|
||||
#define CAN_TIMING_CONFIG_20KBITS() TWAI_TIMING_CONFIG_20KBITS()
|
||||
|
@ -28,6 +28,7 @@ extern "C" {
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/twai_types.h"
|
||||
#include "soc/twai_periph.h"
|
||||
|
||||
@ -336,8 +337,8 @@ 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
|
||||
#if (CONFIG_ESP32_REV_MIN >= 2)
|
||||
//ESP32 Rev 2 or later has brp div field. Need to mask it out
|
||||
hw->interrupt_enable_reg.val = (hw->interrupt_enable_reg.val & 0x10) | intr_mask;
|
||||
#else
|
||||
hw->interrupt_enable_reg.val = intr_mask;
|
||||
@ -362,11 +363,13 @@ static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask)
|
||||
*/
|
||||
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 (CONFIG_ESP32_REV_MIN >= 2)
|
||||
if (brp > TWAI_BRP_DIV_THRESH) {
|
||||
//Need to set brp_div bit
|
||||
hw->interrupt_enable_reg.brp_div = 1;
|
||||
brp /= 2;
|
||||
} else {
|
||||
hw->interrupt_enable_reg.brp_div = 0;
|
||||
}
|
||||
#endif
|
||||
hw->bus_timing_0_reg.brp = (brp / 2) - 1;
|
||||
|
@ -78,70 +78,4 @@ bool twai_hal_stop(twai_hal_context_t *hal_ctx)
|
||||
(void) twai_ll_get_and_clear_intrs(hal_ctx->dev);
|
||||
twai_ll_set_mode(hal_ctx->dev, TWAI_MODE_LISTEN_ONLY); //Freeze REC by changing to LOM mode
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t twai_hal_decode_interrupt_events(twai_hal_context_t *hal_ctx, bool bus_recovering)
|
||||
{
|
||||
uint32_t events = 0;
|
||||
//Read interrupt, status
|
||||
uint32_t interrupts = twai_ll_get_and_clear_intrs(hal_ctx->dev);
|
||||
uint32_t status = twai_ll_get_status(hal_ctx->dev);
|
||||
uint32_t tec = twai_ll_get_tec(hal_ctx->dev);
|
||||
uint32_t rec = twai_ll_get_rec(hal_ctx->dev);
|
||||
|
||||
//Receive Interrupt set whenever RX FIFO is not empty
|
||||
if (interrupts & TWAI_LL_INTR_RI) {
|
||||
events |= TWAI_HAL_EVENT_RX_BUFF_FRAME;
|
||||
}
|
||||
//Transmit interrupt set whenever TX buffer becomes free
|
||||
if (interrupts & TWAI_LL_INTR_TI) {
|
||||
events |= TWAI_HAL_EVENT_TX_BUFF_FREE;
|
||||
}
|
||||
//Error Warning Interrupt set whenever Error or Bus Status bit changes
|
||||
if (interrupts & TWAI_LL_INTR_EI) {
|
||||
if (status & TWAI_LL_STATUS_BS) {
|
||||
//Currently in BUS OFF state
|
||||
//EWL is exceeded, thus must have entered BUS OFF
|
||||
//Below EWL. Therefore TEC is counting down in bus recovery
|
||||
//Todo: Check if BUS Recov can be removed for esp32s2
|
||||
events |= (status & TWAI_LL_STATUS_ES) ? TWAI_HAL_EVENT_BUS_OFF : TWAI_HAL_EVENT_BUS_RECOV_PROGRESS;
|
||||
} else {
|
||||
//Not in BUS OFF
|
||||
events |= (status & TWAI_LL_STATUS_ES) ? TWAI_HAL_EVENT_ABOVE_EWL : //Just Exceeded EWL
|
||||
((bus_recovering) ? //If previously undergoing bus recovery
|
||||
TWAI_HAL_EVENT_BUS_RECOV_CPLT :
|
||||
TWAI_HAL_EVENT_BELOW_EWL);
|
||||
}
|
||||
}
|
||||
//Error Passive Interrupt on transition from error active to passive or vice versa
|
||||
if (interrupts & TWAI_LL_INTR_EPI) {
|
||||
events |= (tec >= TWAI_ERR_PASS_THRESH || rec >= TWAI_ERR_PASS_THRESH) ? TWAI_HAL_EVENT_ERROR_PASSIVE : TWAI_HAL_EVENT_ERROR_ACTIVE;
|
||||
}
|
||||
//Arbitration Lost Interrupt triggered on losing arbitration
|
||||
if (interrupts & TWAI_LL_INTR_ALI) {
|
||||
events |= TWAI_HAL_EVENT_ARB_LOST;
|
||||
}
|
||||
//Bus error interrupt triggered on a bus error (e.g. bit, ACK, stuff etc)
|
||||
if (interrupts & TWAI_LL_INTR_BEI) {
|
||||
events |= TWAI_HAL_EVENT_BUS_ERR;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_frame_t *tx_frame)
|
||||
{
|
||||
//Copy frame into tx buffer
|
||||
twai_ll_set_tx_buffer(hal_ctx->dev, tx_frame);
|
||||
//Hit the send command
|
||||
if (tx_frame->self_reception) {
|
||||
if (tx_frame->single_shot) {
|
||||
twai_ll_set_cmd_self_rx_single_shot(hal_ctx->dev);
|
||||
} else {
|
||||
twai_ll_set_cmd_self_rx_request(hal_ctx->dev);
|
||||
}
|
||||
} else if (tx_frame->single_shot){
|
||||
twai_ll_set_cmd_tx_single_shot(hal_ctx->dev);
|
||||
} else {
|
||||
twai_ll_set_cmd_tx(hal_ctx->dev);
|
||||
}
|
||||
}
|
||||
}
|
82
components/soc/src/hal/twai_hal_iram.c
Normal file
82
components/soc/src/hal/twai_hal_iram.c
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2015-2019 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.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hal/twai_hal.h"
|
||||
|
||||
uint32_t twai_hal_decode_interrupt_events(twai_hal_context_t *hal_ctx, bool bus_recovering)
|
||||
{
|
||||
uint32_t events = 0;
|
||||
//Read interrupt, status
|
||||
uint32_t interrupts = twai_ll_get_and_clear_intrs(hal_ctx->dev);
|
||||
uint32_t status = twai_ll_get_status(hal_ctx->dev);
|
||||
uint32_t tec = twai_ll_get_tec(hal_ctx->dev);
|
||||
uint32_t rec = twai_ll_get_rec(hal_ctx->dev);
|
||||
|
||||
//Receive Interrupt set whenever RX FIFO is not empty
|
||||
if (interrupts & TWAI_LL_INTR_RI) {
|
||||
events |= TWAI_HAL_EVENT_RX_BUFF_FRAME;
|
||||
}
|
||||
//Transmit interrupt set whenever TX buffer becomes free
|
||||
if (interrupts & TWAI_LL_INTR_TI) {
|
||||
events |= TWAI_HAL_EVENT_TX_BUFF_FREE;
|
||||
}
|
||||
//Error Warning Interrupt set whenever Error or Bus Status bit changes
|
||||
if (interrupts & TWAI_LL_INTR_EI) {
|
||||
if (status & TWAI_LL_STATUS_BS) {
|
||||
//Currently in BUS OFF state
|
||||
//EWL is exceeded, thus must have entered BUS OFF
|
||||
//Below EWL. Therefore TEC is counting down in bus recovery
|
||||
//Todo: Check if BUS Recov can be removed for esp32s2
|
||||
events |= (status & TWAI_LL_STATUS_ES) ? TWAI_HAL_EVENT_BUS_OFF : TWAI_HAL_EVENT_BUS_RECOV_PROGRESS;
|
||||
} else {
|
||||
//Not in BUS OFF
|
||||
events |= (status & TWAI_LL_STATUS_ES) ? TWAI_HAL_EVENT_ABOVE_EWL : //Just Exceeded EWL
|
||||
((bus_recovering) ? //If previously undergoing bus recovery
|
||||
TWAI_HAL_EVENT_BUS_RECOV_CPLT :
|
||||
TWAI_HAL_EVENT_BELOW_EWL);
|
||||
}
|
||||
}
|
||||
//Error Passive Interrupt on transition from error active to passive or vice versa
|
||||
if (interrupts & TWAI_LL_INTR_EPI) {
|
||||
events |= (tec >= TWAI_ERR_PASS_THRESH || rec >= TWAI_ERR_PASS_THRESH) ? TWAI_HAL_EVENT_ERROR_PASSIVE : TWAI_HAL_EVENT_ERROR_ACTIVE;
|
||||
}
|
||||
//Arbitration Lost Interrupt triggered on losing arbitration
|
||||
if (interrupts & TWAI_LL_INTR_ALI) {
|
||||
events |= TWAI_HAL_EVENT_ARB_LOST;
|
||||
}
|
||||
//Bus error interrupt triggered on a bus error (e.g. bit, ACK, stuff etc)
|
||||
if (interrupts & TWAI_LL_INTR_BEI) {
|
||||
events |= TWAI_HAL_EVENT_BUS_ERR;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_frame_t *tx_frame)
|
||||
{
|
||||
//Copy frame into tx buffer
|
||||
twai_ll_set_tx_buffer(hal_ctx->dev, tx_frame);
|
||||
//Hit the send command
|
||||
if (tx_frame->self_reception) {
|
||||
if (tx_frame->single_shot) {
|
||||
twai_ll_set_cmd_self_rx_single_shot(hal_ctx->dev);
|
||||
} else {
|
||||
twai_ll_set_cmd_self_rx_request(hal_ctx->dev);
|
||||
}
|
||||
} else if (tx_frame->single_shot){
|
||||
twai_ll_set_cmd_tx_single_shot(hal_ctx->dev);
|
||||
} else {
|
||||
twai_ll_set_cmd_tx(hal_ctx->dev);
|
||||
}
|
||||
}
|
@ -151,7 +151,10 @@ The TWAI driver contains an alert feature that is used to notify the application
|
||||
The TWAI controller's **error warning limit** is used to preemptively warn the application of bus errors before the error passive state is reached. By default, the TWAI driver sets the **error warning limit** to **96**. The ``TWAI_ALERT_ABOVE_ERR_WARN`` is raised when the TEC or REC becomes larger then or equal to the error warning limit. The ``TWAI_ALERT_BELOW_ERR_WARN`` is raised when both TEC and REC return back to values below **96**.
|
||||
|
||||
.. note::
|
||||
When enabling alerts, the ``TWAI_ALERT_AND_LOG`` flag can be used to cause the TWAI driver to log any raised alerts to UART. The ``TWAI_ALERT_ALL`` and ``TWAI_ALERT_NONE`` macros can also be used to enable/disable all alerts during configuration/reconfiguration.
|
||||
When enabling alerts, the ``TWAI_ALERT_AND_LOG`` flag can be used to cause the TWAI driver to log any raised alerts to UART. However, alert logging is disabled and ``TWAI_ALERT_AND_LOG`` if the :ref:`CONFIG_TWAI_ISR_IN_IRAM` option is enabled (see :ref:`placing-isr-into-iram`).
|
||||
|
||||
.. note::
|
||||
The ``TWAI_ALERT_ALL`` and ``TWAI_ALERT_NONE`` macros can also be used to enable/disable all alerts during configuration/reconfiguration.
|
||||
|
||||
Bit Timing
|
||||
^^^^^^^^^^
|
||||
@ -232,6 +235,23 @@ Disabling TX Queue
|
||||
|
||||
The TX queue can be disabled during configuration by setting the ``tx_queue_len`` member of :cpp:type:`twai_general_config_t` to ``0``. This will allow applications that do not require message transmission to save a small amount of memory when using the TWAI driver.
|
||||
|
||||
.. _placing-isr-into-iram:
|
||||
|
||||
Placing ISR into IRAM
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The TWAI driver's ISR (Interrupt Service Routine) can be placed into IRAM so that the ISR can still run whilst the cache is disabled. Placing the ISR into IRAM may be necessary to maintain the TWAI driver's functionality during lengthy cache disabling operations (such as SPI Flash writes, OTA updates etc). Whilst the cache is disabled, the ISR will continue to:
|
||||
|
||||
- Read received messages from the RX buffer and place them into the driver's RX queue.
|
||||
- Load messages pending transmission from the driver's TX queue and write them into the TX buffer.
|
||||
|
||||
To place the TWAI driver's ISR, users must do the following:
|
||||
|
||||
- Enable the :ref:`CONFIG_TWAI_ISR_IN_IRAM` option using ``idf.py menuconfig``.
|
||||
- When calling :cpp:func:`twai_driver_install`, the `intr_flags` member of :cpp:type:`twai_general_config_t` should set the :c:macro:`ESP_INTR_FLAG_IRAM` set.
|
||||
|
||||
.. note::
|
||||
When the :ref:`CONFIG_TWAI_ISR_IN_IRAM` option is enabled, the TWAI driver will no longer log any alerts (i.e., the ``TWAI_ALERT_AND_LOG`` flag will not have any effect).
|
||||
|
||||
.. ------------------------------- TWAI Driver ---------------------------------
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user