1// +build stm32,stm32f103xx
2
3package runtime
4
5import (
6	"device/arm"
7	"device/stm32"
8	"machine"
9	"runtime/interrupt"
10	"runtime/volatile"
11)
12
13func init() {
14	initCLK()
15	initRTC()
16	initTIM()
17	machine.UART0.Configure(machine.UARTConfig{})
18}
19
20func putchar(c byte) {
21	machine.UART0.WriteByte(c)
22}
23
24// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
25func initCLK() {
26	stm32.FLASH.ACR.SetBits(stm32.FLASH_ACR_LATENCY_2)    // Two wait states, per datasheet
27	stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE1_DIV_2)    // prescale PCLK1 = HCLK/2
28	stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE2_DIV_NONE) // prescale PCLK2 = HCLK/1
29	stm32.RCC.CR.SetBits(stm32.RCC_CR_HSEON)              // enable HSE clock
30
31	// wait for the HSEREADY flag
32	for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) {
33	}
34
35	stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION) // enable HSI clock
36
37	// wait for the HSIREADY flag
38	for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSIRDY) {
39	}
40
41	stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLSRC)   // set PLL source to HSE
42	stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLMUL_9) // multiply by 9
43	stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)        // enable the PLL
44
45	// wait for the PLLRDY flag
46	for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
47	}
48
49	stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_SW_PLL) // set clock source to pll
50
51	// wait for PLL to be CLK
52	for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_SWS_PLL) {
53	}
54}
55
56var (
57	timestamp        timeUnit // microseconds since boottime
58	timerLastCounter uint64
59)
60
61var timerWakeup volatile.Register8
62
63func initRTC() {
64	// Enable the PWR and BKP.
65	stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN)
66
67	// access to backup register
68	stm32.PWR.CR.SetBits(stm32.PWR_CR_DBP)
69
70	// Enable LSE
71	stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_LSEON)
72
73	// wait until LSE is ready
74	for !stm32.RCC.BDCR.HasBits(stm32.RCC_BDCR_LSERDY) {
75	}
76
77	// Select LSE
78	stm32.RCC.BDCR.SetBits(stm32.RCC_RTCCLKSource_LSE)
79
80	// set prescaler to "max" per datasheet
81	stm32.RTC.PRLH.Set(stm32.RTC_PRLH_PRLH_Msk)
82	stm32.RTC.PRLL.Set(stm32.RTC_PRLL_PRLL_Msk)
83
84	// set count to zero
85	stm32.RTC.CNTH.Set(0x0)
86	stm32.RTC.CNTL.Set(0x0)
87
88	// Enable RTC
89	stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_RTCEN)
90
91	// Clear RSF
92	stm32.RTC.CRL.ClearBits(stm32.RTC_CRL_RSF)
93
94	// Wait till flag is set
95	for !stm32.RTC.CRL.HasBits(stm32.RTC_CRL_RSF) {
96	}
97}
98
99// Enable the TIM3 clock.
100func initTIM() {
101	stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
102
103	intr := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
104	intr.SetPriority(0xc3)
105	intr.Enable()
106}
107
108const asyncScheduler = false
109
110func ticksToNanoseconds(ticks timeUnit) int64 {
111	return int64(ticks) * 1000
112}
113
114func nanosecondsToTicks(ns int64) timeUnit {
115	return timeUnit(ns / 1000)
116}
117
118// sleepTicks should sleep for specific number of microseconds.
119func sleepTicks(d timeUnit) {
120	for d != 0 {
121		ticks()            // update timestamp
122		ticks := uint32(d) // current scaling only supports 100 usec to 6553 msec
123		timerSleep(ticks)
124		d -= timeUnit(ticks)
125	}
126}
127
128// number of ticks (microseconds) since start.
129func ticks() timeUnit {
130	// convert RTC counter from seconds to microseconds
131	timerCounter := uint64(stm32.RTC.CNTH.Get()<<16|stm32.RTC.CNTL.Get()) * 1000 * 1000
132
133	// add the fractional part of current time using DIV register
134	timerCounter += uint64(0x8000-stm32.RTC.DIVL.Get()) * 31
135
136	// change since last measurement
137	offset := (timerCounter - timerLastCounter)
138	timerLastCounter = timerCounter
139	timestamp += timeUnit(offset)
140	return timestamp
141}
142
143// ticks are in microseconds
144func timerSleep(ticks uint32) {
145	timerWakeup.Set(0)
146
147	// STM32 timer update event period is calculated as follows:
148	//
149	// 			Update_event = TIM_CLK/((PSC + 1)*(ARR + 1)*(RCR + 1))
150	//
151	// Where:
152	//
153	//			TIM_CLK = timer clock input
154	// 			PSC = 16-bit prescaler register
155	// 			ARR = 16/32-bit Autoreload register
156	// 			RCR = 16-bit repetition counter
157	//
158	// Example:
159	//
160	//			TIM_CLK = 72 MHz
161	// 			Prescaler = 1
162	// 			Auto reload = 65535
163	// 			No repetition counter RCR = 0
164	// 			Update_event = 72*(10^6)/((1 + 1)*(65535 + 1)*(1))
165	// 			Update_event = 549.3 Hz
166	//
167	// Set the timer prescaler/autoreload timing registers.
168
169	// TODO: support smaller or larger scales (autoscaling) based
170	// on the length of sleep time requested.
171	// The current scaling only supports a range of 200 usec to 6553 msec.
172
173	// prescale counter down from 72mhz to 10khz aka 0.1 ms frequency.
174	stm32.TIM3.PSC.Set(machine.CPUFrequency()/10000 - 1) // 7199
175
176	// Set duty aka duration.
177	// STM32 dividers use n-1, i.e. n counts from 0 to n-1.
178	// As a result, with these prescaler settings,
179	// the minimum allowed duration is 200 microseconds.
180	if ticks < 200 {
181		ticks = 200
182	}
183	stm32.TIM3.ARR.Set(ticks/100 - 1) // convert from microseconds to 0.1 ms
184
185	// Enable the hardware interrupt.
186	stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
187
188	// Enable the timer.
189	stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
190
191	// wait till timer wakes up
192	for timerWakeup.Get() == 0 {
193		arm.Asm("wfi")
194	}
195}
196
197func handleTIM3(interrupt.Interrupt) {
198	if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
199		// Disable the timer.
200		stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
201
202		// clear the update flag
203		stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
204
205		// timer was triggered
206		timerWakeup.Set(1)
207	}
208}
209