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");
// 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
@@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <esp_types.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "esp_attr.h"
@@ -29,6 +29,7 @@
#include "driver/periph_ctrl.h"
#include "esp_int_wdt.h"
#include "esp_private/system_internal.h"
#include "hal/cpu_hal.h"
#include "hal/timer_types.h"
#include "hal/wdt_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
/*
* 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.
*/
#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.
bool int_wdt_app_cpu_ticked = false;
static void IRAM_ATTR tick_hook(void) {
if (xPortGetCoreID()!=0) {
static void IRAM_ATTR tick_hook(void)
{
if (cpu_hal_get_core_id() != 0) {
int_wdt_app_cpu_ticked = true;
} else {
//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
_l4_intr_livelock_counter = 0;
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
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
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_write_protect_enable(&iwdt_context);
int_wdt_app_cpu_ticked = false;
@@ -82,32 +84,31 @@ static void IRAM_ATTR tick_hook(void) {
}
}
#else
static void IRAM_ATTR tick_hook(void) {
static void IRAM_ATTR tick_hook(void)
{
#if !CONFIG_FREERTOS_UNICORE
if (xPortGetCoreID()!=0) {
if (cpu_hal_get_core_id() != 0) {
return;
}
#endif
//Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
wdt_hal_write_protect_disable(&iwdt_context);
//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_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_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_feed(&iwdt_context);
wdt_hal_write_protect_enable(&iwdt_context);
}
#endif
void esp_int_wdt_init(void) {
void esp_int_wdt_init(void)
{
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
//it to their actual value.
wdt_hal_init(&iwdt_context, IWDT_INSTANCE, IWDT_PRESCALER, true);
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
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
@@ -119,18 +120,15 @@ void esp_int_wdt_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!");
esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID());
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, cpu_hal_get_core_id());
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. */
#if SOC_INTERRUPT_TYPE_CAN_SET
interrupt_controller_hal_set_type(WDT_INT_NUM, INTR_TYPE_LEVEL);
#endif
#if SOC_INTERRUPT_LEVEL_CAN_SET
interrupt_controller_hal_set_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM);
/* Set the type and priority to watch dog interrupts */
#if SOC_CPU_HAS_FLEXIBLE_INTC
interrupt_controller_hal_set_int_type(WDT_INT_NUM, INTR_TYPE_LEVEL);
interrupt_controller_hal_set_int_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM);
#endif
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
@@ -140,15 +138,15 @@ void esp_int_wdt_cpu_init(void)
*/
_l4_intr_livelock_counter = 0;
if (soc_has_cache_lock_bug()) {
assert((portTICK_PERIOD_MS<<1) <= IWDT_LIVELOCK_TIMEOUT_MS);
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;
assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS);
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;
}
#endif
//We do not register a handler for the interrupt because it is interrupt level 4 which
//is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for
//this interrupt.
// We do not register a handler for the watchdog interrupt because:
// 1. Interrupt level 4 on Xtensa architecture is not servicable from C
// 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);
}

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");
// 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
// limitations under the License.
#ifndef __ESP_INTR_ALLOC_H__
#define __ESP_INTR_ALLOC_H__
#pragma once
#include <stdint.h>
#include <stdbool.h>
@@ -37,24 +36,24 @@ extern "C" {
*/
//Keep the LEVELx values as they are here; they match up with (1<<level)
#define ESP_INTR_FLAG_LEVEL1 (1<<1) ///< Accept a Level 1 interrupt vector (lowest priority)
#define ESP_INTR_FLAG_LEVEL2 (1<<2) ///< Accept a Level 2 interrupt vector
#define ESP_INTR_FLAG_LEVEL3 (1<<3) ///< Accept a Level 3 interrupt vector
#define ESP_INTR_FLAG_LEVEL4 (1<<4) ///< Accept a Level 4 interrupt vector
#define ESP_INTR_FLAG_LEVEL5 (1<<5) ///< Accept a Level 5 interrupt vector
#define ESP_INTR_FLAG_LEVEL6 (1<<6) ///< Accept a Level 6 interrupt vector
#define ESP_INTR_FLAG_NMI (1<<7) ///< Accept a Level 7 interrupt vector (highest priority)
#define ESP_INTR_FLAG_SHARED (1<<8) ///< Interrupt can be shared between ISRs
#define ESP_INTR_FLAG_EDGE (1<<9) ///< Edge-triggered interrupt
#define ESP_INTR_FLAG_IRAM (1<<10) ///< ISR can be called if cache is disabled
#define ESP_INTR_FLAG_INTRDISABLED (1<<11) ///< Return with this interrupt disabled
#define ESP_INTR_FLAG_LEVEL1 (1<<1) ///< Accept a Level 1 interrupt vector (lowest priority)
#define ESP_INTR_FLAG_LEVEL2 (1<<2) ///< Accept a Level 2 interrupt vector
#define ESP_INTR_FLAG_LEVEL3 (1<<3) ///< Accept a Level 3 interrupt vector
#define ESP_INTR_FLAG_LEVEL4 (1<<4) ///< Accept a Level 4 interrupt vector
#define ESP_INTR_FLAG_LEVEL5 (1<<5) ///< Accept a Level 5 interrupt vector
#define ESP_INTR_FLAG_LEVEL6 (1<<6) ///< Accept a Level 6 interrupt vector
#define ESP_INTR_FLAG_NMI (1<<7) ///< Accept a Level 7 interrupt vector (highest priority)
#define ESP_INTR_FLAG_SHARED (1<<8) ///< Interrupt can be shared between ISRs
#define ESP_INTR_FLAG_EDGE (1<<9) ///< Edge-triggered interrupt
#define ESP_INTR_FLAG_IRAM (1<<10) ///< ISR can be called if cache is disabled
#define ESP_INTR_FLAG_INTRDISABLED (1<<11) ///< Return with this interrupt disabled
#define ESP_INTR_FLAG_LOWMED (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C.
#define ESP_INTR_FLAG_HIGH (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly.
#define ESP_INTR_FLAG_LOWMED (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C.
#define ESP_INTR_FLAG_HIGH (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly.
#define ESP_INTR_FLAG_LEVELMASK (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \
ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \
ESP_INTR_FLAG_NMI) ///< Mask for all level flags
#define ESP_INTR_FLAG_LEVELMASK (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \
ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \
ESP_INTR_FLAG_NMI) ///< Mask for all level flags
/** @addtogroup Intr_Alloc_Pseudo_Src
@@ -67,18 +66,18 @@ extern "C" {
* sources that do not pass through the interrupt mux. To allocate an interrupt for these sources,
* pass these pseudo-sources to the functions.
*/
#define ETS_INTERNAL_TIMER0_INTR_SOURCE -1 ///< Platform timer 0 interrupt source
#define ETS_INTERNAL_TIMER1_INTR_SOURCE -2 ///< Platform timer 1 interrupt source
#define ETS_INTERNAL_TIMER2_INTR_SOURCE -3 ///< Platform timer 2 interrupt source
#define ETS_INTERNAL_SW0_INTR_SOURCE -4 ///< Software int source 1
#define ETS_INTERNAL_SW1_INTR_SOURCE -5 ///< Software int source 2
#define ETS_INTERNAL_PROFILING_INTR_SOURCE -6 ///< Int source for profiling
#define ETS_INTERNAL_TIMER0_INTR_SOURCE -1 ///< Platform timer 0 interrupt source
#define ETS_INTERNAL_TIMER1_INTR_SOURCE -2 ///< Platform timer 1 interrupt source
#define ETS_INTERNAL_TIMER2_INTR_SOURCE -3 ///< Platform timer 2 interrupt source
#define ETS_INTERNAL_SW0_INTR_SOURCE -4 ///< Software int source 1
#define ETS_INTERNAL_SW1_INTR_SOURCE -5 ///< Software int source 2
#define ETS_INTERNAL_PROFILING_INTR_SOURCE -6 ///< Int source for profiling
/**@}*/
/** Provides SystemView with positive IRQ IDs, otherwise scheduler events are not shown properly
*/
#define ETS_INTERNAL_INTR_SOURCE_OFF (-ETS_INTERNAL_PROFILING_INTR_SOURCE)
#define ETS_INTERNAL_INTR_SOURCE_OFF (-ETS_INTERNAL_PROFILING_INTR_SOURCE)
/** Enable interrupt by interrupt number */
#define ESP_INTR_ENABLE(inum) esp_intr_enable_source(inum)
@@ -93,7 +92,7 @@ typedef void (*intr_handler_t)(void *arg);
typedef struct intr_handle_data_t intr_handle_data_t;
/** 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
@@ -306,11 +305,18 @@ void esp_intr_enable_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
}
#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");
// 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
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -21,6 +20,7 @@
#include <esp_types.h>
#include <limits.h>
#include <assert.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.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
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
# define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__)
#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");
return false;
}
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
//Check if the interrupt level is acceptable
if (!(flags&(1<<interrupt_controller_hal_get_level(x)))) {
ALCHLOG("....Unusable: incompatible level");
@@ -244,10 +247,12 @@ static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force
}
//check if edge/level type matches what we want
if (((flags&ESP_INTR_FLAG_EDGE) && (interrupt_controller_hal_get_type(x)==INTTP_LEVEL)) ||
(((!(flags&ESP_INTR_FLAG_EDGE)) && (interrupt_controller_hal_get_type(x)==INTTP_EDGE)))) {
(((!(flags&ESP_INTR_FLAG_EDGE)) && (interrupt_controller_hal_get_type(x)==INTTP_EDGE)))) {
ALCHLOG("....Unusable: incompatible trigger type");
return false;
}
#endif
//check if interrupt is reserved at runtime
if (vd->flags&VECDESC_FL_RESERVED) {
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);
#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) {
ESP_INTR_DISABLE(intr);
esprv_intc_int_set_priority(intr, 0);
interrupt_controller_hal_edge_int_acknowledge(intr);
}
#endif
vd->source=source;
}
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);
}
#if CONFIG_IDF_TARGET_ESP32C3
// TODO ESP32-C3 IDF-2126, these need to be set or the new interrupt won't fire, but are currently hard-coded
// for priority and level...
esprv_intc_int_set_priority(intr, 1);
esprv_intc_int_set_type(BIT(intr), INTR_TYPE_LEVEL);
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
//Extract the level from the interrupt passed flags
int level = esp_intr_flags_to_level(flags);
interrupt_controller_hal_set_int_level(intr, 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
portEXIT_CRITICAL(&spinlock);

View File

@@ -77,19 +77,23 @@
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "sdkconfig.h"
#include "portmacro.h"
#include "riscv/interrupt.h"
#include "riscv/rvruntime-frames.h"
#include "sdkconfig.h"
#include "soc/periph_defs.h"
#include "soc/system_reg.h"
#include "soc/interrupt_reg.h"
#include "hal/systimer_hal.h"
#include "hal/systimer_ll.h"
#include "riscv/rvruntime-frames.h"
#include "riscv/riscv_interrupts.h"
#include "riscv/interrupt.h"
#include "esp_system.h"
#include "esp_intr_alloc.h"
#include "esp_private/crosscore_int.h"
#include "esp_attr.h"
#include "esp_log.h"
/**
@@ -102,15 +106,14 @@ static UBaseType_t uxCriticalNesting = 0;
static UBaseType_t uxSavedInterruptState = 0;
BaseType_t uxSchedulerRunning = 0;
UBaseType_t uxInterruptNesting = 0;
BaseType_t xPortSwitchFlag = 0;
__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE];
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 void vPortSysTickHandler(void);
static void vPortSysTickHandler(void *arg);
static void vPortSetupTimer(void);
static void vPortSetupSoftwareInterrupt(void);
static void vPortSoftwareInterrupt(void);
static void prvTaskExitError(void);
extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only
@@ -121,7 +124,6 @@ void vPortEnterCritical(void)
uxCriticalNesting++;
if (uxCriticalNesting == 1) {
//portDISABLE_INTERRUPTS();
uxSavedInterruptState = state;
}
}
@@ -132,7 +134,6 @@ void vPortExitCritical(void)
uxCriticalNesting--;
if (uxCriticalNesting == 0) {
portEXIT_CRITICAL_NESTED(uxSavedInterruptState);
//portENABLE_INTERRUPTS();
}
}
}
@@ -143,16 +144,9 @@ void vPortExitCritical(void)
*/
void vPortSetupTimer(void)
{
/* register the interrupt handler */
intr_handler_set(ETS_SYSTICK_INUM, (intr_handler_t)&vPortSysTickHandler, NULL);
/* 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);
/* set system timer interrupt vector */
esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, vPortSysTickHandler, NULL, NULL);
assert(err == ESP_OK);
/* configure the timer */
systimer_hal_init();
@@ -163,24 +157,6 @@ void vPortSetupTimer(void)
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)
{
/* 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. */
configASSERT(uxCriticalNesting == ~0UL);
portDISABLE_INTERRUPTS();
for (;;)
;
abort();
}
/* Clear current interrupt mask and set given mask */
@@ -212,9 +187,6 @@ int vPortSetInterruptMask(void)
return ret;
}
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
{
extern uint32_t __global_pointer$;
@@ -231,11 +203,15 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
frame->a1 = 0x11111111;
frame->a2 = 0x22222222;
frame->a3 = 0x33333333;
//TODO: IDF-2393
return (StackType_t *)frame;
}
void vPortSysTickHandler(void)
IRAM_ATTR void vPortSysTickHandler(void *arg)
{
(void)arg;
systimer_ll_clear_alarm_int(SYSTIMER_ALARM_0);
if (!uxSchedulerRunning) {
@@ -243,19 +219,23 @@ void vPortSysTickHandler(void)
}
if (xTaskIncrementTick() != pdFALSE) {
vTaskSwitchContext();
vPortYieldFromISR();
}
}
BaseType_t xPortStartScheduler(void)
{
vPortSetupTimer();
vPortSetupSoftwareInterrupt();
uxInterruptNesting = 0;
uxCriticalNesting = 0;
uxSchedulerRunning = 0; /* this means first yield */
uxSchedulerRunning = 0;
vPortSetupTimer();
esprv_intc_int_set_threshold(1); /* set global INTC masking level */
riscv_global_interrupts_enable();
vPortYield();
/*Should not get here*/
return pdFALSE;
}
@@ -263,21 +243,18 @@ BaseType_t xPortStartScheduler(void)
void vPortEndScheduler(void)
{
/* very unlikely this function will be called, so just trap here */
while (1)
;
}
void vPortSoftwareInterrupt(void)
{
uxSchedulerRunning = 1;
vTaskSwitchContext();
REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0);
abort();
}
void vPortYieldOtherCore(BaseType_t coreid)
{
(void)coreid;
vPortYield();
esp_crosscore_int_send_yield(coreid);
}
void vPortYieldFromISR( void )
{
uxSchedulerRunning = 1;
xPortSwitchFlag = 1;
}
void vPortYield(void)
@@ -285,8 +262,8 @@ void vPortYield(void)
if (uxInterruptNesting) {
vPortYieldFromISR();
} 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
interrupt and the CPU interrupt happening. Make sure it happened before
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
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)
@@ -319,30 +292,30 @@ BaseType_t xPortInIsrContext(void)
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
{
/* For single core, this can be the same as xPortInIsrContext() because reading it is atomic */
return uxInterruptNesting;
return uxInterruptNesting;
}
void vPortCPUInitializeMutex(portMUX_TYPE *mux)
{
(void)mux;
(void)mux; //TODO: IDF-2393
}
void vPortCPUAcquireMutex(portMUX_TYPE *mux)
{
(void)mux;
(void)mux; //TODO: IDF-2393
}
bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles)
{
(void)mux;
(void)mux; //TODO: IDF-2393
(void)timeout_cycles;
return true;
}
void vPortCPUReleaseMutex(portMUX_TYPE *mux)
{
(void)mux;
(void)mux; //TODO: IDF-2393
}
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 */
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
sw t2, 0x0(t0)
lw sp, xIsrStackTop
not_rtos_enter:
rtos_enter_end:
mv ra, t1
ret
@@ -56,10 +65,23 @@ not_rtos_enter:
.global rtos_int_exit
.type rtos_int_exit, @function
rtos_int_exit:
/* may skip RTOS aware interrupt since scheduler was not started */
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 */
la t0, xPortSwitchFlag
@@ -83,5 +105,5 @@ no_switch:
lw a0, pxCurrentTCB
lw a0, 0x0(a0)
not_rtos_exit:
rtos_exit_end:
ret

View File

@@ -28,8 +28,7 @@ if(NOT BOOTLOADER_BUILD)
"soc_hal.c"
"interrupt_controller_hal.c"
"sha_hal.c"
"aes_hal.c"
"${target}/interrupt_descriptor_table.c")
"aes_hal.c")
if(${target} STREQUAL "esp32")
list(APPEND srcs
@@ -43,6 +42,7 @@ if(NOT BOOTLOADER_BUILD)
"twai_hal_iram.c"
"esp32/adc_hal.c"
"esp32/brownout_hal.c"
"esp32/interrupt_descriptor_table.c"
"esp32/touch_sensor_hal.c")
if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC)
list(APPEND srcs "esp32/emac_hal.c")
@@ -65,6 +65,7 @@ if(NOT BOOTLOADER_BUILD)
"esp32s2/systimer_hal.c"
"esp32s2/touch_sensor_hal.c"
"esp32s2/dac_hal.c"
"esp32s2/interrupt_descriptor_table.c"
"esp32s2/usb_hal.c")
endif()
@@ -79,6 +80,7 @@ if(NOT BOOTLOADER_BUILD)
"twai_hal.c"
"twai_hal_iram.c"
"esp32s3/brownout_hal.c"
"esp32s3/interrupt_descriptor_table.c"
"esp32s3/systimer_hal.c"
"esp32s3/touch_sensor_hal.c")
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 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);
}
@@ -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
*/
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);
}
@@ -100,6 +100,16 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t 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
}
#endif

View File

@@ -30,7 +30,7 @@
extern "C" {
#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
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 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);
}
@@ -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
*/
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);
}
@@ -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 type new type for this interrupt
* @param intr interrupt number ranged from 0 to 31
*/
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 level new level for this interrupt
* @param interrupt_number Interrupt number 0 to 31
* @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
}

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 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);
}
@@ -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
*/
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);
}
@@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t 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
}
#endif

View File

@@ -21,13 +21,14 @@
#include "xtensa/config/specreg.h"
#include "xtensa/config/extreg.h"
#include "esp_bit_defs.h"
#include "esp_attr.h"
#include "xtensa/config/core.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline int cpu_ll_get_core_id(void)
static inline int IRAM_ATTR cpu_ll_get_core_id(void)
{
uint32_t id;
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 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);
}
@@ -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
*/
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);
}
@@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t 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
}
#endif

View File

@@ -23,12 +23,14 @@
extern "C" {
#endif
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
/**
* @brief Gets target platform interrupt descriptor table
*
* @return Address of interrupt descriptor table
*/
__attribute__((pure)) const int_desc_t *interrupt_controller_hal_desc_table(void);
#endif
/**
* @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);
#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.
*
@@ -95,6 +79,30 @@ static inline int interrupt_controller_hal_get_level(int 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.
*
@@ -184,6 +192,16 @@ static inline void interrupt_controller_hal_enable_int_mask(uint32_t 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
}
#endif

View File

@@ -24,13 +24,13 @@ extern "C" {
typedef enum {
INTDESC_NORMAL=0,
INTDESC_RESVD,
INTDESC_SPECIAL
INTDESC_SPECIAL,
} int_desc_flag_t;
typedef enum {
INTTP_LEVEL=0,
INTTP_EDGE,
INTTP_NA
INTTP_NA,
} int_type_t;
typedef struct {

View File

@@ -14,36 +14,52 @@
#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)
{
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
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)
{
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
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)
{
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
const int_desc_t *int_desc = interrupt_controller_hal_desc_table();
return(int_desc[interrupt_number].cpuflags[cpu_number]);
}
#if SOC_INTERRUPT_LEVEL_CAN_SET
void interrupt_controller_hal_set_level(int interrupt_number, int level) {
intr_cntrl_ll_set_level(interrupt_number, level);
}
return (int_desc[interrupt_number].cpuflags[cpu_number]);
#else
#if __riscv
return is_interrupt_number_reserved(interrupt_number) ? INTDESC_RESVD : INTDESC_NORMAL;
#else
return INTDESC_NORMAL;
#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
}

View File

@@ -7,6 +7,9 @@ if(BOOTLOADER_BUILD)
else()
set(priv_requires soc freertos)
set(srcs
"expression_with_stack_riscv.c"
"expression_with_stack_riscv_asm.S"
"instruction_decode.c"
"interrupt.c"
"stdatomic.c"
"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");
// 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
@@ -14,12 +14,20 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#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
}

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
.endm
.global vPortYieldFromISR
.global uxInterruptNesting
.global uxSchedulerRunning
.global xIsrStackTop
.global pxCurrentTCB
.global rtos_int_enter
.global rtos_int_exit
.global _global_interrupt_handler
.section .exception_vectors.text
@@ -219,25 +216,11 @@ _interrupt_handler:
save_regs
save_mepc
/* scheduler not enabled, jump directly to ISR handler */
lw t0, uxSchedulerRunning
beq t0, zero, already_on_handler
/* Before doing anythig preserve the stack pointer */
/* It will be saved in current TCB, if needed */
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 */
csrr s1, mcause
csrr s2, mstatus
@@ -278,29 +261,13 @@ already_on_handler:
sw s3, 0(t0)
fence
/* may skip RTOS aware interrupt since scheduler was not started */
lw t1, uxSchedulerRunning
beq t1,zero, isr_exit
/* Yield to the next task is needed: */
mv a0, sp
call rtos_int_exit
/* update nesting interrupts counter */
la t0, uxInterruptNesting
lw t1, 0x0(t0)
/* The next (or current) stack pointer is returned in a0 */
mv sp, a0
/* 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 */
csrw mcause, s1
csrw mstatus, s2

View File

@@ -16,5 +16,6 @@
#define SOC_CPU_BREAKPOINTS_NUM 8
#define SOC_CPU_WATCHPOINTS_NUM 8
#define SOC_CPU_HAS_FLEXIBLE_INTC 1
#define SOC_CPU_WATCHPOINT_SIZE 0x80000000 // bytes

View File

@@ -43,7 +43,6 @@
#include "rmt_caps.h"
#include "spi_caps.h"
#include "uart_caps.h"
#include "int_caps.h"
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
#define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */