Harmonize stm32 ticks and sleep (#1673)
machine/stm32f*: move to harmonized tick / sleep logic code
Этот коммит содержится в:
родитель
5a4dcfb367
коммит
b0b84c48ec
7 изменённых файлов: 446 добавлений и 792 удалений
201
src/runtime/runtime_stm32_timers.go
Обычный файл
201
src/runtime/runtime_stm32_timers.go
Обычный файл
|
@ -0,0 +1,201 @@
|
||||||
|
// +build stm32
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
// This file implements a common implementation of implementing 'ticks' and 'sleep' for STM32 devices. The
|
||||||
|
// implementation uses two 'basic' timers, so should be compatible with a broad range of STM32 MCUs.
|
||||||
|
//
|
||||||
|
// This implementation is of 'sleep' is for running in a normal power mode. Use of the RTC to enter and
|
||||||
|
// resume from low-power states is out of scope.
|
||||||
|
//
|
||||||
|
// Interface
|
||||||
|
// ---------
|
||||||
|
// For each MCU, the following constants should be defined:
|
||||||
|
// TICK_RATE The desired frequency of ticks, e.g. 1000 for 1KHz ticks
|
||||||
|
// TICK_TIMER_IRQ Which timer to use for counting ticks (e.g. stm32.IRQ_TIM7)
|
||||||
|
// TICK_TIMER_FREQ The frequency the clock feeding the sleep timer is set to (e.g. 84MHz)
|
||||||
|
// SLEEP_TIMER_IRQ Which timer to use for sleeping (e.g. stm32.IRQ_TIM3)
|
||||||
|
// SLEEP_TIMER_FREQ The frequency the clock feeding the sleep timer is set to (e.g. 84MHz)
|
||||||
|
//
|
||||||
|
// The type alias `arrtype` should be defined to either uint32 or uint16 depending on the
|
||||||
|
// size of that register in the MCU's TIM_Type structure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/stm32"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"runtime/volatile"
|
||||||
|
)
|
||||||
|
|
||||||
|
type timerInfo struct {
|
||||||
|
EnableRegister *volatile.Register32
|
||||||
|
EnableFlag uint32
|
||||||
|
Device *stm32.TIM_Type
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
TICKS_PER_NS = 1000000000 / TICK_RATE
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Tick count since boot
|
||||||
|
tickCount volatile.Register64
|
||||||
|
|
||||||
|
// The timer used for counting ticks
|
||||||
|
tickTimer *timerInfo
|
||||||
|
|
||||||
|
// The timer used for sleeping
|
||||||
|
sleepTimer *timerInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
|
return int64(ticks) * TICKS_PER_NS
|
||||||
|
}
|
||||||
|
|
||||||
|
func nanosecondsToTicks(ns int64) timeUnit {
|
||||||
|
return timeUnit(ns / TICKS_PER_NS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of ticks (microseconds) since start.
|
||||||
|
func ticks() timeUnit {
|
||||||
|
return timeUnit(tickCount.Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// -- Ticks ---
|
||||||
|
//
|
||||||
|
|
||||||
|
// Enable the timer used to count ticks
|
||||||
|
func initTickTimer(ti *timerInfo) {
|
||||||
|
tickTimer = ti
|
||||||
|
ti.EnableRegister.SetBits(ti.EnableFlag)
|
||||||
|
|
||||||
|
psc := uint32(TICK_TIMER_FREQ / TICK_RATE)
|
||||||
|
period := uint32(1)
|
||||||
|
|
||||||
|
// Get the pre-scale into range, with interrupt firing
|
||||||
|
// once per tick.
|
||||||
|
for psc > 0x10000 || period == 1 {
|
||||||
|
psc >>= 1
|
||||||
|
period <<= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp overflow
|
||||||
|
if period > 0x10000 {
|
||||||
|
period = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
ti.Device.PSC.Set(psc - 1)
|
||||||
|
ti.Device.ARR.Set(arrtype(period - 1))
|
||||||
|
|
||||||
|
// Auto-repeat
|
||||||
|
ti.Device.EGR.SetBits(stm32.TIM_EGR_UG)
|
||||||
|
|
||||||
|
// Register the interrupt handler
|
||||||
|
intr := interrupt.New(TICK_TIMER_IRQ, handleTick)
|
||||||
|
intr.SetPriority(0xc1)
|
||||||
|
intr.Enable()
|
||||||
|
|
||||||
|
// Clear update flag
|
||||||
|
ti.Device.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
|
|
||||||
|
// Enable the hardware interrupt
|
||||||
|
ti.Device.DIER.SetBits(stm32.TIM_DIER_UIE)
|
||||||
|
|
||||||
|
// Enable the timer
|
||||||
|
ti.Device.CR1.SetBits(stm32.TIM_CR1_CEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleTick(interrupt.Interrupt) {
|
||||||
|
if tickTimer.Device.SR.HasBits(stm32.TIM_SR_UIF) {
|
||||||
|
// clear the update flag
|
||||||
|
tickTimer.Device.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
|
|
||||||
|
// increment tick count
|
||||||
|
tickCount.Set(tickCount.Get() + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// --- Sleep ---
|
||||||
|
//
|
||||||
|
|
||||||
|
func sleepTicks(d timeUnit) {
|
||||||
|
// If there is a scheduler, we sleep until any kind of CPU event up to
|
||||||
|
// a maximum of the requested sleep duration.
|
||||||
|
//
|
||||||
|
// The scheduler will call again if there is nothing to do and a further
|
||||||
|
// sleep is required.
|
||||||
|
if hasScheduler {
|
||||||
|
timerSleep(ticksToNanoseconds(d))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no scheduler, so we sleep until at least the requested number
|
||||||
|
// of ticks has passed.
|
||||||
|
end := ticks() + d
|
||||||
|
for ticks() < end {
|
||||||
|
timerSleep(ticksToNanoseconds(d))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the Sleep clock
|
||||||
|
func initSleepTimer(ti *timerInfo) {
|
||||||
|
sleepTimer = ti
|
||||||
|
|
||||||
|
ti.EnableRegister.SetBits(ti.EnableFlag)
|
||||||
|
|
||||||
|
// No auto-repeat
|
||||||
|
ti.Device.EGR.SetBits(stm32.TIM_EGR_UG)
|
||||||
|
|
||||||
|
// Enable the hardware interrupt.
|
||||||
|
ti.Device.DIER.SetBits(stm32.TIM_DIER_UIE)
|
||||||
|
|
||||||
|
intr := interrupt.New(SLEEP_TIMER_IRQ, handleSleep)
|
||||||
|
intr.SetPriority(0xc3)
|
||||||
|
intr.Enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// timerSleep sleeps for 'at most' ns nanoseconds, but possibly less.
|
||||||
|
func timerSleep(ns int64) {
|
||||||
|
// Calculate initial pre-scale value.
|
||||||
|
// delay (in ns) and clock freq are both large values, so do the nanosecs
|
||||||
|
// conversion (divide by 1G) by pre-dividing each by 1000 to avoid overflow
|
||||||
|
// in any meaningful time period.
|
||||||
|
psc := ((ns / 1000) * (SLEEP_TIMER_FREQ / 1000)) / 1000
|
||||||
|
period := int64(1)
|
||||||
|
|
||||||
|
// Get the pre-scale into range, with interrupt firing
|
||||||
|
// once per tick.
|
||||||
|
for psc > 0x10000 || period == 1 {
|
||||||
|
psc >>= 1
|
||||||
|
period <<= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp overflow
|
||||||
|
if period > 0x10000 {
|
||||||
|
period = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the desired duration and enable
|
||||||
|
sleepTimer.Device.PSC.Set(uint32(psc) - 1)
|
||||||
|
sleepTimer.Device.ARR.Set(arrtype(period) - 1)
|
||||||
|
sleepTimer.Device.CR1.SetBits(stm32.TIM_CR1_CEN)
|
||||||
|
|
||||||
|
// Wait till either the timer or some other event wakes
|
||||||
|
// up the CPU
|
||||||
|
waitForEvents()
|
||||||
|
|
||||||
|
// In case it was not the sleep timer that woke the
|
||||||
|
// CPU, disable the timer now.
|
||||||
|
disableSleepTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleSleep(interrupt.Interrupt) {
|
||||||
|
disableSleepTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func disableSleepTimer() {
|
||||||
|
// Disable and clear the update flag.
|
||||||
|
sleepTimer.Device.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
||||||
|
sleepTimer.Device.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
|
}
|
|
@ -3,18 +3,45 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
|
||||||
"runtime/volatile"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer settings used for tick and sleep.
|
||||||
|
|
||||||
|
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
||||||
|
settings configured in initCLK, so must be kept in sync if the clock settings
|
||||||
|
are changed.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
TICK_RATE = 1000 // 1 KHz
|
||||||
|
SLEEP_TIMER_IRQ = stm32.IRQ_TIM3
|
||||||
|
SLEEP_TIMER_FREQ = 72000000 // 72 MHz
|
||||||
|
TICK_TIMER_IRQ = stm32.IRQ_TIM4
|
||||||
|
TICK_TIMER_FREQ = 72000000 // 72 MHz
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
initRTC()
|
|
||||||
initTIM()
|
initSleepTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
||||||
|
Device: stm32.TIM3,
|
||||||
|
})
|
||||||
|
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
|
initTickTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM4EN,
|
||||||
|
Device: stm32.TIM4,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
@ -52,157 +79,3 @@ func initCLK() {
|
||||||
for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_SWS_PLL << stm32.RCC_CFGR_SWS_Pos) {
|
for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_SWS_PLL << stm32.RCC_CFGR_SWS_Pos) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
timestamp timeUnit // microseconds since boottime
|
|
||||||
timerLastCounter uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
|
||||||
|
|
||||||
func initRTC() {
|
|
||||||
// Enable the PWR and BKP.
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN)
|
|
||||||
|
|
||||||
// access to backup register
|
|
||||||
stm32.PWR.CR.SetBits(stm32.PWR_CR_DBP)
|
|
||||||
|
|
||||||
// Enable LSE
|
|
||||||
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_LSEON)
|
|
||||||
|
|
||||||
// wait until LSE is ready
|
|
||||||
for !stm32.RCC.BDCR.HasBits(stm32.RCC_BDCR_LSERDY) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select LSE
|
|
||||||
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_RTCSEL_LSE << stm32.RCC_BDCR_RTCSEL_Pos)
|
|
||||||
|
|
||||||
// set prescaler to "max" per datasheet
|
|
||||||
stm32.RTC.PRLH.Set(stm32.RTC_PRLH_PRLH_Msk)
|
|
||||||
stm32.RTC.PRLL.Set(stm32.RTC_PRLL_PRLL_Msk)
|
|
||||||
|
|
||||||
// set count to zero
|
|
||||||
stm32.RTC.CNTH.Set(0x0)
|
|
||||||
stm32.RTC.CNTL.Set(0x0)
|
|
||||||
|
|
||||||
// Enable RTC
|
|
||||||
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_RTCEN)
|
|
||||||
|
|
||||||
// Clear RSF
|
|
||||||
stm32.RTC.CRL.ClearBits(stm32.RTC_CRL_RSF)
|
|
||||||
|
|
||||||
// Wait till flag is set
|
|
||||||
for !stm32.RTC.CRL.HasBits(stm32.RTC_CRL_RSF) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM3 clock.
|
|
||||||
func initTIM() {
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
|
|
||||||
intr.SetPriority(0xc3)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
const asyncScheduler = false
|
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
||||||
return int64(ticks) * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
|
||||||
return timeUnit(ns / 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sleepTicks should sleep for specific number of microseconds.
|
|
||||||
func sleepTicks(d timeUnit) {
|
|
||||||
for d != 0 {
|
|
||||||
ticks() // update timestamp
|
|
||||||
ticks := uint32(d) // current scaling only supports 100 usec to 6553 msec
|
|
||||||
timerSleep(ticks)
|
|
||||||
d -= timeUnit(ticks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// number of ticks (microseconds) since start.
|
|
||||||
func ticks() timeUnit {
|
|
||||||
// convert RTC counter from seconds to microseconds
|
|
||||||
timerCounter := uint64(stm32.RTC.CNTH.Get()<<16|stm32.RTC.CNTL.Get()) * 1000 * 1000
|
|
||||||
|
|
||||||
// add the fractional part of current time using DIV register
|
|
||||||
timerCounter += uint64(0x8000-stm32.RTC.DIVL.Get()) * 31
|
|
||||||
|
|
||||||
// change since last measurement
|
|
||||||
offset := (timerCounter - timerLastCounter)
|
|
||||||
timerLastCounter = timerCounter
|
|
||||||
timestamp += timeUnit(offset)
|
|
||||||
return timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
// ticks are in microseconds
|
|
||||||
func timerSleep(ticks uint32) {
|
|
||||||
timerWakeup.Set(0)
|
|
||||||
|
|
||||||
// STM32 timer update event period is calculated as follows:
|
|
||||||
//
|
|
||||||
// Update_event = TIM_CLK/((PSC + 1)*(ARR + 1)*(RCR + 1))
|
|
||||||
//
|
|
||||||
// Where:
|
|
||||||
//
|
|
||||||
// TIM_CLK = timer clock input
|
|
||||||
// PSC = 16-bit prescaler register
|
|
||||||
// ARR = 16/32-bit Autoreload register
|
|
||||||
// RCR = 16-bit repetition counter
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// TIM_CLK = 72 MHz
|
|
||||||
// Prescaler = 1
|
|
||||||
// Auto reload = 65535
|
|
||||||
// No repetition counter RCR = 0
|
|
||||||
// Update_event = 72*(10^6)/((1 + 1)*(65535 + 1)*(1))
|
|
||||||
// Update_event = 549.3 Hz
|
|
||||||
//
|
|
||||||
// Set the timer prescaler/autoreload timing registers.
|
|
||||||
|
|
||||||
// TODO: support smaller or larger scales (autoscaling) based
|
|
||||||
// on the length of sleep time requested.
|
|
||||||
// The current scaling only supports a range of 200 usec to 6553 msec.
|
|
||||||
|
|
||||||
// prescale counter down from 72mhz to 10khz aka 0.1 ms frequency.
|
|
||||||
stm32.TIM3.PSC.Set(machine.CPUFrequency()/10000 - 1) // 7199
|
|
||||||
|
|
||||||
// Set duty aka duration.
|
|
||||||
// STM32 dividers use n-1, i.e. n counts from 0 to n-1.
|
|
||||||
// As a result, with these prescaler settings,
|
|
||||||
// the minimum allowed duration is 200 microseconds.
|
|
||||||
if ticks < 200 {
|
|
||||||
ticks = 200
|
|
||||||
}
|
|
||||||
stm32.TIM3.ARR.Set(ticks/100 - 1) // convert from microseconds to 0.1 ms
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// wait till timer wakes up
|
|
||||||
for timerWakeup.Get() == 0 {
|
|
||||||
arm.Asm("wfi")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM3(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// Disable the timer.
|
|
||||||
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
|
|
||||||
// timer was triggered
|
|
||||||
timerWakeup.Set(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,20 +3,10 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
|
||||||
"runtime/volatile"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
initOSC() // configure oscillators
|
|
||||||
initCLK() // configure CPU, AHB, and APB bus clocks
|
|
||||||
initTIM() // configure timers
|
|
||||||
initCOM() // configure serial comm interfaces
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// +----------------------+
|
// +----------------------+
|
||||||
// | Clock Settings |
|
// | Clock Settings |
|
||||||
|
@ -74,6 +64,43 @@ const (
|
||||||
FLASH_OPTIONS = stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | stm32.FLASH_ACR_PRFTEN
|
FLASH_OPTIONS = stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | stm32.FLASH_ACR_PRFTEN
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer settings used for tick and sleep.
|
||||||
|
|
||||||
|
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
||||||
|
settings above, so must be kept in sync if the clock settings are changed.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
TICK_RATE = 1000 // 1 KHz
|
||||||
|
SLEEP_TIMER_IRQ = stm32.IRQ_TIM3
|
||||||
|
SLEEP_TIMER_FREQ = PCLK1_FREQ_HZ * 2
|
||||||
|
TICK_TIMER_IRQ = stm32.IRQ_TIM7
|
||||||
|
TICK_TIMER_FREQ = PCLK1_FREQ_HZ * 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initOSC() // configure oscillators
|
||||||
|
initCLK()
|
||||||
|
|
||||||
|
initSleepTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
||||||
|
Device: stm32.TIM3,
|
||||||
|
})
|
||||||
|
|
||||||
|
initCOM()
|
||||||
|
|
||||||
|
initTickTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
||||||
|
Device: stm32.TIM7,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func initOSC() {
|
func initOSC() {
|
||||||
// enable voltage regulator
|
// enable voltage regulator
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
||||||
|
@ -154,95 +181,12 @@ func initCLK() {
|
||||||
stm32.RCC.AHB1ENR.SetBits(CLK_CCM_RAM)
|
stm32.RCC.AHB1ENR.SetBits(CLK_CCM_RAM)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initTIM() {
|
|
||||||
// enable sleep counter (TIM3)
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
|
||||||
|
|
||||||
tim3 := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
|
|
||||||
tim3.SetPriority(0xC3)
|
|
||||||
tim3.Enable()
|
|
||||||
|
|
||||||
// enable tick counter (TIM7)
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN)
|
|
||||||
|
|
||||||
stm32.TIM7.PSC.Set((PCLK1_FREQ_HZ*2)/10000 - 1) // 84mhz to 10khz(0.1ms)
|
|
||||||
stm32.TIM7.ARR.Set(10 - 1) // interrupt per 1ms
|
|
||||||
|
|
||||||
stm32.TIM7.DIER.SetBits(stm32.TIM_DIER_UIE) // enable interrupt
|
|
||||||
stm32.TIM7.CR1.SetBits(stm32.TIM_CR1_CEN) // enable timer
|
|
||||||
|
|
||||||
tim7 := interrupt.New(stm32.IRQ_TIM7, handleTIM7)
|
|
||||||
tim7.SetPriority(0xC1)
|
|
||||||
tim7.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
func initCOM() {
|
func initCOM() {
|
||||||
if machine.NUM_UART_INTERFACES > 0 {
|
if machine.NUM_UART_INTERFACES > 0 {
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// tick in milliseconds
|
|
||||||
tickCount timeUnit
|
|
||||||
timerWakeup volatile.Register8
|
|
||||||
)
|
|
||||||
|
|
||||||
const asyncScheduler = false
|
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
||||||
return int64(ticks) * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
|
||||||
return timeUnit(ns / 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sleepTicks should sleep for specific number of microseconds.
|
|
||||||
func sleepTicks(d timeUnit) {
|
|
||||||
timerSleep(uint32(d))
|
|
||||||
}
|
|
||||||
|
|
||||||
// number of ticks (microseconds) since start.
|
|
||||||
func ticks() timeUnit {
|
|
||||||
return tickCount * 1000 // milliseconds to microseconds
|
|
||||||
}
|
|
||||||
|
|
||||||
// ticks are in microseconds
|
|
||||||
func timerSleep(ticks uint32) {
|
|
||||||
timerWakeup.Set(0)
|
|
||||||
|
|
||||||
stm32.TIM3.PSC.Set((PCLK1_FREQ_HZ*2)/10000 - 1) // 8399
|
|
||||||
arr := (ticks / 100) - 1 // microseconds to 0.1 ms
|
|
||||||
if arr == 0 {
|
|
||||||
arr = 1 // avoid blocking
|
|
||||||
}
|
|
||||||
stm32.TIM3.ARR.Set(arr)
|
|
||||||
|
|
||||||
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE) // enable interrupt
|
|
||||||
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN) // enable the timer
|
|
||||||
|
|
||||||
// wait for timer
|
|
||||||
for timerWakeup.Get() == 0 {
|
|
||||||
arm.Asm("wfi")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM3(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN) // disable the timer
|
|
||||||
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF) // clear the update flag
|
|
||||||
timerWakeup.Set(1) // flag timer ISR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM7(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM7.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
stm32.TIM7.SR.ClearBits(stm32.TIM_SR_UIF) // clear the update flag
|
|
||||||
tickCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
machine.UART0.WriteByte(c)
|
machine.UART0.WriteByte(c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,31 +3,8 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
|
||||||
"runtime/volatile"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
initCLK()
|
|
||||||
initTIM3()
|
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
|
||||||
initTIM7()
|
|
||||||
}
|
|
||||||
|
|
||||||
func putchar(c byte) {
|
|
||||||
machine.UART0.WriteByte(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
HSE_STARTUP_TIMEOUT = 0x0500
|
|
||||||
/* PLL Options - See RM0090 Reference Manual pg. 95 */
|
|
||||||
PLL_M = 8 /* PLL_VCO = (HSE_VALUE or HSI_VLAUE / PLL_M) * PLL_N */
|
|
||||||
PLL_N = 336
|
|
||||||
PLL_P = 2 /* SYSCLK = PLL_VCO / PLL_P */
|
|
||||||
PLL_Q = 7 /* USB OTS FS, SDIO and RNG Clock = PLL_VCO / PLL_Q */
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -40,8 +17,56 @@ const (
|
||||||
| APB1(PCLK1) | 42mhz |
|
| APB1(PCLK1) | 42mhz |
|
||||||
+-------------+--------+
|
+-------------+--------+
|
||||||
*/
|
*/
|
||||||
func initCLK() {
|
const (
|
||||||
|
HSE_STARTUP_TIMEOUT = 0x0500
|
||||||
|
// PLL Options - See RM0090 Reference Manual pg. 95
|
||||||
|
PLL_M = 8 // PLL_VCO = (HSE_VALUE or HSI_VLAUE / PLL_M) * PLL_N
|
||||||
|
PLL_N = 336
|
||||||
|
PLL_P = 2 // SYSCLK = PLL_VCO / PLL_P
|
||||||
|
PLL_Q = 7 // USB OTS FS, SDIO and RNG Clock = PLL_VCO / PLL_Q
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer settings used for tick and sleep.
|
||||||
|
|
||||||
|
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
||||||
|
settings above, so must be kept in sync if the clock settings are changed.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
TICK_RATE = 1000 // 1 KHz
|
||||||
|
TICK_TIMER_IRQ = stm32.IRQ_TIM7
|
||||||
|
TICK_TIMER_FREQ = 84000000 // 84 MHz
|
||||||
|
SLEEP_TIMER_IRQ = stm32.IRQ_TIM3
|
||||||
|
SLEEP_TIMER_FREQ = 84000000 // 84 MHz
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initCLK()
|
||||||
|
|
||||||
|
initSleepTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
||||||
|
Device: stm32.TIM3,
|
||||||
|
})
|
||||||
|
|
||||||
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
|
initTickTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
||||||
|
Device: stm32.TIM7,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func putchar(c byte) {
|
||||||
|
machine.UART0.WriteByte(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initCLK() {
|
||||||
// Reset clock registers
|
// Reset clock registers
|
||||||
// Set HSION
|
// Set HSION
|
||||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION)
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION)
|
||||||
|
@ -104,111 +129,7 @@ func initCLK() {
|
||||||
for {
|
for {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the CCM RAM clock
|
// Enable the CCM RAM clock
|
||||||
stm32.RCC.AHB1ENR.SetBits(1 << 20)
|
stm32.RCC.AHB1ENR.SetBits(1 << 20)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// tick in milliseconds
|
|
||||||
tickCount timeUnit
|
|
||||||
)
|
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
||||||
return int64(ticks) * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
|
||||||
return timeUnit(ns / 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM3 clock.(sleep count)
|
|
||||||
func initTIM3() {
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
|
|
||||||
intr.SetPriority(0xc3)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM7 clock.(tick count)
|
|
||||||
func initTIM7() {
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN)
|
|
||||||
|
|
||||||
// CK_INT = APB1 x2 = 84mhz
|
|
||||||
stm32.TIM7.PSC.Set(84000000/10000 - 1) // 84mhz to 10khz(0.1ms)
|
|
||||||
stm32.TIM7.ARR.Set(10 - 1) // interrupt per 1ms
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM7.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM7.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM7, handleTIM7)
|
|
||||||
intr.SetPriority(0xc1)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
const asyncScheduler = false
|
|
||||||
|
|
||||||
// sleepTicks should sleep for specific number of microseconds.
|
|
||||||
func sleepTicks(d timeUnit) {
|
|
||||||
timerSleep(uint32(d))
|
|
||||||
}
|
|
||||||
|
|
||||||
// number of ticks (microseconds) since start.
|
|
||||||
func ticks() timeUnit {
|
|
||||||
// milliseconds to microseconds
|
|
||||||
return tickCount * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
// ticks are in microseconds
|
|
||||||
func timerSleep(ticks uint32) {
|
|
||||||
timerWakeup.Set(0)
|
|
||||||
|
|
||||||
// CK_INT = APB1 x2 = 84mhz
|
|
||||||
// prescale counter down from 84mhz to 10khz aka 0.1 ms frequency.
|
|
||||||
stm32.TIM3.PSC.Set(84000000/10000 - 1) // 8399
|
|
||||||
|
|
||||||
// set duty aka duration
|
|
||||||
arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms
|
|
||||||
if arr == 0 {
|
|
||||||
arr = 1 // avoid blocking
|
|
||||||
}
|
|
||||||
stm32.TIM3.ARR.Set(arr)
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// wait till timer wakes up
|
|
||||||
for timerWakeup.Get() == 0 {
|
|
||||||
arm.Asm("wfi")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM3(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// Disable the timer.
|
|
||||||
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
|
|
||||||
// timer was triggered
|
|
||||||
timerWakeup.Set(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM7(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM7.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM7.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
tickCount++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,30 +3,8 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
|
||||||
"runtime/volatile"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
initCLK()
|
|
||||||
initTIM3()
|
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
|
||||||
initTIM7()
|
|
||||||
}
|
|
||||||
|
|
||||||
func putchar(c byte) {
|
|
||||||
machine.UART0.WriteByte(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
HSE_STARTUP_TIMEOUT = 0x0500
|
|
||||||
PLL_M = 4
|
|
||||||
PLL_N = 216
|
|
||||||
PLL_P = 2
|
|
||||||
PLL_Q = 2
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -39,6 +17,54 @@ const (
|
||||||
| APB2(PCLK2) | 108mhz |
|
| APB2(PCLK2) | 108mhz |
|
||||||
+-------------+--------+
|
+-------------+--------+
|
||||||
*/
|
*/
|
||||||
|
const (
|
||||||
|
HSE_STARTUP_TIMEOUT = 0x0500
|
||||||
|
PLL_M = 4
|
||||||
|
PLL_N = 216
|
||||||
|
PLL_P = 2
|
||||||
|
PLL_Q = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer settings used for tick and sleep.
|
||||||
|
|
||||||
|
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
||||||
|
settings above, so must be kept in sync if the clock settings are changed.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
TICK_RATE = 1000 // 1 KHz
|
||||||
|
SLEEP_TIMER_IRQ = stm32.IRQ_TIM3
|
||||||
|
SLEEP_TIMER_FREQ = 54000000 // 54 MHz (2x APB1)
|
||||||
|
TICK_TIMER_IRQ = stm32.IRQ_TIM7
|
||||||
|
TICK_TIMER_FREQ = 54000000 // 54 MHz (2x APB1)
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initCLK()
|
||||||
|
|
||||||
|
initSleepTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
||||||
|
Device: stm32.TIM3,
|
||||||
|
})
|
||||||
|
|
||||||
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
|
initTickTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
||||||
|
Device: stm32.TIM7,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func putchar(c byte) {
|
||||||
|
machine.UART0.WriteByte(c)
|
||||||
|
}
|
||||||
|
|
||||||
func initCLK() {
|
func initCLK() {
|
||||||
// PWR_CLK_ENABLE
|
// PWR_CLK_ENABLE
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
||||||
|
@ -102,107 +128,3 @@ func initOsc() {
|
||||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// tick in milliseconds
|
|
||||||
tickCount timeUnit
|
|
||||||
)
|
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
||||||
return int64(ticks) * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
|
||||||
return timeUnit(ns / 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM3 clock.(sleep count)
|
|
||||||
func initTIM3() {
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
|
|
||||||
intr.SetPriority(0xc3)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM7 clock.(tick count)
|
|
||||||
func initTIM7() {
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN)
|
|
||||||
|
|
||||||
// CK_INT = APB1 x2 = 54mhz
|
|
||||||
stm32.TIM7.PSC.Set(54000000/10000 - 1) // 54mhz to 10khz(0.1ms)
|
|
||||||
stm32.TIM7.ARR.Set(10 - 1) // interrupt per 1ms
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM7.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM7.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM7, handleTIM7)
|
|
||||||
intr.SetPriority(0xc1)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
const asyncScheduler = false
|
|
||||||
|
|
||||||
// sleepTicks should sleep for specific number of microseconds.
|
|
||||||
func sleepTicks(d timeUnit) {
|
|
||||||
timerSleep(uint32(d))
|
|
||||||
}
|
|
||||||
|
|
||||||
// number of ticks (microseconds) since start.
|
|
||||||
func ticks() timeUnit {
|
|
||||||
// milliseconds to microseconds
|
|
||||||
return tickCount * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
// ticks are in microseconds
|
|
||||||
func timerSleep(ticks uint32) {
|
|
||||||
timerWakeup.Set(0)
|
|
||||||
|
|
||||||
// CK_INT = APB1 x2 = 54mhz
|
|
||||||
// prescale counter down from 54mhz to 10khz aka 0.1 ms frequency.
|
|
||||||
stm32.TIM3.PSC.Set(54000000/10000 - 1)
|
|
||||||
|
|
||||||
// set duty aka duration
|
|
||||||
arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms
|
|
||||||
if arr == 0 {
|
|
||||||
arr = 1 // avoid blocking
|
|
||||||
}
|
|
||||||
stm32.TIM3.ARR.Set(arr)
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// wait till timer wakes up
|
|
||||||
for timerWakeup.Get() == 0 {
|
|
||||||
arm.Asm("wfi")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM3(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// Disable the timer.
|
|
||||||
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
|
|
||||||
// timer was triggered
|
|
||||||
timerWakeup.Set(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM7(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM7.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM7.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
tickCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,18 +3,42 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
|
||||||
"runtime/volatile"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer settings used for tick and sleep.
|
||||||
|
|
||||||
|
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
||||||
|
settings above, so must be kept in sync if the clock settings are changed.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
TICK_RATE = 1000 // 1 KHz
|
||||||
|
TICK_TIMER_IRQ = stm32.IRQ_TIM7
|
||||||
|
TICK_TIMER_FREQ = 32000000 // 32 MHz
|
||||||
|
SLEEP_TIMER_IRQ = stm32.IRQ_TIM3
|
||||||
|
SLEEP_TIMER_FREQ = 32000000 // 32 MHz
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrtype = uint16
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
initRTC()
|
|
||||||
initTIM()
|
initSleepTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
||||||
|
Device: stm32.TIM3,
|
||||||
|
})
|
||||||
|
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
|
initTickTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB1ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
||||||
|
Device: stm32.TIM7,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
@ -58,157 +82,4 @@ func initCLK() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
timestamp timeUnit // microseconds since boottime
|
|
||||||
timerLastCounter uint64
|
|
||||||
)
|
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
|
||||||
|
|
||||||
func initRTC() {
|
|
||||||
|
|
||||||
// Enable power
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
|
||||||
|
|
||||||
// access to backup register
|
|
||||||
stm32.PWR.CR.SetBits(stm32.PWR_CR_DBP)
|
|
||||||
|
|
||||||
// Enable LSE
|
|
||||||
stm32.RCC.CSR.SetBits(stm32.RCC_CSR_LSEON)
|
|
||||||
|
|
||||||
// wait until LSE is ready
|
|
||||||
for !stm32.RCC.CSR.HasBits(stm32.RCC_CSR_LSERDY) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select Clock Source LSE
|
|
||||||
stm32.RCC.CSR.SetBits(0x01 << stm32.RCC_CSR_RTCSEL_Pos)
|
|
||||||
stm32.RCC.CSR.ClearBits(0x02 << stm32.RCC_CSR_RTCSEL_Pos)
|
|
||||||
|
|
||||||
// Enable clock
|
|
||||||
stm32.RCC.CSR.SetBits(stm32.RCC_CSR_RTCEN)
|
|
||||||
|
|
||||||
stm32.RTC.WPR.Set(0xCA) // Enable Write Access for RTC Registers
|
|
||||||
stm32.RTC.WPR.Set(0x53) // Enable Write Access for RTC Registers
|
|
||||||
stm32.RTC.ISR.SetBits(stm32.RTC_ISR_INIT) // Enable init phase
|
|
||||||
|
|
||||||
// Wait for initialization state
|
|
||||||
for !stm32.RTC.ISR.HasBits(stm32.RTC_ISR_INITF) {
|
|
||||||
}
|
|
||||||
|
|
||||||
stm32.RTC.PRER.Set(0x003F0270) // set prescaler, 40kHz/64 => 625Hz, 625Hz/625 => 1Hz
|
|
||||||
|
|
||||||
// Set initial date
|
|
||||||
//RTC->TR = RTC_TR_PM | 0;
|
|
||||||
|
|
||||||
stm32.RTC.ISR.ClearBits(stm32.RTC_ISR_INIT) // Disable init phase
|
|
||||||
stm32.RTC.WPR.Set(0xFE) // Disable Write Access for RTC Registers
|
|
||||||
stm32.RTC.WPR.Set(0x64) // Disable Write Access for RTC Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM3 clock.
|
|
||||||
func initTIM() {
|
|
||||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
|
|
||||||
intr.SetPriority(0xc3)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
const asyncScheduler = false
|
const asyncScheduler = false
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
||||||
return int64(ticks) * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
|
||||||
return timeUnit(ns / 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sleepTicks should sleep for specific number of microseconds.
|
|
||||||
func sleepTicks(d timeUnit) {
|
|
||||||
for d != 0 {
|
|
||||||
ticks() // update timestamp
|
|
||||||
ticks := uint32(d) // current scaling only supports 100 usec to 6553 msec
|
|
||||||
timerSleep(ticks)
|
|
||||||
d -= timeUnit(ticks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// number of ticks (microseconds) since start.
|
|
||||||
func ticks() timeUnit {
|
|
||||||
|
|
||||||
// Read twice to force shadow register cache update
|
|
||||||
rSubSec := stm32.RTC.SSR.Get() & stm32.RTC_SSR_SS_Msk
|
|
||||||
rSubSec = stm32.RTC.SSR.Get() & stm32.RTC_SSR_SS_Msk
|
|
||||||
rDate := stm32.RTC.DR.Get()
|
|
||||||
rDate = stm32.RTC.DR.Get()
|
|
||||||
rDate++
|
|
||||||
rTime := stm32.RTC.TR.Get()
|
|
||||||
rTime = stm32.RTC.TR.Get()
|
|
||||||
prediv := stm32.RTC.PRER.Get() & stm32.RTC_PRER_PREDIV_S_Msk
|
|
||||||
|
|
||||||
var tsec uint64
|
|
||||||
|
|
||||||
// Timestamp in seconds
|
|
||||||
tsec = uint64(((rTime & 0x300000) >> 20) * 36000) // Hours Tens
|
|
||||||
tsec += uint64(((rTime & 0xf0000) >> 16) * 3600) // Hours Units
|
|
||||||
tsec += uint64(((rTime & 0x7000) >> 12) * 600) // Minutes Tens
|
|
||||||
tsec += uint64(((rTime & 0xf00) >> 8) * 60) // Minutes Units
|
|
||||||
tsec += uint64(((rTime & 0x70) >> 4) * 10) // Second Tens
|
|
||||||
tsec += uint64(rTime & 0xf) // Seconds Units
|
|
||||||
|
|
||||||
//Second fraction in milliseconds
|
|
||||||
ssec := uint64((1000 * (prediv - rSubSec)) / (prediv + 1))
|
|
||||||
|
|
||||||
timerCounter := uint64(tsec * 1000) // Timestamp in millis
|
|
||||||
timerCounter += ssec // Add sub-seconds
|
|
||||||
timerCounter *= 1000 // Convert to micros
|
|
||||||
|
|
||||||
// change since last measurement
|
|
||||||
offset := (timerCounter - timerLastCounter)
|
|
||||||
timerLastCounter = timerCounter
|
|
||||||
timestamp += timeUnit(offset)
|
|
||||||
return timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
// ticks are in microseconds
|
|
||||||
func timerSleep(ticks uint32) {
|
|
||||||
timerWakeup.Set(0)
|
|
||||||
|
|
||||||
// prescale counter down from 32mhz to 10khz aka 0.1 ms frequency.
|
|
||||||
clk := machine.CPUFrequency() / 2
|
|
||||||
stm32.TIM3.PSC.Set(clk/10000 - 1)
|
|
||||||
|
|
||||||
// Set duty aka duration.
|
|
||||||
// STM32 dividers use n-1, i.e. n counts from 0 to n-1.
|
|
||||||
// As a result, with these prescaler settings,
|
|
||||||
// the minimum allowed duration is 200 microseconds.
|
|
||||||
if ticks < 200 {
|
|
||||||
ticks = 200
|
|
||||||
}
|
|
||||||
stm32.TIM3.ARR.Set(uint16(ticks/100 - 1)) // convert from microseconds to 0.1 ms
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// wait till timer wakes up
|
|
||||||
for timerWakeup.Get() == 0 {
|
|
||||||
arm.Asm("wfi")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM3(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// Disable the timer.
|
|
||||||
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
|
|
||||||
// timer was triggered
|
|
||||||
timerWakeup.Set(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,31 +3,8 @@
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
|
||||||
"runtime/volatile"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
initCLK()
|
|
||||||
initTIM15()
|
|
||||||
machine.UART0.Configure(machine.UARTConfig{})
|
|
||||||
initTIM16()
|
|
||||||
}
|
|
||||||
|
|
||||||
func putchar(c byte) {
|
|
||||||
machine.UART0.WriteByte(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
HSE_STARTUP_TIMEOUT = 0x0500
|
|
||||||
PLL_M = 1
|
|
||||||
PLL_N = 55
|
|
||||||
PLL_P = 7 // RCC_PLLP_DIV7
|
|
||||||
PLL_Q = 2 // RCC_PLLQ_DIV2
|
|
||||||
PLL_R = 2 // RCC_PLLR_DIV2
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -40,6 +17,55 @@ const (
|
||||||
| APB2(PCLK2) | 110mhz |
|
| APB2(PCLK2) | 110mhz |
|
||||||
+-------------+-----------+
|
+-------------+-----------+
|
||||||
*/
|
*/
|
||||||
|
const (
|
||||||
|
HSE_STARTUP_TIMEOUT = 0x0500
|
||||||
|
PLL_M = 1
|
||||||
|
PLL_N = 55
|
||||||
|
PLL_P = 7 // RCC_PLLP_DIV7
|
||||||
|
PLL_Q = 2 // RCC_PLLQ_DIV2
|
||||||
|
PLL_R = 2 // RCC_PLLR_DIV2
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer settings used for tick and sleep.
|
||||||
|
|
||||||
|
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
||||||
|
settings above, so must be kept in sync if the clock settings are changed.
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
TICK_RATE = 1000 // 1 KHz
|
||||||
|
SLEEP_TIMER_IRQ = stm32.IRQ_TIM15
|
||||||
|
SLEEP_TIMER_FREQ = 110000000 // 110 MHz
|
||||||
|
TICK_TIMER_IRQ = stm32.IRQ_TIM16
|
||||||
|
TICK_TIMER_FREQ = 110000000 // 110 MHz
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initCLK()
|
||||||
|
|
||||||
|
initSleepTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB2ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB2ENR_TIM15EN,
|
||||||
|
Device: stm32.TIM15,
|
||||||
|
})
|
||||||
|
|
||||||
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
|
initTickTimer(&timerInfo{
|
||||||
|
EnableRegister: &stm32.RCC.APB2ENR,
|
||||||
|
EnableFlag: stm32.RCC_APB2ENR_TIM16EN,
|
||||||
|
Device: stm32.TIM16,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func putchar(c byte) {
|
||||||
|
machine.UART0.WriteByte(c)
|
||||||
|
}
|
||||||
|
|
||||||
func initCLK() {
|
func initCLK() {
|
||||||
|
|
||||||
// PWR_CLK_ENABLE
|
// PWR_CLK_ENABLE
|
||||||
|
@ -137,107 +163,3 @@ func initOsc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// tick in milliseconds
|
|
||||||
tickCount timeUnit
|
|
||||||
)
|
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
|
||||||
return int64(ticks) * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
|
||||||
return timeUnit(ns / 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM15 clock.(sleep count)
|
|
||||||
func initTIM15() {
|
|
||||||
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM15EN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM15, handleTIM15)
|
|
||||||
intr.SetPriority(0xc3)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the TIM16 clock.(tick count)
|
|
||||||
func initTIM16() {
|
|
||||||
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM16EN)
|
|
||||||
|
|
||||||
// CK_INT = APB1 = 110mhz
|
|
||||||
stm32.TIM16.PSC.Set(110000000/10000 - 1) // 110mhz to 10khz(0.1ms)
|
|
||||||
stm32.TIM16.ARR.Set(10 - 1) // interrupt per 1ms
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM16.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM16.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
intr := interrupt.New(stm32.IRQ_TIM16, handleTIM16)
|
|
||||||
intr.SetPriority(0xc1)
|
|
||||||
intr.Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
const asyncScheduler = false
|
|
||||||
|
|
||||||
// sleepTicks should sleep for specific number of microseconds.
|
|
||||||
func sleepTicks(d timeUnit) {
|
|
||||||
timerSleep(uint32(d))
|
|
||||||
}
|
|
||||||
|
|
||||||
// number of ticks (microseconds) since start.
|
|
||||||
func ticks() timeUnit {
|
|
||||||
// milliseconds to microseconds
|
|
||||||
return tickCount * 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
// ticks are in microseconds
|
|
||||||
func timerSleep(ticks uint32) {
|
|
||||||
timerWakeup.Set(0)
|
|
||||||
|
|
||||||
// CK_INT = APB1 = 110mhz
|
|
||||||
// prescale counter down from 110mhz to 10khz aka 0.1 ms frequency.
|
|
||||||
stm32.TIM15.PSC.Set(110000000/10000 - 1)
|
|
||||||
|
|
||||||
// set duty aka duration
|
|
||||||
arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms
|
|
||||||
if arr == 0 {
|
|
||||||
arr = 1 // avoid blocking
|
|
||||||
}
|
|
||||||
stm32.TIM15.ARR.Set(arr)
|
|
||||||
|
|
||||||
// Enable the hardware interrupt.
|
|
||||||
stm32.TIM15.DIER.SetBits(stm32.TIM_DIER_UIE)
|
|
||||||
|
|
||||||
// Enable the timer.
|
|
||||||
stm32.TIM15.CR1.SetBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// wait till timer wakes up
|
|
||||||
for timerWakeup.Get() == 0 {
|
|
||||||
arm.Asm("wfi")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM15(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM15.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// Disable the timer.
|
|
||||||
stm32.TIM15.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
|
||||||
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM15.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
|
|
||||||
// timer was triggered
|
|
||||||
timerWakeup.Set(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleTIM16(interrupt.Interrupt) {
|
|
||||||
if stm32.TIM16.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// clear the update flag
|
|
||||||
stm32.TIM16.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
tickCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче