Simplify interrupt and RTOS timer tick handlers

RTOS Timer tick handler is now the same as any other ISR.

This causes a few subtle behaviour changes that seem OK but are worth noting:

* RTOS tick handler sdk__xt_timer_int() is now called from one stack
  frame deeper (inside _xt_isr_handler()), whereas before it was called
  from the level above in UserHandleInterrupt. I can't see any way that
  the extra ~40 bytes of stack use here hurt, though.

* sdk__xt_timer_int() was previous called after all other interrupts
  flagged in the handler, now it's called before the TIMER FRC1 & FRC2
  handlers. The tick handler doesn't appear to do anything particularly
  timing intensive, though.

* GPIO interrupt (value 3) is now lower priority than the SPI
  interrupt (value 2), whereas before it would have been called before
  SPI if both interrupts triggered at once.
This commit is contained in:
Angus Gratton 2015-09-24 10:17:07 +10:00
parent 9f7a5a7fdd
commit 23ea182e83
4 changed files with 31 additions and 68 deletions

View file

@ -198,6 +198,8 @@ portBASE_TYPE xPortStartScheduler( void )
} }
/* Initialize system tick timer interrupt and schedule the first tick. */ /* Initialize system tick timer interrupt and schedule the first tick. */
_xt_isr_attach(INUM_TICK, sdk__xt_timer_int);
_xt_isr_unmask(BIT(INUM_TICK));
sdk__xt_tick_timer_init(); sdk__xt_tick_timer_init();
vTaskSwitchContext(); vTaskSwitchContext();

View file

@ -14,47 +14,26 @@ void IRAM _xt_isr_attach(uint8_t i, _xt_isr func)
isr[i] = func; isr[i] = func;
} }
/* This ISR handler is taken directly from the FreeRTOS port and /* Generic ISR handler.
probably could use a cleanup.
Handles all flags set for interrupts in 'intset'.
*/ */
uint16_t IRAM _xt_isr_handler(uint16_t i) uint16_t IRAM _xt_isr_handler(uint16_t intset)
{ {
uint8_t index; /* WDT has highest priority (occasional WDT resets otherwise) */
if(intset & BIT(INUM_WDT)) {
/* I think this is implementing some kind of interrupt priority or _xt_clear_ints(BIT(INUM_WDT));
short-circuiting an expensive ffs for most common interrupts - ie isr[INUM_WDT]();
WDT And GPIO are common or high priority, then remaining flags. intset -= BIT(INUM_WDT);
*/
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); while(intset) {
uint8_t index = __builtin_ffs(intset) - 1;
uint16_t mask = BIT(index);
_xt_clear_ints(mask);
isr[index](); isr[index]();
intset -= mask;
return i & ~(1 << index); }
return 0;
} }

View file

@ -469,7 +469,6 @@ CallNMIExceptionHandler:
* LoadStoreCause. */ * LoadStoreCause. */
.literal_position .literal_position
.balign 4 .balign 4
UserExceptionHandler: UserExceptionHandler:
.type UserExceptionHandler, @function .type UserExceptionHandler, @function
@ -490,46 +489,28 @@ UserExceptionHandler:
wsr a0, ps wsr a0, ps
rsync rsync
rsr a2, exccause rsr a2, exccause
beqi a2, CAUSE_LVL1INT, UserHandleInterrupt /* Any UserException cause other than a level 1 interrupt is fatal */
/* Any UserException cause other than level 1 interrupt should panic */ bnei a2, CAUSE_LVL1INT, .UserFailOtherExceptionCause
UserFailOtherExceptionCause: .UserHandleInterrupt:
break 1, 1
call0 sdk_user_fatal_exception_handler
UserHandleInterrupt:
rsil a0, 1 rsil a0, 1
rsr a2, intenable rsr a2, intenable
rsr a3, interrupt rsr a3, interrupt
movi a4, 0x3fff movi a4, 0x3fff
and a2, a2, a3 and a2, a2, a3
and a2, a2, a4 # a2 = 0x3FFF & INTENABLE & INTERRUPT and a2, a2, a4 # a2 = 0x3FFF & INTENABLE & INTERRUPT
UserHandleTimer:
movi a3, 0xffbf
and a3, a2, a3 # a3 = a2 with bit 6 cleared
bnez a3, UserTimerDone # If any non-timer interrupt bits set
movi a3, 0x40
sub a12, a2, a3 # a12 = a2 - 0x40 -- Will be zero if bit 6 set
call0 sdk__xt_timer_int # tick timer interrupt
mov a2, a12 # restore a2 from a12, ie zero
beqz a2, UserIntDone
UserTimerDone:
call0 _xt_isr_handler call0 _xt_isr_handler
bnez a2, UserHandleTimer j sdk__xt_int_exit # once finished, jumps to _xt_user_exit via stack
UserIntDone:
beqz a2, UserIntExit .literal_position
/* FIXME: this code will never be reached */ .UserFailOtherExceptionCause:
break 1, 1 break 1, 1
call0 sdk_user_fatal_exception_handler call0 sdk_user_fatal_exception_handler
UserIntExit:
call0 sdk__xt_int_exit # jumps to _xt_user_exit. Never returns here
.section .text /* _xt_user_exit is pushed onto the stack as part of the user exception handler,
restores same set registers which were saved there and returns from exception */
/* _xt_user_exit is used to exit interrupt context. */
/* TODO: Find a better place for this to live. */
_xt_user_exit: _xt_user_exit:
.global _xt_user_exit .global _xt_user_exit
.type _xt_user_exit, @function .type _xt_user_exit, @function
l32i a0, sp, 0x8 l32i a0, sp, 0x8
wsr a0, ps wsr a0, ps
l32i a0, sp, 0x4 l32i a0, sp, 0x4

View file

@ -20,7 +20,7 @@ typedef enum {
INUM_SPI = 2, INUM_SPI = 2,
INUM_GPIO = 4, INUM_GPIO = 4,
INUM_UART = 5, INUM_UART = 5,
INUM_MAX = 6, /* in some places this is documented as timer0 CCOMPARE0 interrupt */ INUM_TICK = 6, /* RTOS timer tick, possibly xtensa CPU CCOMPARE0(?) */
INUM_SOFT = 7, INUM_SOFT = 7,
INUM_WDT = 8, INUM_WDT = 8,
INUM_TIMER_FRC1 = 9, INUM_TIMER_FRC1 = 9,
@ -35,6 +35,7 @@ typedef enum {
void sdk__xt_int_exit (void); void sdk__xt_int_exit (void);
void _xt_user_exit (void); void _xt_user_exit (void);
void sdk__xt_tick_timer_init (void); void sdk__xt_tick_timer_init (void);
void sdk__xt_timer_int(void);
void sdk__xt_timer_int1(void); void sdk__xt_timer_int1(void);
INLINED uint32_t _xt_get_intlevel(void) INLINED uint32_t _xt_get_intlevel(void)