@@ -5,6 +5,8 @@ package runtime
55import (
66 "device/esp"
77 "machine"
8+ "runtime/interrupt"
9+ "runtime/volatile"
810 "unsafe"
911)
1012
@@ -73,11 +75,62 @@ func ticksToNanoseconds(ticks timeUnit) int64 {
7375 return int64 (ticks ) * 25
7476}
7577
76- // sleepTicks busy-waits until the given number of ticks have passed.
78+ // CPU interrupt number used for the TIMG0 timer alarm.
79+ const timerAlarmCPUInterrupt = 9
80+
81+ var interruptPending volatile.Register8
82+
83+ func signalInterrupt () {
84+ interruptPending .Set (1 )
85+ }
86+
87+ var timerAlarmInterrupt interrupt.Interrupt
88+
89+ // timerAlarmHandler clears the timer interrupt at the peripheral level
90+ // and disables INT_ENA to prevent level-triggered re-assertion.
91+ func timerAlarmHandler (interrupt.Interrupt ) {
92+ esp .TIMG0 .INT_ENA_TIMERS .ClearBits (1 )
93+ esp .TIMG0 .INT_CLR_TIMERS .Set (1 )
94+ }
95+
96+ // initTimerInterrupt routes the TIMG0 timer 0 alarm interrupt to a CPU
97+ // interrupt and registers a handler that clears the alarm flag.
98+ func initTimerInterrupt () {
99+ // Clear any stale timer interrupt before enabling.
100+ esp .TIMG0 .INT_CLR_TIMERS .Set (1 )
101+
102+ // Map the TIMG0 T0 peripheral interrupt to a CPU interrupt line.
103+ esp .INTERRUPT_CORE0 .SetTG_T0_INT_MAP (timerAlarmCPUInterrupt )
104+
105+ // Register the interrupt handler and enable it once.
106+ timerAlarmInterrupt = interrupt .New (timerAlarmCPUInterrupt , timerAlarmHandler )
107+ timerAlarmInterrupt .Enable ()
108+ }
109+
110+ // sleepTicks spins until the given number of ticks have elapsed, using the
111+ // TIMG0 alarm interrupt to avoid busy-waiting for the entire duration.
77112func sleepTicks (d timeUnit ) {
78- sleepUntil := ticks () + d
79- for ticks () < sleepUntil {
80- // TODO: suspend the CPU to not burn power here unnecessarily.
113+ target := ticks () + d
114+ for ticks () < target {
115+ // Set the alarm to fire at the target tick count.
116+ interruptPending .Set (0 )
117+
118+ esp .TIMG0 .T0ALARMLO .Set (uint32 (target ))
119+ esp .TIMG0 .T0ALARMHI .Set (uint32 (target >> 32 ))
120+
121+ // Enable the alarm (auto-clears when alarm fires).
122+ esp .TIMG0 .T0CONFIG .SetBits (esp .TIMG_TCONFIG_ALARM_EN )
123+
124+ // Re-enable the timer interrupt (handler disables INT_ENA).
125+ esp .TIMG0 .INT_CLR_TIMERS .Set (1 )
126+ esp .TIMG0 .INT_ENA_TIMERS .SetBits (1 )
127+
128+ // Wait for any interrupt (timer alarm or other) or timeout.
129+ for interruptPending .Get () == 0 {
130+ if ticks () >= target {
131+ return
132+ }
133+ }
81134 }
82135}
83136
0 commit comments