device/arm: add system timer registers (#654)

* device/arm: add system timer registers
Add SYST registers and bit definitions to device/arm.
Add a setup function.
Add an example that uses it to blink an LED.
Этот коммит содержится в:
Infinoid 2019-10-24 15:17:06 -04:00 коммит произвёл Ron Evans
родитель 2c15f36702
коммит 6b1faeb882
3 изменённых файлов: 114 добавлений и 0 удалений

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

@ -30,6 +30,7 @@
package arm
import (
"errors"
"runtime/volatile"
"unsafe"
)
@ -72,6 +73,7 @@ func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
const (
SCS_BASE = 0xE000E000
SYST_BASE = SCS_BASE + 0x0010
NVIC_BASE = SCS_BASE + 0x0100
SCB_BASE = SCS_BASE + 0x0D00
)
@ -119,6 +121,53 @@ type NVIC_Type struct {
var NVIC = (*NVIC_Type)(unsafe.Pointer(uintptr(NVIC_BASE)))
// System Timer (SYST)
//
// Source: https://static.docs.arm.com/ddi0403/e/DDI0403E_d_armv7m_arm.pdf B3.3
type SYST_Type struct {
SYST_CSR volatile.Register32
SYST_RVR volatile.Register32
SYST_CVR volatile.Register32
SYST_CALIB volatile.Register32
}
var SYST = (*SYST_Type)(unsafe.Pointer(uintptr(SYST_BASE)))
// Bitfields for SYST: System Timer
const (
// SYST.SYST_CSR: SysTick Control and Status Register
SYST_CSR_ENABLE_Pos = 0x0 // Position of ENABLE field.
SYST_CSR_ENABLE_Msk = 0x1 // Bit mask of ENABLE field.
SYST_CSR_ENABLE = 0x1 // Bit ENABLE.
SYST_CSR_TICKINT_Pos = 0x1 // Position of TICKINT field.
SYST_CSR_TICKINT_Msk = 0x2 // Bit mask of TICKINT field.
SYST_CSR_TICKINT = 0x2 // Bit TICKINT.
SYST_CSR_CLKSOURCE_Pos = 0x2 // Position of CLKSOURCE field.
SYST_CSR_CLKSOURCE_Msk = 0x4 // Bit mask of CLKSOURCE field.
SYST_CSR_CLKSOURCE = 0x4 // Bit CLKSOURCE.
SYST_CSR_COUNTFLAG_Pos = 0x10 // Position of COUNTFLAG field.
SYST_CSR_COUNTFLAG_Msk = 0x10000 // Bit mask of COUNTFLAG field.
SYST_CSR_COUNTFLAG = 0x10000 // Bit COUNTFLAG.
// SYST.SYST_RVR: SysTick Reload Value Register
SYST_RVR_RELOAD_Pos = 0x0 // Position of RELOAD field.
SYST_RVR_RELOAD_Msk = 0xffffff // Bit mask of RELOAD field.
// SYST.SYST_CVR: SysTick Current Value Register
SYST_CVR_CURRENT_Pos = 0x0 // Position of CURRENT field.
SYST_CVR_CURRENT_Msk = 0xffffff // Bit mask of CURRENT field.
// SYST.SYST_CALIB: SysTick Calibration Value Register
SYST_CALIB_TENMS_Pos = 0x0 // Position of TENMS field.
SYST_CALIB_TENMS_Msk = 0xffffff // Bit mask of TENMS field.
SYST_CALIB_SKEW_Pos = 0x1e // Position of SKEW field.
SYST_CALIB_SKEW_Msk = 0x40000000 // Bit mask of SKEW field.
SYST_CALIB_SKEW = 0x40000000 // Bit SKEW.
SYST_CALIB_NOREF_Pos = 0x1f // Position of NOREF field.
SYST_CALIB_NOREF_Msk = 0x80000000 // Bit mask of NOREF field.
SYST_CALIB_NOREF = 0x80000000 // Bit NOREF.
)
// Enable the given interrupt number.
func EnableIRQ(irq uint32) {
NVIC.ISER[irq>>5].Set(1 << (irq & 0x1F))
@ -169,3 +218,28 @@ func SystemReset() {
Asm("wfi")
}
}
// Set up the system timer to generate periodic tick events.
// This will cause SysTick_Handler to fire once per tick.
// The cyclecount parameter is a counter value which can range from 0 to
// 0xffffff. A value of 0 disables the timer.
func SetupSystemTimer(cyclecount uint32) error {
// turn it off
SYST.SYST_CSR.ClearBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE)
if cyclecount == 0 {
// leave the system timer turned off.
return nil
}
if cyclecount&SYST_RVR_RELOAD_Msk != cyclecount {
// The cycle refresh register is only 24 bits wide. The user-specified value will overflow.
return errors.New("requested cycle count is too large, overflows 24 bit counter")
}
// set refresh count
SYST.SYST_RVR.Set(cyclecount)
// set current counter value
SYST.SYST_CVR.Set(cyclecount)
// enable clock, enable SysTick interrupt when clock reaches 0, run it off of the processor clock
SYST.SYST_CSR.SetBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE | SYST_CSR_CLKSOURCE)
return nil
}

12
src/examples/systick/README.md Обычный файл
Просмотреть файл

@ -0,0 +1,12 @@
# TinyGo ARM SysTick example
This example uses the ARM System Timer to blink an LED. The timer fires
an interrupt 10 times per second. The interrupt handler toggles the LED on
and off.
Many ARM-based chips have this timer feature. If you run the example and the
LED blinks, then you have one.
The System Timer runs from a cycle counter. The more cycles, the slower the
LED will blink. This counter is 24 bits wide, which places an upper bound on
the number of cycles, and the slowness of the blinking.

28
src/examples/systick/systick.go Обычный файл
Просмотреть файл

@ -0,0 +1,28 @@
package main
import (
"device/arm"
"machine"
)
func main() {
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
// timer fires 10 times per second
arm.SetupSystemTimer(machine.CPU_FREQUENCY / 10)
for {
}
}
var led_state bool
//go:export SysTick_Handler
func timer_isr() {
if led_state {
machine.LED.Low()
} else {
machine.LED.High()
}
led_state = !led_state
}