mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 05:04:33 +02:00
Merge branch 'feature/high_level_interrupt_in_bluetooth' into 'master'
Bluetooth: High level interrupt in bluetooth See merge request espressif/esp-idf!11156
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
if(CONFIG_BT_ENABLED)
|
if(CONFIG_BT_ENABLED)
|
||||||
if(CONFIG_IDF_TARGET_ESP32)
|
if(CONFIG_IDF_TARGET_ESP32)
|
||||||
set(srcs "controller/esp32/bt.c")
|
set(srcs "controller/esp32/bt.c"
|
||||||
|
"controller/esp32/hli_api.c"
|
||||||
|
"controller/esp32/hli_vectors.S")
|
||||||
elseif(CONFIG_IDF_TARGET_ESP32C3)
|
elseif(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
set(srcs "controller/esp32c3/bt.c")
|
set(srcs "controller/esp32c3/bt.c")
|
||||||
elseif(CONFIG_IDF_TARGET_ESP32S3)
|
elseif(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
@@ -608,6 +610,8 @@ if(CONFIG_BT_ENABLED)
|
|||||||
if(CONFIG_IDF_TARGET_ESP32)
|
if(CONFIG_IDF_TARGET_ESP32)
|
||||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32/esp32")
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32/esp32")
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app)
|
target_link_libraries(${COMPONENT_LIB} PUBLIC btdm_app)
|
||||||
|
|
||||||
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u ld_include_hli_vectors_bt")
|
||||||
elseif(CONFIG_IDF_TARGET_ESP32C3)
|
elseif(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
||||||
"-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32c3")
|
"-L${CMAKE_CURRENT_LIST_DIR}/controller/lib_esp32c3_family/esp32c3")
|
||||||
|
@@ -10,6 +10,7 @@ COMPONENT_ADD_INCLUDEDIRS := include
|
|||||||
LIBS := btdm_app
|
LIBS := btdm_app
|
||||||
|
|
||||||
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/controller/lib_esp32/esp32 \
|
COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/controller/lib_esp32/esp32 \
|
||||||
|
-u ld_include_hli_vectors_bt \
|
||||||
$(addprefix -l,$(LIBS))
|
$(addprefix -l,$(LIBS))
|
||||||
|
|
||||||
# re-link program if BT binary libs change
|
# re-link program if BT binary libs change
|
||||||
|
@@ -415,3 +415,10 @@ config BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD
|
|||||||
of ADV packets lost in the controller reaches this threshold. It is better to set a larger value.
|
of ADV packets lost in the controller reaches this threshold. It is better to set a larger value.
|
||||||
If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it
|
If you set `BTDM_BLE_ADV_REPORT_DISCARD_THRSHOLD` to a small value or printf every adv lost event, it
|
||||||
may cause adv packets lost more.
|
may cause adv packets lost more.
|
||||||
|
|
||||||
|
config BTDM_CTRL_HLI
|
||||||
|
bool "High level interrupt"
|
||||||
|
depends on BT_ENABLED
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Using Level 4 interrupt for Bluetooth.
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
#include "driver/periph_ctrl.h"
|
#include "driver/periph_ctrl.h"
|
||||||
#include "soc/rtc.h"
|
#include "soc/rtc.h"
|
||||||
#include "soc/soc_memory_layout.h"
|
#include "soc/soc_memory_layout.h"
|
||||||
|
#include "soc/dport_reg.h"
|
||||||
#include "esp32/clk.h"
|
#include "esp32/clk.h"
|
||||||
#include "esp_coexist_internal.h"
|
#include "esp_coexist_internal.h"
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "esp_rom_sys.h"
|
#include "esp_rom_sys.h"
|
||||||
|
#include "hli_api.h"
|
||||||
|
|
||||||
#if CONFIG_BT_ENABLED
|
#if CONFIG_BT_ENABLED
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@
|
|||||||
************************************************************************
|
************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)(x)
|
||||||
#define BTDM_LOG_TAG "BTDM_INIT"
|
#define BTDM_LOG_TAG "BTDM_INIT"
|
||||||
|
|
||||||
#define BTDM_INIT_PERIOD (5000) /* ms */
|
#define BTDM_INIT_PERIOD (5000) /* ms */
|
||||||
@@ -92,7 +95,7 @@ do{\
|
|||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff
|
#define OSI_FUNCS_TIME_BLOCKING 0xffffffff
|
||||||
#define OSI_VERSION 0x00010002
|
#define OSI_VERSION 0x00010003
|
||||||
#define OSI_MAGIC_VALUE 0xFADEBEAD
|
#define OSI_MAGIC_VALUE 0xFADEBEAD
|
||||||
|
|
||||||
/* SPIRAM Configuration */
|
/* SPIRAM Configuration */
|
||||||
@@ -184,6 +187,10 @@ struct osi_funcs_t {
|
|||||||
void *(* _coex_schm_curr_phase_get)(void);
|
void *(* _coex_schm_curr_phase_get)(void);
|
||||||
int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary);
|
int (* _coex_wifi_channel_get)(uint8_t *primary, uint8_t *secondary);
|
||||||
int (* _coex_register_wifi_channel_change_callback)(void *cb);
|
int (* _coex_register_wifi_channel_change_callback)(void *cb);
|
||||||
|
xt_handler (*_set_isr_l3)(int n, xt_handler f, void *arg);
|
||||||
|
void (*_interrupt_l3_disable)(void);
|
||||||
|
void (*_interrupt_l3_restore)(void);
|
||||||
|
void *(* _customer_queue_create)(uint32_t queue_len, uint32_t item_size);
|
||||||
uint32_t _magic;
|
uint32_t _magic;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -268,8 +275,13 @@ extern uint32_t _btdm_data_end;
|
|||||||
static bool btdm_queue_generic_register(const btdm_queue_item_t *queue);
|
static bool btdm_queue_generic_register(const btdm_queue_item_t *queue);
|
||||||
static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue);
|
static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue);
|
||||||
#endif /* CONFIG_SPIRAM_USE_MALLOC */
|
#endif /* CONFIG_SPIRAM_USE_MALLOC */
|
||||||
static void IRAM_ATTR interrupt_disable(void);
|
|
||||||
static void IRAM_ATTR interrupt_restore(void);
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
static xt_handler set_isr_hlevel_wrapper(int n, xt_handler f, void *arg);
|
||||||
|
static void IRAM_ATTR interrupt_hlevel_disable(void);
|
||||||
|
static void IRAM_ATTR interrupt_hlevel_restore(void);
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
static void IRAM_ATTR task_yield(void);
|
||||||
static void IRAM_ATTR task_yield_from_isr(void);
|
static void IRAM_ATTR task_yield_from_isr(void);
|
||||||
static void *semphr_create_wrapper(uint32_t max, uint32_t init);
|
static void *semphr_create_wrapper(uint32_t max, uint32_t init);
|
||||||
static void semphr_delete_wrapper(void *semphr);
|
static void semphr_delete_wrapper(void *semphr);
|
||||||
@@ -281,12 +293,21 @@ static void *mutex_create_wrapper(void);
|
|||||||
static void mutex_delete_wrapper(void *mutex);
|
static void mutex_delete_wrapper(void *mutex);
|
||||||
static int32_t mutex_lock_wrapper(void *mutex);
|
static int32_t mutex_lock_wrapper(void *mutex);
|
||||||
static int32_t mutex_unlock_wrapper(void *mutex);
|
static int32_t mutex_unlock_wrapper(void *mutex);
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
|
||||||
|
static void queue_delete_hlevel_wrapper(void *queue);
|
||||||
|
static int32_t IRAM_ATTR queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
|
||||||
|
static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
|
||||||
|
static int32_t IRAM_ATTR queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms);
|
||||||
|
static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw);
|
||||||
|
#else
|
||||||
static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size);
|
static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size);
|
||||||
static void queue_delete_wrapper(void *queue);
|
static void queue_delete_wrapper(void *queue);
|
||||||
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
|
static int32_t IRAM_ATTR queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms);
|
||||||
static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw);
|
static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, void *hptw);
|
||||||
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
|
static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms);
|
||||||
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw);
|
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw);
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
|
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id);
|
||||||
static void task_delete_wrapper(void *task_handle);
|
static void task_delete_wrapper(void *task_handle);
|
||||||
static bool IRAM_ATTR is_in_isr_wrapper(void);
|
static bool IRAM_ATTR is_in_isr_wrapper(void);
|
||||||
@@ -317,17 +338,30 @@ static uint8_t coex_schm_curr_period_get_wrapper(void);
|
|||||||
static void * coex_schm_curr_phase_get_wrapper(void);
|
static void * coex_schm_curr_phase_get_wrapper(void);
|
||||||
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary);
|
static int coex_wifi_channel_get_wrapper(uint8_t *primary, uint8_t *secondary);
|
||||||
static int coex_register_wifi_channel_change_callback_wrapper(void *cb);
|
static int coex_register_wifi_channel_change_callback_wrapper(void *cb);
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size);
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
static void IRAM_ATTR interrupt_l3_disable(void);
|
||||||
|
static void IRAM_ATTR interrupt_l3_restore(void);
|
||||||
|
|
||||||
/* Local variable definition
|
/* Local variable definition
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
*/
|
*/
|
||||||
/* OSI funcs */
|
/* OSI funcs */
|
||||||
static const struct osi_funcs_t osi_funcs_ro = {
|
static const struct osi_funcs_t osi_funcs_ro = {
|
||||||
._version = OSI_VERSION,
|
._version = OSI_VERSION,
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
._set_isr = set_isr_hlevel_wrapper,
|
||||||
|
._ints_on = xt_ints_on,
|
||||||
|
._interrupt_disable = interrupt_hlevel_disable,
|
||||||
|
._interrupt_restore = interrupt_hlevel_restore,
|
||||||
|
#else
|
||||||
._set_isr = xt_set_interrupt_handler,
|
._set_isr = xt_set_interrupt_handler,
|
||||||
._ints_on = xt_ints_on,
|
._ints_on = xt_ints_on,
|
||||||
._interrupt_disable = interrupt_disable,
|
._interrupt_disable = interrupt_l3_disable,
|
||||||
._interrupt_restore = interrupt_restore,
|
._interrupt_restore = interrupt_l3_restore,
|
||||||
._task_yield = vPortYield,
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
._task_yield = task_yield,
|
||||||
._task_yield_from_isr = task_yield_from_isr,
|
._task_yield_from_isr = task_yield_from_isr,
|
||||||
._semphr_create = semphr_create_wrapper,
|
._semphr_create = semphr_create_wrapper,
|
||||||
._semphr_delete = semphr_delete_wrapper,
|
._semphr_delete = semphr_delete_wrapper,
|
||||||
@@ -339,12 +373,21 @@ static const struct osi_funcs_t osi_funcs_ro = {
|
|||||||
._mutex_delete = mutex_delete_wrapper,
|
._mutex_delete = mutex_delete_wrapper,
|
||||||
._mutex_lock = mutex_lock_wrapper,
|
._mutex_lock = mutex_lock_wrapper,
|
||||||
._mutex_unlock = mutex_unlock_wrapper,
|
._mutex_unlock = mutex_unlock_wrapper,
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
._queue_create = queue_create_hlevel_wrapper,
|
||||||
|
._queue_delete = queue_delete_hlevel_wrapper,
|
||||||
|
._queue_send = queue_send_hlevel_wrapper,
|
||||||
|
._queue_send_from_isr = queue_send_from_isr_hlevel_wrapper,
|
||||||
|
._queue_recv = queue_recv_hlevel_wrapper,
|
||||||
|
._queue_recv_from_isr = queue_recv_from_isr_hlevel_wrapper,
|
||||||
|
#else
|
||||||
._queue_create = queue_create_wrapper,
|
._queue_create = queue_create_wrapper,
|
||||||
._queue_delete = queue_delete_wrapper,
|
._queue_delete = queue_delete_wrapper,
|
||||||
._queue_send = queue_send_wrapper,
|
._queue_send = queue_send_wrapper,
|
||||||
._queue_send_from_isr = queue_send_from_isr_wrapper,
|
._queue_send_from_isr = queue_send_from_isr_wrapper,
|
||||||
._queue_recv = queue_recv_wrapper,
|
._queue_recv = queue_recv_wrapper,
|
||||||
._queue_recv_from_isr = queue_recv_from_isr_wrapper,
|
._queue_recv_from_isr = queue_recv_from_isr_wrapper,
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
._task_create = task_create_wrapper,
|
._task_create = task_create_wrapper,
|
||||||
._task_delete = task_delete_wrapper,
|
._task_delete = task_delete_wrapper,
|
||||||
._is_in_isr = is_in_isr_wrapper,
|
._is_in_isr = is_in_isr_wrapper,
|
||||||
@@ -378,6 +421,14 @@ static const struct osi_funcs_t osi_funcs_ro = {
|
|||||||
._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper,
|
._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper,
|
||||||
._coex_wifi_channel_get = coex_wifi_channel_get_wrapper,
|
._coex_wifi_channel_get = coex_wifi_channel_get_wrapper,
|
||||||
._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper,
|
._coex_register_wifi_channel_change_callback = coex_register_wifi_channel_change_callback_wrapper,
|
||||||
|
._set_isr_l3 = xt_set_interrupt_handler,
|
||||||
|
._interrupt_l3_disable = interrupt_l3_disable,
|
||||||
|
._interrupt_l3_restore = interrupt_l3_restore,
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
._customer_queue_create = customer_queue_create_hlevel_wrapper,
|
||||||
|
#else
|
||||||
|
._customer_queue_create = NULL,
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
._magic = OSI_MAGIC_VALUE,
|
._magic = OSI_MAGIC_VALUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -494,7 +545,48 @@ static bool btdm_queue_generic_deregister(btdm_queue_item_t *queue)
|
|||||||
|
|
||||||
#endif /* CONFIG_SPIRAM_USE_MALLOC */
|
#endif /* CONFIG_SPIRAM_USE_MALLOC */
|
||||||
|
|
||||||
static void IRAM_ATTR interrupt_disable(void)
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
struct interrupt_hlevel_cb{
|
||||||
|
uint32_t status;
|
||||||
|
uint8_t nested;
|
||||||
|
};
|
||||||
|
|
||||||
|
static DRAM_ATTR struct interrupt_hlevel_cb hli_cb = {
|
||||||
|
.status = 0,
|
||||||
|
.nested = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static xt_handler set_isr_hlevel_wrapper(int mask, xt_handler f, void *arg)
|
||||||
|
{
|
||||||
|
esp_err_t err = hli_intr_register((intr_handler_t) f, arg, DPORT_PRO_INTR_STATUS_0_REG, mask);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
return f;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR interrupt_hlevel_disable(void)
|
||||||
|
{
|
||||||
|
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
|
||||||
|
assert(hli_cb.nested != ~0);
|
||||||
|
uint32_t status = hli_intr_disable();
|
||||||
|
if (hli_cb.nested++ == 0) {
|
||||||
|
hli_cb.status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR interrupt_hlevel_restore(void)
|
||||||
|
{
|
||||||
|
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
|
||||||
|
assert(hli_cb.nested > 0);
|
||||||
|
if (--hli_cb.nested == 0) {
|
||||||
|
hli_intr_restore(hli_cb.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
|
static void IRAM_ATTR interrupt_l3_disable(void)
|
||||||
{
|
{
|
||||||
if (xPortInIsrContext()) {
|
if (xPortInIsrContext()) {
|
||||||
portENTER_CRITICAL_ISR(&global_int_mux);
|
portENTER_CRITICAL_ISR(&global_int_mux);
|
||||||
@@ -503,7 +595,7 @@ static void IRAM_ATTR interrupt_disable(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void IRAM_ATTR interrupt_restore(void)
|
static void IRAM_ATTR interrupt_l3_restore(void)
|
||||||
{
|
{
|
||||||
if (xPortInIsrContext()) {
|
if (xPortInIsrContext()) {
|
||||||
portEXIT_CRITICAL_ISR(&global_int_mux);
|
portEXIT_CRITICAL_ISR(&global_int_mux);
|
||||||
@@ -512,6 +604,12 @@ static void IRAM_ATTR interrupt_restore(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR task_yield(void)
|
||||||
|
{
|
||||||
|
vPortYield();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void IRAM_ATTR task_yield_from_isr(void)
|
static void IRAM_ATTR task_yield_from_isr(void)
|
||||||
{
|
{
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
@@ -519,18 +617,19 @@ static void IRAM_ATTR task_yield_from_isr(void)
|
|||||||
|
|
||||||
static void *semphr_create_wrapper(uint32_t max, uint32_t init)
|
static void *semphr_create_wrapper(uint32_t max, uint32_t init)
|
||||||
{
|
{
|
||||||
|
void *handle = NULL;
|
||||||
|
|
||||||
#if !CONFIG_SPIRAM_USE_MALLOC
|
#if !CONFIG_SPIRAM_USE_MALLOC
|
||||||
return (void *)xSemaphoreCreateCounting(max, init);
|
handle = (void *)xSemaphoreCreateCounting(max, init);
|
||||||
#else
|
#else
|
||||||
StaticQueue_t *queue_buffer = NULL;
|
StaticQueue_t *queue_buffer = NULL;
|
||||||
QueueHandle_t handle = NULL;
|
|
||||||
|
|
||||||
queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
queue_buffer = heap_caps_malloc(sizeof(StaticQueue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
||||||
if (!queue_buffer) {
|
if (!queue_buffer) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle = xSemaphoreCreateCountingStatic(max, init, queue_buffer);
|
handle = (void *)xSemaphoreCreateCountingStatic(max, init, queue_buffer);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -544,8 +643,19 @@ static void *semphr_create_wrapper(uint32_t max, uint32_t init)
|
|||||||
if (!btdm_queue_generic_register(&item)) {
|
if (!btdm_queue_generic_register(&item)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
return handle;
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
SemaphoreHandle_t downstream_semaphore = handle;
|
||||||
|
assert(downstream_semaphore);
|
||||||
|
hli_queue_handle_t s_semaphore = hli_semaphore_create(max, downstream_semaphore);
|
||||||
|
assert(downstream_semaphore);
|
||||||
|
return s_semaphore;
|
||||||
|
#else
|
||||||
|
return handle;
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
|
#if CONFIG_SPIRAM_USE_MALLOC
|
||||||
error:
|
error:
|
||||||
if (handle) {
|
if (handle) {
|
||||||
vSemaphoreDelete(handle);
|
vSemaphoreDelete(handle);
|
||||||
@@ -560,11 +670,22 @@ static void *semphr_create_wrapper(uint32_t max, uint32_t init)
|
|||||||
|
|
||||||
static void semphr_delete_wrapper(void *semphr)
|
static void semphr_delete_wrapper(void *semphr)
|
||||||
{
|
{
|
||||||
|
void *handle = NULL;
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
if (((hli_queue_handle_t)semphr)->downstream != NULL) {
|
||||||
|
handle = ((hli_queue_handle_t)semphr)->downstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
hli_queue_delete(semphr);
|
||||||
|
#else
|
||||||
|
handle = semphr;
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
#if !CONFIG_SPIRAM_USE_MALLOC
|
#if !CONFIG_SPIRAM_USE_MALLOC
|
||||||
vSemaphoreDelete(semphr);
|
vSemaphoreDelete(handle);
|
||||||
#else
|
#else
|
||||||
btdm_queue_item_t item = {
|
btdm_queue_item_t item = {
|
||||||
.handle = semphr,
|
.handle = handle,
|
||||||
.storage = NULL,
|
.storage = NULL,
|
||||||
.buffer = NULL,
|
.buffer = NULL,
|
||||||
};
|
};
|
||||||
@@ -573,33 +694,55 @@ static void semphr_delete_wrapper(void *semphr)
|
|||||||
vSemaphoreDelete(item.handle);
|
vSemaphoreDelete(item.handle);
|
||||||
free(item.buffer);
|
free(item.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw)
|
static int32_t IRAM_ATTR semphr_take_from_isr_wrapper(void *semphr, void *hptw)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
return (int32_t)xSemaphoreTakeFromISR(((hli_queue_handle_t)semphr)->downstream, hptw);
|
||||||
|
#else
|
||||||
return (int32_t)xSemaphoreTakeFromISR(semphr, hptw);
|
return (int32_t)xSemaphoreTakeFromISR(semphr, hptw);
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
|
static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
UNUSED(hptw);
|
||||||
|
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
|
||||||
|
return hli_semaphore_give(semphr);
|
||||||
|
#else
|
||||||
return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
|
return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
|
static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
|
||||||
{
|
{
|
||||||
|
bool ret;
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
||||||
return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY);
|
ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, portMAX_DELAY);
|
||||||
} else {
|
} else {
|
||||||
return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
|
ret = xSemaphoreTake(((hli_queue_handle_t)semphr)->downstream, block_time_ms / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
||||||
|
ret = xSemaphoreTake(semphr, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
ret = xSemaphoreTake(semphr, block_time_ms / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
return (int32_t)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t semphr_give_wrapper(void *semphr)
|
static int32_t semphr_give_wrapper(void *semphr)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
return (int32_t)xSemaphoreGive(((hli_queue_handle_t)semphr)->downstream);
|
||||||
|
#else
|
||||||
return (int32_t)xSemaphoreGive(semphr);
|
return (int32_t)xSemaphoreGive(semphr);
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *mutex_create_wrapper(void)
|
static void *mutex_create_wrapper(void)
|
||||||
@@ -745,6 +888,79 @@ static void queue_delete_wrapper(void *queue)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
static void *queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
|
||||||
|
{
|
||||||
|
QueueHandle_t downstream_queue = queue_create_wrapper(queue_len, item_size);
|
||||||
|
assert(downstream_queue);
|
||||||
|
hli_queue_handle_t queue = hli_queue_create(queue_len, item_size, downstream_queue);
|
||||||
|
assert(queue);
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *customer_queue_create_hlevel_wrapper(uint32_t queue_len, uint32_t item_size)
|
||||||
|
{
|
||||||
|
QueueHandle_t downstream_queue = queue_create_wrapper(queue_len, item_size);
|
||||||
|
assert(downstream_queue);
|
||||||
|
hli_queue_handle_t queue = hli_customer_queue_create(queue_len, item_size, downstream_queue);
|
||||||
|
assert(queue);
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queue_delete_hlevel_wrapper(void *queue)
|
||||||
|
{
|
||||||
|
if (((hli_queue_handle_t)queue)->downstream != NULL) {
|
||||||
|
queue_delete_wrapper(((hli_queue_handle_t)queue)->downstream);
|
||||||
|
}
|
||||||
|
hli_queue_delete(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t queue_send_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
|
||||||
|
{
|
||||||
|
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
||||||
|
return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
return (int32_t)xQueueSend(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue send from isr
|
||||||
|
* @param queue The queue which will send to
|
||||||
|
* @param item The message which will be send
|
||||||
|
* @param hptw need do task yield or not
|
||||||
|
* @return send success or not
|
||||||
|
* There is an issue here: When the queue is full, it may reture true but it send fail to the queue, sometimes.
|
||||||
|
* But in Bluetooth controller's isr, We don't care about the return value.
|
||||||
|
* It only required tp send success when the queue is empty all the time.
|
||||||
|
* So, this function meets the requirement.
|
||||||
|
*/
|
||||||
|
static int32_t IRAM_ATTR queue_send_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
|
||||||
|
{
|
||||||
|
UNUSED(hptw);
|
||||||
|
assert(xPortGetCoreID() == CONFIG_BTDM_CTRL_PINNED_TO_CORE);
|
||||||
|
return hli_queue_put(queue, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t queue_recv_hlevel_wrapper(void *queue, void *item, uint32_t block_time_ms)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
||||||
|
ret = xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
ret = xQueueReceive(((hli_queue_handle_t)queue)->downstream, item, block_time_ms / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int32_t)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t IRAM_ATTR queue_recv_from_isr_hlevel_wrapper(void *queue, void *item, void *hptw)
|
||||||
|
{
|
||||||
|
return (int32_t)xQueueReceiveFromISR(((hli_queue_handle_t)queue)->downstream, item, hptw);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms)
|
static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_ms)
|
||||||
{
|
{
|
||||||
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
||||||
@@ -760,18 +976,23 @@ static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, vo
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms)
|
static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_ms)
|
||||||
{
|
{
|
||||||
|
bool ret;
|
||||||
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
if (block_time_ms == OSI_FUNCS_TIME_BLOCKING) {
|
||||||
return (int32_t)xQueueReceive(queue, item, portMAX_DELAY);
|
ret = xQueueReceive(queue, item, portMAX_DELAY);
|
||||||
} else {
|
} else {
|
||||||
return (int32_t)xQueueReceive(queue, item, block_time_ms / portTICK_PERIOD_MS);
|
ret = xQueueReceive(queue, item, block_time_ms / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return (int32_t)ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw)
|
static int32_t IRAM_ATTR queue_recv_from_isr_wrapper(void *queue, void *item, void *hptw)
|
||||||
{
|
{
|
||||||
return (int32_t)xQueueReceiveFromISR(queue, item, hptw);
|
return (int32_t)xQueueReceiveFromISR(queue, item, hptw);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
|
|
||||||
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
|
static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
|
||||||
{
|
{
|
||||||
@@ -1317,11 +1538,35 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
static void hli_queue_setup_cb(void* arg)
|
||||||
|
{
|
||||||
|
hli_queue_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hli_queue_setup_pinned_to_core(int core_id)
|
||||||
|
{
|
||||||
|
#if CONFIG_FREERTOS_UNICORE
|
||||||
|
hli_queue_setup_cb(NULL);
|
||||||
|
#else /* CONFIG_FREERTOS_UNICORE */
|
||||||
|
if (xPortGetCoreID() == core_id) {
|
||||||
|
hli_queue_setup_cb(NULL);
|
||||||
|
} else {
|
||||||
|
esp_ipc_call(core_id, hli_queue_setup_cb, NULL);
|
||||||
|
}
|
||||||
|
#endif /* !CONFIG_FREERTOS_UNICORE */
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)
|
||||||
{
|
{
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
uint32_t btdm_cfg_mask = 0;
|
uint32_t btdm_cfg_mask = 0;
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
hli_queue_setup_pinned_to_core(CONFIG_BTDM_CTRL_PINNED_TO_CORE);
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
//if all the bt available memory was already released, cannot initialize bluetooth controller
|
//if all the bt available memory was already released, cannot initialize bluetooth controller
|
||||||
if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) {
|
if (btdm_dram_available_region[0].mode == ESP_BT_MODE_IDLE) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
@@ -1736,4 +1981,15 @@ esp_err_t esp_ble_scan_dupilcate_list_flush(void)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function re-write controller's function,
|
||||||
|
* As coredump can not show paramerters in function which is in a .a file.
|
||||||
|
*
|
||||||
|
* After coredump fixing this issue, just delete this function.
|
||||||
|
*/
|
||||||
|
void IRAM_ATTR r_assert(const char *condition, int param0, int param1, const char *file, int line)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__("ill\n");
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_BT_ENABLED */
|
#endif /* CONFIG_BT_ENABLED */
|
||||||
|
306
components/bt/controller/esp32/hli_api.c
Normal file
306
components/bt/controller/esp32/hli_api.c
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
// Copyright 2015-2021 Espressif Systems (Shanghai) CO 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 <string.h>
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "xtensa/core-macros.h"
|
||||||
|
#include "soc/dport_reg.h"
|
||||||
|
#include "hli_api.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
#define HLI_MAX_HANDLERS 4
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
intr_handler_t handler;
|
||||||
|
void* arg;
|
||||||
|
uint32_t intr_reg;
|
||||||
|
uint32_t intr_mask;
|
||||||
|
} hli_handler_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#define CUSTOMER_TYPE_REQUEST (0)
|
||||||
|
#define CUSTOMER_TYPE_RELEASE (1)
|
||||||
|
struct {
|
||||||
|
uint32_t cb_type;
|
||||||
|
union {
|
||||||
|
int (* request)(uint32_t, uint32_t, uint32_t);
|
||||||
|
int (* release)(uint32_t);
|
||||||
|
} cb;
|
||||||
|
} customer_cb;
|
||||||
|
uint32_t arg0, arg1, arg2;
|
||||||
|
} customer_swisr_t;
|
||||||
|
|
||||||
|
static void IRAM_ATTR customer_swisr_handle(customer_swisr_t *cus_swisr)
|
||||||
|
{
|
||||||
|
if (cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_REQUEST) {
|
||||||
|
if (cus_swisr->customer_cb.cb.request != NULL) {
|
||||||
|
cus_swisr->customer_cb.cb.request(cus_swisr->arg0, cus_swisr->arg1, cus_swisr->arg2);
|
||||||
|
}
|
||||||
|
} else if(cus_swisr->customer_cb.cb_type == CUSTOMER_TYPE_RELEASE) {
|
||||||
|
if (cus_swisr->customer_cb.cb.release != NULL) {
|
||||||
|
cus_swisr->customer_cb.cb.release(cus_swisr->arg0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DRAM_ATTR hli_handler_info_t s_hli_handlers[HLI_MAX_HANDLERS];
|
||||||
|
|
||||||
|
esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask)
|
||||||
|
{
|
||||||
|
for (hli_handler_info_t* hip = s_hli_handlers;
|
||||||
|
hip < s_hli_handlers + HLI_MAX_HANDLERS;
|
||||||
|
++hip) {
|
||||||
|
if (hip->handler == NULL) {
|
||||||
|
hip->arg = arg;
|
||||||
|
hip->intr_reg = intr_reg;
|
||||||
|
hip->intr_mask = intr_mask;
|
||||||
|
hip->handler = handler; /* set last, indicates the entry as valid */
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR hli_c_handler(void)
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
/* Iterate over registered interrupt handlers,
|
||||||
|
* and check if the expected mask is present in the interrupt status register.
|
||||||
|
*/
|
||||||
|
for (hli_handler_info_t* hip = s_hli_handlers;
|
||||||
|
hip < s_hli_handlers + HLI_MAX_HANDLERS;
|
||||||
|
++hip) {
|
||||||
|
if (hip->handler == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint32_t reg = hip->intr_reg;
|
||||||
|
uint32_t val;
|
||||||
|
if (reg == 0) { /* special case for CPU internal interrupts */
|
||||||
|
val = XTHAL_GET_INTERRUPT();
|
||||||
|
} else {
|
||||||
|
/* "reg" might not be in DPORT, but this will work in any case */
|
||||||
|
val = DPORT_REG_READ(reg);
|
||||||
|
}
|
||||||
|
if ((val & hip->intr_mask) != 0) {
|
||||||
|
handled = true;
|
||||||
|
(*hip->handler)(hip->arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!handled) {
|
||||||
|
/* no handler found, it is OK in this case. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t IRAM_ATTR hli_intr_disable(void)
|
||||||
|
{
|
||||||
|
/* disable level 4 and below */
|
||||||
|
return XTOS_SET_INTLEVEL(XCHAL_DEBUGLEVEL - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR hli_intr_restore(uint32_t state)
|
||||||
|
{
|
||||||
|
XTOS_RESTORE_JUST_INTLEVEL(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HLI_META_QUEUE_SIZE 16
|
||||||
|
#define HLI_QUEUE_MAX_ELEM_SIZE 32
|
||||||
|
#define HLI_QUEUE_SW_INT_NUM 29
|
||||||
|
|
||||||
|
#define HLI_QUEUE_FLAG_SEMAPHORE BIT(0)
|
||||||
|
#define HLI_QUEUE_FLAG_CUSTOMER BIT(1)
|
||||||
|
|
||||||
|
static DRAM_ATTR struct hli_queue_t *s_meta_queue_ptr = NULL;
|
||||||
|
static intr_handle_t ret_handle;
|
||||||
|
|
||||||
|
static inline char* IRAM_ATTR wrap_ptr(hli_queue_handle_t queue, char *ptr)
|
||||||
|
{
|
||||||
|
return (ptr == queue->bufend) ? queue->buf : ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool IRAM_ATTR queue_empty(hli_queue_handle_t queue)
|
||||||
|
{
|
||||||
|
return queue->begin == queue->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool IRAM_ATTR queue_full(hli_queue_handle_t queue)
|
||||||
|
{
|
||||||
|
return wrap_ptr(queue, queue->end + queue->elem_size) == queue->begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IRAM_ATTR queue_isr_handler(void* arg)
|
||||||
|
{
|
||||||
|
int do_yield = pdFALSE;
|
||||||
|
XTHAL_SET_INTCLEAR(BIT(HLI_QUEUE_SW_INT_NUM));
|
||||||
|
hli_queue_handle_t queue;
|
||||||
|
|
||||||
|
while (hli_queue_get(s_meta_queue_ptr, &queue)) {
|
||||||
|
static DRAM_ATTR char scratch[HLI_QUEUE_MAX_ELEM_SIZE];
|
||||||
|
while (hli_queue_get(queue, scratch)) {
|
||||||
|
int res = pdPASS;
|
||||||
|
if ((queue->flags & HLI_QUEUE_FLAG_CUSTOMER) != 0) {
|
||||||
|
customer_swisr_handle((customer_swisr_t *)scratch);
|
||||||
|
} else if ((queue->flags & HLI_QUEUE_FLAG_SEMAPHORE) != 0) {
|
||||||
|
res = xSemaphoreGiveFromISR((SemaphoreHandle_t) queue->downstream, &do_yield);
|
||||||
|
} else {
|
||||||
|
res = xQueueSendFromISR(queue->downstream, scratch, &do_yield);
|
||||||
|
}
|
||||||
|
if (res == pdFAIL) {
|
||||||
|
/* Failed to send to downstream queue, it is OK in this case. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (do_yield) {
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify the level 3 handler that an element is added to the given hli queue.
|
||||||
|
* Do this by placing the queue handle onto s_meta_queue, and raising a SW interrupt.
|
||||||
|
*
|
||||||
|
* This function must be called with HL interrupts disabled!
|
||||||
|
*/
|
||||||
|
static void IRAM_ATTR queue_signal(hli_queue_handle_t queue)
|
||||||
|
{
|
||||||
|
/* See if the queue is already in s_meta_queue, before adding */
|
||||||
|
bool found = false;
|
||||||
|
const hli_queue_handle_t *end = (hli_queue_handle_t*) s_meta_queue_ptr->end;
|
||||||
|
hli_queue_handle_t *item = (hli_queue_handle_t*) s_meta_queue_ptr->begin;
|
||||||
|
for (;item != end; item = (hli_queue_handle_t*) wrap_ptr(s_meta_queue_ptr, (char*) (item + 1))) {
|
||||||
|
if (*item == queue) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
bool res = hli_queue_put(s_meta_queue_ptr, &queue);
|
||||||
|
if (!res) {
|
||||||
|
esp_rom_printf(DRAM_STR("Fatal error in queue_signal: s_meta_queue full\n"));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
XTHAL_SET_INTSET(BIT(HLI_QUEUE_SW_INT_NUM));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queue_init(hli_queue_handle_t queue, size_t buf_size, size_t elem_size, QueueHandle_t downstream)
|
||||||
|
{
|
||||||
|
queue->elem_size = elem_size;
|
||||||
|
queue->begin = queue->buf;
|
||||||
|
queue->end = queue->buf;
|
||||||
|
queue->bufend = queue->buf + buf_size;
|
||||||
|
queue->downstream = downstream;
|
||||||
|
queue->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hli_queue_setup(void)
|
||||||
|
{
|
||||||
|
if (s_meta_queue_ptr == NULL) {
|
||||||
|
s_meta_queue_ptr = hli_queue_create(HLI_META_QUEUE_SIZE, sizeof(void*), NULL);
|
||||||
|
ESP_ERROR_CHECK(esp_intr_alloc(ETS_INTERNAL_SW1_INTR_SOURCE, ESP_INTR_FLAG_IRAM, queue_isr_handler, NULL, &ret_handle));
|
||||||
|
xt_ints_on(BIT(HLI_QUEUE_SW_INT_NUM));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hli_queue_shutdown(void)
|
||||||
|
{
|
||||||
|
if (s_meta_queue_ptr != NULL) {
|
||||||
|
hli_queue_delete(s_meta_queue_ptr);
|
||||||
|
s_meta_queue_ptr = NULL;
|
||||||
|
esp_intr_free(ret_handle);
|
||||||
|
xt_ints_off(BIT(HLI_QUEUE_SW_INT_NUM));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
|
||||||
|
{
|
||||||
|
const size_t buf_elem = nelem + 1;
|
||||||
|
if (elem_size > HLI_QUEUE_MAX_ELEM_SIZE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t buf_size = buf_elem * elem_size;
|
||||||
|
hli_queue_handle_t res = (hli_queue_handle_t) heap_caps_malloc(sizeof(struct hli_queue_t) + buf_size,
|
||||||
|
MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
|
||||||
|
if (res == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
queue_init(res, buf_size, elem_size, downstream);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream)
|
||||||
|
{
|
||||||
|
hli_queue_handle_t res = hli_queue_create(nelem, elem_size, (QueueHandle_t) downstream);
|
||||||
|
if (res == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
res->flags |= HLI_QUEUE_FLAG_CUSTOMER;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream)
|
||||||
|
{
|
||||||
|
const size_t elem_size = 1;
|
||||||
|
hli_queue_handle_t res = hli_queue_create(max_count, elem_size, (QueueHandle_t) downstream);
|
||||||
|
if (res == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
res->flags |= HLI_QUEUE_FLAG_SEMAPHORE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hli_queue_delete(hli_queue_handle_t queue)
|
||||||
|
{
|
||||||
|
free(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRAM_ATTR hli_queue_get(hli_queue_handle_t queue, void* out)
|
||||||
|
{
|
||||||
|
uint32_t int_state = hli_intr_disable();
|
||||||
|
bool res = false;
|
||||||
|
if (!queue_empty(queue)) {
|
||||||
|
memcpy(out, queue->begin, queue->elem_size);
|
||||||
|
queue->begin = wrap_ptr(queue, queue->begin + queue->elem_size);
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
hli_intr_restore(int_state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRAM_ATTR hli_queue_put(hli_queue_handle_t queue, const void* data)
|
||||||
|
{
|
||||||
|
uint32_t int_state = hli_intr_disable();
|
||||||
|
bool res = false;
|
||||||
|
bool was_empty = queue_empty(queue);
|
||||||
|
if (!queue_full(queue)) {
|
||||||
|
memcpy(queue->end, data, queue->elem_size);
|
||||||
|
queue->end = wrap_ptr(queue, queue->end + queue->elem_size);
|
||||||
|
if (was_empty && queue != s_meta_queue_ptr) {
|
||||||
|
queue_signal(queue);
|
||||||
|
}
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
hli_intr_restore(int_state);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRAM_ATTR hli_semaphore_give(hli_queue_handle_t queue)
|
||||||
|
{
|
||||||
|
uint8_t data = 0;
|
||||||
|
return hli_queue_put(queue, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
176
components/bt/controller/esp32/hli_api.h
Normal file
176
components/bt/controller/esp32/hli_api.h
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2015-2021 Espressif Systems (Shanghai) CO 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.
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_intr_alloc.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
|
||||||
|
/*** Queues ***/
|
||||||
|
|
||||||
|
struct hli_queue_t
|
||||||
|
{
|
||||||
|
size_t elem_size;
|
||||||
|
char* begin;
|
||||||
|
char* end;
|
||||||
|
const char* bufend;
|
||||||
|
QueueHandle_t downstream;
|
||||||
|
int flags;
|
||||||
|
char buf[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a high level interrupt function
|
||||||
|
*
|
||||||
|
* @param handler interrupt handler function
|
||||||
|
* @param arg argument to pass to the interrupt handler
|
||||||
|
* @param intr_reg address of the peripheral register containing the interrupt status,
|
||||||
|
* or value 0 to get the status from CPU INTERRUPT register
|
||||||
|
* @param intr_mask mask of the interrupt, in the interrupt status register
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_NO_MEM if too many handlers are registered
|
||||||
|
*/
|
||||||
|
esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mask all interrupts (including high level ones) on the current CPU
|
||||||
|
*
|
||||||
|
* @return uint32_t interrupt status, pass it to hli_intr_restore
|
||||||
|
*/
|
||||||
|
uint32_t hli_intr_disable(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Re-enable interrupts
|
||||||
|
*
|
||||||
|
* @param state value returned by hli_intr_disable
|
||||||
|
*/
|
||||||
|
void hli_intr_restore(uint32_t state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of a hli queue
|
||||||
|
*/
|
||||||
|
typedef struct hli_queue_t* hli_queue_handle_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize hli_queue module. Must be called once before using hli queue APIs.
|
||||||
|
*/
|
||||||
|
void hli_queue_setup(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shutdown hli_queue module.
|
||||||
|
*/
|
||||||
|
void hli_queue_shutdown(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a hli queue, wrapping a FreeRTOS queue
|
||||||
|
*
|
||||||
|
* This queue can be used from high level interrupts,
|
||||||
|
* but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
|
||||||
|
* queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
|
||||||
|
* software interrupt.
|
||||||
|
*
|
||||||
|
* @param nelem number of elements in the queue
|
||||||
|
* @param elem_size size of one element; must match element size of a downstream queue
|
||||||
|
* @param downstream FreeRTOS queue to send the values to
|
||||||
|
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
|
||||||
|
*/
|
||||||
|
hli_queue_handle_t hli_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a customer hli queue, wrapping a FreeRTOS queue
|
||||||
|
*
|
||||||
|
* This queue can be used from high level interrupts,
|
||||||
|
* but **ONLY ON THE CPU WHERE hli_queue_setup WAS CALLED**. Values sent to this
|
||||||
|
* queue are automatically forwarded to "downstream" FreeRTOS queue using a level 3
|
||||||
|
* software interrupt.
|
||||||
|
*
|
||||||
|
* @param nelem number of elements in the queue
|
||||||
|
* @param elem_size size of one element; must match element size of a downstream queue
|
||||||
|
* @param downstream FreeRTOS queue to send the values to
|
||||||
|
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
|
||||||
|
*/
|
||||||
|
hli_queue_handle_t hli_customer_queue_create(size_t nelem, size_t elem_size, QueueHandle_t downstream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a hli queue, wrapping a FreeRTOS semaphore
|
||||||
|
*
|
||||||
|
* See notes on hli_queue_create.
|
||||||
|
*
|
||||||
|
* @param max_count maximum semaphore count
|
||||||
|
* @param downstream FreeRTOS semaphore to forward the calls to
|
||||||
|
* @return hli_queue_handle_t handle of the created queue, or NULL on failure
|
||||||
|
*/
|
||||||
|
hli_queue_handle_t hli_semaphore_create(size_t max_count, SemaphoreHandle_t downstream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete a hli queue
|
||||||
|
*
|
||||||
|
* Make sure noone is using the queue before deleting it.
|
||||||
|
*
|
||||||
|
* @param queue handle returned by hli_queue_create or hli_semaphore_create
|
||||||
|
*/
|
||||||
|
void hli_queue_delete(hli_queue_handle_t queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get one element from a hli queue
|
||||||
|
*
|
||||||
|
* Usually not used, values get sent to a downstream FreeRTOS queue automatically.
|
||||||
|
* However if downstream queue is NULL, this API can be used to get values from a hli queue.
|
||||||
|
*
|
||||||
|
* @param queue handle of a queue
|
||||||
|
* @param out pointer where to store the element
|
||||||
|
* @return true if the element was successfully read from the queue
|
||||||
|
*/
|
||||||
|
bool hli_queue_get(hli_queue_handle_t queue, void* out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put one element into a hli queue
|
||||||
|
*
|
||||||
|
* This puts copies an element into the queue and raises a software interrupt (level 3).
|
||||||
|
* In the interrupt, the value is copied to a FreeRTOS "downstream" queue.
|
||||||
|
*
|
||||||
|
* Note that if the value does not fit into a downstream queue, no error is returned,
|
||||||
|
* and the value is lost.
|
||||||
|
*
|
||||||
|
* @param queue handle of a queue
|
||||||
|
* @param data pointer to the element to be sent
|
||||||
|
* @return true if data was placed into the hli queue successfully
|
||||||
|
*/
|
||||||
|
bool hli_queue_put(hli_queue_handle_t queue, const void* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief "Give" a semaphore wrapped by a hli queue
|
||||||
|
*
|
||||||
|
* @param queue handle returned by hli_semaphore_create
|
||||||
|
* @return true if the event was sent to a hli queue successfully
|
||||||
|
*/
|
||||||
|
bool hli_semaphore_give(hli_queue_handle_t queue);
|
||||||
|
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
275
components/bt/controller/esp32/hli_vectors.S
Normal file
275
components/bt/controller/esp32/hli_vectors.S
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
// Copyright 2015-2021 Espressif Systems (Shanghai) CO 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 <xtensa/coreasm.h>
|
||||||
|
#include <xtensa/corebits.h>
|
||||||
|
#include <xtensa/config/system.h>
|
||||||
|
#include "freertos/xtensa_context.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "soc/soc.h"
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
|
||||||
|
/* Interrupt stack size, for C code.
|
||||||
|
* TODO: reduce and make configurable.
|
||||||
|
*/
|
||||||
|
#define L4_INTR_STACK_SIZE 4096
|
||||||
|
|
||||||
|
/* Save area for the CPU state:
|
||||||
|
* - 64 words for the general purpose registers
|
||||||
|
* - 7 words for some of the special registers:
|
||||||
|
* - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed
|
||||||
|
* - SAR, LBEG, LEND, LCOUNT — since the C code might use these
|
||||||
|
* - EPC1 — since the C code might cause window overflow exceptions
|
||||||
|
* This is not laid out as standard exception frame structure
|
||||||
|
* for simplicity of the save/restore code.
|
||||||
|
*/
|
||||||
|
#define REG_FILE_SIZE (64 * 4)
|
||||||
|
#define SPECREG_OFFSET REG_FILE_SIZE
|
||||||
|
#define SPECREG_SIZE (7 * 4)
|
||||||
|
#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE)
|
||||||
|
|
||||||
|
.data
|
||||||
|
_l4_intr_stack:
|
||||||
|
.space L4_INTR_STACK_SIZE
|
||||||
|
_l4_save_ctx:
|
||||||
|
.space REG_SAVE_AREA_SIZE
|
||||||
|
|
||||||
|
.section .iram1,"ax"
|
||||||
|
.global xt_highint4
|
||||||
|
.type xt_highint4,@function
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
xt_highint4:
|
||||||
|
|
||||||
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||||
|
/*
|
||||||
|
Here, Timer2 is used to count a little time(50us).
|
||||||
|
The subsequent dram0 write operation is blocked due to live lock, which will
|
||||||
|
cause timer2 to timeout and trigger a level 5 interrupt.
|
||||||
|
*/
|
||||||
|
rsr.ccount a0
|
||||||
|
addmi a0, a0, (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ*50)
|
||||||
|
wsr a0, CCOMPARE2
|
||||||
|
|
||||||
|
/* Enable Timer 2 interrupt */
|
||||||
|
rsr a0, INTENABLE
|
||||||
|
extui a0, a0, 16, 1
|
||||||
|
bnez a0, 1f
|
||||||
|
movi a0, 0
|
||||||
|
xsr a0, INTENABLE /* disable all interrupts */
|
||||||
|
/* And a0 with (1 << 16) for Timer 2 interrupt mask */
|
||||||
|
addmi a0, a0, (1<<14)
|
||||||
|
addmi a0, a0, (1<<14)
|
||||||
|
addmi a0, a0, (1<<14)
|
||||||
|
addmi a0, a0, (1<<14)
|
||||||
|
wsr a0, INTENABLE /* Enable Timer 2 */
|
||||||
|
1:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
movi a0, _l4_save_ctx
|
||||||
|
/* save 4 lower registers */
|
||||||
|
s32i a1, a0, 4
|
||||||
|
s32i a2, a0, 8
|
||||||
|
s32i a3, a0, 12
|
||||||
|
rsr a2, EXCSAVE_4 /* holds the value of a0 */
|
||||||
|
s32i a2, a0, 0
|
||||||
|
|
||||||
|
/* Save special registers */
|
||||||
|
addi a0, a0, SPECREG_OFFSET
|
||||||
|
rsr a2, WINDOWBASE
|
||||||
|
s32i a2, a0, 0
|
||||||
|
rsr a2, WINDOWSTART
|
||||||
|
s32i a2, a0, 4
|
||||||
|
rsr a2, SAR
|
||||||
|
s32i a2, a0, 8
|
||||||
|
rsr a2, LBEG
|
||||||
|
s32i a2, a0, 12
|
||||||
|
rsr a2, LEND
|
||||||
|
s32i a2, a0, 16
|
||||||
|
rsr a2, LCOUNT
|
||||||
|
s32i a2, a0, 20
|
||||||
|
rsr a2, EPC1
|
||||||
|
s32i a2, a0, 24
|
||||||
|
|
||||||
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||||
|
movi a0, 0
|
||||||
|
xsr a0, INTENABLE /* disable all interrupts */
|
||||||
|
movi a2, ~(1<<16)
|
||||||
|
and a0, a2, a0
|
||||||
|
wsr a0, INTENABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* disable exception mode, window overflow */
|
||||||
|
movi a0, PS_INTLEVEL(5) | PS_EXCM
|
||||||
|
wsr a0, PS
|
||||||
|
rsync
|
||||||
|
|
||||||
|
/* Save the remaining physical registers.
|
||||||
|
* 4 registers are already saved, which leaves 60 registers to save.
|
||||||
|
* (FIXME: consider the case when the CPU is configured with physical 32 registers)
|
||||||
|
* These 60 registers are saved in 5 iterations, 12 registers at a time.
|
||||||
|
*/
|
||||||
|
movi a1, 5
|
||||||
|
movi a3, _l4_save_ctx + 4 * 4
|
||||||
|
|
||||||
|
/* This is repeated 5 times, each time the window is shifted by 12 registers.
|
||||||
|
* We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused.
|
||||||
|
*/
|
||||||
|
1:
|
||||||
|
s32i a4, a3, 0
|
||||||
|
s32i a5, a3, 4
|
||||||
|
s32i a6, a3, 8
|
||||||
|
s32i a7, a3, 12
|
||||||
|
s32i a8, a3, 16
|
||||||
|
s32i a9, a3, 20
|
||||||
|
s32i a10, a3, 24
|
||||||
|
s32i a11, a3, 28
|
||||||
|
s32i a12, a3, 32
|
||||||
|
s32i a13, a3, 36
|
||||||
|
s32i a14, a3, 40
|
||||||
|
s32i a15, a3, 44
|
||||||
|
|
||||||
|
/* We are about to rotate the window, so that a12-a15 will become the new a0-a3.
|
||||||
|
* Copy a0-a3 to a12-15 to still have access to these values.
|
||||||
|
* At the same time we can decrement the counter and adjust the save area pointer
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* a0 is constant (_l4_save_ctx), no need to copy */
|
||||||
|
addi a13, a1, -1 /* copy and decrement the downcounter */
|
||||||
|
/* a2 is scratch so no need to copy */
|
||||||
|
addi a15, a3, 48 /* copy and adjust the save area pointer */
|
||||||
|
beqz a13, 2f /* have saved all registers ? */
|
||||||
|
rotw 3 /* rotate the window and go back */
|
||||||
|
j 1b
|
||||||
|
|
||||||
|
/* the loop is complete */
|
||||||
|
2:
|
||||||
|
rotw 4 /* this brings us back to the original window */
|
||||||
|
/* a0 still points to _l4_save_ctx */
|
||||||
|
|
||||||
|
/* Can clear WINDOWSTART now, all registers are saved */
|
||||||
|
rsr a2, WINDOWBASE
|
||||||
|
/* WINDOWSTART = (1 << WINDOWBASE) */
|
||||||
|
movi a3, 1
|
||||||
|
ssl a2
|
||||||
|
sll a3, a3
|
||||||
|
wsr a3, WINDOWSTART
|
||||||
|
|
||||||
|
_highint4_stack_switch:
|
||||||
|
movi a0, 0
|
||||||
|
movi sp, _l4_intr_stack + L4_INTR_STACK_SIZE - 16
|
||||||
|
s32e a0, sp, -12 /* For GDB: set null SP */
|
||||||
|
s32e a0, sp, -16 /* For GDB: set null PC */
|
||||||
|
movi a0, _highint4_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */
|
||||||
|
|
||||||
|
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
|
||||||
|
movi a6, PS_INTLEVEL(4) | PS_UM | PS_WOE
|
||||||
|
wsr a6, PS
|
||||||
|
rsync
|
||||||
|
|
||||||
|
/* Call C handler */
|
||||||
|
mov a6, sp
|
||||||
|
call4 hli_c_handler
|
||||||
|
|
||||||
|
l32e sp, sp, -12 /* switch back to the original stack */
|
||||||
|
|
||||||
|
/* Done with C handler; re-enable exception mode, disabling window overflow */
|
||||||
|
movi a2, PS_INTLEVEL(5) | PS_EXCM /* TOCHECK */
|
||||||
|
wsr a2, PS
|
||||||
|
rsync
|
||||||
|
|
||||||
|
/* Restore the special registers.
|
||||||
|
* WINDOWSTART will be restored near the end.
|
||||||
|
*/
|
||||||
|
movi a0, _l4_save_ctx + SPECREG_OFFSET
|
||||||
|
l32i a2, a0, 8
|
||||||
|
wsr a2, SAR
|
||||||
|
l32i a2, a0, 12
|
||||||
|
wsr a2, LBEG
|
||||||
|
l32i a2, a0, 16
|
||||||
|
wsr a2, LEND
|
||||||
|
l32i a2, a0, 20
|
||||||
|
wsr a2, LCOUNT
|
||||||
|
l32i a2, a0, 24
|
||||||
|
wsr a2, EPC1
|
||||||
|
|
||||||
|
/* Restoring the physical registers.
|
||||||
|
* This is the reverse to the saving process above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Rotate back to the final window, then start loading 12 registers at a time,
|
||||||
|
* in 5 iterations.
|
||||||
|
* Again, a1 is the downcounter and a3 is the save area pointer.
|
||||||
|
* After each rotation, a1 and a3 are copied from a13 and a15.
|
||||||
|
* To simplify the loop, we put the initial values into a13 and a15.
|
||||||
|
*/
|
||||||
|
rotw -4
|
||||||
|
movi a15, _l4_save_ctx + 64 * 4 /* point to the end of the save area */
|
||||||
|
movi a13, 5
|
||||||
|
|
||||||
|
1:
|
||||||
|
/* Copy a1 and a3 from their previous location,
|
||||||
|
* at the same time decrementing and adjusting the save area pointer.
|
||||||
|
*/
|
||||||
|
addi a1, a13, -1
|
||||||
|
addi a3, a15, -48
|
||||||
|
|
||||||
|
/* Load 12 registers */
|
||||||
|
l32i a4, a3, 0
|
||||||
|
l32i a5, a3, 4
|
||||||
|
l32i a6, a3, 8
|
||||||
|
l32i a7, a3, 12
|
||||||
|
l32i a8, a3, 16
|
||||||
|
l32i a9, a3, 20
|
||||||
|
l32i a10, a3, 24
|
||||||
|
l32i a11, a3, 28 /* ensure PS and EPC written */
|
||||||
|
l32i a12, a3, 32
|
||||||
|
l32i a13, a3, 36
|
||||||
|
l32i a14, a3, 40
|
||||||
|
l32i a15, a3, 44
|
||||||
|
|
||||||
|
/* Done with the loop? */
|
||||||
|
beqz a1, 2f
|
||||||
|
/* If no, rotate the window and repeat */
|
||||||
|
rotw -3
|
||||||
|
j 1b
|
||||||
|
|
||||||
|
2:
|
||||||
|
/* Done with the loop. Only 4 registers (a0-a3 in the original window) remain
|
||||||
|
* to be restored. Also need to restore WINDOWSTART, since all the general
|
||||||
|
* registers are now in place.
|
||||||
|
*/
|
||||||
|
movi a0, _l4_save_ctx
|
||||||
|
|
||||||
|
l32i a2, a0, SPECREG_OFFSET + 4
|
||||||
|
wsr a2, WINDOWSTART
|
||||||
|
|
||||||
|
l32i a1, a0, 4
|
||||||
|
l32i a2, a0, 8
|
||||||
|
l32i a3, a0, 12
|
||||||
|
rsr a0, EXCSAVE_4 /* holds the value of a0 before the interrupt handler */
|
||||||
|
|
||||||
|
/* Return from the interrupt, restoring PS from EPS_4 */
|
||||||
|
rfi 4
|
||||||
|
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
|
/* The linker has no reason to link in this file; all symbols it exports are already defined
|
||||||
|
(weakly!) in the default int handler. Define a symbol here so we can use it to have the
|
||||||
|
linker inspect this anyway. */
|
||||||
|
|
||||||
|
.global ld_include_hli_vectors_bt
|
||||||
|
ld_include_hli_vectors_bt:
|
Submodule components/bt/controller/lib_esp32 updated: fb49791b7c...cfbb0571fb
@@ -149,6 +149,12 @@ the adv packet will be discarded until the memory is restored. */
|
|||||||
#define BTDM_CTRL_AUTO_LATENCY_EFF false
|
#define BTDM_CTRL_AUTO_LATENCY_EFF false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTDM_CTRL_HLI
|
||||||
|
#define BTDM_CTRL_HLI CONFIG_BTDM_CTRL_HLI
|
||||||
|
#else
|
||||||
|
#define BTDM_CTRL_HLI false
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF
|
#ifdef CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF
|
||||||
#define BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF
|
#define BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF
|
||||||
#else
|
#else
|
||||||
@@ -183,6 +189,7 @@ the adv packet will be discarded until the memory is restored. */
|
|||||||
.ble_sca = CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF, \
|
.ble_sca = CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF, \
|
||||||
.pcm_role = CONFIG_BTDM_CTRL_PCM_ROLE_EFF, \
|
.pcm_role = CONFIG_BTDM_CTRL_PCM_ROLE_EFF, \
|
||||||
.pcm_polar = CONFIG_BTDM_CTRL_PCM_POLAR_EFF, \
|
.pcm_polar = CONFIG_BTDM_CTRL_PCM_POLAR_EFF, \
|
||||||
|
.hli = BTDM_CTRL_HLI, \
|
||||||
.magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL, \
|
.magic = ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL, \
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -224,6 +231,7 @@ typedef struct {
|
|||||||
uint8_t ble_sca; /*!< BLE low power crystal accuracy index */
|
uint8_t ble_sca; /*!< BLE low power crystal accuracy index */
|
||||||
uint8_t pcm_role; /*!< PCM role (master & slave)*/
|
uint8_t pcm_role; /*!< PCM role (master & slave)*/
|
||||||
uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge) */
|
uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge) */
|
||||||
|
bool hli; /*!< Using high level interrupt or not */
|
||||||
uint32_t magic; /*!< Magic number */
|
uint32_t magic; /*!< Magic number */
|
||||||
} esp_bt_controller_config_t;
|
} esp_bt_controller_config_t;
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include "soc/dport_reg.h"
|
#include "soc/dport_reg.h"
|
||||||
|
|
||||||
#ifndef CONFIG_FREERTOS_UNICORE
|
#ifndef CONFIG_FREERTOS_UNICORE
|
||||||
|
#ifndef CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
|
|
||||||
#define L5_INTR_STACK_SIZE 12
|
#define L5_INTR_STACK_SIZE 12
|
||||||
#define L5_INTR_A2_OFFSET 0
|
#define L5_INTR_A2_OFFSET 0
|
||||||
@@ -77,6 +78,8 @@ xt_highint5:
|
|||||||
|
|
||||||
.global ld_include_test_dport_xt_highint5
|
.global ld_include_test_dport_xt_highint5
|
||||||
ld_include_test_dport_xt_highint5:
|
ld_include_test_dport_xt_highint5:
|
||||||
|
|
||||||
|
#endif // CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
#endif // CONFIG_FREERTOS_UNICORE
|
#endif // CONFIG_FREERTOS_UNICORE
|
||||||
|
|
||||||
#endif // CONFIG_IDF_TARGET_ESP32
|
#endif // CONFIG_IDF_TARGET_ESP32
|
||||||
|
@@ -15,14 +15,30 @@
|
|||||||
|
|
||||||
/* High-priority interrupt - IPC_ISR handler */
|
/* High-priority interrupt - IPC_ISR handler */
|
||||||
|
|
||||||
#define L4_INTR_STACK_SIZE 16
|
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
#define L4_INTR_A0_OFFSET 0
|
#define LX_INTR_STACK_SIZE 16
|
||||||
#define L4_INTR_A2_OFFSET 4
|
#define LX_INTR_A0_OFFSET 0
|
||||||
#define L4_INTR_A3_OFFSET 8
|
#define LX_INTR_A2_OFFSET 4
|
||||||
#define L4_INTR_A4_OFFSET 12
|
#define LX_INTR_A3_OFFSET 8
|
||||||
|
#define LX_INTR_A4_OFFSET 12
|
||||||
|
#define EXCSAVE_X EXCSAVE_5
|
||||||
|
#define RFI_X 5
|
||||||
|
|
||||||
|
#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
|
|
||||||
|
#define LX_INTR_STACK_SIZE 16
|
||||||
|
#define LX_INTR_A0_OFFSET 0
|
||||||
|
#define LX_INTR_A2_OFFSET 4
|
||||||
|
#define LX_INTR_A3_OFFSET 8
|
||||||
|
#define LX_INTR_A4_OFFSET 12
|
||||||
|
#define EXCSAVE_X EXCSAVE_4
|
||||||
|
#define RFI_X 4
|
||||||
|
|
||||||
|
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||||
|
|
||||||
.data
|
.data
|
||||||
_l4_intr_stack:
|
_lx_intr_stack:
|
||||||
.space L4_INTR_STACK_SIZE
|
.space LX_INTR_STACK_SIZE
|
||||||
.section .iram1,"ax"
|
.section .iram1,"ax"
|
||||||
.global esp_ipc_isr_handler
|
.global esp_ipc_isr_handler
|
||||||
.type esp_ipc_isr_handler,@function
|
.type esp_ipc_isr_handler,@function
|
||||||
@@ -30,17 +46,17 @@ _l4_intr_stack:
|
|||||||
esp_ipc_isr_handler:
|
esp_ipc_isr_handler:
|
||||||
/* Allocate exception frame and save minimal context. */
|
/* Allocate exception frame and save minimal context. */
|
||||||
/* Because the interrupt cause code has protection that only
|
/* Because the interrupt cause code has protection that only
|
||||||
allows one cpu to enter in the IPC_ISR section of the L4
|
allows one cpu to enter in the IPC_ISR section of the LX
|
||||||
interrupt at one time, there's no need to have two
|
interrupt at one time, there's no need to have two
|
||||||
_l4_intr_stack for each cpu */
|
_lx_intr_stack for each cpu */
|
||||||
|
|
||||||
/* Save A0, A2, A3, A4 so we can use those registers further*/
|
/* Save A0, A2, A3, A4 so we can use those registers further*/
|
||||||
movi a0, _l4_intr_stack
|
movi a0, _lx_intr_stack
|
||||||
s32i a2, a0, L4_INTR_A2_OFFSET
|
s32i a2, a0, LX_INTR_A2_OFFSET
|
||||||
s32i a3, a0, L4_INTR_A3_OFFSET
|
s32i a3, a0, LX_INTR_A3_OFFSET
|
||||||
s32i a4, a0, L4_INTR_A4_OFFSET
|
s32i a4, a0, LX_INTR_A4_OFFSET
|
||||||
rsr a2, EXCSAVE_4
|
rsr a2, EXCSAVE_X
|
||||||
s32i a2, a0, L4_INTR_A0_OFFSET
|
s32i a2, a0, LX_INTR_A0_OFFSET
|
||||||
|
|
||||||
/* disable nested iterrupts */
|
/* disable nested iterrupts */
|
||||||
/* PS.EXCM is changed from 1 to 0 . It allows using usually exception handler instead of the Double exception handler. */
|
/* PS.EXCM is changed from 1 to 0 . It allows using usually exception handler instead of the Double exception handler. */
|
||||||
@@ -53,9 +69,14 @@ esp_ipc_isr_handler:
|
|||||||
/*
|
/*
|
||||||
* Reset isr interrupt flags
|
* Reset isr interrupt flags
|
||||||
*/
|
*/
|
||||||
|
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
|
/* This int is level-triggered and doesn't need clearing.
|
||||||
|
Do nothing here and clear int status by peripheral register later.*/
|
||||||
|
#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
/* This int is edge-triggered and needs clearing. */
|
/* This int is edge-triggered and needs clearing. */
|
||||||
movi a3, (1 << ETS_IPC_ISR_INUM)
|
movi a3, (1 << ETS_IPC_ISR_INUM)
|
||||||
wsr a3, INTCLEAR
|
wsr a3, INTCLEAR
|
||||||
|
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||||
|
|
||||||
/* get CORE_ID */
|
/* get CORE_ID */
|
||||||
getcoreid a3
|
getcoreid a3
|
||||||
@@ -85,16 +106,16 @@ esp_ipc_isr_handler:
|
|||||||
callx0 a0
|
callx0 a0
|
||||||
|
|
||||||
/* Done. Restore registers and return. */
|
/* Done. Restore registers and return. */
|
||||||
movi a0, _l4_intr_stack
|
movi a0, _lx_intr_stack
|
||||||
l32i a2, a0, L4_INTR_A2_OFFSET
|
l32i a2, a0, LX_INTR_A2_OFFSET
|
||||||
l32i a3, a0, L4_INTR_A3_OFFSET
|
l32i a3, a0, LX_INTR_A3_OFFSET
|
||||||
l32i a4, a0, L4_INTR_A4_OFFSET
|
l32i a4, a0, LX_INTR_A4_OFFSET
|
||||||
|
|
||||||
/* set the end flag */
|
/* set the end flag */
|
||||||
movi a0, esp_ipc_isr_end_fl
|
movi a0, esp_ipc_isr_end_fl
|
||||||
s32i a0, a0, 0
|
s32i a0, a0, 0
|
||||||
|
|
||||||
/* restore a0 */
|
/* restore a0 */
|
||||||
rsr a0, EXCSAVE_4
|
rsr a0, EXCSAVE_X
|
||||||
/* restores PS from EPS[4] and jumps to the address in EPC[4] */
|
/* restores PS from EPS[X] and jumps to the address in EPC[X] */
|
||||||
rfi 4
|
rfi RFI_X
|
||||||
|
@@ -462,5 +462,23 @@ menu "ESP System Settings"
|
|||||||
Debug stubs are used by OpenOCD to execute pre-compiled onboard code
|
Debug stubs are used by OpenOCD to execute pre-compiled onboard code
|
||||||
which does some useful debugging stuff, e.g. GCOV data dump.
|
which does some useful debugging stuff, e.g. GCOV data dump.
|
||||||
|
|
||||||
|
choice ESP_SYSTEM_CHECK_INT_LEVEL
|
||||||
|
prompt "Interrupt level to use for Interrupt Watchdog and other system checks"
|
||||||
|
default ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
|
help
|
||||||
|
Interrupt level to use for Interrupt Watchdog and other system checks.
|
||||||
|
|
||||||
|
config ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
|
bool "Level 5 interrupt"
|
||||||
|
depends on IDF_TARGET_ESP32
|
||||||
|
help
|
||||||
|
Using level 5 interrupt for Interrupt Watchdog and other system checks.
|
||||||
|
|
||||||
|
config ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
|
bool "Level 4 interrupt"
|
||||||
|
depends on !BTDM_CTRL_HLI
|
||||||
|
help
|
||||||
|
Using level 4 interrupt for Interrupt Watchdog and other system checks.
|
||||||
|
endchoice
|
||||||
|
|
||||||
endmenu # ESP System Settings
|
endmenu # ESP System Settings
|
||||||
|
@@ -51,7 +51,7 @@ static wdt_hal_context_t iwdt_context;
|
|||||||
*/
|
*/
|
||||||
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
|
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
|
||||||
|
|
||||||
extern uint32_t _l4_intr_livelock_counter, _l4_intr_livelock_max;
|
extern uint32_t _lx_intr_livelock_counter, _lx_intr_livelock_max;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
|
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
|
||||||
@@ -70,9 +70,9 @@ static void IRAM_ATTR tick_hook(void)
|
|||||||
wdt_hal_write_protect_disable(&iwdt_context);
|
wdt_hal_write_protect_disable(&iwdt_context);
|
||||||
//Reconfigure stage timeouts
|
//Reconfigure stage timeouts
|
||||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||||
_l4_intr_livelock_counter = 0;
|
_lx_intr_livelock_counter = 0;
|
||||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0,
|
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0,
|
||||||
CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / (_l4_intr_livelock_max + 1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / (_lx_intr_livelock_max + 1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||||
#else
|
#else
|
||||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt
|
||||||
#endif
|
#endif
|
||||||
@@ -116,6 +116,38 @@ void esp_int_wdt_init(void)
|
|||||||
//Enable WDT
|
//Enable WDT
|
||||||
wdt_hal_enable(&iwdt_context);
|
wdt_hal_enable(&iwdt_context);
|
||||||
wdt_hal_write_protect_enable(&iwdt_context);
|
wdt_hal_write_protect_enable(&iwdt_context);
|
||||||
|
|
||||||
|
|
||||||
|
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
|
||||||
|
|
||||||
|
#define APB_DCRSET (0x200c)
|
||||||
|
#define APB_ITCTRL (0x3f00)
|
||||||
|
|
||||||
|
#define ERI_ADDR(APB) (0x100000 + (APB))
|
||||||
|
|
||||||
|
#define _SYM2STR(x) # x
|
||||||
|
#define SYM2STR(x) _SYM2STR(x)
|
||||||
|
uint32_t eriadrs, scratch = 0, immediate = 0;
|
||||||
|
if (soc_has_cache_lock_bug()) {
|
||||||
|
if (xPortGetCoreID() != CONFIG_BTDM_CTRL_PINNED_TO_CORE) {
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
/* Enable Xtensa Debug Module Integration Mode */
|
||||||
|
"movi %[ERI], " SYM2STR(ERI_ADDR(APB_ITCTRL)) "\n"
|
||||||
|
"rer %[REG], %[ERI]\n"
|
||||||
|
"movi %[IMM], 1\n"
|
||||||
|
"or %[REG], %[IMM], %[REG]\n"
|
||||||
|
"wer %[REG], %[ERI]\n"
|
||||||
|
/* Enable Xtensa Debug Module BreakIn signal */
|
||||||
|
"movi %[ERI], " SYM2STR(ERI_ADDR(APB_DCRSET)) "\n"
|
||||||
|
"rer %[REG], %[ERI]\n"
|
||||||
|
"movi %[IMM], 0x10000\n"
|
||||||
|
"or %[REG], %[IMM], %[REG]\n"
|
||||||
|
"wer %[REG], %[ERI]\n"
|
||||||
|
: [ERI] "=r" (eriadrs), [REG] "+r" (scratch), [IMM] "+r" (immediate)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void esp_int_wdt_cpu_init(void)
|
void esp_int_wdt_cpu_init(void)
|
||||||
@@ -136,11 +168,11 @@ void esp_int_wdt_cpu_init(void)
|
|||||||
* This is a workaround for issue 3.15 in "ESP32 ECO and workarounds for
|
* This is a workaround for issue 3.15 in "ESP32 ECO and workarounds for
|
||||||
* Bugs" document.
|
* Bugs" document.
|
||||||
*/
|
*/
|
||||||
_l4_intr_livelock_counter = 0;
|
_lx_intr_livelock_counter = 0;
|
||||||
if (soc_has_cache_lock_bug()) {
|
if (soc_has_cache_lock_bug()) {
|
||||||
assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS);
|
assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS);
|
||||||
assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS * 3));
|
assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS * 3));
|
||||||
_l4_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1;
|
_lx_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -54,7 +54,7 @@ _xt_panic:
|
|||||||
s32i a0, sp, XT_STK_A0
|
s32i a0, sp, XT_STK_A0
|
||||||
|
|
||||||
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
|
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
|
||||||
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
|
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE
|
||||||
wsr a0, PS
|
wsr a0, PS
|
||||||
|
|
||||||
//Call panic handler
|
//Call panic handler
|
||||||
|
@@ -33,156 +33,29 @@ Interrupt , a high-priority interrupt, is used for several things:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define L4_INTR_STACK_SIZE 12
|
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
#define L4_INTR_A2_OFFSET 0
|
|
||||||
#define L4_INTR_A3_OFFSET 4
|
|
||||||
#define L4_INTR_A4_OFFSET 8
|
|
||||||
.data
|
|
||||||
_l4_intr_stack:
|
|
||||||
.space L4_INTR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
|
|
||||||
|
|
||||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
#define LX_INTR_STACK_SIZE 12
|
||||||
.global _l4_intr_livelock_counter
|
#define LX_INTR_A2_OFFSET 0
|
||||||
.global _l4_intr_livelock_max
|
#define LX_INTR_A3_OFFSET 4
|
||||||
.align 16
|
#define LX_INTR_A4_OFFSET 8
|
||||||
_l4_intr_livelock_counter:
|
#define EPC_X EPC_5
|
||||||
.word 0
|
#define EXCSAVE_X EXCSAVE_5
|
||||||
_l4_intr_livelock_max:
|
#define RFI_X 5
|
||||||
.word 0
|
#define xt_highintx xt_highint5
|
||||||
_l4_intr_livelock_sync:
|
|
||||||
.word 0, 0
|
|
||||||
_l4_intr_livelock_app:
|
|
||||||
.word 0
|
|
||||||
_l4_intr_livelock_pro:
|
|
||||||
.word 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.section .iram1,"ax"
|
#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
.global xt_highint4
|
|
||||||
.type xt_highint4,@function
|
|
||||||
.align 4
|
|
||||||
xt_highint4:
|
|
||||||
|
|
||||||
#ifndef CONFIG_FREERTOS_UNICORE
|
#define LX_INTR_STACK_SIZE 12
|
||||||
/* See if we're here for the IPC_ISR interrupt */
|
#define LX_INTR_A2_OFFSET 0
|
||||||
rsr a0, INTERRUPT
|
#define LX_INTR_A3_OFFSET 4
|
||||||
extui a0, a0, ETS_IPC_ISR_INUM, 1
|
#define LX_INTR_A4_OFFSET 8
|
||||||
bnez a0, esp_ipc_isr_handler
|
#define EPC_X EPC_4
|
||||||
#endif // not CONFIG_FREERTOS_UNICORE
|
#define EXCSAVE_X EXCSAVE_4
|
||||||
|
#define RFI_X 4
|
||||||
|
#define xt_highintx xt_highint4
|
||||||
|
|
||||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||||
/* See if we're here for the tg1 watchdog interrupt */
|
|
||||||
rsr a0, INTERRUPT
|
|
||||||
extui a0, a0, ETS_T1_WDT_INUM, 1
|
|
||||||
beqz a0, 1f
|
|
||||||
|
|
||||||
wsr a5, depc /* use DEPC as temp storage */
|
|
||||||
movi a0, _l4_intr_livelock_counter
|
|
||||||
l32i a0, a0, 0
|
|
||||||
movi a5, _l4_intr_livelock_max
|
|
||||||
l32i a5, a5, 0
|
|
||||||
bltu a0, a5, .handle_livelock_int /* _l4_intr_livelock_counter < _l4_intr_livelock_max */
|
|
||||||
|
|
||||||
rsr a5, depc /* restore a5 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allocate exception frame and save minimal context. */
|
|
||||||
1: mov a0, sp
|
|
||||||
addi sp, sp, -XT_STK_FRMSZ
|
|
||||||
s32i a0, sp, XT_STK_A1
|
|
||||||
#if XCHAL_HAVE_WINDOWED
|
|
||||||
s32e a0, sp, -12 /* for debug backtrace */
|
|
||||||
#endif
|
|
||||||
rsr a0, PS /* save interruptee's PS */
|
|
||||||
s32i a0, sp, XT_STK_PS
|
|
||||||
rsr a0, EPC_4 /* save interruptee's PC */
|
|
||||||
s32i a0, sp, XT_STK_PC
|
|
||||||
#if XCHAL_HAVE_WINDOWED
|
|
||||||
s32e a0, sp, -16 /* for debug backtrace */
|
|
||||||
#endif
|
|
||||||
s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
|
|
||||||
s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
|
|
||||||
call0 _xt_context_save
|
|
||||||
|
|
||||||
/* Save vaddr into exception frame */
|
|
||||||
rsr a0, EXCVADDR
|
|
||||||
s32i a0, sp, XT_STK_EXCVADDR
|
|
||||||
|
|
||||||
/* Figure out reason, save into EXCCAUSE reg */
|
|
||||||
|
|
||||||
rsr a0, INTERRUPT
|
|
||||||
extui a0, a0, ETS_MEMACCESS_ERR_INUM, 1 /* get cacheerr int bit */
|
|
||||||
beqz a0, 1f
|
|
||||||
/* Kill this interrupt; we cannot reset it. */
|
|
||||||
rsr a0, INTENABLE
|
|
||||||
movi a4, ~(1<<ETS_MEMACCESS_ERR_INUM)
|
|
||||||
and a0, a4, a0
|
|
||||||
wsr a0, INTENABLE
|
|
||||||
movi a0, PANIC_RSN_CACHEERR
|
|
||||||
j 9f
|
|
||||||
1:
|
|
||||||
#if CONFIG_ESP_INT_WDT_CHECK_CPU1
|
|
||||||
/* Check if the cause is the app cpu failing to tick.*/
|
|
||||||
movi a0, int_wdt_app_cpu_ticked
|
|
||||||
l32i a0, a0, 0
|
|
||||||
bnez a0, 2f
|
|
||||||
/* It is. Modify cause. */
|
|
||||||
movi a0,PANIC_RSN_INTWDT_CPU1
|
|
||||||
j 9f
|
|
||||||
2:
|
|
||||||
#endif
|
|
||||||
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
|
|
||||||
movi a0,PANIC_RSN_INTWDT_CPU0
|
|
||||||
9:
|
|
||||||
/* Found the reason, now save it. */
|
|
||||||
s32i a0, sp, XT_STK_EXCCAUSE
|
|
||||||
|
|
||||||
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
|
|
||||||
rsr a0, EXCSAVE_4 /* save interruptee's a0 */
|
|
||||||
|
|
||||||
s32i a0, sp, XT_STK_A0
|
|
||||||
|
|
||||||
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
|
|
||||||
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
|
|
||||||
wsr a0, PS
|
|
||||||
|
|
||||||
//Call panic handler
|
|
||||||
mov a6,sp
|
|
||||||
call4 panicHandler
|
|
||||||
|
|
||||||
call0 _xt_context_restore
|
|
||||||
l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
|
|
||||||
wsr a0, PS
|
|
||||||
l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
|
|
||||||
wsr a0, EPC_4
|
|
||||||
l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
|
|
||||||
l32i sp, sp, XT_STK_A1 /* remove exception frame */
|
|
||||||
rsync /* ensure PS and EPC written */
|
|
||||||
|
|
||||||
rsr a0, EXCSAVE_4 /* restore a0 */
|
|
||||||
rfi 4
|
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
|
||||||
|
|
||||||
/*
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
Macro intr_matrix_map - Attach an CPU interrupt to a hardware source.
|
|
||||||
|
|
||||||
Input : "addr" - Interrupt map configuration base address
|
|
||||||
Input : "src" - Interrupt source.
|
|
||||||
Input : "inum" - Interrupt number.
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
.macro intr_matrix_map addr src inum
|
|
||||||
movi a2, \src
|
|
||||||
slli a2, a2, 2
|
|
||||||
movi a3, \addr
|
|
||||||
add a3, a3, a2
|
|
||||||
movi a2, \inum
|
|
||||||
s32i a2, a3, 0
|
|
||||||
memw
|
|
||||||
.endm
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@@ -190,6 +63,10 @@ xt_highint4:
|
|||||||
Macro wdt_feed - Feed the WDT.
|
Macro wdt_feed - Feed the WDT.
|
||||||
|
|
||||||
Input : "dev" - Beginning address of the peripheral registers
|
Input : "dev" - Beginning address of the peripheral registers
|
||||||
|
|
||||||
|
Macro get_int_status_tg1wdt - Get the ETS_TG1_WDT_LEVEL_INTR_SOURCE bit in interrupt status
|
||||||
|
|
||||||
|
output : "reg" - Store the result into the reg
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -199,6 +76,7 @@ xt_highint4:
|
|||||||
#define TIMG1_WDT_STG0_HOLD_OFFSET TIMG1_REG_OFFSET(TIMG_WDTCONFIG2_REG(1))
|
#define TIMG1_WDT_STG0_HOLD_OFFSET TIMG1_REG_OFFSET(TIMG_WDTCONFIG2_REG(1))
|
||||||
#define TIMG1_WDT_STG1_HOLD_OFFSET TIMG1_REG_OFFSET(TIMG_WDTCONFIG3_REG(1))
|
#define TIMG1_WDT_STG1_HOLD_OFFSET TIMG1_REG_OFFSET(TIMG_WDTCONFIG3_REG(1))
|
||||||
#define TIMG1_WDT_FEED_OFFSET TIMG1_REG_OFFSET(TIMG_WDTFEED_REG(1))
|
#define TIMG1_WDT_FEED_OFFSET TIMG1_REG_OFFSET(TIMG_WDTFEED_REG(1))
|
||||||
|
#define UART0_DATA_REG (0x3FF40078)
|
||||||
|
|
||||||
.macro wdt_clr_intr_status dev
|
.macro wdt_clr_intr_status dev
|
||||||
movi a2, \dev
|
movi a2, \dev
|
||||||
@@ -221,7 +99,7 @@ xt_highint4:
|
|||||||
movi a3, TIMG_WDT_WKEY_VALUE
|
movi a3, TIMG_WDT_WKEY_VALUE
|
||||||
s32i a3, a2, TIMG1_WDTWPROTECT_OFFSET /* disable write protect */
|
s32i a3, a2, TIMG1_WDTWPROTECT_OFFSET /* disable write protect */
|
||||||
memw
|
memw
|
||||||
movi a4, _l4_intr_livelock_max
|
movi a4, _lx_intr_livelock_max
|
||||||
l32i a4, a4, 0
|
l32i a4, a4, 0
|
||||||
memw
|
memw
|
||||||
addi a4, a4, 1
|
addi a4, a4, 1
|
||||||
@@ -240,19 +118,269 @@ xt_highint4:
|
|||||||
memw
|
memw
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro get_int_status_tg1wdt reg
|
||||||
|
rsr \reg, INTERRUPT
|
||||||
|
extui \reg, \reg, ETS_T1_WDT_CACHEERR_INUM, 1
|
||||||
|
beqz \reg, 99f /* not ETS_T1_WDT_INUM or ETS_CACHEERR_INUM */
|
||||||
|
|
||||||
|
getcoreid \reg
|
||||||
|
bnez \reg, 98f
|
||||||
|
/* core 0 */
|
||||||
|
movi \reg, UART0_DATA_REG
|
||||||
|
l32i \reg, \reg, 0 /* Workaround for DPORT read error, for silicon revision 0~2 (ECO V0 ~ ECO V2). */
|
||||||
|
movi \reg, DPORT_PRO_INTR_STATUS_0_REG
|
||||||
|
l32i \reg, \reg, 0
|
||||||
|
extui \reg, \reg, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 1
|
||||||
|
j 99f
|
||||||
|
|
||||||
|
98: /* core 1 */
|
||||||
|
movi \reg, UART0_DATA_REG
|
||||||
|
l32i \reg, \reg, 0 /* Workaround for DPORT read error, for silicon revision 0~2 (ECO V0 ~ ECO V2). */
|
||||||
|
movi \reg, DPORT_APP_INTR_STATUS_0_REG
|
||||||
|
l32i \reg, \reg, 0
|
||||||
|
extui \reg, \reg, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 1
|
||||||
|
99:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.data
|
||||||
|
_lx_intr_stack:
|
||||||
|
.space LX_INTR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
|
||||||
|
|
||||||
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
||||||
|
.global _lx_intr_livelock_counter
|
||||||
|
.global _lx_intr_livelock_max
|
||||||
|
.align 16
|
||||||
|
_lx_intr_livelock_counter:
|
||||||
|
.word 0
|
||||||
|
_lx_intr_livelock_max:
|
||||||
|
.word 0
|
||||||
|
_lx_intr_livelock_sync:
|
||||||
|
.word 0, 0
|
||||||
|
_lx_intr_livelock_app:
|
||||||
|
.word 0
|
||||||
|
_lx_intr_livelock_pro:
|
||||||
|
.word 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.section .iram1,"ax"
|
||||||
|
.global xt_highintx
|
||||||
|
.type xt_highintx,@function
|
||||||
|
.align 4
|
||||||
|
xt_highintx:
|
||||||
|
|
||||||
|
#ifndef CONFIG_FREERTOS_UNICORE
|
||||||
|
/* See if we're here for the IPC_ISR interrupt */
|
||||||
|
rsr a0, INTERRUPT
|
||||||
|
extui a0, a0, ETS_IPC_ISR_INUM, 1
|
||||||
|
beqz a0, 1f
|
||||||
|
j esp_ipc_isr_handler
|
||||||
|
1:
|
||||||
|
#endif /* not CONFIG_FREERTOS_UNICORE */
|
||||||
|
|
||||||
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
||||||
|
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
/* Timer 2 interrupt */
|
||||||
|
rsr a0, INTENABLE
|
||||||
|
extui a0, a0, 16, 1
|
||||||
|
beqz a0, 1f
|
||||||
|
rsr a0, INTERRUPT
|
||||||
|
extui a0, a0, 16, 1
|
||||||
|
bnez a0, .handle_multicore_debug_int
|
||||||
|
1:
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
|
/* ETS_T1_WDT_INUM */
|
||||||
|
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
|
get_int_status_tg1wdt a0
|
||||||
|
#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
|
/* See if we're here for the tg1 watchdog interrupt */
|
||||||
|
rsr a0, INTERRUPT
|
||||||
|
extui a0, a0, ETS_T1_WDT_INUM, 1
|
||||||
|
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||||
|
beqz a0, 1f
|
||||||
|
|
||||||
|
wsr a5, depc /* use DEPC as temp storage */
|
||||||
|
movi a0, _lx_intr_livelock_counter
|
||||||
|
l32i a0, a0, 0
|
||||||
|
movi a5, _lx_intr_livelock_max
|
||||||
|
l32i a5, a5, 0
|
||||||
|
bltu a0, a5, .handle_livelock_int /* _lx_intr_livelock_counter < _lx_intr_livelock_max */
|
||||||
|
|
||||||
|
rsr a5, depc /* restore a5 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
1: /* ETS_CACHEERR_INUM or ETS_T1_WDT_INUM */
|
||||||
|
/* Allocate exception frame and save minimal context. */
|
||||||
|
mov a0, sp
|
||||||
|
addi sp, sp, -XT_STK_FRMSZ
|
||||||
|
s32i a0, sp, XT_STK_A1
|
||||||
|
#if XCHAL_HAVE_WINDOWED
|
||||||
|
s32e a0, sp, -12 /* for debug backtrace */
|
||||||
|
#endif
|
||||||
|
rsr a0, PS /* save interruptee's PS */
|
||||||
|
s32i a0, sp, XT_STK_PS
|
||||||
|
rsr a0, EPC_X /* save interruptee's PC */
|
||||||
|
s32i a0, sp, XT_STK_PC
|
||||||
|
#if XCHAL_HAVE_WINDOWED
|
||||||
|
s32e a0, sp, -16 /* for debug backtrace */
|
||||||
|
#endif
|
||||||
|
s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
|
||||||
|
s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
|
||||||
|
call0 _xt_context_save
|
||||||
|
|
||||||
|
/* Save vaddr into exception frame */
|
||||||
|
rsr a0, EXCVADDR
|
||||||
|
s32i a0, sp, XT_STK_EXCVADDR
|
||||||
|
|
||||||
|
/* Figure out reason, save into EXCCAUSE reg */
|
||||||
|
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
|
get_int_status_tg1wdt a0
|
||||||
|
bnez a0, 1f
|
||||||
|
|
||||||
|
/* TODO: Clear the MEMACCESS_ERR interrupt status. */
|
||||||
|
#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
|
rsr a0, INTERRUPT
|
||||||
|
extui a0, a0, ETS_MEMACCESS_ERR_INUM, 1 /* get cacheerr int bit */
|
||||||
|
beqz a0, 1f
|
||||||
|
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||||
|
|
||||||
|
/* Kill this interrupt; we cannot reset it. */
|
||||||
|
rsr a0, INTENABLE
|
||||||
|
movi a4, ~(1<<ETS_MEMACCESS_ERR_INUM)
|
||||||
|
and a0, a4, a0
|
||||||
|
wsr a0, INTENABLE
|
||||||
|
movi a0, PANIC_RSN_CACHEERR
|
||||||
|
j 9f
|
||||||
|
1:
|
||||||
|
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
|
/* Clear the WDT interrupt status. */
|
||||||
|
wdt_clr_intr_status TIMERG1
|
||||||
|
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||||
|
#if CONFIG_ESP_INT_WDT_CHECK_CPU1
|
||||||
|
/* Check if the cause is the app cpu failing to tick.*/
|
||||||
|
movi a0, int_wdt_app_cpu_ticked
|
||||||
|
l32i a0, a0, 0
|
||||||
|
bnez a0, 2f
|
||||||
|
/* It is. Modify cause. */
|
||||||
|
movi a0,PANIC_RSN_INTWDT_CPU1
|
||||||
|
j 9f
|
||||||
|
2:
|
||||||
|
#endif
|
||||||
|
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
|
||||||
|
movi a0,PANIC_RSN_INTWDT_CPU0
|
||||||
|
9:
|
||||||
|
/* Found the reason, now save it. */
|
||||||
|
s32i a0, sp, XT_STK_EXCCAUSE
|
||||||
|
|
||||||
|
/* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
|
||||||
|
rsr a0, EXCSAVE_X /* save interruptee's a0 */
|
||||||
|
|
||||||
|
s32i a0, sp, XT_STK_A0
|
||||||
|
|
||||||
|
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
|
||||||
|
movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
|
||||||
|
wsr a0, PS
|
||||||
|
|
||||||
|
/* Call panic handler */
|
||||||
|
mov a6,sp
|
||||||
|
call4 panicHandler
|
||||||
|
|
||||||
|
call0 _xt_context_restore
|
||||||
|
l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
|
||||||
|
wsr a0, PS
|
||||||
|
l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
|
||||||
|
wsr a0, EPC_X
|
||||||
|
l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
|
||||||
|
l32i sp, sp, XT_STK_A1 /* remove exception frame */
|
||||||
|
rsync /* ensure PS and EPC written */
|
||||||
|
|
||||||
|
rsr a0, EXCSAVE_X /* restore a0 */
|
||||||
|
rfi RFI_X
|
||||||
|
|
||||||
|
|
||||||
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
||||||
|
#if CONFIG_BTDM_CTRL_HLI
|
||||||
|
#define APB_ITCTRL (0x3f00)
|
||||||
|
#define APB_DCRSET (0x200c)
|
||||||
|
|
||||||
|
#define ERI_ADDR(APB) (0x100000 + (APB))
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.handle_multicore_debug_int:
|
||||||
|
|
||||||
|
wsr a2, depc /* temp storage */
|
||||||
|
|
||||||
|
rsr.ccount a2
|
||||||
|
addmi a2, a2, (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ*50)
|
||||||
|
wsr a2, CCOMPARE2
|
||||||
|
|
||||||
|
/* Enable Integration Mode */
|
||||||
|
movi a2, ERI_ADDR(APB_ITCTRL)
|
||||||
|
rer a0, a2
|
||||||
|
addi a0, a0, 1
|
||||||
|
wer a0, a2
|
||||||
|
|
||||||
|
/* Enable and emit BreakOut signal */
|
||||||
|
movi a2, ERI_ADDR(APB_DCRSET)
|
||||||
|
rer a0, a2
|
||||||
|
movi a2, 0x1020000
|
||||||
|
or a0, a2, a0
|
||||||
|
movi a2, ERI_ADDR(APB_DCRSET)
|
||||||
|
wer a0, a2
|
||||||
|
|
||||||
|
.rept 4
|
||||||
|
nop
|
||||||
|
.endr
|
||||||
|
|
||||||
|
/* Enable Normal Mode */
|
||||||
|
movi a2, ERI_ADDR(APB_ITCTRL)
|
||||||
|
rer a0, a2
|
||||||
|
movi a2, ~0x1
|
||||||
|
and a0, a2, a0
|
||||||
|
movi a2, ERI_ADDR(APB_ITCTRL)
|
||||||
|
wer a0, a2
|
||||||
|
|
||||||
|
rsr a2, depc
|
||||||
|
|
||||||
|
rsr a0, EXCSAVE_5 /* restore a0 */
|
||||||
|
rfi 5
|
||||||
|
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||||
|
|
||||||
|
/*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Macro intr_matrix_map - Attach an CPU interrupt to a hardware source.
|
||||||
|
|
||||||
|
Input : "addr" - Interrupt map configuration base address
|
||||||
|
Input : "src" - Interrupt source.
|
||||||
|
Input : "inum" - Interrupt number.
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
.macro intr_matrix_map addr src inum
|
||||||
|
movi a2, \src
|
||||||
|
slli a2, a2, 2
|
||||||
|
movi a3, \addr
|
||||||
|
add a3, a3, a2
|
||||||
|
movi a2, \inum
|
||||||
|
s32i a2, a3, 0
|
||||||
|
memw
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
.handle_livelock_int:
|
.handle_livelock_int:
|
||||||
|
|
||||||
getcoreid a5
|
getcoreid a5
|
||||||
|
|
||||||
/* Save A2, A3, A4 so we can use those registers */
|
/* Save A2, A3, A4 so we can use those registers */
|
||||||
movi a0, L4_INTR_STACK_SIZE
|
movi a0, LX_INTR_STACK_SIZE
|
||||||
mull a5, a5, a0
|
mull a5, a5, a0
|
||||||
movi a0, _l4_intr_stack
|
movi a0, _lx_intr_stack
|
||||||
add a0, a0, a5
|
add a0, a0, a5
|
||||||
s32i a2, a0, L4_INTR_A2_OFFSET
|
s32i a2, a0, LX_INTR_A2_OFFSET
|
||||||
s32i a3, a0, L4_INTR_A3_OFFSET
|
s32i a3, a0, LX_INTR_A3_OFFSET
|
||||||
s32i a4, a0, L4_INTR_A4_OFFSET
|
s32i a4, a0, LX_INTR_A4_OFFSET
|
||||||
|
|
||||||
/* Here, we can use a0, a2, a3, a4, a5 registers */
|
/* Here, we can use a0, a2, a3, a4, a5 registers */
|
||||||
getcoreid a5
|
getcoreid a5
|
||||||
@@ -260,18 +388,18 @@ xt_highint4:
|
|||||||
rsil a0, CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL /* disable nested interrupt */
|
rsil a0, CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL /* disable nested interrupt */
|
||||||
|
|
||||||
beqz a5, 1f
|
beqz a5, 1f
|
||||||
movi a2, _l4_intr_livelock_app
|
movi a2, _lx_intr_livelock_app
|
||||||
l32i a3, a2, 0
|
l32i a3, a2, 0
|
||||||
addi a3, a3, 1
|
addi a3, a3, 1
|
||||||
s32i a3, a2, 0
|
s32i a3, a2, 0
|
||||||
|
|
||||||
/* Dual core synchronization, ensuring that both cores enter interrupts */
|
/* Dual core synchronization, ensuring that both cores enter interrupts */
|
||||||
1: movi a4, 0x1
|
1: movi a4, 0x1
|
||||||
movi a2, _l4_intr_livelock_sync
|
movi a2, _lx_intr_livelock_sync
|
||||||
addx4 a3, a5, a2
|
addx4 a3, a5, a2
|
||||||
s32i a4, a3, 0
|
s32i a4, a3, 0
|
||||||
|
|
||||||
1: movi a2, _l4_intr_livelock_sync
|
1: movi a2, _lx_intr_livelock_sync
|
||||||
movi a3, 1
|
movi a3, 1
|
||||||
addx4 a3, a3, a2
|
addx4 a3, a3, a2
|
||||||
l32i a2, a2, 0
|
l32i a2, a2, 0
|
||||||
@@ -281,10 +409,10 @@ xt_highint4:
|
|||||||
|
|
||||||
beqz a5, 1f /* Pro cpu (Core 0) jump bypass */
|
beqz a5, 1f /* Pro cpu (Core 0) jump bypass */
|
||||||
|
|
||||||
movi a2, _l4_intr_livelock_app
|
movi a2, _lx_intr_livelock_app
|
||||||
l32i a2, a2, 0
|
l32i a2, a2, 0
|
||||||
bnei a2, 2, 1f
|
bnei a2, 2, 1f
|
||||||
movi a2, _l4_intr_livelock_counter /* _l4_intr_livelock_counter++ */
|
movi a2, _lx_intr_livelock_counter /* _lx_intr_livelock_counter++ */
|
||||||
l32i a3, a2, 0
|
l32i a3, a2, 0
|
||||||
addi a3, a3, 1
|
addi a3, a3, 1
|
||||||
s32i a3, a2, 0
|
s32i a3, a2, 0
|
||||||
@@ -333,17 +461,17 @@ xt_highint4:
|
|||||||
bltu a4, a3, 2b
|
bltu a4, a3, 2b
|
||||||
|
|
||||||
beqz a5, 2f
|
beqz a5, 2f
|
||||||
movi a2, _l4_intr_livelock_app
|
movi a2, _lx_intr_livelock_app
|
||||||
l32i a2, a2, 0
|
l32i a2, a2, 0
|
||||||
beqi a2, 2, 8f
|
beqi a2, 2, 8f
|
||||||
j 3f
|
j 3f
|
||||||
|
|
||||||
2: movi a2, _l4_intr_livelock_pro
|
2: movi a2, _lx_intr_livelock_pro
|
||||||
l32i a4, a2, 0
|
l32i a4, a2, 0
|
||||||
addi a4, a4, 1
|
addi a4, a4, 1
|
||||||
s32i a4, a2, 0
|
s32i a4, a2, 0
|
||||||
|
|
||||||
movi a2, _l4_intr_livelock_sync
|
movi a2, _lx_intr_livelock_sync
|
||||||
movi a3, 1
|
movi a3, 1
|
||||||
addx4 a3, a3, a2
|
addx4 a3, a3, a2
|
||||||
l32i a2, a2, 0
|
l32i a2, a2, 0
|
||||||
@@ -357,7 +485,7 @@ xt_highint4:
|
|||||||
/*
|
/*
|
||||||
Pro cpu (Core 0) jump bypass, continue waiting, App cpu (Core 1)
|
Pro cpu (Core 0) jump bypass, continue waiting, App cpu (Core 1)
|
||||||
can execute to here, unmap itself tg1 1st stage timeout interrupt
|
can execute to here, unmap itself tg1 1st stage timeout interrupt
|
||||||
then restore registers and exit highint4.
|
then restore registers and exit highint5/4.
|
||||||
*/
|
*/
|
||||||
3: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 16
|
3: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 16
|
||||||
j 9f
|
j 9f
|
||||||
@@ -368,13 +496,13 @@ xt_highint4:
|
|||||||
*/
|
*/
|
||||||
4: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, ETS_T1_WDT_INUM
|
4: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, ETS_T1_WDT_INUM
|
||||||
|
|
||||||
1: movi a2, _l4_intr_livelock_sync
|
1: movi a2, _lx_intr_livelock_sync
|
||||||
movi a4, 1
|
movi a4, 1
|
||||||
addx4 a3, a4, a2
|
addx4 a3, a4, a2
|
||||||
l32i a2, a2, 0
|
l32i a2, a2, 0
|
||||||
l32i a3, a3, 0
|
l32i a3, a3, 0
|
||||||
and a2, a2, a3
|
and a2, a2, a3
|
||||||
beqz a2, 1b /* Wait for App cpu to enter highint4 again */
|
beqz a2, 1b /* Wait for App cpu to enter highint5/4 again */
|
||||||
|
|
||||||
wdt_clr_intr_status TIMERG1
|
wdt_clr_intr_status TIMERG1
|
||||||
j 9f
|
j 9f
|
||||||
@@ -386,32 +514,32 @@ xt_highint4:
|
|||||||
|
|
||||||
movi a0, 0
|
movi a0, 0
|
||||||
beqz a5, 1f
|
beqz a5, 1f
|
||||||
movi a2, _l4_intr_livelock_app
|
movi a2, _lx_intr_livelock_app
|
||||||
l32i a3, a2, 0
|
l32i a3, a2, 0
|
||||||
bnei a3, 2, 1f
|
bnei a3, 2, 1f
|
||||||
s32i a0, a2, 0
|
s32i a0, a2, 0
|
||||||
|
|
||||||
1: bnez a5, 2f
|
1: bnez a5, 2f
|
||||||
movi a2, _l4_intr_livelock_pro
|
movi a2, _lx_intr_livelock_pro
|
||||||
s32i a0, a2, 0
|
s32i a0, a2, 0
|
||||||
2: movi a2, _l4_intr_livelock_sync
|
2: movi a2, _lx_intr_livelock_sync
|
||||||
addx4 a2, a5, a2
|
addx4 a2, a5, a2
|
||||||
s32i a0, a2, 0
|
s32i a0, a2, 0
|
||||||
|
|
||||||
/* Done. Restore registers and return. */
|
/* Done. Restore registers and return. */
|
||||||
movi a0, L4_INTR_STACK_SIZE
|
movi a0, LX_INTR_STACK_SIZE
|
||||||
mull a5, a5, a0
|
mull a5, a5, a0
|
||||||
movi a0, _l4_intr_stack
|
movi a0, _lx_intr_stack
|
||||||
add a0, a0, a5
|
add a0, a0, a5
|
||||||
l32i a2, a0, L4_INTR_A2_OFFSET
|
l32i a2, a0, LX_INTR_A2_OFFSET
|
||||||
l32i a3, a0, L4_INTR_A3_OFFSET
|
l32i a3, a0, LX_INTR_A3_OFFSET
|
||||||
l32i a4, a0, L4_INTR_A4_OFFSET
|
l32i a4, a0, LX_INTR_A4_OFFSET
|
||||||
rsync /* ensure register restored */
|
rsync /* ensure register restored */
|
||||||
|
|
||||||
rsr a5, depc
|
rsr a5, depc
|
||||||
|
|
||||||
rsr a0, EXCSAVE_4 /* restore a0 */
|
rsr a0, EXCSAVE_X /* restore a0 */
|
||||||
rfi 4
|
rfi RFI_X
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -32,6 +32,21 @@ The default behaviour is to just exit the interrupt or call the panic handler on
|
|||||||
.align 4
|
.align 4
|
||||||
|
|
||||||
_xt_debugexception:
|
_xt_debugexception:
|
||||||
|
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
|
||||||
|
#define XT_DEBUGCAUSE_DI (5)
|
||||||
|
getcoreid a0
|
||||||
|
#if (CONFIG_BTDM_CTRL_PINNED_TO_CORE == PRO_CPU_NUM)
|
||||||
|
beqz a0, 1f
|
||||||
|
#else
|
||||||
|
bnez a0, 1f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rsr a0, DEBUGCAUSE
|
||||||
|
extui a0, a0, XT_DEBUGCAUSE_DI, 1
|
||||||
|
bnez a0, _xt_debug_di_exc
|
||||||
|
1:
|
||||||
|
#endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
|
||||||
|
|
||||||
movi a0,PANIC_RSN_DEBUGEXCEPTION
|
movi a0,PANIC_RSN_DEBUGEXCEPTION
|
||||||
wsr a0,EXCCAUSE
|
wsr a0,EXCCAUSE
|
||||||
/* _xt_panic assumes a level 1 exception. As we're
|
/* _xt_panic assumes a level 1 exception. As we're
|
||||||
@@ -44,6 +59,66 @@ _xt_debugexception:
|
|||||||
call0 _xt_panic /* does not return */
|
call0 _xt_panic /* does not return */
|
||||||
rfi XCHAL_DEBUGLEVEL
|
rfi XCHAL_DEBUGLEVEL
|
||||||
|
|
||||||
|
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
|
||||||
|
.align 4
|
||||||
|
_xt_debug_di_exc:
|
||||||
|
|
||||||
|
/*
|
||||||
|
The delay time can be calculated by the following formula:
|
||||||
|
T = ceil(0.25 + max(t1, t2)) us
|
||||||
|
|
||||||
|
t1 = 80 / f1, t2 = (1 + 14/N) * 20 / f2
|
||||||
|
|
||||||
|
f1: PSRAM access frequency, unit: MHz.
|
||||||
|
f2: Flash access frequency, unit: MHz.
|
||||||
|
|
||||||
|
When flash is slow/fast read, N = 1.
|
||||||
|
When flash is DOUT/DIO read, N = 2.
|
||||||
|
When flash is QOUT/QIO read, N = 4.
|
||||||
|
|
||||||
|
And after testing, when CPU frequency is 240 MHz, it will take 1us to loop 27 times.
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT)
|
||||||
|
|
||||||
|
# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
|
||||||
|
movi a0, 54
|
||||||
|
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
||||||
|
movi a0, 81
|
||||||
|
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
||||||
|
movi a0, 81
|
||||||
|
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
||||||
|
movi a0, 108
|
||||||
|
# else
|
||||||
|
movi a0, 135
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
|
||||||
|
|
||||||
|
# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
|
||||||
|
movi a0, 81
|
||||||
|
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
||||||
|
movi a0, 81
|
||||||
|
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
||||||
|
movi a0, 135
|
||||||
|
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
||||||
|
movi a0, 189
|
||||||
|
# else
|
||||||
|
movi a0, 243
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
movi a0, 243
|
||||||
|
#endif
|
||||||
|
|
||||||
|
1: addi a0, a0, -1 /* delay_us(N) */
|
||||||
|
.rept 4
|
||||||
|
nop
|
||||||
|
.endr
|
||||||
|
bnez a0, 1b
|
||||||
|
|
||||||
|
rsr a0, EXCSAVE+XCHAL_DEBUGLEVEL
|
||||||
|
rfi XCHAL_DEBUGLEVEL
|
||||||
|
#endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
|
||||||
#endif /* Debug exception */
|
#endif /* Debug exception */
|
||||||
|
|
||||||
|
|
||||||
|
@@ -639,11 +639,11 @@ _xt_user_exc:
|
|||||||
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
|
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
|
||||||
s32i a0, sp, XT_STK_A0
|
s32i a0, sp, XT_STK_A0
|
||||||
|
|
||||||
/* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */
|
/* Set up PS for C, reenable debug and NMI interrupts, and clear EXCM. */
|
||||||
#ifdef __XTENSA_CALL0_ABI__
|
#ifdef __XTENSA_CALL0_ABI__
|
||||||
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM
|
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM
|
||||||
#else
|
#else
|
||||||
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
|
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE
|
||||||
#endif
|
#endif
|
||||||
wsr a0, PS
|
wsr a0, PS
|
||||||
|
|
||||||
|
@@ -351,6 +351,60 @@
|
|||||||
#define ETS_CACHE_IA_INTR_SOURCE 68/**< interrupt of Cache Invalied Access, LEVEL*/
|
#define ETS_CACHE_IA_INTR_SOURCE 68/**< interrupt of Cache Invalied Access, LEVEL*/
|
||||||
#define ETS_MAX_INTR_SOURCE 69/**< total number of interrupt sources*/
|
#define ETS_MAX_INTR_SOURCE 69/**< total number of interrupt sources*/
|
||||||
|
|
||||||
|
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||||
|
//interrupt cpu using table, Please see the core-isa.h
|
||||||
|
/*************************************************************************************************************
|
||||||
|
* Intr num Level Type PRO CPU usage APP CPU uasge
|
||||||
|
* 0 1 extern level WMAC Reserved
|
||||||
|
* 1 1 extern level BT/BLE Host HCI DMA BT/BLE Host HCI DMA
|
||||||
|
* 2 1 extern level
|
||||||
|
* 3 1 extern level
|
||||||
|
* 4 1 extern level WBB
|
||||||
|
* 5 1 extern level
|
||||||
|
* 6 1 timer FreeRTOS Tick(L1) FreeRTOS Tick(L1)
|
||||||
|
* 7 1 software BT/BLE VHCI BT/BLE VHCI
|
||||||
|
* 8 1 extern level BT/BLE BB(RX/TX) BT/BLE BB(RX/TX)
|
||||||
|
* 9 1 extern level
|
||||||
|
* 10 1 extern edge
|
||||||
|
* 11 3 profiling
|
||||||
|
* 12 1 extern level
|
||||||
|
* 13 1 extern level
|
||||||
|
* 14 7 nmi Reserved Reserved
|
||||||
|
* 15 3 timer FreeRTOS Tick(L3) FreeRTOS Tick(L3)
|
||||||
|
* 16 5 timer Reserved Reserved
|
||||||
|
* 17 1 extern level
|
||||||
|
* 18 1 extern level
|
||||||
|
* 19 2 extern level
|
||||||
|
* 20 2 extern level
|
||||||
|
* 21 2 extern level
|
||||||
|
* 22 3 extern edge
|
||||||
|
* 23 3 extern level
|
||||||
|
* 24 4 extern level
|
||||||
|
* 25 4 extern level BT/BLE Controller BT/BLE Controller
|
||||||
|
* 26 5 extern level TG1_WDT & CACHEERR
|
||||||
|
* 27 3 extern level Reserved Reserved
|
||||||
|
* 28 4 extern edge
|
||||||
|
* 29 3 software BT/BLE hli BT/BLE hli
|
||||||
|
* 30 4 extern edge Reserved Reserved
|
||||||
|
* 31 5 extern level IPC_ISR IPC_ISR
|
||||||
|
*************************************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//CPU0 Interrupt number reserved, not touch this.
|
||||||
|
#define ETS_WMAC_INUM 0
|
||||||
|
#define ETS_BT_HOST_INUM 1
|
||||||
|
#define ETS_WBB_INUM 4
|
||||||
|
#define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/
|
||||||
|
#define ETS_FRC1_INUM 22
|
||||||
|
#define ETS_T1_WDT_CACHEERR_INUM 26
|
||||||
|
#define ETS_T1_WDT_INUM ETS_T1_WDT_CACHEERR_INUM
|
||||||
|
#define ETS_MEMACCESS_ERR_INUM ETS_T1_WDT_CACHEERR_INUM
|
||||||
|
/* backwards compatibility only, use ETS_MEMACCESS_ERR_INUM instead*/
|
||||||
|
#define ETS_CACHEERR_INUM ETS_MEMACCESS_ERR_INUM
|
||||||
|
#define ETS_IPC_ISR_INUM 31
|
||||||
|
|
||||||
|
#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
|
||||||
|
|
||||||
//interrupt cpu using table, Please see the core-isa.h
|
//interrupt cpu using table, Please see the core-isa.h
|
||||||
/*************************************************************************************************************
|
/*************************************************************************************************************
|
||||||
* Intr num Level Type PRO CPU usage APP CPU uasge
|
* Intr num Level Type PRO CPU usage APP CPU uasge
|
||||||
@@ -401,6 +455,8 @@
|
|||||||
#define ETS_CACHEERR_INUM ETS_MEMACCESS_ERR_INUM
|
#define ETS_CACHEERR_INUM ETS_MEMACCESS_ERR_INUM
|
||||||
#define ETS_IPC_ISR_INUM 28
|
#define ETS_IPC_ISR_INUM 28
|
||||||
|
|
||||||
|
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||||
|
|
||||||
//CPU0 Interrupt number used in ROM, should be cancelled in SDK
|
//CPU0 Interrupt number used in ROM, should be cancelled in SDK
|
||||||
#define ETS_SLC_INUM 1
|
#define ETS_SLC_INUM 1
|
||||||
#define ETS_UART0_INUM 5
|
#define ETS_UART0_INUM 5
|
||||||
|
@@ -9,16 +9,39 @@ The Xtensa architecture has support for 32 interrupts, divided over 8 levels, pl
|
|||||||
Interrupt Levels
|
Interrupt Levels
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
===== ================= ====================================================
|
.. only:: esp32
|
||||||
Level Symbol Remark
|
|
||||||
===== ================= ====================================================
|
===== ================= ====================================================
|
||||||
1 N/A Exception and level 0 interrupts. Handled by ESP-IDF
|
Level Symbol Remark
|
||||||
2-3 N/A Medium level interrupts. Handled by ESP-IDF
|
===== ================= ====================================================
|
||||||
4 xt_highint4 Normally used by ESP-IDF debug logic
|
1 N/A Exception and level 0 interrupts. Handled by ESP-IDF
|
||||||
5 xt_highint5 Free to use
|
2-3 N/A Medium level interrupts. Handled by ESP-IDF
|
||||||
NMI xt_nmi Free to use
|
4 xt_highint4 Free to use :ref:`(See 1) <hlinterrupts-pin-notes>`
|
||||||
dbg xt_debugexception Debug exception. Called on e.g. a BREAK instruction.
|
5 xt_highint5 Normally used by ESP-IDF debug logic :ref:`(See 1) <hlinterrupts-pin-notes>`
|
||||||
===== ================= ====================================================
|
NMI xt_nmi Free to use
|
||||||
|
dbg xt_debugexception Debug exception. Called on e.g. a BREAK instruction. :ref:`(See 2) <hlinterrupts-pin-notes>`
|
||||||
|
===== ================= ====================================================
|
||||||
|
|
||||||
|
|
||||||
|
.. _hlinterrupts-pin-notes:
|
||||||
|
|
||||||
|
The following notes give more information about the items in the tables above.
|
||||||
|
|
||||||
|
1. ESP-IDF debug logic can be configured to run on `xt_highint4` or `xt_highint5` in :ref:`CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL`. Bluetooth's interrupt can be configured to run on level 4 by enabling :ref:`CONFIG_BTDM_CTRL_HLI`. If :ref:`CONFIG_BTDM_CTRL_HLI` is enabled, ESP-IDF debug logic must be running on level 5 interrupt.
|
||||||
|
2. If :ref:`CONFIG_BTDM_CTRL_HLI` is enabled, `xt_debugexception` is used to fix `live lock issue <https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf>`_ in ESP32 ECO3.
|
||||||
|
|
||||||
|
.. only:: not esp32
|
||||||
|
|
||||||
|
===== ================= ====================================================
|
||||||
|
Level Symbol Remark
|
||||||
|
===== ================= ====================================================
|
||||||
|
1 N/A Exception and level 0 interrupts. Handled by ESP-IDF
|
||||||
|
2-3 N/A Medium level interrupts. Handled by ESP-IDF
|
||||||
|
4 xt_highint4 Normally used by ESP-IDF debug logic
|
||||||
|
5 xt_highint5 Free to use
|
||||||
|
NMI xt_nmi Free to use
|
||||||
|
dbg xt_debugexception Debug exception. Called on e.g. a BREAK instruction.
|
||||||
|
===== ================= ====================================================
|
||||||
|
|
||||||
Using these symbols is done by creating an assembly file (suffix .S) and defining the named symbols, like this::
|
Using these symbols is done by creating an assembly file (suffix .S) and defining the named symbols, like this::
|
||||||
|
|
||||||
@@ -41,6 +64,10 @@ Notes
|
|||||||
(The panic handler interrupt does call normal C code, but this is OK because there is no intention of returning to the normal code
|
(The panic handler interrupt does call normal C code, but this is OK because there is no intention of returning to the normal code
|
||||||
flow afterwards.)
|
flow afterwards.)
|
||||||
|
|
||||||
|
.. only:: esp32
|
||||||
|
|
||||||
|
And if :ref:`CONFIG_BTDM_CTRL_HLI` is enabled, it does call normal C code in high-level interrupt, but this is OK becase we add some protection for it.
|
||||||
|
|
||||||
- Make sure your assembly code gets linked in. If the interrupt handler symbol is the only symbol the rest of the code uses from this
|
- Make sure your assembly code gets linked in. If the interrupt handler symbol is the only symbol the rest of the code uses from this
|
||||||
file, the linker will take the default ISR instead and not link the assembly file into the final project. To get around this, in the
|
file, the linker will take the default ISR instead and not link the assembly file into the final project. To get around this, in the
|
||||||
assembly file, define a symbol, like this::
|
assembly file, define a symbol, like this::
|
||||||
|
Reference in New Issue
Block a user