stm32: Use TIM for runtime clock
Этот коммит содержится в:
родитель
003c96edc0
коммит
fa3dd41a4f
9 изменённых файлов: 122 добавлений и 307 удалений
|
@ -2,26 +2,19 @@
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
// This file implements a common implementation of implementing 'ticks' and 'sleep' for STM32 devices. The
|
// This file implements a common implementation of implementing 'ticks' and
|
||||||
// implementation uses two 'basic' timers, so should be compatible with a broad range of STM32 MCUs.
|
// 'sleep' for STM32 devices. The implementation uses a single timer. The
|
||||||
|
// timer's PWM frequency (controlled by PSC and ARR) are configured for
|
||||||
|
// periodic interrupts at 100Hz (TICK_INTR_PERIOD_NS). The PWM counter
|
||||||
|
// register is used for fine-grained resolution (down to ~150ns) with an
|
||||||
|
// Output Comparator used for fine-grained sleeps.
|
||||||
//
|
//
|
||||||
// This implementation is of 'sleep' is for running in a normal power mode. Use of the RTC to enter and
|
// The type alias `arrtype` should be defined to either uint32 or uint16
|
||||||
// resume from low-power states is out of scope.
|
// depending on the size of that register in the MCU's TIM_Type structure.
|
||||||
//
|
|
||||||
// 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 (
|
import (
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
|
"machine"
|
||||||
"runtime/interrupt"
|
"runtime/interrupt"
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
@ -33,7 +26,22 @@ type timerInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TICKS_PER_NS = 1000000000 / TICK_RATE
|
// All STM32 do a constant 16ns per tick. This keeps time
|
||||||
|
// conversion between ticks and ns fast (shift operation)
|
||||||
|
// at the expense of more complex logic when getting current
|
||||||
|
// time (which is already slow due to interfacing with hardware)
|
||||||
|
NS_PER_TICK = 16
|
||||||
|
|
||||||
|
// For very short sleeps a busy loop is used to avoid race
|
||||||
|
// conditions where a trigger would take longer to setup than
|
||||||
|
// the sleep duration.
|
||||||
|
MAX_BUSY_LOOP_NS = 10e3 // 10us
|
||||||
|
|
||||||
|
// The period of tick interrupts in nanoseconds
|
||||||
|
TICK_INTR_PERIOD_NS = 10e6 // 10ms = 100Hz
|
||||||
|
|
||||||
|
// The number of ticks that happen per overflow interrupt
|
||||||
|
TICK_PER_INTR = TICK_INTR_PERIOD_NS / NS_PER_TICK
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -41,79 +49,65 @@ var (
|
||||||
tickCount volatile.Register64
|
tickCount volatile.Register64
|
||||||
|
|
||||||
// The timer used for counting ticks
|
// The timer used for counting ticks
|
||||||
tickTimer *timerInfo
|
tickTimer *machine.TIM
|
||||||
|
|
||||||
// The timer used for sleeping
|
// The max counter value (fractional part)
|
||||||
sleepTimer *timerInfo
|
countMax uint32
|
||||||
)
|
)
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
return int64(ticks) * TICKS_PER_NS
|
return int64(ticks) * NS_PER_TICK
|
||||||
}
|
}
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
func nanosecondsToTicks(ns int64) timeUnit {
|
||||||
return timeUnit(ns / TICKS_PER_NS)
|
return timeUnit(ns / NS_PER_TICK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// number of ticks (microseconds) since start.
|
// number of ticks since start.
|
||||||
//go:linkname ticks runtime.ticks
|
//go:linkname ticks runtime.ticks
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
return timeUnit(tickCount.Get())
|
// For some ways of capturing the time atomically, see this thread:
|
||||||
|
// https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
|
||||||
|
// Here, instead of re-reading the counter register if an overflow has been
|
||||||
|
// detected, we simply try again because that results in smaller code.
|
||||||
|
for {
|
||||||
|
mask := interrupt.Disable()
|
||||||
|
counter := tickTimer.Count()
|
||||||
|
overflows := uint64(tickCount.Get())
|
||||||
|
hasOverflow := tickTimer.Device.SR.HasBits(stm32.TIM_SR_UIF)
|
||||||
|
interrupt.Restore(mask)
|
||||||
|
|
||||||
|
if hasOverflow {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeUnit(overflows*TICK_PER_INTR + countToTicks(counter))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// -- Ticks ---
|
// -- Ticks ---
|
||||||
//
|
//
|
||||||
|
|
||||||
// Enable the timer used to count ticks
|
// Enable the timer used to count ticks.
|
||||||
func initTickTimer(ti *timerInfo) {
|
//
|
||||||
tickTimer = ti
|
// For precise sleeps use a timer with at least one OutputCompare
|
||||||
ti.EnableRegister.SetBits(ti.EnableFlag)
|
// channel otherwise minimum reliable sleep resolution is bounded
|
||||||
|
// by TICK_INTR_PERIOD_NS.
|
||||||
|
//
|
||||||
|
// Typically avoid TIM6 / TIM7 as they often do not include an
|
||||||
|
// output comparator.
|
||||||
|
func initTickTimer(tim *machine.TIM) {
|
||||||
|
tickTimer = tim
|
||||||
|
tickTimer.Configure(machine.PWMConfig{Period: TICK_INTR_PERIOD_NS})
|
||||||
|
|
||||||
psc := uint32(TICK_TIMER_FREQ / TICK_RATE)
|
countMax = tickTimer.Top()
|
||||||
period := uint32(1)
|
tickTimer.SetWraparoundInterrupt(handleTick)
|
||||||
|
|
||||||
// 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) {
|
func handleTick() {
|
||||||
if tickTimer.Device.SR.HasBits(stm32.TIM_SR_UIF) {
|
|
||||||
// clear the update flag
|
|
||||||
tickTimer.Device.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
|
|
||||||
// increment tick count
|
// increment tick count
|
||||||
tickCount.Set(tickCount.Get() + 1)
|
tickCount.Set(tickCount.Get() + 1)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -127,76 +121,76 @@ func sleepTicks(d timeUnit) {
|
||||||
// The scheduler will call again if there is nothing to do and a further
|
// The scheduler will call again if there is nothing to do and a further
|
||||||
// sleep is required.
|
// sleep is required.
|
||||||
if hasScheduler {
|
if hasScheduler {
|
||||||
timerSleep(ticksToNanoseconds(d))
|
timerSleep(uint64(d))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's no scheduler, so we sleep until at least the requested number
|
// There's no scheduler, so we sleep until at least the requested number
|
||||||
// of ticks has passed.
|
// of ticks has passed. For short sleeps, this forms a busy loop since
|
||||||
|
// timerSleep will return immediately.
|
||||||
end := ticks() + d
|
end := ticks() + d
|
||||||
for ticks() < end {
|
for ticks() < end {
|
||||||
timerSleep(ticksToNanoseconds(d))
|
timerSleep(uint64(d))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the Sleep clock
|
// timerSleep sleeps for 'at most' ticks, but possibly less.
|
||||||
func initSleepTimer(ti *timerInfo) {
|
func timerSleep(ticks uint64) {
|
||||||
sleepTimer = ti
|
// If the sleep is super-small (<10us), busy loop by returning
|
||||||
|
// to the scheduler (if any). This avoids a busy loop here
|
||||||
ti.EnableRegister.SetBits(ti.EnableFlag)
|
// that might delay tasks from being scheduled triggered by
|
||||||
|
// an interrupt (e.g. channels).
|
||||||
// No auto-repeat
|
if ticksToNanoseconds(timeUnit(ticks)) < MAX_BUSY_LOOP_NS {
|
||||||
ti.Device.EGR.SetBits(stm32.TIM_EGR_UG)
|
return
|
||||||
|
|
||||||
// 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 the sleep is long, the tick interrupt will occur before
|
||||||
if period > 0x10000 {
|
// the sleep expires, so just use that. This routine will be
|
||||||
period = 0x10000
|
// called again if the sleep is incomplete.
|
||||||
|
if ticks >= TICK_PER_INTR {
|
||||||
|
waitForEvents()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the desired duration and enable
|
// Sleeping for less than one tick interrupt, now see if the
|
||||||
sleepTimer.Device.PSC.Set(uint32(psc) - 1)
|
// next tick interrupt will occur before the sleep expires. If
|
||||||
sleepTimer.Device.ARR.Set(arrtype(period) - 1)
|
// so, use that interrupt. (this routine will be called
|
||||||
sleepTimer.Device.CR1.SetBits(stm32.TIM_CR1_CEN)
|
// again if sleep is incomplete)
|
||||||
|
cnt := tickTimer.Count()
|
||||||
|
ticksUntilOverflow := countToTicks(countMax - cnt)
|
||||||
|
if ticksUntilOverflow <= ticks {
|
||||||
|
waitForEvents()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The sleep is now known to be:
|
||||||
|
// - More than a few CPU cycles
|
||||||
|
// - Less than one interrupt period
|
||||||
|
// - Expiring before the next interrupt
|
||||||
|
//
|
||||||
|
// Setup a PWM channel to trigger an interrupt.
|
||||||
|
// NOTE: ticks is known to be < MAX_UINT32 at this point.
|
||||||
|
tickTimer.SetMatchInterrupt(0, handleSleep)
|
||||||
|
tickTimer.Set(0, cnt+ticksToCount(ticks))
|
||||||
|
|
||||||
// Wait till either the timer or some other event wakes
|
// Wait till either the timer or some other event wakes
|
||||||
// up the CPU
|
// up the CPU
|
||||||
waitForEvents()
|
waitForEvents()
|
||||||
|
|
||||||
// In case it was not the sleep timer that woke the
|
// In case it was not the sleep interrupt that woke the
|
||||||
// CPU, disable the timer now.
|
// CPU, disable the sleep interrupt now.
|
||||||
disableSleepTimer()
|
tickTimer.Unset(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSleep(interrupt.Interrupt) {
|
func handleSleep(ch uint8) {
|
||||||
disableSleepTimer()
|
// Disable the sleep interrupt
|
||||||
|
tickTimer.Unset(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func disableSleepTimer() {
|
func countToTicks(count uint32) uint64 {
|
||||||
// Disable and clear the update flag.
|
return (uint64(count) * TICK_PER_INTR) / uint64(countMax)
|
||||||
sleepTimer.Device.CR1.ClearBits(stm32.TIM_CR1_CEN)
|
}
|
||||||
sleepTimer.Device.SR.ClearBits(stm32.TIM_SR_UIF)
|
|
||||||
|
func ticksToCount(ticks uint64) uint32 {
|
||||||
|
return uint32((ticks * uint64(countMax)) / TICK_PER_INTR)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,39 +7,14 @@ import (
|
||||||
"machine"
|
"machine"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
type arrtype = uint32
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
|
||||||
Device: stm32.TIM3,
|
|
||||||
})
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM4)
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM4EN,
|
|
||||||
Device: stm32.TIM4,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
|
|
@ -64,39 +64,15 @@ 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
|
type arrtype = uint32
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initOSC() // configure oscillators
|
initOSC() // configure oscillators
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
|
||||||
Device: stm32.TIM3,
|
|
||||||
})
|
|
||||||
|
|
||||||
initCOM()
|
initCOM()
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM3)
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
|
||||||
Device: stm32.TIM7,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initOSC() {
|
func initOSC() {
|
||||||
|
|
|
@ -26,38 +26,14 @@ const (
|
||||||
PLL_Q = 7 // USB OTS FS, SDIO and RNG Clock = PLL_VCO / PLL_Q
|
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
|
type arrtype = uint32
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
|
||||||
Device: stm32.TIM3,
|
|
||||||
})
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM2)
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
|
||||||
Device: stm32.TIM7,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
|
|
@ -25,38 +25,14 @@ const (
|
||||||
PLL_Q = 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
|
type arrtype = uint32
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
|
||||||
Device: stm32.TIM3,
|
|
||||||
})
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM3)
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
|
||||||
Device: stm32.TIM7,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
|
|
@ -7,20 +7,6 @@ import (
|
||||||
"machine"
|
"machine"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
timer settings used for tick and sleep.
|
|
||||||
|
|
||||||
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
|
||||||
settings, so must be kept in sync if the clock settings are changed.
|
|
||||||
*/
|
|
||||||
const (
|
|
||||||
TICK_RATE = 1000 // 1 KHz
|
|
||||||
TICK_TIMER_IRQ = stm32.IRQ_TIM21
|
|
||||||
TICK_TIMER_FREQ = 32000000 // 32 MHz
|
|
||||||
SLEEP_TIMER_IRQ = stm32.IRQ_TIM22
|
|
||||||
SLEEP_TIMER_FREQ = 32000000 // 32 MHz
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FlashLatency = stm32.Flash_ACR_LATENCY_WS1
|
FlashLatency = stm32.Flash_ACR_LATENCY_WS1
|
||||||
)
|
)
|
||||||
|
@ -28,17 +14,7 @@ const (
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB2ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB2ENR_TIM22EN,
|
|
||||||
Device: stm32.TIM22,
|
|
||||||
})
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM21)
|
||||||
EnableRegister: &stm32.RCC.APB2ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB2ENR_TIM21EN,
|
|
||||||
Device: stm32.TIM21,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,6 @@ import (
|
||||||
"machine"
|
"machine"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
timer settings used for tick and sleep.
|
|
||||||
|
|
||||||
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
|
|
||||||
settings, 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
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FlashLatency = stm32.Flash_ACR_LATENCY_WS1
|
FlashLatency = stm32.Flash_ACR_LATENCY_WS1
|
||||||
)
|
)
|
||||||
|
@ -28,17 +14,7 @@ const (
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM3EN,
|
|
||||||
Device: stm32.TIM3,
|
|
||||||
})
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM3)
|
||||||
EnableRegister: &stm32.RCC.APB1ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB1ENR_TIM7EN,
|
|
||||||
Device: stm32.TIM7,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,38 +50,14 @@ const (
|
||||||
RCC_PLL_SYSCLK = stm32.RCC_PLLCFGR_PLLREN
|
RCC_PLL_SYSCLK = stm32.RCC_PLLCFGR_PLLREN
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
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_TIM1_UP_TIM16
|
|
||||||
TICK_TIMER_FREQ = 80000000 // 80 MHz
|
|
||||||
SLEEP_TIMER_IRQ = stm32.IRQ_TIM1_BRK_TIM15
|
|
||||||
SLEEP_TIMER_FREQ = 80000000 // 84 MHz
|
|
||||||
)
|
|
||||||
|
|
||||||
type arrtype = uint32
|
type arrtype = uint32
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB2ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB2ENR_TIM15EN,
|
|
||||||
Device: stm32.TIM15,
|
|
||||||
})
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM15)
|
||||||
EnableRegister: &stm32.RCC.APB2ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB2ENR_TIM16EN,
|
|
||||||
Device: stm32.TIM16,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
|
|
@ -31,19 +31,9 @@ type arrtype = uint32
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
initSleepTimer(&timerInfo{
|
|
||||||
EnableRegister: &stm32.RCC.APB2ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB2ENR_TIM15EN,
|
|
||||||
Device: stm32.TIM15,
|
|
||||||
})
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
initTickTimer(&timerInfo{
|
initTickTimer(&machine.TIM16)
|
||||||
EnableRegister: &stm32.RCC.APB2ENR,
|
|
||||||
EnableFlag: stm32.RCC_APB2ENR_TIM16EN,
|
|
||||||
Device: stm32.TIM16,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче