|
|
@@ -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"
|
|
|
@@ -45,7 +47,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])
|
|
|
|
|
|
@@ -65,6 +74,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;
|
|
|
@@ -90,12 +106,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);
|
|
|
@@ -105,6 +122,7 @@ static void twai_alert_handler(uint32_t alert_code, int *alert_req)
|
|
|
ESP_EARLY_LOGI(TWAI_TAG, "Alert %d", alert_code);
|
|
|
}
|
|
|
}
|
|
|
+#endif //CONFIG_TWAI_ISR_IN_IRAM
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -154,7 +172,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;
|
|
|
@@ -180,7 +198,6 @@ static void twai_intr_handler_main(void *arg)
|
|
|
twai_alert_handler(TWAI_ALERT_BUS_OFF, &alert_req);
|
|
|
}
|
|
|
if (event & TWAI_HAL_EVENT_BUS_RECOV_CPLT) {
|
|
|
- //Reset and set flags to the equivalent of the stopped state
|
|
|
p_twai_obj->state = TWAI_STATE_STOPPED;
|
|
|
twai_alert_handler(TWAI_ALERT_BUS_RECOVERED, &alert_req);
|
|
|
}
|
|
|
@@ -194,7 +211,7 @@ static void twai_intr_handler_main(void *arg)
|
|
|
}
|
|
|
if (event & TWAI_HAL_EVENT_BUS_RECOV_PROGRESS) {
|
|
|
//Bus-recovery in progress. TEC has dropped below error warning limit
|
|
|
- twai_alert_handler(TWAI_ALERT_RECOVERY_IN_PROGRESS, &alert_req);
|
|
|
+ twai_alert_handler(TWAI_ALERT_RECOVERY_IN_PROGRESS, &alert_req);
|
|
|
}
|
|
|
if (event & TWAI_HAL_EVENT_ERROR_PASSIVE) {
|
|
|
//Entered error passive
|
|
|
@@ -224,7 +241,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)
|
|
|
{
|
|
|
@@ -254,6 +271,96 @@ 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)
|
|
|
@@ -270,33 +377,21 @@ esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_
|
|
|
#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->state = TWAI_STATE_STOPPED;
|
|
|
p_twai_obj_dummy->mode = g_config->mode;
|
|
|
p_twai_obj_dummy->alerts_enabled = g_config->alerts_enabled;
|
|
|
@@ -320,35 +415,15 @@ 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:
|
|
|
+ twai_free_driver_obj(p_twai_obj_dummy);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
@@ -369,19 +444,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;
|
|
|
}
|
|
|
|