Consolidate interrupt management in core as esp/interrupts.h & esp_interrupts.c

This commit is contained in:
Angus Gratton 2015-09-24 08:58:34 +10:00
parent 65307aed75
commit ed8470631f
8 changed files with 83 additions and 98 deletions

60
core/esp_interrupts.c Normal file
View file

@ -0,0 +1,60 @@
/* ESP8266 Xtensa interrupt management functions
*
*
* Part of esp-open-rtos
* Copyright (C) 2015 Angus Gratton
* BSD Licensed as described in the file LICENSE
*/
#include <esp/interrupts.h>
_xt_isr isr[16];
void IRAM _xt_isr_attach(uint8_t i, _xt_isr func)
{
isr[i] = func;
}
/* This ISR handler is taken directly from the FreeRTOS port and
probably could use a cleanup.
*/
uint16_t IRAM _xt_isr_handler(uint16_t i)
{
uint8_t index;
/* I think this is implementing some kind of interrupt priority or
short-circuiting an expensive ffs for most common interrupts - ie
WDT And GPIO are common or high priority, then remaining flags.
*/
if (i & (1 << INUM_WDT)) {
index = INUM_WDT;
}
else if (i & (1 << INUM_GPIO)) {
index = INUM_GPIO;
}else {
index = __builtin_ffs(i) - 1;
if (index == INUM_MAX) {
/* I don't understand what happens here. INUM_MAX is not
the highest interrupt number listed (and the isr array
has 16 entries).
Clearing that flag and then setting index to
__builtin_ffs(i)-1 may result in index == 255 if no
higher flags are set, unless this is guarded against
somehow by the caller?
I also don't understand why the code is written like
this in esp_iot_rtos_sdk instead of just putting the i
&= line near the top... Probably no good reason?
*/
i &= ~(1 << INUM_MAX);
index = __builtin_ffs(i) - 1;
}
}
_xt_clear_ints(1<<index);
isr[index]();
return i & ~(1 << index);
}

View file

@ -1,33 +0,0 @@
/* esp/cpu.h
*
* Details relating to the ESP8266 Xtensa core.
*
*/
#ifndef _ESP_CPU_H
#define _ESP_CPU_H
#include <stdbool.h>
/* Interrupt numbers for level 1 exception handler.
*
* Currently the UserExceptionVector calls down to _xt_isr_handler,
* defined in port.c, for at least some of these interrupts. Some are handled
* on the SDK side, though.
*/
typedef enum {
INUM_SPI = 2,
INUM_GPIO = 4,
INUM_UART = 5,
INUM_MAX = 6, /* in some places this is documented as timer0 CCOMPARE0 interrupt */
INUM_SOFT = 7,
INUM_WDT = 8,
INUM_TIMER_FRC1 = 9,
/* FRC2 default handler. Configured by sdk_ets_timer_init, which
runs as part of default libmain.a startup code, assigns
interrupt handler to sdk_vApplicationTickHook+0x68
*/
INUM_TIMER_FRC2 = 10,
} xt_isr_num_t;
#endif

View file

@ -11,8 +11,7 @@
#include <stdbool.h>
#include "esp/gpio_regs.h"
#include "esp/iomux.h"
#include "esp/cpu.h"
#include "xtensa_interrupts.h"
#include "esp/interrupts.h"
typedef enum {
GPIO_INPUT,

View file

@ -0,0 +1,102 @@
/* ESP8266 Xtensa interrupt management functions
*
* Some (w/ sdk_ prefix) are implemented in binary libs, rest are
* inlines replacing functions in the binary libraries.
*
* Part of esp-open-rtos
* Copyright (C) 2015 Superhouse Automation Pty Ltd
* BSD Licensed as described in the file LICENSE
*/
#ifndef _XTENSA_INTERRUPTS_H
#define _XTENSA_INTERRUPTS_H
#include <stdint.h>
#include <stdbool.h>
#include <xtruntime.h>
#include <xtensa/hal.h>
#include <common_macros.h>
/* Interrupt numbers for level 1 exception handler. */
typedef enum {
INUM_SPI = 2,
INUM_GPIO = 4,
INUM_UART = 5,
INUM_MAX = 6, /* in some places this is documented as timer0 CCOMPARE0 interrupt */
INUM_SOFT = 7,
INUM_WDT = 8,
INUM_TIMER_FRC1 = 9,
/* FRC2 default handler. Configured by sdk_ets_timer_init, which
runs as part of default libmain.a startup code, assigns
interrupt handler to sdk_vApplicationTickHook+0x68
*/
INUM_TIMER_FRC2 = 10,
} xt_isr_num_t;
void sdk__xt_int_exit (void);
void _xt_user_exit (void);
void sdk__xt_tick_timer_init (void);
void sdk__xt_timer_int1(void);
INLINED uint32_t _xt_get_intlevel(void)
{
uint32_t level;
__asm__ volatile("rsr %0, intlevel" : "=a"(level));
return level;
}
/* Disable interrupts and return the old ps value, to pass into
_xt_restore_interrupts later.
This is desirable to use in place of
portDISABLE_INTERRUPTS/portENABLE_INTERRUPTS for
non-FreeRTOS & non-portable code.
*/
INLINED uint32_t _xt_disable_interrupts(void)
{
uint32_t old_level;
__asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (old_level));
return old_level;
}
/* Restore PS level. Intended to be used with _xt_disable_interrupts */
INLINED void _xt_restore_interrupts(uint32_t new_ps)
{
__asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
}
/* ESPTODO: the mask/unmask functions aren't thread safe */
INLINED void _xt_isr_unmask(uint32_t unmask)
{
uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (intenable));
intenable |= unmask;
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
}
INLINED void _xt_isr_mask (uint32_t mask)
{
uint32_t intenable;
asm volatile ("rsr %0, intenable" : "=a" (intenable));
intenable &= ~mask;
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
}
INLINED uint32_t _xt_read_ints (void)
{
uint32_t interrupt;
asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
return interrupt;
}
INLINED void _xt_clear_ints(uint32_t mask)
{
asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
}
typedef void (* _xt_isr)(void);
/* This function is implemeneted in FreeRTOS port.c at the moment,
should be moved or converted to an inline */
void _xt_isr_attach (uint8_t i, _xt_isr func);
#endif

View file

@ -10,9 +10,8 @@
#define _ESP_TIMER_H
#include <stdbool.h>
#include <xtensa_interrupts.h>
#include "esp/timer_regs.h"
#include "esp/cpu.h"
#include "esp/interrupts.h"
typedef enum {
FRC1 = 0,

View file

@ -13,7 +13,7 @@
#include "common_macros.h"
#include "esp/registers.h"
#include "esp/cpu.h"
#include "esp/interrupts.h"
#include "esp/iomux.h"
#include "esp/gpio.h"
#include "esp/timer.h"