stm32: add blues wireless swan
Этот коммит содержится в:
родитель
21c76c0cb0
коммит
14ce531498
11 изменённых файлов: 421 добавлений и 249 удалений
2
Makefile
2
Makefile
|
@ -462,6 +462,8 @@ ifneq ($(STM32), 0)
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=lorae5 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=lorae5 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
endif
|
endif
|
||||||
ifneq ($(AVR), 0)
|
ifneq ($(AVR), 0)
|
||||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
||||||
|
|
|
@ -79,6 +79,7 @@ The following 79 microcontroller boards are currently supported:
|
||||||
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
||||||
* [BBC micro:bit](https://microbit.org/)
|
* [BBC micro:bit](https://microbit.org/)
|
||||||
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
|
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
|
||||||
|
* [blues wireless Swan](https://blues.io/products/swan/)
|
||||||
* [Digispark](http://digistump.com/products/1)
|
* [Digispark](http://digistump.com/products/1)
|
||||||
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
||||||
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
||||||
|
|
63
src/machine/board_swan.go
Обычный файл
63
src/machine/board_swan.go
Обычный файл
|
@ -0,0 +1,63 @@
|
||||||
|
//go:build swan
|
||||||
|
// +build swan
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/stm32"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LED on the SWAN
|
||||||
|
LED = PE2
|
||||||
|
|
||||||
|
// UART pins
|
||||||
|
// PA9 and PA10 are connected to the SWAN Tx/Rx
|
||||||
|
UART_TX_PIN = PA9
|
||||||
|
UART_RX_PIN = PA10
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
// PB6 is SCL
|
||||||
|
// PB7 is SDA
|
||||||
|
I2C0_SCL_PIN = PB6
|
||||||
|
I2C0_SDA_PIN = PB7
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
SPI1_SCK_PIN = PD1
|
||||||
|
SPI1_SDI_PIN = PB14
|
||||||
|
SPI1_SDO_PIN = PB15
|
||||||
|
SPI0_SCK_PIN = SPI1_SCK_PIN
|
||||||
|
SPI0_SDI_PIN = SPI1_SDI_PIN
|
||||||
|
SPI0_SDO_PIN = SPI1_SDO_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// USART1 is connected to the TX/RX pins
|
||||||
|
UART1 = &_UART1
|
||||||
|
_UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: stm32.USART1,
|
||||||
|
TxAltFuncSelector: 7,
|
||||||
|
RxAltFuncSelector: 7,
|
||||||
|
}
|
||||||
|
DefaultUART = UART1
|
||||||
|
|
||||||
|
// I2C1 is documented, alias to I2C0 as well
|
||||||
|
I2C1 = &I2C{
|
||||||
|
Bus: stm32.I2C1,
|
||||||
|
AltFuncSelector: 4,
|
||||||
|
}
|
||||||
|
I2C0 = I2C1
|
||||||
|
|
||||||
|
// SPI1 is documented, alias to SPI0 as well
|
||||||
|
SPI1 = &SPI{
|
||||||
|
Bus: stm32.SPI2,
|
||||||
|
AltFuncSelector: 5,
|
||||||
|
}
|
||||||
|
SPI0 = SPI1
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART1.handleInterrupt)
|
||||||
|
}
|
|
@ -117,6 +117,25 @@ const (
|
||||||
PE15 = portE + 15
|
PE15 = portE + 15
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// IRQs are defined here as they vary in the SVDs, but do have consistent mapping
|
||||||
|
// to Timer Interrupts.
|
||||||
|
const (
|
||||||
|
irq_TIM1_BRK_TIM15 = 24
|
||||||
|
irq_TIM1_UP_TIM16 = 25
|
||||||
|
irq_TIM1_TRG_COM_TIM17 = 26
|
||||||
|
irq_TIM1_CC = 27
|
||||||
|
irq_TIM2 = 28
|
||||||
|
irq_TIM3 = 29
|
||||||
|
irq_TIM4 = 30
|
||||||
|
irq_TIM5 = 50
|
||||||
|
irq_TIM6 = 54
|
||||||
|
irq_TIM7 = 55
|
||||||
|
irq_TIM8_BRK = 43
|
||||||
|
irq_TIM8_UP = 44
|
||||||
|
irq_TIM8_TRG_COM = 45
|
||||||
|
irq_TIM8_CC = 46
|
||||||
|
)
|
||||||
|
|
||||||
func (p Pin) getPort() *stm32.GPIO_Type {
|
func (p Pin) getPort() *stm32.GPIO_Type {
|
||||||
switch p / 16 {
|
switch p / 16 {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -185,8 +204,6 @@ func enableAltFuncClock(bus unsafe.Pointer) {
|
||||||
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM2EN)
|
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM2EN)
|
||||||
case unsafe.Pointer(stm32.LPTIM2): // LPTIM2 clock enable
|
case unsafe.Pointer(stm32.LPTIM2): // LPTIM2 clock enable
|
||||||
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPTIM2EN)
|
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPTIM2EN)
|
||||||
case unsafe.Pointer(stm32.I2C4): // I2C4 clock enable
|
|
||||||
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_I2C4EN)
|
|
||||||
case unsafe.Pointer(stm32.LPUART1): // LPUART1 clock enable
|
case unsafe.Pointer(stm32.LPUART1): // LPUART1 clock enable
|
||||||
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPUART1EN)
|
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPUART1EN)
|
||||||
case unsafe.Pointer(stm32.TIM16): // TIM16 clock enable
|
case unsafe.Pointer(stm32.TIM16): // TIM16 clock enable
|
||||||
|
@ -258,6 +275,29 @@ func (p Pin) registerInterrupt() interrupt.Interrupt {
|
||||||
return interrupt.Interrupt{}
|
return interrupt.Interrupt{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------- UART related code
|
||||||
|
|
||||||
|
// Configure the UART.
|
||||||
|
func (uart *UART) configurePins(config UARTConfig) {
|
||||||
|
// enable the alternate functions on the TX and RX pins
|
||||||
|
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
|
||||||
|
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UART baudrate calc based on the bus and clockspeed
|
||||||
|
// NOTE: keep this in sync with the runtime/runtime_stm32l5x2.go clock init code
|
||||||
|
func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
|
||||||
|
return (CPUFrequency() / baudRate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register names vary by ST processor, these are for STM L5
|
||||||
|
func (uart *UART) setRegisters() {
|
||||||
|
uart.rxReg = &uart.Bus.RDR
|
||||||
|
uart.txReg = &uart.Bus.TDR
|
||||||
|
uart.statusReg = &uart.Bus.ISR
|
||||||
|
uart.txEmptyFlag = stm32.USART_ISR_TXE
|
||||||
|
}
|
||||||
|
|
||||||
//---------- SPI related types and code
|
//---------- SPI related types and code
|
||||||
|
|
||||||
// SPI on the STM32Fxxx using MODER / alternate function pins
|
// SPI on the STM32Fxxx using MODER / alternate function pins
|
||||||
|
@ -445,19 +485,19 @@ var (
|
||||||
func (t *TIM) registerUPInterrupt() interrupt.Interrupt {
|
func (t *TIM) registerUPInterrupt() interrupt.Interrupt {
|
||||||
switch t {
|
switch t {
|
||||||
case &TIM1:
|
case &TIM1:
|
||||||
return interrupt.New(stm32.IRQ_TIM1_UP_TIM16, TIM1.handleUPInterrupt)
|
return interrupt.New(irq_TIM1_UP_TIM16, TIM1.handleUPInterrupt)
|
||||||
case &TIM2:
|
case &TIM2:
|
||||||
return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt)
|
return interrupt.New(irq_TIM2, TIM2.handleUPInterrupt)
|
||||||
case &TIM3:
|
case &TIM3:
|
||||||
return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt)
|
return interrupt.New(irq_TIM3, TIM3.handleUPInterrupt)
|
||||||
case &TIM6:
|
case &TIM6:
|
||||||
return interrupt.New(stm32.IRQ_TIM6_DACUNDER, TIM6.handleUPInterrupt)
|
return interrupt.New(irq_TIM6, TIM6.handleUPInterrupt)
|
||||||
case &TIM7:
|
case &TIM7:
|
||||||
return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt)
|
return interrupt.New(irq_TIM7, TIM7.handleUPInterrupt)
|
||||||
case &TIM15:
|
case &TIM15:
|
||||||
return interrupt.New(stm32.IRQ_TIM1_BRK_TIM15, TIM15.handleUPInterrupt)
|
return interrupt.New(irq_TIM1_BRK_TIM15, TIM15.handleUPInterrupt)
|
||||||
case &TIM16:
|
case &TIM16:
|
||||||
return interrupt.New(stm32.IRQ_TIM1_UP_TIM16, TIM16.handleUPInterrupt)
|
return interrupt.New(irq_TIM1_UP_TIM16, TIM16.handleUPInterrupt)
|
||||||
}
|
}
|
||||||
|
|
||||||
return interrupt.Interrupt{}
|
return interrupt.Interrupt{}
|
||||||
|
@ -466,19 +506,19 @@ func (t *TIM) registerUPInterrupt() interrupt.Interrupt {
|
||||||
func (t *TIM) registerOCInterrupt() interrupt.Interrupt {
|
func (t *TIM) registerOCInterrupt() interrupt.Interrupt {
|
||||||
switch t {
|
switch t {
|
||||||
case &TIM1:
|
case &TIM1:
|
||||||
return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleUPInterrupt)
|
return interrupt.New(irq_TIM1_CC, TIM1.handleUPInterrupt)
|
||||||
case &TIM2:
|
case &TIM2:
|
||||||
return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt)
|
return interrupt.New(irq_TIM2, TIM2.handleOCInterrupt)
|
||||||
case &TIM3:
|
case &TIM3:
|
||||||
return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt)
|
return interrupt.New(irq_TIM3, TIM3.handleOCInterrupt)
|
||||||
case &TIM6:
|
case &TIM6:
|
||||||
return interrupt.New(stm32.IRQ_TIM6_DACUNDER, TIM6.handleOCInterrupt)
|
return interrupt.New(irq_TIM6, TIM6.handleOCInterrupt)
|
||||||
case &TIM7:
|
case &TIM7:
|
||||||
return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt)
|
return interrupt.New(irq_TIM7, TIM7.handleOCInterrupt)
|
||||||
case &TIM15:
|
case &TIM15:
|
||||||
return interrupt.New(stm32.IRQ_TIM1_BRK_TIM15, TIM15.handleOCInterrupt)
|
return interrupt.New(irq_TIM1_BRK_TIM15, TIM15.handleOCInterrupt)
|
||||||
case &TIM16:
|
case &TIM16:
|
||||||
return interrupt.New(stm32.IRQ_TIM1_UP_TIM16, TIM16.handleOCInterrupt)
|
return interrupt.New(irq_TIM1_UP_TIM16, TIM16.handleOCInterrupt)
|
||||||
}
|
}
|
||||||
|
|
||||||
return interrupt.Interrupt{}
|
return interrupt.Interrupt{}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
|
//go:build stm32l4x2
|
||||||
// +build stm32l4x2
|
// +build stm32l4x2
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
// Peripheral abstraction layer for the stm32l4x2
|
// Peripheral abstraction layer for the stm32l4x2
|
||||||
|
|
||||||
import (
|
|
||||||
"device/stm32"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CPUFrequency() uint32 {
|
func CPUFrequency() uint32 {
|
||||||
return 80000000
|
return 80000000
|
||||||
}
|
}
|
||||||
|
@ -18,29 +15,6 @@ func CPUFrequency() uint32 {
|
||||||
const APB1_TIM_FREQ = 80e6 // 80MHz
|
const APB1_TIM_FREQ = 80e6 // 80MHz
|
||||||
const APB2_TIM_FREQ = 80e6 // 80MHz
|
const APB2_TIM_FREQ = 80e6 // 80MHz
|
||||||
|
|
||||||
//---------- UART related code
|
|
||||||
|
|
||||||
// Configure the UART.
|
|
||||||
func (uart *UART) configurePins(config UARTConfig) {
|
|
||||||
// enable the alternate functions on the TX and RX pins
|
|
||||||
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
|
|
||||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UART baudrate calc based on the bus and clockspeed
|
|
||||||
// NOTE: keep this in sync with the runtime/runtime_stm32l5x2.go clock init code
|
|
||||||
func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
|
|
||||||
return (CPUFrequency() / baudRate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register names vary by ST processor, these are for STM L5
|
|
||||||
func (uart *UART) setRegisters() {
|
|
||||||
uart.rxReg = &uart.Bus.RDR
|
|
||||||
uart.txReg = &uart.Bus.TDR
|
|
||||||
uart.statusReg = &uart.Bus.ISR
|
|
||||||
uart.txEmptyFlag = stm32.USART_ISR_TXE
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------- I2C related code
|
//---------- I2C related code
|
||||||
|
|
||||||
// Gets the value for TIMINGR register
|
// Gets the value for TIMINGR register
|
||||||
|
|
26
src/machine/machine_stm32l4x5.go
Обычный файл
26
src/machine/machine_stm32l4x5.go
Обычный файл
|
@ -0,0 +1,26 @@
|
||||||
|
//go:build stm32l4x5
|
||||||
|
// +build stm32l4x5
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// Peripheral abstraction layer for the stm32l4x5
|
||||||
|
|
||||||
|
func CPUFrequency() uint32 {
|
||||||
|
return 120e6
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept
|
||||||
|
// in sync with any changes to runtime package which configures the oscillators
|
||||||
|
// and clock frequencies
|
||||||
|
const APB1_TIM_FREQ = 120e6 // 120MHz
|
||||||
|
const APB2_TIM_FREQ = 120e6 // 120MHz
|
||||||
|
|
||||||
|
//---------- I2C related code
|
||||||
|
|
||||||
|
// Gets the value for TIMINGR register
|
||||||
|
func (i2c *I2C) getFreqRange() uint32 {
|
||||||
|
// This is a 'magic' value calculated by STM32CubeMX
|
||||||
|
// for 120MHz PCLK1.
|
||||||
|
// TODO: Do calculations based on PCLK1
|
||||||
|
return 0x307075B1
|
||||||
|
}
|
219
src/runtime/runtime_stm32l4.go
Обычный файл
219
src/runtime/runtime_stm32l4.go
Обычный файл
|
@ -0,0 +1,219 @@
|
||||||
|
//go:build stm32 && stm32l4
|
||||||
|
// +build stm32,stm32l4
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/stm32"
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PWR_CR1_VOS_0 = 1 << stm32.PWR_CR1_VOS_Pos
|
||||||
|
PWR_CR1_VOS_1 = 2 << stm32.PWR_CR1_VOS_Pos
|
||||||
|
PWR_REGULATOR_VOLTAGE_SCALE1 = PWR_CR1_VOS_0
|
||||||
|
PWR_REGULATOR_VOLTAGE_SCALE2 = PWR_CR1_VOS_1
|
||||||
|
|
||||||
|
FLASH_LATENCY_0 = 0
|
||||||
|
FLASH_LATENCY_1 = 1
|
||||||
|
FLASH_LATENCY_2 = 2
|
||||||
|
FLASH_LATENCY_3 = 3
|
||||||
|
FLASH_LATENCY_4 = 4
|
||||||
|
|
||||||
|
RCC_PLLP_DIV2 = 2
|
||||||
|
RCC_PLLP_DIV7 = 7
|
||||||
|
RCC_PLLQ_DIV2 = 2
|
||||||
|
RCC_PLLR_DIV2 = 2
|
||||||
|
|
||||||
|
RCC_CFGR_SWS_MSI = 0x0
|
||||||
|
RCC_CFGR_SWS_PLL = 0xC
|
||||||
|
|
||||||
|
RCC_PLLSOURCE_MSI = 1
|
||||||
|
|
||||||
|
RCC_PLL_SYSCLK = stm32.RCC_PLLCFGR_PLLREN
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrtype = uint32
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initCLK()
|
||||||
|
|
||||||
|
machine.Serial.Configure(machine.UARTConfig{})
|
||||||
|
|
||||||
|
initTickTimer(&machine.TIM15)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putchar(c byte) {
|
||||||
|
machine.Serial.WriteByte(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initCLK() {
|
||||||
|
// PWR_CLK_ENABLE
|
||||||
|
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
|
||||||
|
_ = stm32.RCC.APB1ENR1.Get()
|
||||||
|
|
||||||
|
// Disable Backup domain protection
|
||||||
|
if !stm32.PWR.CR1.HasBits(stm32.PWR_CR1_DBP) {
|
||||||
|
stm32.PWR.CR1.SetBits(stm32.PWR_CR1_DBP)
|
||||||
|
for !stm32.PWR.CR1.HasBits(stm32.PWR_CR1_DBP) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set LSE Drive to LOW
|
||||||
|
stm32.RCC.BDCR.ReplaceBits(0, stm32.RCC_BDCR_LSEDRV_Msk, 0)
|
||||||
|
|
||||||
|
// Initialize the High-Speed External Oscillator
|
||||||
|
initOsc()
|
||||||
|
|
||||||
|
// PWR_VOLTAGESCALING_CONFIG
|
||||||
|
stm32.PWR.CR1.ReplaceBits(0, stm32.PWR_CR1_VOS_Msk, 0)
|
||||||
|
_ = stm32.PWR.CR1.Get()
|
||||||
|
|
||||||
|
// Set flash wait states (min 5 latency units) based on clock
|
||||||
|
if (stm32.FLASH.ACR.Get() & 0xF) < 5 {
|
||||||
|
stm32.FLASH.ACR.ReplaceBits(5, 0xF, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure HCLK does not exceed max during transition
|
||||||
|
stm32.RCC.CFGR.ReplaceBits(8<<stm32.RCC_CFGR_HPRE_Pos, stm32.RCC_CFGR_HPRE_Msk, 0)
|
||||||
|
|
||||||
|
// Set SYSCLK source and wait
|
||||||
|
// (3 = RCC_SYSCLKSOURCE_PLLCLK, 2=RCC_CFGR_SWS_Pos)
|
||||||
|
stm32.RCC.CFGR.ReplaceBits(3, stm32.RCC_CFGR_SW_Msk, 0)
|
||||||
|
for stm32.RCC.CFGR.Get()&(3<<2) != (3 << 2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set HCLK
|
||||||
|
// (0 = RCC_SYSCLKSOURCE_PLLCLK)
|
||||||
|
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_HPRE_Msk, 0)
|
||||||
|
|
||||||
|
// Set flash wait states (max 5 latency units) based on clock
|
||||||
|
if (stm32.FLASH.ACR.Get() & 0xF) > 5 {
|
||||||
|
stm32.FLASH.ACR.ReplaceBits(5, 0xF, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set APB1 and APB2 clocks (0 = DIV1)
|
||||||
|
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_PPRE1_Msk, 0)
|
||||||
|
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_PPRE2_Msk, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initOsc() {
|
||||||
|
sysclkSource := stm32.RCC.CFGR.Get() & stm32.RCC_CFGR_SWS_Msk
|
||||||
|
pllConfig := stm32.RCC.PLLCFGR.Get() & stm32.RCC_PLLCFGR_PLLSRC_Msk
|
||||||
|
|
||||||
|
// Enable MSI, adjusting flash latency
|
||||||
|
if sysclkSource == RCC_CFGR_SWS_MSI ||
|
||||||
|
(sysclkSource == RCC_CFGR_SWS_PLL && pllConfig == RCC_PLLSOURCE_MSI) {
|
||||||
|
if MSIRANGE > getMSIRange() {
|
||||||
|
setFlashLatencyFromMSIRange(MSIRANGE)
|
||||||
|
|
||||||
|
setMSIFreq(MSIRANGE, 0)
|
||||||
|
} else {
|
||||||
|
setMSIFreq(MSIRANGE, 0)
|
||||||
|
|
||||||
|
if sysclkSource == RCC_CFGR_SWS_MSI {
|
||||||
|
setFlashLatencyFromMSIRange(MSIRANGE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_MSION)
|
||||||
|
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_MSIRDY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
setMSIFreq(MSIRANGE, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable LSE, wait until ready
|
||||||
|
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_LSEON)
|
||||||
|
for !stm32.RCC.BDCR.HasBits(stm32.RCC_BDCR_LSEON) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the PLL, wait until disabled
|
||||||
|
stm32.RCC.CR.ClearBits(stm32.RCC_CR_PLLON)
|
||||||
|
for stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the PLL
|
||||||
|
stm32.RCC.PLLCFGR.ReplaceBits(
|
||||||
|
(1)| // 1 = RCC_PLLSOURCE_MSI
|
||||||
|
(PLL_M-1)<<stm32.RCC_PLLCFGR_PLLM_Pos|
|
||||||
|
(PLL_N<<stm32.RCC_PLLCFGR_PLLN_Pos)|
|
||||||
|
(((PLL_Q>>1)-1)<<stm32.RCC_PLLCFGR_PLLQ_Pos)|
|
||||||
|
(((PLL_R>>1)-1)<<stm32.RCC_PLLCFGR_PLLR_Pos)|
|
||||||
|
(PLL_P<<stm32.RCC_PLLCFGR_PLLP_Pos),
|
||||||
|
stm32.RCC_PLLCFGR_PLLSRC_Msk|stm32.RCC_PLLCFGR_PLLM_Msk|
|
||||||
|
stm32.RCC_PLLCFGR_PLLN_Msk|stm32.RCC_PLLCFGR_PLLP_Msk|
|
||||||
|
stm32.RCC_PLLCFGR_PLLR_Msk|stm32.RCC_PLLCFGR_PLLP_Msk,
|
||||||
|
0)
|
||||||
|
|
||||||
|
// Enable the PLL and PLL System Clock Output, wait until ready
|
||||||
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
||||||
|
stm32.RCC.PLLCFGR.SetBits(stm32.RCC_PLLCFGR_PLLREN) // = RCC_PLL_SYSCLK
|
||||||
|
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable system clock output
|
||||||
|
stm32.RCC.PLLCFGR.SetBits(RCC_PLL_SYSCLK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMSIRange() uint32 {
|
||||||
|
if stm32.RCC.CR.HasBits(stm32.RCC_CR_MSIRGSEL) {
|
||||||
|
return (stm32.RCC.CR.Get() & stm32.RCC_CR_MSIRANGE_Msk) >> stm32.RCC_CR_MSIRANGE_Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stm32.RCC.CSR.Get() & stm32.RCC_CSR_MSISRANGE_Msk) >> stm32.RCC_CSR_MSISRANGE_Pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func setMSIFreq(r uint32, calibration uint32) {
|
||||||
|
stm32.RCC.CR.SetBits(stm32.RCC_CR_MSIRGSEL)
|
||||||
|
stm32.RCC.CR.ReplaceBits(r<<stm32.RCC_CR_MSIRANGE_Pos, stm32.RCC_CR_MSIRANGE_Msk, 0)
|
||||||
|
|
||||||
|
stm32.RCC.ICSCR.ReplaceBits(calibration<<stm32.RCC_ICSCR_MSITRIM_Pos, stm32.RCC_ICSCR_MSITRIM_Msk, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFlashLatencyFromMSIRange(r uint32) {
|
||||||
|
var vos uint32
|
||||||
|
if pwrIsClkEnabled() {
|
||||||
|
vos = pwrExGetVoltageRange()
|
||||||
|
} else {
|
||||||
|
pwrClkEnable()
|
||||||
|
vos = pwrExGetVoltageRange()
|
||||||
|
pwrClkDisable()
|
||||||
|
}
|
||||||
|
|
||||||
|
latency := uint32(FLASH_LATENCY_0)
|
||||||
|
if vos == PWR_REGULATOR_VOLTAGE_SCALE1 {
|
||||||
|
if r > stm32.RCC_CR_MSIRANGE_Range16M {
|
||||||
|
if r > stm32.RCC_CR_MSIRANGE_Range32M {
|
||||||
|
latency = FLASH_LATENCY_2
|
||||||
|
} else {
|
||||||
|
latency = FLASH_LATENCY_1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if r > stm32.RCC_CR_MSIRANGE_Range16M {
|
||||||
|
latency = FLASH_LATENCY_3
|
||||||
|
} else {
|
||||||
|
if r == stm32.RCC_CR_MSIRANGE_Range16M {
|
||||||
|
latency = FLASH_LATENCY_2
|
||||||
|
} else if r == stm32.RCC_CR_MSIRANGE_Range8M {
|
||||||
|
latency = FLASH_LATENCY_1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stm32.FLASH.ACR.ReplaceBits(latency, stm32.Flash_ACR_LATENCY_Msk, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pwrIsClkEnabled() bool {
|
||||||
|
return stm32.RCC.APB1ENR1.HasBits(stm32.RCC_APB1ENR1_PWREN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pwrClkEnable() {
|
||||||
|
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
|
||||||
|
}
|
||||||
|
func pwrClkDisable() {
|
||||||
|
stm32.RCC.APB1ENR1.ClearBits(stm32.RCC_APB1ENR1_PWREN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pwrExGetVoltageRange() uint32 {
|
||||||
|
return stm32.PWR.CR1.Get() & stm32.PWR_CR1_VOS_Msk
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
|
//go:build stm32 && stm32l4x2
|
||||||
// +build stm32,stm32l4x2
|
// +build stm32,stm32l4x2
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
"machine"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -26,209 +26,4 @@ const (
|
||||||
PLL_R = RCC_PLLR_DIV2
|
PLL_R = RCC_PLLR_DIV2
|
||||||
|
|
||||||
MSIRANGE = stm32.RCC_CR_MSIRANGE_Range4M
|
MSIRANGE = stm32.RCC_CR_MSIRANGE_Range4M
|
||||||
|
|
||||||
PWR_CR1_VOS_0 = 1 << stm32.PWR_CR1_VOS_Pos
|
|
||||||
PWR_CR1_VOS_1 = 2 << stm32.PWR_CR1_VOS_Pos
|
|
||||||
PWR_REGULATOR_VOLTAGE_SCALE1 = PWR_CR1_VOS_0
|
|
||||||
PWR_REGULATOR_VOLTAGE_SCALE2 = PWR_CR1_VOS_1
|
|
||||||
|
|
||||||
FLASH_LATENCY_0 = 0
|
|
||||||
FLASH_LATENCY_1 = 1
|
|
||||||
FLASH_LATENCY_2 = 2
|
|
||||||
FLASH_LATENCY_3 = 3
|
|
||||||
FLASH_LATENCY_4 = 4
|
|
||||||
|
|
||||||
RCC_PLLP_DIV7 = 7
|
|
||||||
RCC_PLLQ_DIV2 = 2
|
|
||||||
RCC_PLLR_DIV2 = 2
|
|
||||||
|
|
||||||
RCC_CFGR_SWS_MSI = 0x0
|
|
||||||
RCC_CFGR_SWS_PLL = 0xC
|
|
||||||
|
|
||||||
RCC_PLLSOURCE_MSI = 1
|
|
||||||
|
|
||||||
RCC_PLL_SYSCLK = stm32.RCC_PLLCFGR_PLLREN
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
initCLK()
|
|
||||||
|
|
||||||
machine.Serial.Configure(machine.UARTConfig{})
|
|
||||||
|
|
||||||
initTickTimer(&machine.TIM15)
|
|
||||||
}
|
|
||||||
|
|
||||||
func putchar(c byte) {
|
|
||||||
machine.Serial.WriteByte(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initCLK() {
|
|
||||||
// PWR_CLK_ENABLE
|
|
||||||
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
|
|
||||||
_ = stm32.RCC.APB1ENR1.Get()
|
|
||||||
|
|
||||||
// Disable Backup domain protection
|
|
||||||
if !stm32.PWR.CR1.HasBits(stm32.PWR_CR1_DBP) {
|
|
||||||
stm32.PWR.CR1.SetBits(stm32.PWR_CR1_DBP)
|
|
||||||
for !stm32.PWR.CR1.HasBits(stm32.PWR_CR1_DBP) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set LSE Drive to LOW
|
|
||||||
stm32.RCC.BDCR.ReplaceBits(0, stm32.RCC_BDCR_LSEDRV_Msk, 0)
|
|
||||||
|
|
||||||
// Initialize the High-Speed External Oscillator
|
|
||||||
initOsc()
|
|
||||||
|
|
||||||
// PWR_VOLTAGESCALING_CONFIG
|
|
||||||
stm32.PWR.CR1.ReplaceBits(0, stm32.PWR_CR1_VOS_Msk, 0)
|
|
||||||
_ = stm32.PWR.CR1.Get()
|
|
||||||
|
|
||||||
// Set flash wait states (min 5 latency units) based on clock
|
|
||||||
if (stm32.FLASH.ACR.Get() & 0xF) < 5 {
|
|
||||||
stm32.FLASH.ACR.ReplaceBits(5, 0xF, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure HCLK does not exceed max during transition
|
|
||||||
stm32.RCC.CFGR.ReplaceBits(8<<stm32.RCC_CFGR_HPRE_Pos, stm32.RCC_CFGR_HPRE_Msk, 0)
|
|
||||||
|
|
||||||
// Set SYSCLK source and wait
|
|
||||||
// (3 = RCC_SYSCLKSOURCE_PLLCLK, 2=RCC_CFGR_SWS_Pos)
|
|
||||||
stm32.RCC.CFGR.ReplaceBits(3, stm32.RCC_CFGR_SW_Msk, 0)
|
|
||||||
for stm32.RCC.CFGR.Get()&(3<<2) != (3 << 2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set HCLK
|
|
||||||
// (0 = RCC_SYSCLKSOURCE_PLLCLK)
|
|
||||||
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_HPRE_Msk, 0)
|
|
||||||
|
|
||||||
// Set flash wait states (max 5 latency units) based on clock
|
|
||||||
if (stm32.FLASH.ACR.Get() & 0xF) > 5 {
|
|
||||||
stm32.FLASH.ACR.ReplaceBits(5, 0xF, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set APB1 and APB2 clocks (0 = DIV1)
|
|
||||||
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_PPRE1_Msk, 0)
|
|
||||||
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_PPRE2_Msk, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initOsc() {
|
|
||||||
sysclkSource := stm32.RCC.CFGR.Get() & stm32.RCC_CFGR_SWS_Msk
|
|
||||||
pllConfig := stm32.RCC.PLLCFGR.Get() & stm32.RCC_PLLCFGR_PLLSRC_Msk
|
|
||||||
|
|
||||||
// Enable MSI, adjusting flash latency
|
|
||||||
if sysclkSource == RCC_CFGR_SWS_MSI ||
|
|
||||||
(sysclkSource == RCC_CFGR_SWS_PLL && pllConfig == RCC_PLLSOURCE_MSI) {
|
|
||||||
if MSIRANGE > getMSIRange() {
|
|
||||||
setFlashLatencyFromMSIRange(MSIRANGE)
|
|
||||||
|
|
||||||
setMSIFreq(MSIRANGE, 0)
|
|
||||||
} else {
|
|
||||||
setMSIFreq(MSIRANGE, 0)
|
|
||||||
|
|
||||||
if sysclkSource == RCC_CFGR_SWS_MSI {
|
|
||||||
setFlashLatencyFromMSIRange(MSIRANGE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_MSION)
|
|
||||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_MSIRDY) {
|
|
||||||
}
|
|
||||||
|
|
||||||
setMSIFreq(MSIRANGE, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable LSE, wait until ready
|
|
||||||
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_LSEON)
|
|
||||||
for !stm32.RCC.BDCR.HasBits(stm32.RCC_BDCR_LSEON) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable the PLL, wait until disabled
|
|
||||||
stm32.RCC.CR.ClearBits(stm32.RCC_CR_PLLON)
|
|
||||||
for stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the PLL
|
|
||||||
stm32.RCC.PLLCFGR.ReplaceBits(
|
|
||||||
(1)| // 1 = RCC_PLLSOURCE_MSI
|
|
||||||
(PLL_M-1)<<stm32.RCC_PLLCFGR_PLLM_Pos|
|
|
||||||
(PLL_N<<stm32.RCC_PLLCFGR_PLLN_Pos)|
|
|
||||||
(((PLL_Q>>1)-1)<<stm32.RCC_PLLCFGR_PLLQ_Pos)|
|
|
||||||
(((PLL_R>>1)-1)<<stm32.RCC_PLLCFGR_PLLR_Pos)|
|
|
||||||
(PLL_P<<stm32.RCC_PLLCFGR_PLLPDIV_Pos),
|
|
||||||
stm32.RCC_PLLCFGR_PLLSRC_Msk|stm32.RCC_PLLCFGR_PLLM_Msk|
|
|
||||||
stm32.RCC_PLLCFGR_PLLN_Msk|stm32.RCC_PLLCFGR_PLLP_Msk|
|
|
||||||
stm32.RCC_PLLCFGR_PLLR_Msk|stm32.RCC_PLLCFGR_PLLPDIV_Msk,
|
|
||||||
0)
|
|
||||||
|
|
||||||
// Enable the PLL and PLL System Clock Output, wait until ready
|
|
||||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
|
||||||
stm32.RCC.PLLCFGR.SetBits(stm32.RCC_PLLCFGR_PLLREN) // = RCC_PLL_SYSCLK
|
|
||||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable system clock output
|
|
||||||
stm32.RCC.PLLCFGR.SetBits(RCC_PLL_SYSCLK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMSIRange() uint32 {
|
|
||||||
if stm32.RCC.CR.HasBits(stm32.RCC_CR_MSIRGSEL) {
|
|
||||||
return (stm32.RCC.CR.Get() & stm32.RCC_CR_MSIRANGE_Msk) >> stm32.RCC_CR_MSIRANGE_Pos
|
|
||||||
}
|
|
||||||
|
|
||||||
return (stm32.RCC.CSR.Get() & stm32.RCC_CSR_MSISRANGE_Msk) >> stm32.RCC_CSR_MSISRANGE_Pos
|
|
||||||
}
|
|
||||||
|
|
||||||
func setMSIFreq(r uint32, calibration uint32) {
|
|
||||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_MSIRGSEL)
|
|
||||||
stm32.RCC.CR.ReplaceBits(r<<stm32.RCC_CR_MSIRANGE_Pos, stm32.RCC_CR_MSIRANGE_Msk, 0)
|
|
||||||
|
|
||||||
stm32.RCC.ICSCR.ReplaceBits(calibration<<stm32.RCC_ICSCR_MSITRIM_Pos, stm32.RCC_ICSCR_MSITRIM_Msk, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setFlashLatencyFromMSIRange(r uint32) {
|
|
||||||
var vos uint32
|
|
||||||
if pwrIsClkEnabled() {
|
|
||||||
vos = pwrExGetVoltageRange()
|
|
||||||
} else {
|
|
||||||
pwrClkEnable()
|
|
||||||
vos = pwrExGetVoltageRange()
|
|
||||||
pwrClkDisable()
|
|
||||||
}
|
|
||||||
|
|
||||||
latency := uint32(FLASH_LATENCY_0)
|
|
||||||
if vos == PWR_REGULATOR_VOLTAGE_SCALE1 {
|
|
||||||
if r > stm32.RCC_CR_MSIRANGE_Range16M {
|
|
||||||
if r > stm32.RCC_CR_MSIRANGE_Range32M {
|
|
||||||
latency = FLASH_LATENCY_2
|
|
||||||
} else {
|
|
||||||
latency = FLASH_LATENCY_1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if r > stm32.RCC_CR_MSIRANGE_Range16M {
|
|
||||||
latency = FLASH_LATENCY_3
|
|
||||||
} else {
|
|
||||||
if r == stm32.RCC_CR_MSIRANGE_Range16M {
|
|
||||||
latency = FLASH_LATENCY_2
|
|
||||||
} else if r == stm32.RCC_CR_MSIRANGE_Range8M {
|
|
||||||
latency = FLASH_LATENCY_1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stm32.FLASH.ACR.ReplaceBits(latency, stm32.Flash_ACR_LATENCY_Msk, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func pwrIsClkEnabled() bool {
|
|
||||||
return stm32.RCC.APB1ENR1.HasBits(stm32.RCC_APB1ENR1_PWREN)
|
|
||||||
}
|
|
||||||
|
|
||||||
func pwrClkEnable() {
|
|
||||||
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
|
|
||||||
}
|
|
||||||
func pwrClkDisable() {
|
|
||||||
stm32.RCC.APB1ENR1.ClearBits(stm32.RCC_APB1ENR1_PWREN)
|
|
||||||
}
|
|
||||||
|
|
||||||
func pwrExGetVoltageRange() uint32 {
|
|
||||||
return stm32.PWR.CR1.Get() & stm32.PWR_CR1_VOS_Msk
|
|
||||||
}
|
|
||||||
|
|
29
src/runtime/runtime_stm32l4x5.go
Обычный файл
29
src/runtime/runtime_stm32l4x5.go
Обычный файл
|
@ -0,0 +1,29 @@
|
||||||
|
//go:build stm32 && stm32l4x5
|
||||||
|
// +build stm32,stm32l4x5
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/stm32"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
clock settings
|
||||||
|
+-------------+-----------+
|
||||||
|
| LSE | 32.768khz |
|
||||||
|
| SYSCLK | 120mhz |
|
||||||
|
| HCLK | 120mhz |
|
||||||
|
| APB1(PCLK1) | 120mhz |
|
||||||
|
| APB2(PCLK2) | 120mhz |
|
||||||
|
+-------------+-----------+
|
||||||
|
*/
|
||||||
|
const (
|
||||||
|
HSE_STARTUP_TIMEOUT = 0x0500
|
||||||
|
PLL_M = 1
|
||||||
|
PLL_N = 60
|
||||||
|
PLL_P = RCC_PLLP_DIV2
|
||||||
|
PLL_Q = RCC_PLLQ_DIV2
|
||||||
|
PLL_R = RCC_PLLR_DIV2
|
||||||
|
|
||||||
|
MSIRANGE = stm32.RCC_CR_MSIRANGE_Range4M
|
||||||
|
)
|
10
targets/stm32l4x5.ld
Обычный файл
10
targets/stm32l4x5.ld
Обычный файл
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH_TEXT (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 640K
|
||||||
|
}
|
||||||
|
|
||||||
|
_stack_size = 4K;
|
||||||
|
|
||||||
|
INCLUDE "targets/arm.ld"
|
13
targets/swan.json
Обычный файл
13
targets/swan.json
Обычный файл
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"inherits": ["cortex-m4"],
|
||||||
|
"build-tags": ["swan", "stm32l4r5", "stm32l4x5", "stm32l4", "stm32"],
|
||||||
|
"serial": "uart",
|
||||||
|
"linkerscript": "targets/stm32l4x5.ld",
|
||||||
|
"extra-files": [
|
||||||
|
"src/device/stm32/stm32l4x5.s"
|
||||||
|
],
|
||||||
|
"flash-method": "command",
|
||||||
|
"flash-command": "dfu-util --alt 0 --dfuse-address 0x08000000 --download {bin}",
|
||||||
|
"openocd-interface": "stlink",
|
||||||
|
"openocd-target": "stm32l4x"
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче