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:
Angus Gratton
2021-01-06 12:36:29 +08:00
24 changed files with 480 additions and 323 deletions

View File

@@ -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);
} }

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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
} }

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 (

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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")

View 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);
}

View 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

View File

@@ -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
} }

View 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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 */