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:
		
							parent
							
								
									9f7a5a7fdd
								
							
						
					
					
						commit
						23ea182e83
					
				
					 4 changed files with 31 additions and 68 deletions
				
			
		|  | @ -198,6 +198,8 @@ portBASE_TYPE xPortStartScheduler( void ) | |||
|     } | ||||
| 
 | ||||
|     /* 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(); | ||||
| 
 | ||||
|     vTaskSwitchContext(); | ||||
|  |  | |||
|  | @ -14,47 +14,26 @@ 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. | ||||
| /* Generic ISR handler.
 | ||||
| 
 | ||||
|    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; | ||||
| 
 | ||||
|     /* 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; | ||||
| 	} | ||||
|     /* WDT has highest priority (occasional WDT resets otherwise) */ | ||||
|     if(intset & BIT(INUM_WDT)) { | ||||
|         _xt_clear_ints(BIT(INUM_WDT)); | ||||
|         isr[INUM_WDT](); | ||||
|         intset -= BIT(INUM_WDT); | ||||
|     } | ||||
| 
 | ||||
|     _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](); | ||||
|         intset -= mask; | ||||
|     } | ||||
| 
 | ||||
|     isr[index](); | ||||
| 
 | ||||
|     return i & ~(1 << index); | ||||
|     return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -469,7 +469,6 @@ CallNMIExceptionHandler: | |||
|  * LoadStoreCause. */ | ||||
| 
 | ||||
|         .literal_position | ||||
| 
 | ||||
|         .balign  4
 | ||||
| UserExceptionHandler: | ||||
|         .type   UserExceptionHandler, @function
 | ||||
|  | @ -490,46 +489,28 @@ UserExceptionHandler: | |||
|         wsr     a0, ps | ||||
|         rsync | ||||
|         rsr     a2, exccause | ||||
|         beqi    a2, CAUSE_LVL1INT, UserHandleInterrupt | ||||
|         /* Any UserException cause other than level 1 interrupt should panic */ | ||||
| UserFailOtherExceptionCause: | ||||
|         break   1, 1 | ||||
|         call0   sdk_user_fatal_exception_handler | ||||
| UserHandleInterrupt: | ||||
|         /* Any UserException cause other than a level 1 interrupt is fatal */ | ||||
|         bnei    a2, CAUSE_LVL1INT, .UserFailOtherExceptionCause | ||||
| .UserHandleInterrupt: | ||||
|         rsil    a0, 1 | ||||
|         rsr     a2, intenable | ||||
|         rsr     a3, interrupt | ||||
|         movi    a4, 0x3fff | ||||
|         and     a2, a2, a3 | ||||
|         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: | ||||
|         and     a2, a2, a4       # a2 = 0x3FFF & INTENABLE & INTERRUPT | ||||
|         call0   _xt_isr_handler | ||||
|         bnez    a2, UserHandleTimer | ||||
| UserIntDone: | ||||
|         beqz    a2, UserIntExit | ||||
|         /* FIXME: this code will never be reached */ | ||||
|         j       sdk__xt_int_exit # once finished, jumps to _xt_user_exit via stack | ||||
| 
 | ||||
|         .literal_position | ||||
| .UserFailOtherExceptionCause: | ||||
|         break   1, 1 | ||||
|         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 used to exit interrupt context. */ | ||||
| /* TODO: Find a better place for this to live. */ | ||||
| /* _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: | ||||
|         .global _xt_user_exit
 | ||||
|         .type _xt_user_exit, @function
 | ||||
| 
 | ||||
|         l32i    a0, sp, 0x8 | ||||
|         wsr     a0, ps | ||||
|         l32i    a0, sp, 0x4 | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ 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_TICK = 6, /* RTOS timer tick, possibly xtensa CPU CCOMPARE0(?) */ | ||||
|     INUM_SOFT = 7, | ||||
|     INUM_WDT = 8, | ||||
|     INUM_TIMER_FRC1 = 9, | ||||
|  | @ -35,6 +35,7 @@ typedef enum { | |||
| void sdk__xt_int_exit (void); | ||||
| void _xt_user_exit (void); | ||||
| void sdk__xt_tick_timer_init (void); | ||||
| void sdk__xt_timer_int(void); | ||||
| void sdk__xt_timer_int1(void); | ||||
| 
 | ||||
| INLINED uint32_t _xt_get_intlevel(void) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue