Improvements for stm32wle targets :
- board/stm32: Add STM32 Nucleo WL55JC board - stm32/stm32wl: Set 48Mhz HSE32/PLL as default Clock, SPI implementation
Этот коммит содержится в:
родитель
718746dd21
коммит
b0fce80b50
9 изменённых файлов: 249 добавлений и 15 удалений
2
Makefile
2
Makefile
|
@ -435,6 +435,8 @@ ifneq ($(STM32), 0)
|
|||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nucleo-wl55jc examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
|
||||
|
|
|
@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
|||
|
||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||
|
||||
The following 72 microcontroller boards are currently supported:
|
||||
The following 74 microcontroller boards are currently supported:
|
||||
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
|
@ -115,6 +115,7 @@ The following 72 microcontroller boards are currently supported:
|
|||
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
|
||||
* [ST Micro "Nucleo" L432KC](https://www.st.com/ja/evaluation-tools/nucleo-l432kc.html)
|
||||
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
|
||||
* [ST Micro "Nucleo" WL55JC](https://www.st.com/en/evaluation-tools/nucleo-wl55jc.html)
|
||||
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
|
||||
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
|
||||
* [X9 Pro smartwatch](https://github.com/curtpw/nRF5x-device-reverse-engineering/tree/master/X9-nrf52832-activity-tracker/)
|
||||
|
|
|
@ -9,8 +9,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
LED1 = PB5
|
||||
LED = LED1 // Default LED
|
||||
// We assume a LED is connected on PB5
|
||||
LED = PB5 // Default LED
|
||||
)
|
||||
|
||||
// SubGhz (SPI3)
|
||||
|
@ -46,6 +46,11 @@ var (
|
|||
RxAltFuncSelector: AF7_USART1_2,
|
||||
}
|
||||
DefaultUART = UART0
|
||||
|
||||
// SPI
|
||||
SPI3 = SPI{
|
||||
Bus: stm32.SPI3,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
72
src/machine/board_nucleowl55jc.go
Обычный файл
72
src/machine/board_nucleowl55jc.go
Обычный файл
|
@ -0,0 +1,72 @@
|
|||
//go:build nucleowl55jc
|
||||
// +build nucleowl55jc
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const (
|
||||
LED_BLUE = PB15
|
||||
LED_GREEN = PB9
|
||||
LED_RED = PB11
|
||||
LED = LED_RED
|
||||
|
||||
BTN1 = PA0
|
||||
BTN2 = PA1
|
||||
BTN3 = PC6
|
||||
BUTTON = BTN1
|
||||
|
||||
// SubGhz (SPI3)
|
||||
SPI0_NSS_PIN = PA4
|
||||
SPI0_SCK_PIN = PA5
|
||||
SPI0_SDO_PIN = PA6
|
||||
SPI0_SDI_PIN = PA7
|
||||
|
||||
//MCU USART1
|
||||
UART1_TX_PIN = PB6
|
||||
UART1_RX_PIN = PB7
|
||||
|
||||
//MCU USART2
|
||||
UART2_RX_PIN = PA3
|
||||
UART2_TX_PIN = PA2
|
||||
|
||||
// DEFAULT USART
|
||||
UART_RX_PIN = UART2_RX_PIN
|
||||
UART_TX_PIN = UART2_TX_PIN
|
||||
)
|
||||
|
||||
var (
|
||||
// STM32 UART2 is connected to the embedded STLINKV3 Virtual Com Port
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART2,
|
||||
TxAltFuncSelector: 7,
|
||||
RxAltFuncSelector: 7,
|
||||
}
|
||||
|
||||
// UART1 is free
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART1,
|
||||
TxAltFuncSelector: 7,
|
||||
RxAltFuncSelector: 7,
|
||||
}
|
||||
|
||||
DefaultUART = UART0
|
||||
|
||||
// SPI
|
||||
SPI3 = SPI{
|
||||
Bus: stm32.SPI3,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Enable UARTs Interrupts
|
||||
UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, _UART0.handleInterrupt)
|
||||
UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART1.handleInterrupt)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//go:build stm32 && !stm32f7x2 && !stm32l5x2 && !stm32wle5
|
||||
// +build stm32,!stm32f7x2,!stm32l5x2,!stm32wle5
|
||||
//go:build stm32 && !stm32f7x2 && !stm32l5x2
|
||||
// +build stm32,!stm32f7x2,!stm32l5x2
|
||||
|
||||
package machine
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ package machine
|
|||
|
||||
import (
|
||||
"device/stm32"
|
||||
"math/bits"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
|
@ -28,12 +29,15 @@ const (
|
|||
AF15_EVENTOUT = 15
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 4e6
|
||||
}
|
||||
const (
|
||||
SYSCLK = 48e6
|
||||
APB1_TIM_FREQ = SYSCLK
|
||||
APB2_TIM_FREQ = SYSCLK
|
||||
)
|
||||
|
||||
const APB1_TIM_FREQ = 4e6
|
||||
const APB2_TIM_FREQ = 4e6
|
||||
func CPUFrequency() uint32 {
|
||||
return SYSCLK
|
||||
}
|
||||
|
||||
const (
|
||||
PA0 = portA + 0
|
||||
|
@ -221,6 +225,64 @@ func (p Pin) registerInterrupt() interrupt.Interrupt {
|
|||
return interrupt.Interrupt{}
|
||||
}
|
||||
|
||||
// -- SPI ----------------------------------------------------------------------
|
||||
|
||||
type SPI struct {
|
||||
Bus *stm32.SPI_Type
|
||||
AltFuncSelector uint8
|
||||
}
|
||||
|
||||
func (spi SPI) config8Bits() {
|
||||
// Set rx threshold to 8-bits, so RXNE flag is set for 1 byte
|
||||
// (common STM32 SPI implementation does 8-bit transfers only)
|
||||
spi.Bus.CR2.SetBits(stm32.SPI_CR2_FRXTH)
|
||||
}
|
||||
|
||||
func (spi SPI) configurePins(config SPIConfig) {
|
||||
config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector)
|
||||
config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector)
|
||||
config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector)
|
||||
}
|
||||
|
||||
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
|
||||
var clock uint32
|
||||
|
||||
// We keep this switch and separate management of SPI Clocks
|
||||
// for future improvement of system/bus clocks and prescalers
|
||||
switch spi.Bus {
|
||||
case stm32.SPI1:
|
||||
clock = CPUFrequency()
|
||||
case stm32.SPI2, stm32.SPI3:
|
||||
clock = CPUFrequency()
|
||||
}
|
||||
|
||||
// limit requested frequency to bus frequency and min frequency (DIV256)
|
||||
freq := config.Frequency
|
||||
if min := clock / 256; freq < min {
|
||||
freq = min
|
||||
} else if freq > clock {
|
||||
freq = clock
|
||||
}
|
||||
|
||||
// calculate the exact clock divisor (freq=clock/div -> div=clock/freq).
|
||||
// truncation is fine, since it produces a less-than-or-equal divisor, and
|
||||
// thus a greater-than-or-equal frequency.
|
||||
// divisors only come in consecutive powers of 2, so we can use log2 (or,
|
||||
// equivalently, bits.Len - 1) to convert to respective enum value.
|
||||
div := bits.Len32(clock/freq) - 1
|
||||
|
||||
// but DIV1 (2^0) is not permitted, as the least divisor is DIV2 (2^1), so
|
||||
// subtract 1 from the log2 value, keeping a lower bound of 0
|
||||
if div < 0 {
|
||||
div = 0
|
||||
} else if div > 0 {
|
||||
div--
|
||||
}
|
||||
|
||||
// finally, shift the enumerated value into position for SPI CR1
|
||||
return uint32(div) << stm32.SPI_CR1_BR_Pos
|
||||
}
|
||||
|
||||
//---------- UART related code
|
||||
|
||||
// Configure the UART.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:build !baremetal || (stm32 && !stm32f7x2 && !stm32l5x2 && !stm32wle5) || fe310 || k210 || atmega
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2,!stm32wle5 fe310 k210 atmega
|
||||
//go:build !baremetal || (stm32 && !stm32f7x2 && !stm32l5x2) || fe310 || k210 || atmega
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 atmega
|
||||
|
||||
package machine
|
||||
|
||||
|
|
|
@ -4,21 +4,100 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"machine"
|
||||
)
|
||||
|
||||
type arrtype = uint32
|
||||
|
||||
const (
|
||||
/* PLL Options RMN0461.p247 */
|
||||
PLL_M = 2
|
||||
PLL_N = 6
|
||||
PLL_R = 2
|
||||
PLL_P = 2
|
||||
PLL_Q = 2
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Currently the clock is not configured, which means
|
||||
// the MCU runs at default reset clock speed (4Mhz).
|
||||
// Code to initialize RCC and PLL can go here.
|
||||
|
||||
// Configure 48Mhz clock
|
||||
initCLK()
|
||||
|
||||
// UART init
|
||||
machine.Serial.Configure(machine.UARTConfig{})
|
||||
|
||||
// Timers init
|
||||
initTickTimer(&machine.TIM1)
|
||||
|
||||
}
|
||||
|
||||
func initCLK() {
|
||||
|
||||
// Enable HSE32 VDDTCXO output on package pin PB0-VDDTCXO
|
||||
stm32.RCC.CR.ReplaceBits(stm32.RCC_CR_HSEBYPPWR_VDDTCXO, stm32.RCC_CR_HSEBYPPWR_Msk, 0)
|
||||
|
||||
// SYSCLOCK from HSE32 clock division factor (SYSCLOCK=HSE32)
|
||||
stm32.RCC.CR.ReplaceBits(stm32.RCC_CR_HSEPRE_Div1, stm32.RCC_CR_HSEPRE_Msk, 0)
|
||||
|
||||
// enable external Clock HSE32 TXCO (RM0461p226)
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSEBYPPWR)
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSEON)
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) {
|
||||
}
|
||||
|
||||
// Disable PLL
|
||||
stm32.RCC.CR.ClearBits(stm32.RCC_CR_PLLON)
|
||||
for stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||
}
|
||||
|
||||
// Configure the PLL
|
||||
stm32.RCC.PLLCFGR.Set((PLL_M-1)<<stm32.RCC_PLLCFGR_PLLM_Pos |
|
||||
((PLL_N) << stm32.RCC_PLLCFGR_PLLN_Pos) |
|
||||
((PLL_Q - 1) << stm32.RCC_PLLCFGR_PLLQ_Pos) |
|
||||
((PLL_R - 1) << stm32.RCC_PLLCFGR_PLLR_Pos) |
|
||||
((PLL_P - 1) << stm32.RCC_PLLCFGR_PLLP_Pos) |
|
||||
stm32.RCC_PLLCFGR_PLLSRC_HSE32 | stm32.RCC_PLLCFGR_PLLPEN)
|
||||
|
||||
// Enable PLL
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||
}
|
||||
|
||||
// Enable PLL System Clock output.
|
||||
stm32.RCC.PLLCFGR.SetBits(stm32.RCC_PLLCFGR_PLLREN)
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||
}
|
||||
|
||||
// Set Flash Latency of 2
|
||||
stm32.FLASH.ACR.ReplaceBits(stm32.Flash_ACR_LATENCY_WS2, stm32.Flash_ACR_LATENCY_Msk, 0)
|
||||
for (stm32.FLASH.ACR.Get() & stm32.Flash_ACR_LATENCY_Msk) != stm32.Flash_ACR_LATENCY_WS2 {
|
||||
}
|
||||
|
||||
// HCLK1 clock division factor
|
||||
stm32.RCC.CFGR.ReplaceBits(stm32.RCC_CFGR_HPRE_Div1, stm32.RCC_CFGR_HPRE_Msk, 0)
|
||||
for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_HPREF) {
|
||||
}
|
||||
|
||||
// HCLK3 clock division factor
|
||||
stm32.RCC.EXTCFGR.ReplaceBits(stm32.RCC_EXTCFGR_SHDHPRE_Div1, stm32.RCC_EXTCFGR_SHDHPRE_Msk, 0)
|
||||
for !stm32.RCC.EXTCFGR.HasBits(stm32.RCC_EXTCFGR_SHDHPREF) {
|
||||
}
|
||||
|
||||
// PCLK1 clock division factor
|
||||
stm32.RCC.CFGR.ReplaceBits(stm32.RCC_CFGR_PPRE1_Div1, stm32.RCC_CFGR_PPRE1_Msk, 0)
|
||||
for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_PPRE1F) {
|
||||
}
|
||||
|
||||
// PCLK2 clock division factor
|
||||
stm32.RCC.CFGR.ReplaceBits(stm32.RCC_CFGR_PPRE2_Div1, stm32.RCC_CFGR_PPRE2_Msk, 0)
|
||||
for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_PPRE2F) {
|
||||
}
|
||||
|
||||
// Set clock source to PLL
|
||||
stm32.RCC.CFGR.ReplaceBits(stm32.RCC_CFGR_SW_PLLR, stm32.RCC_CFGR_SW_Msk, 0)
|
||||
for (stm32.RCC.CFGR.Get() & stm32.RCC_CFGR_SWS_Msk) != (stm32.RCC_CFGR_SWS_PLLR << stm32.RCC_CFGR_SWS_Pos) {
|
||||
}
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
|
|
13
targets/nucleo-wl55jc.json
Обычный файл
13
targets/nucleo-wl55jc.json
Обычный файл
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"inherits": [
|
||||
"stm32wle5"
|
||||
],
|
||||
"build-tags": [
|
||||
"nucleowl55jc"
|
||||
],
|
||||
"serial": "uart",
|
||||
"linkerscript": "targets/stm32wle5.ld",
|
||||
"flash-method": "openocd",
|
||||
"openocd-interface": "stlink",
|
||||
"openocd-target": "stm32wlx"
|
||||
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче