rp2040: replace sleep 'busy loop' with timer alarm
Этот коммит содержится в:
		
							родитель
							
								
									fa673f0827
								
							
						
					
					
						коммит
						8f40b107d9
					
				
					 3 изменённых файлов: 72 добавлений и 0 удалений
				
			
		| 
						 | 
					@ -86,6 +86,11 @@ func ticks() uint64 {
 | 
				
			||||||
	return timer.timeElapsed()
 | 
						return timer.timeElapsed()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//go:linkname lightSleep runtime.machineLightSleep
 | 
				
			||||||
 | 
					func lightSleep(ticks uint64) {
 | 
				
			||||||
 | 
						timer.lightSleep(ticks)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UART pins
 | 
					// UART pins
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	UART_TX_PIN  = UART0_TX_PIN
 | 
						UART_TX_PIN  = UART0_TX_PIN
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,13 +4,23 @@
 | 
				
			||||||
package machine
 | 
					package machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"device/arm"
 | 
				
			||||||
	"device/rp"
 | 
						"device/rp"
 | 
				
			||||||
 | 
						"runtime/interrupt"
 | 
				
			||||||
	"runtime/volatile"
 | 
						"runtime/volatile"
 | 
				
			||||||
	"unsafe"
 | 
						"unsafe"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const numTimers = 4
 | 
					const numTimers = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Alarm0 is reserved for sleeping by tinygo runtime code for RP2040.
 | 
				
			||||||
 | 
					// Alarm0 is also IRQ0
 | 
				
			||||||
 | 
					const sleepAlarm = 0
 | 
				
			||||||
 | 
					const sleepAlarmIRQ = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The minimum sleep duration in μs (ticks)
 | 
				
			||||||
 | 
					const minSleep = 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type timerType struct {
 | 
					type timerType struct {
 | 
				
			||||||
	timeHW   volatile.Register32
 | 
						timeHW   volatile.Register32
 | 
				
			||||||
	timeLW   volatile.Register32
 | 
						timeLW   volatile.Register32
 | 
				
			||||||
| 
						 | 
					@ -50,3 +60,47 @@ func (tmr *timerType) timeElapsed() (us uint64) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return uint64(hi)<<32 | uint64(lo)
 | 
						return uint64(hi)<<32 | uint64(lo)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// lightSleep will put the processor into a sleep state a short period
 | 
				
			||||||
 | 
					// (up to approx 72mins per RP2040 datasheet, 4.6.3. Alarms).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This function is a 'light' sleep and will return early if another
 | 
				
			||||||
 | 
					// interrupt or event triggers.  This is intentional since the
 | 
				
			||||||
 | 
					// primary use-case is for use by the TinyGo scheduler which will
 | 
				
			||||||
 | 
					// re-sleep if needed.
 | 
				
			||||||
 | 
					func (tmr *timerType) lightSleep(us uint64) {
 | 
				
			||||||
 | 
						// minSleep is a way to avoid race conditions for short
 | 
				
			||||||
 | 
						// sleeps by ensuring there is enough time to setup the
 | 
				
			||||||
 | 
						// alarm before sleeping.  For very short sleeps, this
 | 
				
			||||||
 | 
						// effectively becomes a 'busy loop'.
 | 
				
			||||||
 | 
						if us < minSleep {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Interrupt handler is essentially a no-op, we're just relying
 | 
				
			||||||
 | 
						// on the side-effect of waking the CPU from "wfe"
 | 
				
			||||||
 | 
						intr := interrupt.New(sleepAlarmIRQ, func(interrupt.Interrupt) {
 | 
				
			||||||
 | 
							// Clear the IRQ
 | 
				
			||||||
 | 
							timer.intR.Set(1 << sleepAlarm)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Reset interrupt flag
 | 
				
			||||||
 | 
						tmr.intR.Set(1 << sleepAlarm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Enable interrupt
 | 
				
			||||||
 | 
						tmr.intE.SetBits(1 << sleepAlarm)
 | 
				
			||||||
 | 
						intr.Enable()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Only the low 32 bits of time can be used for alarms
 | 
				
			||||||
 | 
						target := uint64(tmr.timeRawL.Get()) + us
 | 
				
			||||||
 | 
						tmr.alarm[sleepAlarm].Set(uint32(target))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Wait for sleep (or any other) interrupt
 | 
				
			||||||
 | 
						arm.Asm("wfe")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Disarm timer
 | 
				
			||||||
 | 
						tmr.armed.Set(1 << sleepAlarm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Disable interrupt
 | 
				
			||||||
 | 
						intr.Disable()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,9 @@ import (
 | 
				
			||||||
// machineTicks is provided by package machine.
 | 
					// machineTicks is provided by package machine.
 | 
				
			||||||
func machineTicks() uint64
 | 
					func machineTicks() uint64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// machineLightSleep is provided by package machine.
 | 
				
			||||||
 | 
					func machineLightSleep(uint64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type timeUnit uint64
 | 
					type timeUnit uint64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ticks returns the number of ticks (microseconds) elapsed since power up.
 | 
					// ticks returns the number of ticks (microseconds) elapsed since power up.
 | 
				
			||||||
| 
						 | 
					@ -32,6 +35,16 @@ func sleepTicks(d timeUnit) {
 | 
				
			||||||
	if d == 0 {
 | 
						if d == 0 {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if hasScheduler {
 | 
				
			||||||
 | 
							// With scheduler, sleepTicks may return early if an interrupt or
 | 
				
			||||||
 | 
							// event fires - so scheduler can schedule any go routines now
 | 
				
			||||||
 | 
							// eligible to run
 | 
				
			||||||
 | 
							machineLightSleep(uint64(d))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Busy loop
 | 
				
			||||||
	sleepUntil := ticks() + d
 | 
						sleepUntil := ticks() + d
 | 
				
			||||||
	for ticks() < sleepUntil {
 | 
						for ticks() < sleepUntil {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче