mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
Merge branch 'feature/riscv_test_branch_cleanup' into 'master'
cleanup: move freertos code out from riscv component plus complete the interrupt-allocator implementation for C3 Closes IDF-2126, IDF-2228, IDF-2301, and IDF-2545 See merge request espressif/esp-idf!11136
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
@@ -12,14 +12,14 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include <esp_types.h>
|
#include "esp_types.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_intr_alloc.h"
|
#include "esp_intr_alloc.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "driver/periph_ctrl.h"
|
#include "driver/periph_ctrl.h"
|
||||||
#include "esp_int_wdt.h"
|
#include "esp_int_wdt.h"
|
||||||
#include "esp_private/system_internal.h"
|
#include "esp_private/system_internal.h"
|
||||||
|
#include "hal/cpu_hal.h"
|
||||||
#include "hal/timer_types.h"
|
#include "hal/timer_types.h"
|
||||||
#include "hal/wdt_hal.h"
|
#include "hal/wdt_hal.h"
|
||||||
#include "hal/interrupt_controller_hal.h"
|
#include "hal/interrupt_controller_hal.h"
|
||||||
@@ -45,7 +46,7 @@ static wdt_hal_context_t iwdt_context;
|
|||||||
|
|
||||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||||
/*
|
/*
|
||||||
* This parameter is indicates the response time of Interrupt watchdog to
|
* This parameter is used to indicate the response time of Interrupt watchdog to
|
||||||
* identify the live lock.
|
* identify the live lock.
|
||||||
*/
|
*/
|
||||||
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
|
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
|
||||||
@@ -58,8 +59,9 @@ extern uint32_t _l4_intr_livelock_counter, _l4_intr_livelock_max;
|
|||||||
//Not static; the ISR assembly checks this.
|
//Not static; the ISR assembly checks this.
|
||||||
bool int_wdt_app_cpu_ticked = false;
|
bool int_wdt_app_cpu_ticked = false;
|
||||||
|
|
||||||
static void IRAM_ATTR tick_hook(void) {
|
static void IRAM_ATTR tick_hook(void)
|
||||||
if (xPortGetCoreID()!=0) {
|
{
|
||||||
|
if (cpu_hal_get_core_id() != 0) {
|
||||||
int_wdt_app_cpu_ticked = true;
|
int_wdt_app_cpu_ticked = true;
|
||||||
} else {
|
} else {
|
||||||
//Only feed wdt if app cpu also ticked.
|
//Only feed wdt if app cpu also ticked.
|
||||||
@@ -70,11 +72,11 @@ static void IRAM_ATTR tick_hook(void) {
|
|||||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||||
_l4_intr_livelock_counter = 0;
|
_l4_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 / (_l4_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
|
||||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
||||||
wdt_hal_feed(&iwdt_context);
|
wdt_hal_feed(&iwdt_context);
|
||||||
wdt_hal_write_protect_enable(&iwdt_context);
|
wdt_hal_write_protect_enable(&iwdt_context);
|
||||||
int_wdt_app_cpu_ticked = false;
|
int_wdt_app_cpu_ticked = false;
|
||||||
@@ -82,32 +84,31 @@ static void IRAM_ATTR tick_hook(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void IRAM_ATTR tick_hook(void) {
|
static void IRAM_ATTR tick_hook(void)
|
||||||
|
{
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
if (xPortGetCoreID()!=0) {
|
if (cpu_hal_get_core_id() != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
|
//Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
|
||||||
wdt_hal_write_protect_disable(&iwdt_context);
|
wdt_hal_write_protect_disable(&iwdt_context);
|
||||||
//Reconfigure stage timeouts
|
//Reconfigure stage timeouts
|
||||||
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
|
||||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset
|
||||||
wdt_hal_feed(&iwdt_context);
|
wdt_hal_feed(&iwdt_context);
|
||||||
wdt_hal_write_protect_enable(&iwdt_context);
|
wdt_hal_write_protect_enable(&iwdt_context);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void esp_int_wdt_init(void) {
|
void esp_int_wdt_init(void)
|
||||||
|
{
|
||||||
periph_module_enable(PERIPH_TIMG1_MODULE);
|
periph_module_enable(PERIPH_TIMG1_MODULE);
|
||||||
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
|
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
|
||||||
//it to their actual value.
|
//it to their actual value.
|
||||||
wdt_hal_init(&iwdt_context, IWDT_INSTANCE, IWDT_PRESCALER, true);
|
wdt_hal_init(&iwdt_context, IWDT_INSTANCE, IWDT_PRESCALER, true);
|
||||||
wdt_hal_write_protect_disable(&iwdt_context);
|
wdt_hal_write_protect_disable(&iwdt_context);
|
||||||
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
|
|
||||||
//it to their actual value.
|
|
||||||
|
|
||||||
//1st stage timeout: interrupt
|
//1st stage timeout: interrupt
|
||||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT);
|
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT);
|
||||||
//2nd stage timeout: reset system
|
//2nd stage timeout: reset system
|
||||||
@@ -119,18 +120,15 @@ void esp_int_wdt_init(void) {
|
|||||||
|
|
||||||
void esp_int_wdt_cpu_init(void)
|
void esp_int_wdt_cpu_init(void)
|
||||||
{
|
{
|
||||||
assert((CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (portTICK_PERIOD_MS<<1)) && "Interrupt watchdog timeout needs to meet twice the RTOS tick period!");
|
assert((CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (portTICK_PERIOD_MS << 1)) && "Interrupt watchdog timeout needs to meet twice the RTOS tick period!");
|
||||||
esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID());
|
esp_register_freertos_tick_hook_for_cpu(tick_hook, cpu_hal_get_core_id());
|
||||||
ESP_INTR_DISABLE(WDT_INT_NUM);
|
ESP_INTR_DISABLE(WDT_INT_NUM);
|
||||||
intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
|
intr_matrix_set(cpu_hal_get_core_id(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
|
||||||
|
|
||||||
/* Set the type and priority to cache error interrupts, if supported. */
|
/* Set the type and priority to watch dog interrupts */
|
||||||
#if SOC_INTERRUPT_TYPE_CAN_SET
|
#if SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
interrupt_controller_hal_set_type(WDT_INT_NUM, INTR_TYPE_LEVEL);
|
interrupt_controller_hal_set_int_type(WDT_INT_NUM, INTR_TYPE_LEVEL);
|
||||||
#endif
|
interrupt_controller_hal_set_int_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM);
|
||||||
|
|
||||||
#if SOC_INTERRUPT_LEVEL_CAN_SET
|
|
||||||
interrupt_controller_hal_set_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||||
@@ -140,15 +138,15 @@ void esp_int_wdt_cpu_init(void)
|
|||||||
*/
|
*/
|
||||||
_l4_intr_livelock_counter = 0;
|
_l4_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;
|
_l4_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//We do not register a handler for the interrupt because it is interrupt level 4 which
|
// We do not register a handler for the watchdog interrupt because:
|
||||||
//is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for
|
// 1. Interrupt level 4 on Xtensa architecture is not servicable from C
|
||||||
//this interrupt.
|
// 2. Instead, we set the entry of watchdog interrupt to the panic handler, see riscv/vector.S and xtensa_vectors.S
|
||||||
ESP_INTR_ENABLE(WDT_INT_NUM);
|
ESP_INTR_ENABLE(WDT_INT_NUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -12,8 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#ifndef __ESP_INTR_ALLOC_H__
|
#pragma once
|
||||||
#define __ESP_INTR_ALLOC_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -93,7 +92,7 @@ typedef void (*intr_handler_t)(void *arg);
|
|||||||
typedef struct intr_handle_data_t intr_handle_data_t;
|
typedef struct intr_handle_data_t intr_handle_data_t;
|
||||||
|
|
||||||
/** Handle to an interrupt handler */
|
/** Handle to an interrupt handler */
|
||||||
typedef intr_handle_data_t* intr_handle_t ;
|
typedef intr_handle_data_t *intr_handle_t ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Mark an interrupt as a shared interrupt
|
* @brief Mark an interrupt as a shared interrupt
|
||||||
@@ -306,11 +305,18 @@ void esp_intr_enable_source(int inum);
|
|||||||
*/
|
*/
|
||||||
void esp_intr_disable_source(int inum);
|
void esp_intr_disable_source(int inum);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the lowest interrupt level from the flags
|
||||||
|
* @param flags The same flags that pass to `esp_intr_alloc_intrstatus` API
|
||||||
|
*/
|
||||||
|
static inline int esp_intr_flags_to_level(int flags)
|
||||||
|
{
|
||||||
|
return __builtin_ffs((flags & ESP_INTR_FLAG_LEVELMASK) >> 1) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
@@ -12,7 +12,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -21,6 +20,7 @@
|
|||||||
#include <esp_types.h>
|
#include <esp_types.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
@@ -48,7 +48,8 @@ Define this to debug the choices made when allocating the interrupt. This leads
|
|||||||
output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
|
output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
|
||||||
being triggered, that is why it is separate from the normal LOG* scheme.
|
being triggered, that is why it is separate from the normal LOG* scheme.
|
||||||
*/
|
*/
|
||||||
//define DEBUG_INT_ALLOC_DECISIONS
|
// #define DEBUG_INT_ALLOC_DECISIONS
|
||||||
|
|
||||||
#ifdef DEBUG_INT_ALLOC_DECISIONS
|
#ifdef DEBUG_INT_ALLOC_DECISIONS
|
||||||
# define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
|
# define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
@@ -237,6 +238,8 @@ static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force
|
|||||||
ALCHLOG("....Unusable: special-purpose int");
|
ALCHLOG("....Unusable: special-purpose int");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
//Check if the interrupt level is acceptable
|
//Check if the interrupt level is acceptable
|
||||||
if (!(flags&(1<<interrupt_controller_hal_get_level(x)))) {
|
if (!(flags&(1<<interrupt_controller_hal_get_level(x)))) {
|
||||||
ALCHLOG("....Unusable: incompatible level");
|
ALCHLOG("....Unusable: incompatible level");
|
||||||
@@ -248,6 +251,8 @@ static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force
|
|||||||
ALCHLOG("....Unusable: incompatible trigger type");
|
ALCHLOG("....Unusable: incompatible trigger type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//check if interrupt is reserved at runtime
|
//check if interrupt is reserved at runtime
|
||||||
if (vd->flags&VECDESC_FL_RESERVED) {
|
if (vd->flags&VECDESC_FL_RESERVED) {
|
||||||
ALCHLOG("....Unusable: reserved at runtime.");
|
ALCHLOG("....Unusable: reserved at runtime.");
|
||||||
@@ -551,14 +556,11 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
|
|||||||
interrupt_controller_hal_set_int_handler(intr, handler, arg);
|
interrupt_controller_hal_set_int_handler(intr, handler, arg);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef __XTENSA__ // TODO ESP32-C3 IDF-2126
|
|
||||||
if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr);
|
|
||||||
#else
|
|
||||||
if (flags & ESP_INTR_FLAG_EDGE) {
|
if (flags & ESP_INTR_FLAG_EDGE) {
|
||||||
ESP_INTR_DISABLE(intr);
|
interrupt_controller_hal_edge_int_acknowledge(intr);
|
||||||
esprv_intc_int_set_priority(intr, 0);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
vd->source=source;
|
vd->source=source;
|
||||||
}
|
}
|
||||||
if (flags&ESP_INTR_FLAG_IRAM) {
|
if (flags&ESP_INTR_FLAG_IRAM) {
|
||||||
@@ -585,11 +587,16 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
|
|||||||
esp_intr_disable(ret);
|
esp_intr_disable(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32C3
|
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
// TODO ESP32-C3 IDF-2126, these need to be set or the new interrupt won't fire, but are currently hard-coded
|
//Extract the level from the interrupt passed flags
|
||||||
// for priority and level...
|
int level = esp_intr_flags_to_level(flags);
|
||||||
esprv_intc_int_set_priority(intr, 1);
|
interrupt_controller_hal_set_int_level(intr, level);
|
||||||
esprv_intc_int_set_type(BIT(intr), INTR_TYPE_LEVEL);
|
|
||||||
|
if (flags & ESP_INTR_FLAG_EDGE) {
|
||||||
|
interrupt_controller_hal_set_int_type(intr, INTTP_EDGE);
|
||||||
|
} else {
|
||||||
|
interrupt_controller_hal_set_int_type(intr, INTTP_LEVEL);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
portEXIT_CRITICAL(&spinlock);
|
portEXIT_CRITICAL(&spinlock);
|
||||||
|
@@ -77,19 +77,23 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "portmacro.h"
|
#include "portmacro.h"
|
||||||
#include "riscv/interrupt.h"
|
|
||||||
#include "riscv/rvruntime-frames.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#include "soc/periph_defs.h"
|
#include "soc/periph_defs.h"
|
||||||
#include "soc/system_reg.h"
|
#include "soc/system_reg.h"
|
||||||
#include "soc/interrupt_reg.h"
|
|
||||||
#include "hal/systimer_hal.h"
|
#include "hal/systimer_hal.h"
|
||||||
#include "hal/systimer_ll.h"
|
#include "hal/systimer_ll.h"
|
||||||
|
|
||||||
|
#include "riscv/rvruntime-frames.h"
|
||||||
#include "riscv/riscv_interrupts.h"
|
#include "riscv/riscv_interrupts.h"
|
||||||
#include "riscv/interrupt.h"
|
#include "riscv/interrupt.h"
|
||||||
|
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_intr_alloc.h"
|
#include "esp_intr_alloc.h"
|
||||||
|
#include "esp_private/crosscore_int.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,15 +106,14 @@ static UBaseType_t uxCriticalNesting = 0;
|
|||||||
static UBaseType_t uxSavedInterruptState = 0;
|
static UBaseType_t uxSavedInterruptState = 0;
|
||||||
BaseType_t uxSchedulerRunning = 0;
|
BaseType_t uxSchedulerRunning = 0;
|
||||||
UBaseType_t uxInterruptNesting = 0;
|
UBaseType_t uxInterruptNesting = 0;
|
||||||
|
BaseType_t xPortSwitchFlag = 0;
|
||||||
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
|
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
|
||||||
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
|
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
|
||||||
|
|
||||||
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
||||||
|
|
||||||
static void vPortSysTickHandler(void);
|
static void vPortSysTickHandler(void *arg);
|
||||||
static void vPortSetupTimer(void);
|
static void vPortSetupTimer(void);
|
||||||
static void vPortSetupSoftwareInterrupt(void);
|
|
||||||
static void vPortSoftwareInterrupt(void);
|
|
||||||
static void prvTaskExitError(void);
|
static void prvTaskExitError(void);
|
||||||
|
|
||||||
extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only
|
extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only
|
||||||
@@ -121,7 +124,6 @@ void vPortEnterCritical(void)
|
|||||||
uxCriticalNesting++;
|
uxCriticalNesting++;
|
||||||
|
|
||||||
if (uxCriticalNesting == 1) {
|
if (uxCriticalNesting == 1) {
|
||||||
//portDISABLE_INTERRUPTS();
|
|
||||||
uxSavedInterruptState = state;
|
uxSavedInterruptState = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,7 +134,6 @@ void vPortExitCritical(void)
|
|||||||
uxCriticalNesting--;
|
uxCriticalNesting--;
|
||||||
if (uxCriticalNesting == 0) {
|
if (uxCriticalNesting == 0) {
|
||||||
portEXIT_CRITICAL_NESTED(uxSavedInterruptState);
|
portEXIT_CRITICAL_NESTED(uxSavedInterruptState);
|
||||||
//portENABLE_INTERRUPTS();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,16 +144,9 @@ void vPortExitCritical(void)
|
|||||||
*/
|
*/
|
||||||
void vPortSetupTimer(void)
|
void vPortSetupTimer(void)
|
||||||
{
|
{
|
||||||
/* register the interrupt handler */
|
/* set system timer interrupt vector */
|
||||||
intr_handler_set(ETS_SYSTICK_INUM, (intr_handler_t)&vPortSysTickHandler, NULL);
|
esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, vPortSysTickHandler, NULL, NULL);
|
||||||
|
assert(err == ESP_OK);
|
||||||
/* pass the timer interrupt through the interrupt matrix */
|
|
||||||
intr_matrix_route(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ETS_SYSTICK_INUM);
|
|
||||||
|
|
||||||
/* enable the interrupt in the INTC */
|
|
||||||
esprv_intc_int_enable(BIT(ETS_SYSTICK_INUM));
|
|
||||||
esprv_intc_int_set_type(BIT(ETS_SYSTICK_INUM), INTR_TYPE_LEVEL);
|
|
||||||
esprv_intc_int_set_priority(ETS_SYSTICK_INUM, 1);
|
|
||||||
|
|
||||||
/* configure the timer */
|
/* configure the timer */
|
||||||
systimer_hal_init();
|
systimer_hal_init();
|
||||||
@@ -163,24 +157,6 @@ void vPortSetupTimer(void)
|
|||||||
systimer_hal_connect_alarm_counter(SYSTIMER_ALARM_0, SYSTIMER_COUNTER_1);
|
systimer_hal_connect_alarm_counter(SYSTIMER_ALARM_0, SYSTIMER_COUNTER_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup software interrupt */
|
|
||||||
void vPortSetupSoftwareInterrupt(void)
|
|
||||||
{
|
|
||||||
/* register the interrupt handler, see interrupt.h */
|
|
||||||
intr_handler_set(ETS_CPU_INTR0_INUM, (intr_handler_t)&vPortSoftwareInterrupt, NULL);
|
|
||||||
|
|
||||||
/* pass the "FROM_CPU_0", a.k.a. cross-core interrupt, through the interrupt matrix */
|
|
||||||
intr_matrix_route(ETS_FROM_CPU_INTR0_SOURCE, ETS_CPU_INTR0_INUM);
|
|
||||||
|
|
||||||
/* enable the interrupt in the INTC */
|
|
||||||
esprv_intc_int_enable(BIT(ETS_CPU_INTR0_INUM));
|
|
||||||
esprv_intc_int_set_type(BIT(ETS_CPU_INTR0_INUM), INTR_TYPE_LEVEL);
|
|
||||||
esprv_intc_int_set_priority(ETS_CPU_INTR0_INUM, 1);
|
|
||||||
|
|
||||||
// TODO ESP32-C3 IDF-2126, maybe can use interrupt allocation API for all of the above? unsure...
|
|
||||||
esp_intr_reserve(ETS_CPU_INTR0_INUM, xPortGetCoreID());
|
|
||||||
}
|
|
||||||
|
|
||||||
void prvTaskExitError(void)
|
void prvTaskExitError(void)
|
||||||
{
|
{
|
||||||
/* A function that implements a task must not exit or attempt to return to
|
/* A function that implements a task must not exit or attempt to return to
|
||||||
@@ -191,8 +167,7 @@ void prvTaskExitError(void)
|
|||||||
defined, then stop here so application writers can catch the error. */
|
defined, then stop here so application writers can catch the error. */
|
||||||
configASSERT(uxCriticalNesting == ~0UL);
|
configASSERT(uxCriticalNesting == ~0UL);
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
for (;;)
|
abort();
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear current interrupt mask and set given mask */
|
/* Clear current interrupt mask and set given mask */
|
||||||
@@ -212,9 +187,6 @@ int vPortSetInterruptMask(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* See header file for description.
|
|
||||||
*/
|
|
||||||
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
||||||
{
|
{
|
||||||
extern uint32_t __global_pointer$;
|
extern uint32_t __global_pointer$;
|
||||||
@@ -231,11 +203,15 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
|||||||
frame->a1 = 0x11111111;
|
frame->a1 = 0x11111111;
|
||||||
frame->a2 = 0x22222222;
|
frame->a2 = 0x22222222;
|
||||||
frame->a3 = 0x33333333;
|
frame->a3 = 0x33333333;
|
||||||
|
|
||||||
|
//TODO: IDF-2393
|
||||||
return (StackType_t *)frame;
|
return (StackType_t *)frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortSysTickHandler(void)
|
IRAM_ATTR void vPortSysTickHandler(void *arg)
|
||||||
{
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
systimer_ll_clear_alarm_int(SYSTIMER_ALARM_0);
|
systimer_ll_clear_alarm_int(SYSTIMER_ALARM_0);
|
||||||
|
|
||||||
if (!uxSchedulerRunning) {
|
if (!uxSchedulerRunning) {
|
||||||
@@ -243,19 +219,23 @@ void vPortSysTickHandler(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xTaskIncrementTick() != pdFALSE) {
|
if (xTaskIncrementTick() != pdFALSE) {
|
||||||
vTaskSwitchContext();
|
vPortYieldFromISR();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseType_t xPortStartScheduler(void)
|
BaseType_t xPortStartScheduler(void)
|
||||||
{
|
{
|
||||||
vPortSetupTimer();
|
uxInterruptNesting = 0;
|
||||||
vPortSetupSoftwareInterrupt();
|
|
||||||
uxCriticalNesting = 0;
|
uxCriticalNesting = 0;
|
||||||
uxSchedulerRunning = 0; /* this means first yield */
|
uxSchedulerRunning = 0;
|
||||||
|
|
||||||
|
vPortSetupTimer();
|
||||||
|
|
||||||
esprv_intc_int_set_threshold(1); /* set global INTC masking level */
|
esprv_intc_int_set_threshold(1); /* set global INTC masking level */
|
||||||
riscv_global_interrupts_enable();
|
riscv_global_interrupts_enable();
|
||||||
|
|
||||||
vPortYield();
|
vPortYield();
|
||||||
|
|
||||||
/*Should not get here*/
|
/*Should not get here*/
|
||||||
return pdFALSE;
|
return pdFALSE;
|
||||||
}
|
}
|
||||||
@@ -263,21 +243,18 @@ BaseType_t xPortStartScheduler(void)
|
|||||||
void vPortEndScheduler(void)
|
void vPortEndScheduler(void)
|
||||||
{
|
{
|
||||||
/* very unlikely this function will be called, so just trap here */
|
/* very unlikely this function will be called, so just trap here */
|
||||||
while (1)
|
abort();
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void vPortSoftwareInterrupt(void)
|
|
||||||
{
|
|
||||||
uxSchedulerRunning = 1;
|
|
||||||
vTaskSwitchContext();
|
|
||||||
REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortYieldOtherCore(BaseType_t coreid)
|
void vPortYieldOtherCore(BaseType_t coreid)
|
||||||
{
|
{
|
||||||
(void)coreid;
|
esp_crosscore_int_send_yield(coreid);
|
||||||
vPortYield();
|
}
|
||||||
|
|
||||||
|
void vPortYieldFromISR( void )
|
||||||
|
{
|
||||||
|
uxSchedulerRunning = 1;
|
||||||
|
xPortSwitchFlag = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortYield(void)
|
void vPortYield(void)
|
||||||
@@ -285,8 +262,8 @@ void vPortYield(void)
|
|||||||
if (uxInterruptNesting) {
|
if (uxInterruptNesting) {
|
||||||
vPortYieldFromISR();
|
vPortYieldFromISR();
|
||||||
} else {
|
} else {
|
||||||
REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 1);
|
|
||||||
|
|
||||||
|
esp_crosscore_int_send_yield(0);
|
||||||
/* There are 3-4 instructions of latency between triggering the software
|
/* There are 3-4 instructions of latency between triggering the software
|
||||||
interrupt and the CPU interrupt happening. Make sure it happened before
|
interrupt and the CPU interrupt happening. Make sure it happened before
|
||||||
we return, otherwise vTaskDelay() may return and execute 1-2
|
we return, otherwise vTaskDelay() may return and execute 1-2
|
||||||
@@ -297,13 +274,9 @@ void vPortYield(void)
|
|||||||
for an instant yield, and if that happens then the WFI would be
|
for an instant yield, and if that happens then the WFI would be
|
||||||
waiting for the next interrupt to occur...)
|
waiting for the next interrupt to occur...)
|
||||||
*/
|
*/
|
||||||
while(uxSchedulerRunning && uxCriticalNesting == 0 && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) { }
|
while (uxSchedulerRunning && uxCriticalNesting == 0 && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void vPortYieldFromISR(void)
|
|
||||||
{
|
|
||||||
vTaskSwitchContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortSetStackWatchpoint(void *pxStackStart)
|
void vPortSetStackWatchpoint(void *pxStackStart)
|
||||||
@@ -325,24 +298,24 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
|
|||||||
|
|
||||||
void vPortCPUInitializeMutex(portMUX_TYPE *mux)
|
void vPortCPUInitializeMutex(portMUX_TYPE *mux)
|
||||||
{
|
{
|
||||||
(void)mux;
|
(void)mux; //TODO: IDF-2393
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortCPUAcquireMutex(portMUX_TYPE *mux)
|
void vPortCPUAcquireMutex(portMUX_TYPE *mux)
|
||||||
{
|
{
|
||||||
(void)mux;
|
(void)mux; //TODO: IDF-2393
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles)
|
bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles)
|
||||||
{
|
{
|
||||||
(void)mux;
|
(void)mux; //TODO: IDF-2393
|
||||||
(void)timeout_cycles;
|
(void)timeout_cycles;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vPortCPUReleaseMutex(portMUX_TYPE *mux)
|
void vPortCPUReleaseMutex(portMUX_TYPE *mux)
|
||||||
{
|
{
|
||||||
(void)mux;
|
(void)mux; //TODO: IDF-2393
|
||||||
}
|
}
|
||||||
|
|
||||||
void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
||||||
|
@@ -37,14 +37,23 @@ rtos_int_enter:
|
|||||||
|
|
||||||
/* scheduler not enabled, jump directly to ISR handler */
|
/* scheduler not enabled, jump directly to ISR handler */
|
||||||
lw t0, uxSchedulerRunning
|
lw t0, uxSchedulerRunning
|
||||||
beq t0,zero, not_rtos_enter
|
beq t0,zero, rtos_enter_end
|
||||||
|
|
||||||
/* Sabe current TCB and load the ISR stack */
|
/* increments the ISR nesting count */
|
||||||
|
la t3, uxInterruptNesting
|
||||||
|
lw t4, 0x0(t3)
|
||||||
|
addi t5,t4,1
|
||||||
|
sw t5, 0x0(t3)
|
||||||
|
|
||||||
|
/* If reached here from another low-prio ISR, skip stack pushing to TCB */
|
||||||
|
bne t4,zero, rtos_enter_end
|
||||||
|
|
||||||
|
/* Save current TCB and load the ISR stack */
|
||||||
lw t0, pxCurrentTCB
|
lw t0, pxCurrentTCB
|
||||||
sw t2, 0x0(t0)
|
sw t2, 0x0(t0)
|
||||||
lw sp, xIsrStackTop
|
lw sp, xIsrStackTop
|
||||||
|
|
||||||
not_rtos_enter:
|
rtos_enter_end:
|
||||||
mv ra, t1
|
mv ra, t1
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@@ -56,10 +65,23 @@ not_rtos_enter:
|
|||||||
.global rtos_int_exit
|
.global rtos_int_exit
|
||||||
.type rtos_int_exit, @function
|
.type rtos_int_exit, @function
|
||||||
rtos_int_exit:
|
rtos_int_exit:
|
||||||
|
|
||||||
/* may skip RTOS aware interrupt since scheduler was not started */
|
/* may skip RTOS aware interrupt since scheduler was not started */
|
||||||
lw t0, uxSchedulerRunning
|
lw t0, uxSchedulerRunning
|
||||||
beq t0,zero, not_rtos_exit
|
beq t0,zero, rtos_exit_end
|
||||||
|
|
||||||
|
/* update nesting interrupts counter */
|
||||||
|
la t2, uxInterruptNesting
|
||||||
|
lw t3, 0x0(t2)
|
||||||
|
|
||||||
|
/* Already zero, protect against underflow */
|
||||||
|
beq t3, zero, isr_skip_decrement
|
||||||
|
addi t3,t3, -1
|
||||||
|
sw t3, 0x0(t2)
|
||||||
|
|
||||||
|
isr_skip_decrement:
|
||||||
|
|
||||||
|
/* may still have interrupts pending, skip section below and exit */
|
||||||
|
bne t3,zero,rtos_exit_end
|
||||||
|
|
||||||
/* Schedule the next task if a yield is pending */
|
/* Schedule the next task if a yield is pending */
|
||||||
la t0, xPortSwitchFlag
|
la t0, xPortSwitchFlag
|
||||||
@@ -83,5 +105,5 @@ no_switch:
|
|||||||
lw a0, pxCurrentTCB
|
lw a0, pxCurrentTCB
|
||||||
lw a0, 0x0(a0)
|
lw a0, 0x0(a0)
|
||||||
|
|
||||||
not_rtos_exit:
|
rtos_exit_end:
|
||||||
ret
|
ret
|
||||||
|
@@ -28,8 +28,7 @@ if(NOT BOOTLOADER_BUILD)
|
|||||||
"soc_hal.c"
|
"soc_hal.c"
|
||||||
"interrupt_controller_hal.c"
|
"interrupt_controller_hal.c"
|
||||||
"sha_hal.c"
|
"sha_hal.c"
|
||||||
"aes_hal.c"
|
"aes_hal.c")
|
||||||
"${target}/interrupt_descriptor_table.c")
|
|
||||||
|
|
||||||
if(${target} STREQUAL "esp32")
|
if(${target} STREQUAL "esp32")
|
||||||
list(APPEND srcs
|
list(APPEND srcs
|
||||||
@@ -43,6 +42,7 @@ if(NOT BOOTLOADER_BUILD)
|
|||||||
"twai_hal_iram.c"
|
"twai_hal_iram.c"
|
||||||
"esp32/adc_hal.c"
|
"esp32/adc_hal.c"
|
||||||
"esp32/brownout_hal.c"
|
"esp32/brownout_hal.c"
|
||||||
|
"esp32/interrupt_descriptor_table.c"
|
||||||
"esp32/touch_sensor_hal.c")
|
"esp32/touch_sensor_hal.c")
|
||||||
if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC)
|
if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC)
|
||||||
list(APPEND srcs "esp32/emac_hal.c")
|
list(APPEND srcs "esp32/emac_hal.c")
|
||||||
@@ -65,6 +65,7 @@ if(NOT BOOTLOADER_BUILD)
|
|||||||
"esp32s2/systimer_hal.c"
|
"esp32s2/systimer_hal.c"
|
||||||
"esp32s2/touch_sensor_hal.c"
|
"esp32s2/touch_sensor_hal.c"
|
||||||
"esp32s2/dac_hal.c"
|
"esp32s2/dac_hal.c"
|
||||||
|
"esp32s2/interrupt_descriptor_table.c"
|
||||||
"esp32s2/usb_hal.c")
|
"esp32s2/usb_hal.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ if(NOT BOOTLOADER_BUILD)
|
|||||||
"twai_hal.c"
|
"twai_hal.c"
|
||||||
"twai_hal_iram.c"
|
"twai_hal_iram.c"
|
||||||
"esp32s3/brownout_hal.c"
|
"esp32s3/brownout_hal.c"
|
||||||
|
"esp32s3/interrupt_descriptor_table.c"
|
||||||
"esp32s3/systimer_hal.c"
|
"esp32s3/systimer_hal.c"
|
||||||
"esp32s3/touch_sensor_hal.c")
|
"esp32s3/touch_sensor_hal.c")
|
||||||
endif()
|
endif()
|
||||||
|
@@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
|||||||
* @param handler handler invoked when an interrupt occurs
|
* @param handler handler invoked when an interrupt occurs
|
||||||
* @param arg optional argument to pass to the handler
|
* @param arg optional argument to pass to the handler
|
||||||
*/
|
*/
|
||||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||||
{
|
{
|
||||||
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
|||||||
*
|
*
|
||||||
* @return argument used by handler of passed interrupt number
|
* @return argument used by handler of passed interrupt number
|
||||||
*/
|
*/
|
||||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||||
{
|
{
|
||||||
return xt_get_interrupt_handler_arg(intr);
|
return xt_get_interrupt_handler_arg(intr);
|
||||||
}
|
}
|
||||||
@@ -100,6 +100,16 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
|||||||
xt_int_enable_mask(newmask);
|
xt_int_enable_mask(newmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||||
|
*
|
||||||
|
* @param intr interrupt number ranged from 0 to 31
|
||||||
|
*/
|
||||||
|
static inline void intr_cntrl_ll_edge_int_acknowledge(int intr)
|
||||||
|
{
|
||||||
|
xthal_set_intclear(1 << intr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int cpu_ll_get_core_id(void)
|
static inline int IRAM_ATTR cpu_ll_get_core_id(void)
|
||||||
{
|
{
|
||||||
#if SOC_CPU_CORES_NUM == 1
|
#if SOC_CPU_CORES_NUM == 1
|
||||||
return 0; // No need to check core ID on single core hardware
|
return 0; // No need to check core ID on single core hardware
|
||||||
|
@@ -68,7 +68,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
|||||||
* @param handler handler invoked when an interrupt occurs
|
* @param handler handler invoked when an interrupt occurs
|
||||||
* @param arg optional argument to pass to the handler
|
* @param arg optional argument to pass to the handler
|
||||||
*/
|
*/
|
||||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||||
{
|
{
|
||||||
intr_handler_set(intr, (void *)handler, arg);
|
intr_handler_set(intr, (void *)handler, arg);
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
|||||||
*
|
*
|
||||||
* @return argument used by handler of passed interrupt number
|
* @return argument used by handler of passed interrupt number
|
||||||
*/
|
*/
|
||||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||||
{
|
{
|
||||||
return intr_handler_get_arg(intr);
|
return intr_handler_get_arg(intr);
|
||||||
}
|
}
|
||||||
@@ -116,27 +116,36 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the interrupt type given an interrupt number.
|
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||||
*
|
*
|
||||||
* @param interrupt_number number of the interrupt
|
* @param intr interrupt number ranged from 0 to 31
|
||||||
* @param type new type for this interrupt
|
|
||||||
*/
|
*/
|
||||||
static inline void intr_cntrl_ll_set_type(int interrupt_number, int_type_t type)
|
static inline void intr_cntrl_ll_edge_int_acknowledge(int intr)
|
||||||
{
|
{
|
||||||
esprv_intc_int_set_type(BIT(interrupt_number), type);
|
REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the interrupt level (priority) given an interrupt number.
|
* @brief Sets the interrupt level int the interrupt controller.
|
||||||
*
|
*
|
||||||
* @param interrupt_number number of the interrupt
|
* @param interrupt_number Interrupt number 0 to 31
|
||||||
* @param level new level for this interrupt
|
* @param level priority between 1 (lowest) to 7 (highest)
|
||||||
*/
|
*/
|
||||||
static inline void intr_cntrl_ll_set_level(int interrupt_number, int level)
|
static inline void intr_cntrl_ll_set_int_level(int intr, int level)
|
||||||
{
|
{
|
||||||
esprv_intc_int_set_priority(interrupt_number, level);
|
esprv_intc_int_set_priority(intr, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the type of an interrupt in the controller.
|
||||||
|
*
|
||||||
|
* @param interrupt_number Interrupt number 0 to 31
|
||||||
|
* @param type interrupt type as edge or level triggered
|
||||||
|
*/
|
||||||
|
static inline void intr_cntrl_ll_set_int_type(int intr, int_type_t type)
|
||||||
|
{
|
||||||
|
esprv_intc_int_set_type(BIT(intr), type);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -1,61 +0,0 @@
|
|||||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "hal/interrupt_controller_hal.h"
|
|
||||||
#include "soc/soc_caps.h"
|
|
||||||
#include "soc/soc.h"
|
|
||||||
|
|
||||||
// TODO ESP32-C3 IDF-2126 check this table is correct, some interrupts may be unnecessarily reserved or not reserved
|
|
||||||
// or marked as the wrong type
|
|
||||||
|
|
||||||
//This is basically a software-readable version of the interrupt usage table in include/soc/soc.h
|
|
||||||
const int_desc_t interrupt_descriptor_table[32] = {
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_RESVD } }, //0
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //1
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //2
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //3
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //4
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //5
|
|
||||||
{ 1, INTTP_NA, {INTDESC_NORMAL } }, //6
|
|
||||||
{ 1, INTTP_NA, {INTDESC_NORMAL } }, //7
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //8
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //9
|
|
||||||
{ 1, INTTP_EDGE, {INTDESC_NORMAL } }, //10
|
|
||||||
{ 3, INTTP_NA, {INTDESC_NORMAL } }, //11
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //12
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //13
|
|
||||||
{ 7, INTTP_LEVEL, {INTDESC_NORMAL } }, //14
|
|
||||||
{ 3, INTTP_NA, {INTDESC_NORMAL } }, //15
|
|
||||||
{ 5, INTTP_NA, {INTDESC_NORMAL } }, //16
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //17
|
|
||||||
{ 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //18
|
|
||||||
{ 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //19
|
|
||||||
{ 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //20
|
|
||||||
{ 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //21
|
|
||||||
{ 3, INTTP_EDGE, {INTDESC_NORMAL } }, //22
|
|
||||||
{ 3, INTTP_LEVEL, {INTDESC_NORMAL } }, //23
|
|
||||||
{ 4, INTTP_LEVEL, {INTDESC_RESVD } }, //24
|
|
||||||
{ 4, INTTP_LEVEL, {INTDESC_RESVD } }, //25
|
|
||||||
{ 5, INTTP_LEVEL, {INTDESC_NORMAL } }, //26
|
|
||||||
{ 3, INTTP_LEVEL, {INTDESC_NORMAL } }, //27
|
|
||||||
{ 4, INTTP_EDGE, {INTDESC_NORMAL } }, //28
|
|
||||||
{ 3, INTTP_NA, {INTDESC_NORMAL } }, //29
|
|
||||||
{ 4, INTTP_EDGE, {INTDESC_NORMAL } }, //30
|
|
||||||
{ 5, INTTP_LEVEL, {INTDESC_NORMAL } }, //31
|
|
||||||
};
|
|
||||||
|
|
||||||
const int_desc_t *interrupt_controller_hal_desc_table(void)
|
|
||||||
{
|
|
||||||
return interrupt_descriptor_table;
|
|
||||||
}
|
|
@@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
|||||||
* @param handler handler invoked when an interrupt occurs
|
* @param handler handler invoked when an interrupt occurs
|
||||||
* @param arg optional argument to pass to the handler
|
* @param arg optional argument to pass to the handler
|
||||||
*/
|
*/
|
||||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||||
{
|
{
|
||||||
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
|||||||
*
|
*
|
||||||
* @return argument used by handler of passed interrupt number
|
* @return argument used by handler of passed interrupt number
|
||||||
*/
|
*/
|
||||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||||
{
|
{
|
||||||
return xt_get_interrupt_handler_arg(intr);
|
return xt_get_interrupt_handler_arg(intr);
|
||||||
}
|
}
|
||||||
@@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
|||||||
xt_int_enable_mask(newmask);
|
xt_int_enable_mask(newmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||||
|
*
|
||||||
|
* @param intr interrupt number ranged from 0 to 31
|
||||||
|
*/
|
||||||
|
static inline void intr_cntrl_ll_edge_int_acknowledge (int intr)
|
||||||
|
{
|
||||||
|
xthal_set_intclear(1 << intr);
|
||||||
|
}
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -21,13 +21,14 @@
|
|||||||
#include "xtensa/config/specreg.h"
|
#include "xtensa/config/specreg.h"
|
||||||
#include "xtensa/config/extreg.h"
|
#include "xtensa/config/extreg.h"
|
||||||
#include "esp_bit_defs.h"
|
#include "esp_bit_defs.h"
|
||||||
|
#include "esp_attr.h"
|
||||||
#include "xtensa/config/core.h"
|
#include "xtensa/config/core.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int cpu_ll_get_core_id(void)
|
static inline int IRAM_ATTR cpu_ll_get_core_id(void)
|
||||||
{
|
{
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
asm volatile (
|
asm volatile (
|
||||||
|
@@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
|
|||||||
* @param handler handler invoked when an interrupt occurs
|
* @param handler handler invoked when an interrupt occurs
|
||||||
* @param arg optional argument to pass to the handler
|
* @param arg optional argument to pass to the handler
|
||||||
*/
|
*/
|
||||||
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg)
|
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
|
||||||
{
|
{
|
||||||
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler
|
|||||||
*
|
*
|
||||||
* @return argument used by handler of passed interrupt number
|
* @return argument used by handler of passed interrupt number
|
||||||
*/
|
*/
|
||||||
static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
|
||||||
{
|
{
|
||||||
return xt_get_interrupt_handler_arg(intr);
|
return xt_get_interrupt_handler_arg(intr);
|
||||||
}
|
}
|
||||||
@@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
|
|||||||
xt_int_enable_mask(newmask);
|
xt_int_enable_mask(newmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||||
|
*
|
||||||
|
* @param intr interrupt number ranged from 0 to 31
|
||||||
|
*/
|
||||||
|
static inline void intr_cntrl_ll_edge_int_acknowledge (int intr)
|
||||||
|
{
|
||||||
|
xthal_set_intclear(1 << intr);
|
||||||
|
}
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -23,12 +23,14 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
/**
|
/**
|
||||||
* @brief Gets target platform interrupt descriptor table
|
* @brief Gets target platform interrupt descriptor table
|
||||||
*
|
*
|
||||||
* @return Address of interrupt descriptor table
|
* @return Address of interrupt descriptor table
|
||||||
*/
|
*/
|
||||||
__attribute__((pure)) const int_desc_t *interrupt_controller_hal_desc_table(void);
|
__attribute__((pure)) const int_desc_t *interrupt_controller_hal_desc_table(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the interrupt type given an interrupt number.
|
* @brief Gets the interrupt type given an interrupt number.
|
||||||
@@ -55,24 +57,6 @@ __attribute__((pure)) int interrupt_controller_hal_desc_level(int interrupt_num
|
|||||||
*/
|
*/
|
||||||
__attribute__((pure)) int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number);
|
__attribute__((pure)) int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number);
|
||||||
|
|
||||||
#if SOC_INTERRUPT_LEVEL_CAN_SET
|
|
||||||
/**
|
|
||||||
* @brief Set the interrupt level given an interrupt number.
|
|
||||||
*
|
|
||||||
* @param interrupt_number number of the interrupt
|
|
||||||
* @param level new level for this interrupt
|
|
||||||
*/
|
|
||||||
void interrupt_controller_hal_set_level(int interrupt_number, int level);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the interrupt type given an interrupt number.
|
|
||||||
*
|
|
||||||
* @param interrupt_number number of the interrupt
|
|
||||||
* @param type new type for this interrupt
|
|
||||||
*/
|
|
||||||
void interrupt_controller_hal_set_type(int interrupt_number, int_type_t type);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the interrupt type given an interrupt number.
|
* @brief Gets the interrupt type given an interrupt number.
|
||||||
*
|
*
|
||||||
@@ -95,6 +79,30 @@ static inline int interrupt_controller_hal_get_level(int interrupt_number)
|
|||||||
return interrupt_controller_hal_desc_level(interrupt_number);
|
return interrupt_controller_hal_desc_level(interrupt_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
|
/**
|
||||||
|
* @brief Set the type of an interrupt in the controller.
|
||||||
|
*
|
||||||
|
* @param interrupt_number Interrupt number 0 to 31
|
||||||
|
* @param type interrupt type as edge or level triggered
|
||||||
|
*/
|
||||||
|
static inline void interrupt_controller_hal_set_int_type(int intr, int_type_t type)
|
||||||
|
{
|
||||||
|
intr_cntrl_ll_set_int_type(intr, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the interrupt level int the interrupt controller.
|
||||||
|
*
|
||||||
|
* @param interrupt_number Interrupt number 0 to 31
|
||||||
|
* @param level priority between 1 (lowest) to 7 (highest)
|
||||||
|
*/
|
||||||
|
static inline void interrupt_controller_hal_set_int_level(int intr, int level)
|
||||||
|
{
|
||||||
|
intr_cntrl_ll_set_int_level(intr, level);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the cpu flags given the interrupt number and target cpu.
|
* @brief Gets the cpu flags given the interrupt number and target cpu.
|
||||||
*
|
*
|
||||||
@@ -184,6 +192,16 @@ static inline void interrupt_controller_hal_enable_int_mask(uint32_t newmask)
|
|||||||
intr_cntrl_ll_enable_int_mask(newmask);
|
intr_cntrl_ll_enable_int_mask(newmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
|
||||||
|
*
|
||||||
|
* @param intr interrupt number ranged from 0 to 31
|
||||||
|
*/
|
||||||
|
static inline void interrupt_controller_hal_edge_int_acknowledge(int intr)
|
||||||
|
{
|
||||||
|
intr_cntrl_ll_edge_int_acknowledge(intr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -24,13 +24,13 @@ extern "C" {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
INTDESC_NORMAL=0,
|
INTDESC_NORMAL=0,
|
||||||
INTDESC_RESVD,
|
INTDESC_RESVD,
|
||||||
INTDESC_SPECIAL
|
INTDESC_SPECIAL,
|
||||||
} int_desc_flag_t;
|
} int_desc_flag_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
INTTP_LEVEL=0,
|
INTTP_LEVEL=0,
|
||||||
INTTP_EDGE,
|
INTTP_EDGE,
|
||||||
INTTP_NA
|
INTTP_NA,
|
||||||
} int_type_t;
|
} int_type_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@@ -14,36 +14,52 @@
|
|||||||
|
|
||||||
#include "hal/interrupt_controller_hal.h"
|
#include "hal/interrupt_controller_hal.h"
|
||||||
|
|
||||||
|
#if __riscv
|
||||||
|
#include "riscv/instruction_decode.h"
|
||||||
|
|
||||||
|
static bool is_interrupt_number_reserved(int interrupt_number)
|
||||||
|
{
|
||||||
|
extern int _vector_table;
|
||||||
|
extern int _interrupt_handler;
|
||||||
|
const intptr_t pc = (intptr_t)(&_vector_table + interrupt_number);
|
||||||
|
|
||||||
|
/* JAL instructions are relative to the PC there are executed from. */
|
||||||
|
const intptr_t destination = pc + riscv_decode_offset_from_jal_instruction(pc);
|
||||||
|
|
||||||
|
return destination != (intptr_t)&_interrupt_handler;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int_type_t interrupt_controller_hal_desc_type(int interrupt_number)
|
int_type_t interrupt_controller_hal_desc_type(int interrupt_number)
|
||||||
{
|
{
|
||||||
|
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
||||||
return(int_desc[interrupt_number].type);
|
return (int_desc[interrupt_number].type);
|
||||||
|
#else
|
||||||
|
return (INTTP_NA);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int interrupt_controller_hal_desc_level(int interrupt_number)
|
int interrupt_controller_hal_desc_level(int interrupt_number)
|
||||||
{
|
{
|
||||||
|
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
||||||
return(int_desc[interrupt_number].level);
|
return (int_desc[interrupt_number].level);
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number)
|
int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number)
|
||||||
{
|
{
|
||||||
|
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
|
||||||
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
|
||||||
return(int_desc[interrupt_number].cpuflags[cpu_number]);
|
return (int_desc[interrupt_number].cpuflags[cpu_number]);
|
||||||
}
|
#else
|
||||||
|
#if __riscv
|
||||||
#if SOC_INTERRUPT_LEVEL_CAN_SET
|
return is_interrupt_number_reserved(interrupt_number) ? INTDESC_RESVD : INTDESC_NORMAL;
|
||||||
|
#else
|
||||||
void interrupt_controller_hal_set_level(int interrupt_number, int level) {
|
return INTDESC_NORMAL;
|
||||||
intr_cntrl_ll_set_level(interrupt_number, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SOC_INTERRUPT_TYPE_CAN_SET
|
|
||||||
|
|
||||||
void interrupt_controller_hal_set_type(int interrupt_number, int_type_t type) {
|
|
||||||
intr_cntrl_ll_set_type(interrupt_number, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
@@ -7,6 +7,9 @@ if(BOOTLOADER_BUILD)
|
|||||||
else()
|
else()
|
||||||
set(priv_requires soc freertos)
|
set(priv_requires soc freertos)
|
||||||
set(srcs
|
set(srcs
|
||||||
|
"expression_with_stack_riscv.c"
|
||||||
|
"expression_with_stack_riscv_asm.S"
|
||||||
|
"instruction_decode.c"
|
||||||
"interrupt.c"
|
"interrupt.c"
|
||||||
"stdatomic.c"
|
"stdatomic.c"
|
||||||
"vectors.S")
|
"vectors.S")
|
||||||
|
79
components/riscv/expression_with_stack_riscv.c
Normal file
79
components/riscv/expression_with_stack_riscv.c
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <esp_expression_with_stack.h>
|
||||||
|
#include <riscv/rvruntime-frames.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static portMUX_TYPE shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
static void *current_task_stack = NULL;
|
||||||
|
|
||||||
|
extern void esp_shared_stack_invoke_function(shared_stack_function function, void *stack);
|
||||||
|
|
||||||
|
static StackType_t *esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
|
||||||
|
{
|
||||||
|
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||||
|
// TODO ESP32-C3 IDF-2207
|
||||||
|
// esp_clear_watchpoint(1);
|
||||||
|
// uint32_t watchpoint_place = ((uint32_t)stack + 32) & ~0x1f ;
|
||||||
|
#endif
|
||||||
|
//We need also to tweak current task stackpointer to avoid erroneous
|
||||||
|
//stack overflow indication, so fills the stack with freertos known pattern:
|
||||||
|
memset(stack, 0xa5U, stack_size * sizeof(StackType_t));
|
||||||
|
|
||||||
|
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
|
||||||
|
//Then put the fake stack inside of TCB:
|
||||||
|
current_task_stack = current->pxDummy6;
|
||||||
|
current->pxDummy6 = (void *)stack;
|
||||||
|
|
||||||
|
StackType_t *top_of_stack = stack + stack_size;
|
||||||
|
|
||||||
|
//Align stack to a 16byte boundary, as required by CPU specific:
|
||||||
|
top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf));
|
||||||
|
RvExcFrame *adjusted_top_of_stack = (RvExcFrame *) top_of_stack;
|
||||||
|
adjusted_top_of_stack--;
|
||||||
|
|
||||||
|
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
|
||||||
|
// TODO ESP32-C3 IDF-2207
|
||||||
|
//esp_set_watchpoint(1, (uint8_t *)watchpoint_place, 32, ESP_WATCHPOINT_STORE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ((StackType_t *)adjusted_top_of_stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function)
|
||||||
|
{
|
||||||
|
assert(lock);
|
||||||
|
assert(stack);
|
||||||
|
assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE);
|
||||||
|
assert(function);
|
||||||
|
|
||||||
|
xSemaphoreTake(lock, portMAX_DELAY);
|
||||||
|
portENTER_CRITICAL(&shared_stack_spinlock);
|
||||||
|
stack = esp_switch_stack_setup(stack, stack_size);
|
||||||
|
portEXIT_CRITICAL(&shared_stack_spinlock);
|
||||||
|
|
||||||
|
esp_shared_stack_invoke_function(function, stack);
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&shared_stack_spinlock);
|
||||||
|
StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
|
||||||
|
|
||||||
|
//Restore current task stack:
|
||||||
|
current->pxDummy6 = (StackType_t *)current_task_stack;
|
||||||
|
vPortSetStackWatchpoint(current->pxDummy6);
|
||||||
|
portEXIT_CRITICAL(&shared_stack_spinlock);
|
||||||
|
|
||||||
|
xSemaphoreGive(lock);
|
||||||
|
}
|
43
components/riscv/expression_with_stack_riscv_asm.S
Normal file
43
components/riscv/expression_with_stack_riscv_asm.S
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
.global esp_shared_stack_invoke_function
|
||||||
|
.type esp_shared_stack_invoke_function, @function
|
||||||
|
esp_shared_stack_invoke_function:
|
||||||
|
/* save current stack and return address */
|
||||||
|
mv t0, sp
|
||||||
|
mv t1, ra
|
||||||
|
|
||||||
|
/* Set shared stack as new stack pointer */
|
||||||
|
mv sp, a1
|
||||||
|
|
||||||
|
/* store the ra and previous stack pointer in a safe place */
|
||||||
|
addi sp,sp,-4
|
||||||
|
sw t0, 0(sp)
|
||||||
|
sw t1, 4(sp)
|
||||||
|
|
||||||
|
/* call the subroutine */
|
||||||
|
jalr a0, 0
|
||||||
|
|
||||||
|
/* gets the ra and stack pointer saved previously */
|
||||||
|
lw t0, 0(sp)
|
||||||
|
lw t1, 4(sp)
|
||||||
|
addi sp, sp, 4
|
||||||
|
|
||||||
|
/* restore both ra and real stack pointer of current task */
|
||||||
|
mv ra, t1
|
||||||
|
mv sp, t0
|
||||||
|
ret
|
@@ -3,7 +3,7 @@
|
|||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
@@ -14,12 +14,20 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SOC_INTERRUPT_LEVEL_CAN_SET (1)
|
/**
|
||||||
#define SOC_INTERRUPT_TYPE_CAN_SET (1)
|
* @brief Decode the offset value from a RISC-V JAL instruction
|
||||||
|
* @note This API will abort if the instruction is not JAL formatted.
|
||||||
|
*
|
||||||
|
* @param inst_addr Address of JAL instruction
|
||||||
|
* @return int offset value
|
||||||
|
*/
|
||||||
|
int riscv_decode_offset_from_jal_instruction(const intptr_t inst_addr);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
38
components/riscv/instruction_decode.c
Normal file
38
components/riscv/instruction_decode.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "riscv/instruction_decode.h"
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
unsigned int opcode: 7;
|
||||||
|
unsigned int rd: 5;
|
||||||
|
int imm_19_12: 8;
|
||||||
|
int imm_11: 1;
|
||||||
|
int imm_10_1: 10;
|
||||||
|
int imm20: 1;
|
||||||
|
};
|
||||||
|
unsigned int inst;
|
||||||
|
} riscv_jal_intruction_t;
|
||||||
|
|
||||||
|
int riscv_decode_offset_from_jal_instruction(const intptr_t inst_addr)
|
||||||
|
{
|
||||||
|
riscv_jal_intruction_t *jal_inst = (riscv_jal_intruction_t *)inst_addr;
|
||||||
|
// check if it's a valid JAL instruction
|
||||||
|
if (jal_inst->opcode != 0x6f && jal_inst->rd != 0) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return (jal_inst->imm_10_1 | jal_inst->imm_11 << 10 | jal_inst->imm_19_12 << 11 | jal_inst->imm20 << 19) << 1;
|
||||||
|
}
|
@@ -97,11 +97,8 @@
|
|||||||
csrw mepc, t0
|
csrw mepc, t0
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.global vPortYieldFromISR
|
.global rtos_int_enter
|
||||||
.global uxInterruptNesting
|
.global rtos_int_exit
|
||||||
.global uxSchedulerRunning
|
|
||||||
.global xIsrStackTop
|
|
||||||
.global pxCurrentTCB
|
|
||||||
.global _global_interrupt_handler
|
.global _global_interrupt_handler
|
||||||
|
|
||||||
.section .exception_vectors.text
|
.section .exception_vectors.text
|
||||||
@@ -219,25 +216,11 @@ _interrupt_handler:
|
|||||||
save_regs
|
save_regs
|
||||||
save_mepc
|
save_mepc
|
||||||
|
|
||||||
/* scheduler not enabled, jump directly to ISR handler */
|
/* Before doing anythig preserve the stack pointer */
|
||||||
lw t0, uxSchedulerRunning
|
/* It will be saved in current TCB, if needed */
|
||||||
beq t0, zero, already_on_handler
|
mv a0, sp
|
||||||
|
call rtos_int_enter
|
||||||
|
|
||||||
/* increments the ISR nesting count */
|
|
||||||
la t0, uxInterruptNesting
|
|
||||||
lw t1, 0x0(t0)
|
|
||||||
addi t2,t1,1
|
|
||||||
sw t2, 0x0(t0)
|
|
||||||
|
|
||||||
/* If reached here from another low priority ISR, skip stack pushing to TCB */
|
|
||||||
bne t1,zero, already_on_handler
|
|
||||||
|
|
||||||
/* Otherwise, save current sp, and use the isr stack from here */
|
|
||||||
lw t0, pxCurrentTCB
|
|
||||||
sw sp, 0x0(t0)
|
|
||||||
lw sp, xIsrStackTop
|
|
||||||
|
|
||||||
already_on_handler:
|
|
||||||
/* Before dispatch c handler, restore interrupt to enable nested intr */
|
/* Before dispatch c handler, restore interrupt to enable nested intr */
|
||||||
csrr s1, mcause
|
csrr s1, mcause
|
||||||
csrr s2, mstatus
|
csrr s2, mstatus
|
||||||
@@ -278,29 +261,13 @@ already_on_handler:
|
|||||||
sw s3, 0(t0)
|
sw s3, 0(t0)
|
||||||
fence
|
fence
|
||||||
|
|
||||||
/* may skip RTOS aware interrupt since scheduler was not started */
|
/* Yield to the next task is needed: */
|
||||||
lw t1, uxSchedulerRunning
|
mv a0, sp
|
||||||
beq t1,zero, isr_exit
|
call rtos_int_exit
|
||||||
|
|
||||||
/* update nesting interrupts counter */
|
/* The next (or current) stack pointer is returned in a0 */
|
||||||
la t0, uxInterruptNesting
|
mv sp, a0
|
||||||
lw t1, 0x0(t0)
|
|
||||||
|
|
||||||
/* Already zero, protect against underflow */
|
|
||||||
beq t1, zero, isr_skip_decrement
|
|
||||||
addi t1,t1, -1
|
|
||||||
sw t1, 0x0(t0)
|
|
||||||
|
|
||||||
isr_skip_decrement:
|
|
||||||
/* may still have interrupts pending, skip section below and exit */
|
|
||||||
bne t1,zero,isr_exit
|
|
||||||
|
|
||||||
/* handled all the ISRs and scheduled the next task, take its stack */
|
|
||||||
/* load on sp, then exit. */
|
|
||||||
lw sp, pxCurrentTCB
|
|
||||||
lw sp, 0x0(sp)
|
|
||||||
|
|
||||||
isr_exit:
|
|
||||||
/* restore the rest of the registers */
|
/* restore the rest of the registers */
|
||||||
csrw mcause, s1
|
csrw mcause, s1
|
||||||
csrw mstatus, s2
|
csrw mstatus, s2
|
||||||
|
@@ -16,5 +16,6 @@
|
|||||||
|
|
||||||
#define SOC_CPU_BREAKPOINTS_NUM 8
|
#define SOC_CPU_BREAKPOINTS_NUM 8
|
||||||
#define SOC_CPU_WATCHPOINTS_NUM 8
|
#define SOC_CPU_WATCHPOINTS_NUM 8
|
||||||
|
#define SOC_CPU_HAS_FLEXIBLE_INTC 1
|
||||||
|
|
||||||
#define SOC_CPU_WATCHPOINT_SIZE 0x80000000 // bytes
|
#define SOC_CPU_WATCHPOINT_SIZE 0x80000000 // bytes
|
||||||
|
@@ -43,7 +43,6 @@
|
|||||||
#include "rmt_caps.h"
|
#include "rmt_caps.h"
|
||||||
#include "spi_caps.h"
|
#include "spi_caps.h"
|
||||||
#include "uart_caps.h"
|
#include "uart_caps.h"
|
||||||
#include "int_caps.h"
|
|
||||||
|
|
||||||
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
|
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
|
||||||
#define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */
|
#define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */
|
||||||
|
Reference in New Issue
Block a user