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
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/stm32"
|
||||
"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() {
|
||||
initCLK()
|
||||
initRTC()
|
||||
initTIM()
|
||||
|
||||
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_TIM4EN,
|
||||
Device: stm32.TIM4,
|
||||
})
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/stm32"
|
||||
"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 (
|
||||
// +----------------------+
|
||||
// | Clock Settings |
|
||||
|
@ -74,6 +64,43 @@ const (
|
|||
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() {
|
||||
// enable voltage regulator
|
||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
||||
|
@ -154,95 +181,12 @@ func initCLK() {
|
|||
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() {
|
||||
if machine.NUM_UART_INTERFACES > 0 {
|
||||
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) {
|
||||
machine.UART0.WriteByte(c)
|
||||
}
|
||||
|
|
|
@ -3,31 +3,8 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/stm32"
|
||||
"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 |
|
||||
+-------------+--------+
|
||||
*/
|
||||
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
|
||||
// Set HSION
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION)
|
||||
|
@ -104,111 +129,7 @@ func initCLK() {
|
|||
for {
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the CCM RAM clock
|
||||
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
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/stm32"
|
||||
"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 |
|
||||
+-------------+--------+
|
||||
*/
|
||||
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() {
|
||||
// PWR_CLK_ENABLE
|
||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
||||
|
@ -102,107 +128,3 @@ func initOsc() {
|
|||
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
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/stm32"
|
||||
"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() {
|
||||
initCLK()
|
||||
initRTC()
|
||||
initTIM()
|
||||
|
||||
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) {
|
||||
|
@ -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
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/stm32"
|
||||
"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 |
|
||||
+-------------+-----------+
|
||||
*/
|
||||
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() {
|
||||
|
||||
// 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++
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче