Skip to content

Commit 65caf77

Browse files
authored
Support for STM32L0 MCUs and Dragino LGT92 device (#1561)
machine/stm32l0: add support for stm32l0 family and Dragino LGT92 Board
1 parent a4d0877 commit 65caf77

File tree

11 files changed

+707
-3
lines changed

11 files changed

+707
-3
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ smoketest:
297297
@$(MD5SUM) test.hex
298298
$(TINYGO) build -size short -o test.hex -target=pinetime-devkit0 examples/blinky1
299299
@$(MD5SUM) test.hex
300+
$(TINYGO) build -size short -o test.hex -target=lgt92 examples/blinky1
301+
@$(MD5SUM) test.hex
300302
$(TINYGO) build -size short -o test.hex -target=x9pro examples/blinky1
301303
@$(MD5SUM) test.hex
302304
$(TINYGO) build -size short -o test.hex -target=pca10056-s140v7 examples/blinky1

src/machine/board_lgt92.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// +build lgt92
2+
3+
package machine
4+
5+
import (
6+
"device/stm32"
7+
"runtime/interrupt"
8+
)
9+
10+
const (
11+
LED1 = PA12
12+
LED2 = PA8
13+
LED3 = PA11
14+
15+
LED_RED = LED1
16+
LED_BLUE = LED2
17+
LED_GREEN = LED3
18+
19+
// Default led
20+
LED = LED1
21+
22+
BUTTON = PB14
23+
24+
// LG GPS module
25+
GPS_STANDBY_PIN = PB3
26+
GPS_RESET_PIN = PB4
27+
GPS_POWER_PIN = PB5
28+
29+
MEMS_ACCEL_CS = PE3
30+
MEMS_ACCEL_INT1 = PE0
31+
MEMS_ACCEL_INT2 = PE1
32+
33+
// SPI
34+
SPI1_SCK_PIN = PA5
35+
SPI1_SDI_PIN = PA6
36+
SPI1_SDO_PIN = PA7
37+
SPI0_SCK_PIN = SPI1_SCK_PIN
38+
SPI0_SDI_PIN = SPI1_SDI_PIN
39+
SPI0_SDO_PIN = SPI1_SDO_PIN
40+
41+
// LORA RFM95 Radio
42+
RFM95_DIO0_PIN = PC13
43+
44+
//TinyGo UART is MCU LPUSART1
45+
UART_RX_PIN = PA13
46+
UART_TX_PIN = PA14
47+
48+
//TinyGo UART1 is MCU USART1
49+
UART1_RX_PIN = PB6
50+
UART1_TX_PIN = PB7
51+
)
52+
53+
var (
54+
55+
// Console UART (LPUSART1)
56+
UART0 = UART{
57+
Buffer: NewRingBuffer(),
58+
Bus: stm32.LPUSART1,
59+
AltFuncSelector: 6,
60+
}
61+
62+
// Gps UART
63+
UART1 = UART{
64+
Buffer: NewRingBuffer(),
65+
Bus: stm32.USART1,
66+
AltFuncSelector: 0,
67+
}
68+
69+
// SPI
70+
SPI0 = SPI{
71+
Bus: stm32.SPI1,
72+
}
73+
SPI1 = &SPI0
74+
)
75+
76+
func init() {
77+
// Enable UARTs Interrupts
78+
UART0.Interrupt = interrupt.New(stm32.IRQ_AES_RNG_LPUART1, UART0.handleInterrupt)
79+
UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, UART1.handleInterrupt)
80+
}

src/machine/i2c.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +build avr nrf sam stm32,!stm32f407,!stm32f7x2 fe310 k210
1+
// +build avr nrf sam stm32,!stm32f407,!stm32f7x2,!stm32l0 fe310 k210
22

33
package machine
44

src/machine/machine_stm32_i2c.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +build stm32,!stm32f103xx,!stm32f407,!stm32f7x2
1+
// +build stm32,!stm32f103xx,!stm32f407,!stm32f7x2,!stm32l0
22

33
package machine
44

src/machine/machine_stm32_uart.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +build stm32,!stm32f7
1+
// +build stm32,!stm32f7,!stm32l0
22

33
package machine
44

src/machine/machine_stm32l0.go

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
// +build stm32l0
2+
3+
package machine
4+
5+
// Peripheral abstraction layer for the stm32l0
6+
7+
import (
8+
"device/stm32"
9+
"runtime/interrupt"
10+
"unsafe"
11+
)
12+
13+
func CPUFrequency() uint32 {
14+
return 32000000
15+
}
16+
17+
const (
18+
PA0 = portA + 0
19+
PA1 = portA + 1
20+
PA2 = portA + 2
21+
PA3 = portA + 3
22+
PA4 = portA + 4
23+
PA5 = portA + 5
24+
PA6 = portA + 6
25+
PA7 = portA + 7
26+
PA8 = portA + 8
27+
PA9 = portA + 9
28+
PA10 = portA + 10
29+
PA11 = portA + 11
30+
PA12 = portA + 12
31+
PA13 = portA + 13
32+
PA14 = portA + 14
33+
PA15 = portA + 15
34+
35+
PB0 = portB + 0
36+
PB1 = portB + 1
37+
PB2 = portB + 2
38+
PB3 = portB + 3
39+
PB4 = portB + 4
40+
PB5 = portB + 5
41+
PB6 = portB + 6
42+
PB7 = portB + 7
43+
PB8 = portB + 8
44+
PB9 = portB + 9
45+
PB10 = portB + 10
46+
PB11 = portB + 11
47+
PB12 = portB + 12
48+
PB13 = portB + 13
49+
PB14 = portB + 14
50+
PB15 = portB + 15
51+
52+
PC0 = portC + 0
53+
PC1 = portC + 1
54+
PC2 = portC + 2
55+
PC3 = portC + 3
56+
PC4 = portC + 4
57+
PC5 = portC + 5
58+
PC6 = portC + 6
59+
PC7 = portC + 7
60+
PC8 = portC + 8
61+
PC9 = portC + 9
62+
PC10 = portC + 10
63+
PC11 = portC + 11
64+
PC12 = portC + 12
65+
PC13 = portC + 13
66+
PC14 = portC + 14
67+
PC15 = portC + 15
68+
69+
PD0 = portD + 0
70+
PD1 = portD + 1
71+
PD2 = portD + 2
72+
PD3 = portD + 3
73+
PD4 = portD + 4
74+
PD5 = portD + 5
75+
PD6 = portD + 6
76+
PD7 = portD + 7
77+
PD8 = portD + 8
78+
PD9 = portD + 9
79+
PD10 = portD + 10
80+
PD11 = portD + 11
81+
PD12 = portD + 12
82+
PD13 = portD + 13
83+
PD14 = portD + 14
84+
PD15 = portD + 15
85+
86+
PE0 = portE + 0
87+
PE1 = portE + 1
88+
PE2 = portE + 2
89+
PE3 = portE + 3
90+
PE4 = portE + 4
91+
PE5 = portE + 5
92+
PE6 = portE + 6
93+
PE7 = portE + 7
94+
PE8 = portE + 8
95+
PE9 = portE + 9
96+
PE10 = portE + 10
97+
PE11 = portE + 11
98+
PE12 = portE + 12
99+
PE13 = portE + 13
100+
PE14 = portE + 14
101+
PE15 = portE + 15
102+
103+
PH0 = portH + 0
104+
PH1 = portH + 1
105+
)
106+
107+
func (p Pin) getPort() *stm32.GPIO_Type {
108+
switch p / 16 {
109+
case 0:
110+
return stm32.GPIOA
111+
case 1:
112+
return stm32.GPIOB
113+
case 2:
114+
return stm32.GPIOC
115+
case 3:
116+
return stm32.GPIOD
117+
case 4:
118+
return stm32.GPIOE
119+
case 7:
120+
return stm32.GPIOH
121+
default:
122+
panic("machine: unknown port")
123+
}
124+
}
125+
126+
// enableClock enables the clock for this desired GPIO port.
127+
func (p Pin) enableClock() {
128+
switch p / 16 {
129+
case 0:
130+
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPAEN)
131+
case 1:
132+
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPBEN)
133+
case 2:
134+
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPCEN)
135+
case 3:
136+
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPDEN)
137+
case 4:
138+
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPEEN)
139+
case 7:
140+
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPHEN)
141+
default:
142+
panic("machine: unknown port")
143+
}
144+
}
145+
146+
// Enable peripheral clock
147+
func enableAltFuncClock(bus unsafe.Pointer) {
148+
switch bus {
149+
case unsafe.Pointer(stm32.DAC): // DAC interface clock enable
150+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_DACEN)
151+
case unsafe.Pointer(stm32.PWR): // Power interface clock enable
152+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
153+
case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable
154+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C3EN)
155+
case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable
156+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C2EN)
157+
case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable
158+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN)
159+
case unsafe.Pointer(stm32.USART5): // UART5 clock enable
160+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART5EN)
161+
case unsafe.Pointer(stm32.USART4): // UART4 clock enable
162+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART4EN)
163+
case unsafe.Pointer(stm32.USART2): // USART2 clock enable
164+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN)
165+
case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable
166+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_SPI2EN)
167+
case unsafe.Pointer(stm32.LPUSART1): // LPUSART1 clock enable
168+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_LPUART1EN)
169+
case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable
170+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_WWDGEN)
171+
case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable
172+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN)
173+
case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable
174+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM6EN)
175+
case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable
176+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
177+
case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable
178+
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM2EN)
179+
case unsafe.Pointer(stm32.SYSCFG_COMP): // System configuration controller clock enable
180+
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN)
181+
case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable
182+
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN)
183+
case unsafe.Pointer(stm32.ADC): // ADC clock enable
184+
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_ADCEN)
185+
case unsafe.Pointer(stm32.USART1): // USART1 clock enable
186+
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN)
187+
}
188+
}
189+
190+
//---------- UART related types and code
191+
192+
// UART representation
193+
type UART struct {
194+
Buffer *RingBuffer
195+
Bus *stm32.USART_Type
196+
Interrupt interrupt.Interrupt
197+
AltFuncSelector stm32.AltFunc
198+
}
199+
200+
// Configure the UART.
201+
func (uart UART) configurePins(config UARTConfig) {
202+
// enable the alternate functions on the TX and RX pins
203+
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
204+
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
205+
}
206+
207+
// UART baudrate calc based on the bus and clockspeed
208+
func (uart UART) getBaudRateDivisor(baudRate uint32) uint32 {
209+
var clock, rate uint32
210+
switch uart.Bus {
211+
case stm32.LPUSART1:
212+
clock = CPUFrequency() / 2 // APB1 Frequency
213+
rate = uint32((256 * clock) / baudRate)
214+
case stm32.USART1:
215+
clock = CPUFrequency() / 2 // APB2 Frequency
216+
rate = uint32(clock / baudRate)
217+
case stm32.USART2:
218+
clock = CPUFrequency() / 2 // APB1 Frequency
219+
rate = uint32(clock / baudRate)
220+
}
221+
222+
return rate
223+
}
224+
225+
//---------- SPI related types and code
226+
227+
// SPI on the STM32Fxxx using MODER / alternate function pins
228+
type SPI struct {
229+
Bus *stm32.SPI_Type
230+
AltFuncSelector stm32.AltFunc
231+
}
232+
233+
// Set baud rate for SPI
234+
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
235+
var conf uint32
236+
237+
localFrequency := config.Frequency
238+
239+
// Default
240+
if config.Frequency == 0 {
241+
config.Frequency = 4e6
242+
}
243+
244+
if spi.Bus != stm32.SPI1 {
245+
// Assume it's SPI2 or SPI3 on APB1 at 1/2 the clock frequency of APB2, so
246+
// we want to pretend to request 2x the baudrate asked for
247+
localFrequency = localFrequency * 2
248+
}
249+
250+
// set frequency dependent on PCLK prescaler. Since these are rather weird
251+
// speeds due to the CPU freqency, pick a range up to that frquency for
252+
// clients to use more human-understandable numbers, e.g. nearest 100KHz
253+
254+
// These are based on APB2 clock frquency (84MHz on the discovery board)
255+
// TODO: also include the MCU/APB clock setting in the equation
256+
switch {
257+
case localFrequency < 328125:
258+
conf = stm32.SPI_PCLK_256
259+
case localFrequency < 656250:
260+
conf = stm32.SPI_PCLK_128
261+
case localFrequency < 1312500:
262+
conf = stm32.SPI_PCLK_64
263+
case localFrequency < 2625000:
264+
conf = stm32.SPI_PCLK_32
265+
case localFrequency < 5250000:
266+
conf = stm32.SPI_PCLK_16
267+
case localFrequency < 10500000:
268+
conf = stm32.SPI_PCLK_8
269+
// NOTE: many SPI components won't operate reliably (or at all) above 10MHz
270+
// Check the datasheet of the part
271+
case localFrequency < 21000000:
272+
conf = stm32.SPI_PCLK_4
273+
case localFrequency < 42000000:
274+
conf = stm32.SPI_PCLK_2
275+
default:
276+
// None of the specific baudrates were selected; choose the lowest speed
277+
conf = stm32.SPI_PCLK_256
278+
}
279+
280+
return conf << stm32.SPI_CR1_BR_Pos
281+
}
282+
283+
// Configure SPI pins for input output and clock
284+
func (spi SPI) configurePins(config SPIConfig) {
285+
config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector)
286+
config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector)
287+
config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector)
288+
}

0 commit comments

Comments
 (0)