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.
Этот коммит содержится в:
родитель
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
Обычный файл
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
Обычный файл
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
|
||||
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче