@@ -11,10 +11,18 @@ const TIMESLICE_FREQUENCY: Rate = Rate::from_hz(crate::CONFIG.tick_rate_hz);
1111
1212use super :: TIMER ;
1313
14+ // ESP32 uses Software1 (priority 3) for task switching, because it reserves
15+ // Software0 for the Bluetooth stack.
16+ const SW_INTERRUPT : u32 = if cfg ! ( esp32) { 1 << 29 } else { 1 << 7 } ;
17+
1418pub ( crate ) fn setup_timer ( mut timer1 : TimeBase ) {
19+ // The timer needs to tick at Priority 1 to prevent accidentally interrupting
20+ // priority 1 limited locks.
1521 timer1. set_interrupt_handler ( InterruptHandler :: new (
16- unsafe { core:: mem:: transmute :: < * const ( ) , extern "C" fn ( ) > ( handler as * const ( ) ) } ,
17- interrupt:: Priority :: Priority2 ,
22+ unsafe {
23+ core:: mem:: transmute :: < * const ( ) , extern "C" fn ( ) > ( timer_tick_handler as * const ( ) )
24+ } ,
25+ interrupt:: Priority :: Priority1 ,
1826 ) ) ;
1927 unwrap ! ( timer1. start( TIMESLICE_FREQUENCY . as_duration( ) ) ) ;
2028 TIMER . with ( |timer| {
@@ -35,7 +43,7 @@ pub(crate) fn setup_multitasking() {
3543 unsafe {
3644 let enabled = xtensa_lx:: interrupt:: disable ( ) ;
3745 xtensa_lx:: interrupt:: enable_mask (
38- ( 1 << 29 )
46+ SW_INTERRUPT
3947 | xtensa_lx_rt:: interrupt:: CpuInterruptLevel :: Level2 . mask ( )
4048 | xtensa_lx_rt:: interrupt:: CpuInterruptLevel :: Level6 . mask ( )
4149 | enabled,
@@ -44,38 +52,39 @@ pub(crate) fn setup_multitasking() {
4452}
4553
4654pub ( crate ) fn disable_multitasking ( ) {
47- xtensa_lx:: interrupt:: disable_mask (
48- 1 << 29 , // Disable Software1
49- ) ;
55+ xtensa_lx:: interrupt:: disable_mask ( SW_INTERRUPT ) ;
5056}
5157
52- fn do_task_switch ( context : & mut TrapFrame ) {
58+ extern "C" fn timer_tick_handler ( _context : & mut TrapFrame ) {
5359 TIMER . with ( |timer| {
5460 let timer = unwrap ! ( timer. as_mut( ) ) ;
5561 timer. clear_interrupt ( ) ;
5662 } ) ;
5763
58- task_switch ( context) ;
59- }
60-
61- extern "C" fn handler ( context : & mut TrapFrame ) {
62- do_task_switch ( context) ;
64+ // `task_switch` must be called on a single interrupt priority level only.
65+ // Because on ESP32 the software interrupt is triggered at priority 3 but
66+ // the timer interrupt is triggered at priority 1, we need to trigger the
67+ // software interrupt manually.
68+ cfg_if:: cfg_if! {
69+ if #[ cfg( esp32) ] {
70+ yield_task( ) ;
71+ } else {
72+ task_switch( _context) ;
73+ }
74+ }
6375}
6476
6577#[ allow( non_snake_case) ]
66- #[ no_mangle]
67- fn Software1 ( _level : u32 , context : & mut TrapFrame ) {
68- let intr = 1 << 29 ;
69- unsafe {
70- core:: arch:: asm!( "wsr.intclear {0}" , in( reg) intr, options( nostack) ) ;
71- }
78+ #[ cfg_attr( not( esp32) , export_name = "Software0" ) ]
79+ #[ cfg_attr( esp32, export_name = "Software1" ) ]
80+ fn task_switch_interrupt ( _level : u32 , context : & mut TrapFrame ) {
81+ let intr = SW_INTERRUPT ;
82+ unsafe { core:: arch:: asm!( "wsr.intclear {0}" , in( reg) intr, options( nostack) ) } ;
7283
73- do_task_switch ( context) ;
84+ task_switch ( context) ;
7485}
7586
7687pub ( crate ) fn yield_task ( ) {
77- let intr = 1 << 29 ;
78- unsafe {
79- core:: arch:: asm!( "wsr.intset {0}" , in( reg) intr, options( nostack) ) ;
80- }
88+ let intr = SW_INTERRUPT ;
89+ unsafe { core:: arch:: asm!( "wsr.intset {0}" , in( reg) intr, options( nostack) ) } ;
8190}
0 commit comments