teensy40: init RTC and use ARM cycle counter for improved SysTick accuracy

Этот коммит содержится в:
ardnew 2020-10-22 23:09:53 -05:00 коммит произвёл Ron Evans
родитель 0d9c46b59e
коммит 47410a4b54
2 изменённых файлов: 38 добавлений и 11 удалений

Просмотреть файл

@ -108,6 +108,7 @@ func initPeripherals() {
enableTimerClocks() // activate GPT/PIT clock gates enableTimerClocks() // activate GPT/PIT clock gates
initSysTick() // enable SysTick initSysTick() // enable SysTick
initRTC() // enable real-time clock
enablePinClocks() // activate IOMUXC(_GPR)/GPIO clock gates enablePinClocks() // activate IOMUXC(_GPR)/GPIO clock gates
initPins() // configure GPIO initPins() // configure GPIO

Просмотреть файл

@ -7,13 +7,14 @@ import (
"device/nxp" "device/nxp"
"runtime/interrupt" "runtime/interrupt"
"runtime/volatile" "runtime/volatile"
"unsafe"
) )
type timeUnit int64 type timeUnit int64
const ( // HW divides 24 MHz XTALOSC down to 100 kHz const ( // HW divides 24 MHz XTALOSC down to 100 kHz
lastCycle = SYSTICK_FREQ/1000 - 1 lastCycle = SYSTICK_FREQ/1000 - 1
microsPerCycle = 1000000 / SYSTICK_FREQ cyclesPerMicro = CORE_FREQ / 1000000
) )
const ( const (
@ -24,10 +25,23 @@ const (
var ( var (
tickCount volatile.Register64 tickCount volatile.Register64
cycleCount volatile.Register32
pitActive volatile.Register32 pitActive volatile.Register32
pitTimeout interrupt.Interrupt pitTimeout interrupt.Interrupt
) )
var (
// debug exception and monitor control
DEMCR = (*volatile.Register32)(unsafe.Pointer(uintptr(0xe000edfc)))
DWT_CTRL = (*volatile.Register32)(unsafe.Pointer(uintptr(0xe0001000)))
DWT_CYCCNT = (*volatile.Register32)(unsafe.Pointer(uintptr(0xe0001004)))
)
const (
DEMCR_TRCENA = 0x01000000 // enable debugging & monitoring blocks
DWT_CTRL_CYCCNTENA = 0x00000001 // cycle count register
)
func ticksToNanoseconds(ticks timeUnit) int64 { func ticksToNanoseconds(ticks timeUnit) int64 {
return int64(ticks) * 1000 return int64(ticks) * 1000
} }
@ -49,6 +63,12 @@ func initSysTick() {
// set SysTick and PendSV priority to 32 // set SysTick and PendSV priority to 32
nxp.SystemControl.SHPR3.Set((0x20 << nxp.SCB_SHPR3_PRI_15_Pos) | nxp.SystemControl.SHPR3.Set((0x20 << nxp.SCB_SHPR3_PRI_15_Pos) |
(0x20 << nxp.SCB_SHPR3_PRI_14_Pos)) (0x20 << nxp.SCB_SHPR3_PRI_14_Pos))
// turn on cycle counter
DEMCR.SetBits(DEMCR_TRCENA)
DWT_CTRL.SetBits(DWT_CTRL_CYCCNTENA)
cycleCount.Set(DWT_CYCCNT.Get())
// enable PIT, disable counters // enable PIT, disable counters
nxp.PIT.MCR.Set(0) nxp.PIT.MCR.Set(0)
for i := range nxp.PIT.TIMER { for i := range nxp.PIT.TIMER {
@ -60,26 +80,32 @@ func initSysTick() {
pitTimeout.Enable() pitTimeout.Enable()
} }
func initRTC() {
if !nxp.SNVS.LPCR.HasBits(nxp.SNVS_LPCR_SRTC_ENV) {
// if SRTC isn't running, start it with default Jan 1, 2019
nxp.SNVS.LPSRTCLR.Set(uint32((0x5c2aad80 << 15) & 0xFFFFFFFF))
nxp.SNVS.LPSRTCMR.Set(uint32(0x5c2aad80 >> 17))
nxp.SNVS.LPCR.SetBits(nxp.SNVS_LPCR_SRTC_ENV)
}
}
//go:export SysTick_Handler //go:export SysTick_Handler
func tick() { func tick() {
tickCount.Set(tickCount.Get() + 1) tickCount.Set(tickCount.Get() + 1)
cycleCount.Set(DWT_CYCCNT.Get())
} }
func ticks() timeUnit { func ticks() timeUnit {
mask := arm.DisableInterrupts() mask := arm.DisableInterrupts()
curr := arm.SYST.SYST_CVR.Get()
tick := tickCount.Get() tick := tickCount.Get()
pend := nxp.SystemControl.ICSR.HasBits(nxp.SCB_ICSR_PENDSTSET_Msk) cycs := cycleCount.Get()
curr := DWT_CYCCNT.Get()
arm.EnableInterrupts(mask) arm.EnableInterrupts(mask)
mics := timeUnit(tick * 1000) frac := uint64((curr-cycs)*0xFFFFFFFF/cyclesPerMicro) >> 32
// if the systick counter was about to reset and ICSR indicates a pending if frac > 1000 {
// SysTick IRQ, increment count frac = 1000
if pend && (curr > 50) {
mics += 1000
} else {
mics += timeUnit((lastCycle - curr) * microsPerCycle)
} }
return mics return timeUnit(1000*tick + frac)
} }
func sleepTicks(duration timeUnit) { func sleepTicks(duration timeUnit) {