add STM32F405 machine/runtime, and new board/target feather-stm32f405
Этот коммит содержится в:
родитель
04f65f1189
коммит
20a1c730a1
5 изменённых файлов: 529 добавлений и 0 удалений
167
src/machine/board_feather-stm32f405.go
Обычный файл
167
src/machine/board_feather-stm32f405.go
Обычный файл
|
@ -0,0 +1,167 @@
|
|||
// +build feather_stm32f405
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
const (
|
||||
NUM_DIGITAL_IO_PINS = 39
|
||||
NUM_ANALOG_IO_PINS = 7
|
||||
)
|
||||
|
||||
// Pinout
|
||||
const (
|
||||
// Arduino pin = MCU port pin // primary functions (alternate functions)
|
||||
D0 = PB11 // USART3 RX, PWM TIM2_CH4 (I2C2 SDA)
|
||||
D1 = PB10 // USART3 TX, PWM TIM2_CH3 (I2C2 SCL, I2S2 BCK)
|
||||
D2 = PB3 // GPIO, SPI3 FLASH SCK
|
||||
D3 = PB4 // GPIO, SPI3 FLASH MISO
|
||||
D4 = PB5 // GPIO, SPI3 FLASH MOSI
|
||||
D5 = PC7 // GPIO, PWM TIM3_CH2 (USART6 RX, I2S3 MCK)
|
||||
D6 = PC6 // GPIO, PWM TIM3_CH1 (USART6 TX, I2S2 MCK)
|
||||
D7 = PA15 // GPIO, SPI3 FLASH CS
|
||||
D8 = PC0 // GPIO, Neopixel
|
||||
D9 = PB8 // GPIO, PWM TIM4_CH3 (CAN1 RX, I2C1 SCL)
|
||||
D10 = PB9 // GPIO, PWM TIM4_CH4 (CAN1 TX, I2C1 SDA, I2S2 WSL)
|
||||
D11 = PC3 // GPIO (I2S2 SD, SPI2 MOSI)
|
||||
D12 = PC2 // GPIO (I2S2ext SD, SPI2 MISO)
|
||||
D13 = PC1 // GPIO, Builtin LED
|
||||
D14 = PB7 // I2C1 SDA, PWM TIM4_CH2 (USART1 RX)
|
||||
D15 = PB6 // I2C1 SCL, PWM TIM4_CH1 (USART1 TX, CAN2 TX)
|
||||
D16 = PA4 // A0 (DAC OUT1)
|
||||
D17 = PA5 // A1 (DAC OUT2, SPI1 SCK)
|
||||
D18 = PA6 // A2, PWM TIM3_CH1 (SPI1 MISO)
|
||||
D19 = PA7 // A3, PWM TIM3_CH2 (SPI1 MOSI)
|
||||
D20 = PC4 // A4
|
||||
D21 = PC5 // A5
|
||||
D22 = PA3 // A6
|
||||
D23 = PB13 // SPI2 SCK, PWM TIM1_CH1N (I2S2 BCK, CAN2 TX)
|
||||
D24 = PB14 // SPI2 MISO, PWM TIM1_CH2N (I2S2ext SD)
|
||||
D25 = PB15 // SPI2 MOSI, PWM TIM1_CH3N (I2S2 SD)
|
||||
D26 = PC8 // SDIO
|
||||
D27 = PC9 // SDIO
|
||||
D28 = PC10 // SDIO
|
||||
D29 = PC11 // SDIO
|
||||
D30 = PC12 // SDIO
|
||||
D31 = PD2 // SDIO
|
||||
D32 = PB12 // SD Detect
|
||||
D33 = PC14 // OSC32
|
||||
D34 = PC15 // OSC32
|
||||
D35 = PA11 // USB D+
|
||||
D36 = PA12 // USB D-
|
||||
D37 = PA13 // SWDIO
|
||||
D38 = PA14 // SWCLK
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 = D16 // ADC12 IN4
|
||||
A1 = D17 // ADC12 IN5
|
||||
A2 = D18 // ADC12 IN6
|
||||
A3 = D19 // ADC12 IN7
|
||||
A4 = D20 // ADC12 IN14
|
||||
A5 = D21 // ADC12 IN15
|
||||
A6 = D22 // VBAT
|
||||
)
|
||||
|
||||
// Pretty lights
|
||||
const (
|
||||
LED = LED_BUILTIN
|
||||
LED_BUILTIN = LED_RED
|
||||
LED_RED = D13
|
||||
LED_NEOPIXEL = D8
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
NUM_UART_INTERFACES = 3
|
||||
|
||||
UART_RX_PIN = UART1_RX_PIN
|
||||
UART_TX_PIN = UART1_TX_PIN
|
||||
|
||||
UART0_RX_PIN = D0
|
||||
UART0_TX_PIN = D1
|
||||
UART1_RX_PIN = UART0_RX_PIN
|
||||
UART1_TX_PIN = UART0_TX_PIN
|
||||
|
||||
UART2_RX_PIN = D5
|
||||
UART2_TX_PIN = D6
|
||||
|
||||
UART3_RX_PIN = D14
|
||||
UART3_TX_PIN = D15
|
||||
)
|
||||
|
||||
var (
|
||||
// TBD: why do UART0 and UART1 have different types (struct vs reference)?
|
||||
UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART3,
|
||||
AltFuncSelector: stm32.AF7_USART1_2_3,
|
||||
}
|
||||
UART1 = &UART0
|
||||
|
||||
// UART2 = &UART{
|
||||
// Buffer: NewRingBuffer(),
|
||||
// Bus: stm32.USART6,
|
||||
// AltFuncSelector: stm32.AF8_USART4_5_6,
|
||||
// }
|
||||
// UART3 = &UART{
|
||||
// Buffer: NewRingBuffer(),
|
||||
// Bus: stm32.USART1,
|
||||
// AltFuncSelector: stm32.AF7_USART1_2_3,
|
||||
// }
|
||||
)
|
||||
|
||||
// set up RX IRQ handler. Follow similar pattern for other UARTx instances
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(stm32.IRQ_USART3, UART0.handleInterrupt)
|
||||
//UART2.Interrupt = interrupt.New(stm32.IRQ_USART6, UART2.handleInterrupt)
|
||||
//UART3.Interrupt = interrupt.New(stm32.IRQ_USART1, UART3.handleInterrupt)
|
||||
}
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
NUM_SPI_INTERFACES = 3
|
||||
|
||||
SPI_SCK_PIN = SPI1_SCK_PIN
|
||||
SPI_SDI_PIN = SPI1_SDI_PIN
|
||||
SPI_SDO_PIN = SPI1_SDO_PIN
|
||||
|
||||
SPI0_SCK_PIN = D23
|
||||
SPI0_SDI_PIN = D24
|
||||
SPI0_SDO_PIN = D25
|
||||
SPI1_SCK_PIN = SPI0_SCK_PIN
|
||||
SPI1_SDI_PIN = SPI0_SDI_PIN
|
||||
SPI1_SDO_PIN = SPI0_SDO_PIN
|
||||
|
||||
SPI2_SCK_PIN = D2
|
||||
SPI2_SDI_PIN = D3
|
||||
SPI2_SDO_PIN = D4
|
||||
|
||||
SPI3_SCK_PIN = D17
|
||||
SPI3_SDI_PIN = D18
|
||||
SPI3_SDO_PIN = D19
|
||||
)
|
||||
|
||||
// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1.
|
||||
// TODO: implement SPI2 and SPI3.
|
||||
var (
|
||||
// TBD: why do SPI0 and SPI1 have different types (struct vs reference)?
|
||||
SPI0 = SPI{
|
||||
Bus: stm32.SPI2,
|
||||
AltFuncSelector: stm32.AF5_SPI1_SPI2,
|
||||
}
|
||||
SPI1 = &SPI0
|
||||
|
||||
// SPI2 = &SPI{
|
||||
// Bus: stm32.SPI3,
|
||||
// AltFuncSelector: stm32.AF6_SPI3,
|
||||
// }
|
||||
// SPI3 = &SPI{
|
||||
// Bus: stm32.SPI1,
|
||||
// AltFuncSelector: stm32.AF5_SPI1_SPI2,
|
||||
// }
|
||||
)
|
103
src/machine/machine_stm32f405.go
Обычный файл
103
src/machine/machine_stm32f405.go
Обычный файл
|
@ -0,0 +1,103 @@
|
|||
// +build stm32f405
|
||||
|
||||
package machine
|
||||
|
||||
// Peripheral abstraction layer for the stm32f405
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 168000000
|
||||
}
|
||||
|
||||
//---------- UART related types and code
|
||||
|
||||
// UART representation
|
||||
type UART struct {
|
||||
Buffer *RingBuffer
|
||||
Bus *stm32.USART_Type
|
||||
Interrupt interrupt.Interrupt
|
||||
AltFuncSelector stm32.AltFunc
|
||||
}
|
||||
|
||||
// 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.AltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
|
||||
}
|
||||
|
||||
// UART baudrate calc based on the bus and clockspeed
|
||||
// NOTE: keep this in sync with the runtime/runtime_stm32f407.go clock init code
|
||||
func (uart UART) getBaudRateDivisor(baudRate uint32) uint32 {
|
||||
var clock uint32
|
||||
switch uart.Bus {
|
||||
case stm32.USART1, stm32.USART6:
|
||||
clock = CPUFrequency() / 2 // APB2 Frequency
|
||||
case stm32.USART2, stm32.USART3, stm32.UART4, stm32.UART5:
|
||||
clock = CPUFrequency() / 4 // APB1 Frequency
|
||||
}
|
||||
return clock / baudRate
|
||||
}
|
||||
|
||||
//---------- SPI related types and code
|
||||
|
||||
// SPI on the STM32Fxxx using MODER / alternate function pins
|
||||
type SPI struct {
|
||||
Bus *stm32.SPI_Type
|
||||
AltFuncSelector stm32.AltFunc
|
||||
}
|
||||
|
||||
// Set baud rate for SPI
|
||||
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
|
||||
var conf uint32
|
||||
|
||||
localFrequency := config.Frequency
|
||||
if spi.Bus != stm32.SPI1 {
|
||||
// Assume it's SPI2 or SPI3 on APB1 at 1/2 the clock frequency of APB2, so
|
||||
// we want to pretend to request 2x the baudrate asked for
|
||||
localFrequency = localFrequency * 2
|
||||
}
|
||||
|
||||
// set frequency dependent on PCLK prescaler. Since these are rather weird
|
||||
// speeds due to the CPU freqency, pick a range up to that frquency for
|
||||
// clients to use more human-understandable numbers, e.g. nearest 100KHz
|
||||
|
||||
// These are based on APB2 clock frquency (84MHz on the discovery board)
|
||||
// TODO: also include the MCU/APB clock setting in the equation
|
||||
switch true {
|
||||
case localFrequency < 328125:
|
||||
conf = stm32.SPI_PCLK_256
|
||||
case localFrequency < 656250:
|
||||
conf = stm32.SPI_PCLK_128
|
||||
case localFrequency < 1312500:
|
||||
conf = stm32.SPI_PCLK_64
|
||||
case localFrequency < 2625000:
|
||||
conf = stm32.SPI_PCLK_32
|
||||
case localFrequency < 5250000:
|
||||
conf = stm32.SPI_PCLK_16
|
||||
case localFrequency < 10500000:
|
||||
conf = stm32.SPI_PCLK_8
|
||||
// NOTE: many SPI components won't operate reliably (or at all) above 10MHz
|
||||
// Check the datasheet of the part
|
||||
case localFrequency < 21000000:
|
||||
conf = stm32.SPI_PCLK_4
|
||||
case localFrequency < 42000000:
|
||||
conf = stm32.SPI_PCLK_2
|
||||
default:
|
||||
// None of the specific baudrates were selected; choose the lowest speed
|
||||
conf = stm32.SPI_PCLK_256
|
||||
}
|
||||
|
||||
return conf << stm32.SPI_CR1_BR_Pos
|
||||
}
|
||||
|
||||
// Configure SPI pins for input output and clock
|
||||
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)
|
||||
}
|
237
src/runtime/runtime_stm32f405.go
Обычный файл
237
src/runtime/runtime_stm32f405.go
Обычный файл
|
@ -0,0 +1,237 @@
|
|||
// +build stm32,stm32f4,stm32f405
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"device/stm32"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
)
|
||||
|
||||
func init() {
|
||||
initOSC() // configure oscillators
|
||||
initCLK() // configure CPU, AHB, and APB bus clocks
|
||||
initTIM() // configure timers
|
||||
}
|
||||
|
||||
const (
|
||||
HCLK_FREQ_HZ = 168000000
|
||||
PCLK1_FREQ_HZ = HCLK_FREQ_HZ / 4
|
||||
PCLK2_FREQ_HZ = HCLK_FREQ_HZ / 2
|
||||
)
|
||||
|
||||
const (
|
||||
PWR_SCALE1 = 1 << stm32.PWR_CSR_VOSRDY_Pos // max value of HCLK = 168 MHz
|
||||
PWR_SCALE2 = 0 // max value of HCLK = 144 MHz
|
||||
|
||||
PLL_SRC_HSE = 1 << stm32.RCC_PLLCFGR_PLLSRC_Pos // use HSE for PLL and PLLI2S
|
||||
PLL_SRC_HSI = 0 // use HSI for PLL and PLLI2S
|
||||
|
||||
PLL_DIV_M = 6 << stm32.RCC_PLLCFGR_PLLM0_Pos
|
||||
PLL_MLT_N = 168 << stm32.RCC_PLLCFGR_PLLN0_Pos
|
||||
PLL_DIV_P = ((2 >> 1) - 1) << stm32.RCC_PLLCFGR_PLLP0_Pos
|
||||
PLL_DIV_Q = 7 << stm32.RCC_PLLCFGR_PLLQ0_Pos
|
||||
|
||||
SYSCLK_SRC_PLL = 2 << stm32.RCC_CFGR_SW0_Pos
|
||||
|
||||
RCC_DIV_PCLK1 = 5 << stm32.RCC_CFGR_PPRE1_Pos // HCLK / 4
|
||||
RCC_DIV_PCLK2 = 4 << stm32.RCC_CFGR_PPRE2_Pos // HCLK / 2
|
||||
RCC_DIV_HCLK = 0 << stm32.RCC_CFGR_HPRE_Pos // SYSCLK / 1
|
||||
|
||||
CLK_CCM_RAM = 1 << 20
|
||||
)
|
||||
|
||||
const (
|
||||
// +---------------------+---------------------------------------------------------------------------+
|
||||
// | | HCLK (MHz) |
|
||||
// | +------------------+------------------+------------------+------------------+
|
||||
// | Wait states (WS) | Voltage range | Voltage range | Voltage range | Voltage range |
|
||||
// | (LATENCY) | 2.7 V - 3.6 V | 2.4 V - 2.7 V | 2.1 V - 2.4 V | 1.8 V - 2.1 V |
|
||||
// | | | | | Prefetch OFF |
|
||||
// +---------------------+------------------+------------------+------------------+------------------+
|
||||
// | 0 WS (1 CPU cycle) | 0 < HCLK ≤ 30 | 0 < HCLK ≤ 24 | 0 < HCLK ≤ 22 | 0 < HCLK ≤ 20 |
|
||||
// | 1 WS (2 CPU cycles) | 30 < HCLK ≤ 60 | 24 < HCLK ≤ 48 | 22 < HCLK ≤ 44 | 20 < HCLK ≤ 40 |
|
||||
// | 2 WS (3 CPU cycles) | 60 < HCLK ≤ 90 | 48 < HCLK ≤ 72 | 44 < HCLK ≤ 66 | 40 < HCLK ≤ 60 |
|
||||
// | 3 WS (4 CPU cycles) | 90 < HCLK ≤ 120 | 72 < HCLK ≤ 96 | 66 < HCLK ≤ 88 | 60 < HCLK ≤ 80 |
|
||||
// | 4 WS (5 CPU cycles) | 120 < HCLK ≤ 150 | 96 < HCLK ≤ 120 | 88 < HCLK ≤ 110 | 80 < HCLK ≤ 100 |
|
||||
// | 5 WS (6 CPU cycles) | 150 < HCLK ≤ 168 | 120 < HCLK ≤ 144 | 110 < HCLK ≤ 132 | 100 < HCLK ≤ 120 |
|
||||
// | 6 WS (7 CPU cycles) | | 144 < HCLK ≤ 168 | 132 < HCLK ≤ 154 | 120 < HCLK ≤ 140 |
|
||||
// | 7 WS (8 CPU cycles) | | | 154 < HCLK ≤ 168 | 140 < HCLK ≤ 160 |
|
||||
// +---------------------+------------------+------------------+------------------+------------------+
|
||||
FLASH_LATENCY = 5 << stm32.FLASH_ACR_LATENCY_Pos // 5 WS (6 CPU cycles)
|
||||
|
||||
// instruction cache, data cache, and prefetch
|
||||
FLASH_OPTIONS = stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | stm32.FLASH_ACR_PRFTEN
|
||||
)
|
||||
|
||||
/*
|
||||
clock settings
|
||||
+-------------+--------+
|
||||
| HSE | 12mhz |
|
||||
| SYSCLK | 168mhz |
|
||||
| HCLK | 168mhz |
|
||||
| APB1(PCLK1) | 42mhz |
|
||||
| APB2(PCLK2) | 84mhz |
|
||||
+-------------+--------+
|
||||
*/
|
||||
func initOSC() {
|
||||
// enable voltage regulator
|
||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
|
||||
stm32.PWR.CR.SetBits(PWR_SCALE1)
|
||||
|
||||
// enable HSE
|
||||
stm32.RCC.CR.Set(stm32.RCC_CR_HSEON)
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) {
|
||||
}
|
||||
|
||||
// Since the main-PLL configuration parameters cannot be changed once PLL is
|
||||
// enabled, it is recommended to configure PLL before enabling it (selection
|
||||
// of the HSI or HSE oscillator as PLL clock source, and configuration of
|
||||
// division factors M, N, P, and Q).
|
||||
|
||||
// disable PLL and wait for it to reset
|
||||
stm32.RCC.CR.ClearBits(stm32.RCC_CR_PLLON)
|
||||
for stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||
}
|
||||
|
||||
// set HSE as PLL source and configure clock divisors
|
||||
stm32.RCC.PLLCFGR.Set(PLL_SRC_HSE | PLL_DIV_M | PLL_MLT_N | PLL_DIV_P | PLL_DIV_Q)
|
||||
|
||||
// enable PLL and wait for it to sync
|
||||
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
|
||||
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
|
||||
}
|
||||
}
|
||||
|
||||
func initCLK() {
|
||||
// After reset, the CPU clock frequency is 16 MHz and 0 wait state (WS) is
|
||||
// configured in the FLASH_ACR register.
|
||||
//
|
||||
// It is highly recommended to use the following software sequences to tune
|
||||
// the number of wait states needed to access the Flash memory with the CPU
|
||||
// frequency.
|
||||
//
|
||||
// 1. Program the new number of wait states to the LATENCY bits in the
|
||||
// FLASH_ACR register
|
||||
// 2. Check that the new number of wait states is taken into account to access
|
||||
// the Flash memory by reading the FLASH_ACR register
|
||||
// 3. Modify the CPU clock source by writing the SW bits in the RCC_CFGR
|
||||
// register
|
||||
// 4. If needed, modify the CPU clock prescaler by writing the HPRE bits in
|
||||
// RCC_CFGR
|
||||
// 5. Check that the new CPU clock source or/and the new CPU clock prescaler
|
||||
// value is/are taken into account by reading the clock source status (SWS
|
||||
// bits) or/and the AHB prescaler value (HPRE bits), respectively, in the
|
||||
// RCC_CFGR register.
|
||||
|
||||
// configure instruction/data caching, prefetch, and flash access wait states
|
||||
stm32.FLASH.ACR.Set(FLASH_OPTIONS | FLASH_LATENCY)
|
||||
|
||||
// After a system reset, the HSI oscillator is selected as the system clock.
|
||||
// When a clock source is used directly or through PLL as the system clock, it
|
||||
// is not possible to stop it.
|
||||
//
|
||||
// A switch from one clock source to another occurs only if the target clock
|
||||
// source is ready (clock stable after startup delay or PLL locked). If a
|
||||
// clock source that is not yet ready is selected, the switch occurs when the
|
||||
// clock source is ready. Status bits in the RCC clock control register
|
||||
// (RCC_CR) indicate which clock(s) is (are) ready and which clock is
|
||||
// currently used as the system clock.
|
||||
|
||||
// set CPU clock source to PLL
|
||||
stm32.RCC.CFGR.SetBits(SYSCLK_SRC_PLL)
|
||||
for !stm32.RCC.CFGR.HasBits(SYSCLK_SRC_PLL) {
|
||||
}
|
||||
|
||||
// update PCKL1/2 and HCLK divisors
|
||||
stm32.RCC.CFGR.SetBits(RCC_DIV_PCLK1 | RCC_DIV_PCLK2 | RCC_DIV_HCLK)
|
||||
|
||||
// enable the CCM RAM clock
|
||||
stm32.RCC.AHB1ENR.SetBits(CLK_CCM_RAM)
|
||||
}
|
||||
|
||||
func initTIM() {
|
||||
// enable sleep counter (TIM3)
|
||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
|
||||
|
||||
tim3 := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
|
||||
tim3.SetPriority(0xC3)
|
||||
tim3.Enable()
|
||||
|
||||
// enable tick counter (TIM7)
|
||||
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN)
|
||||
|
||||
stm32.TIM7.PSC.Set((PCLK1_FREQ_HZ*2)/10000 - 1) // 84mhz to 10khz(0.1ms)
|
||||
stm32.TIM7.ARR.Set(10 - 1) // interrupt per 1ms
|
||||
|
||||
stm32.TIM7.DIER.SetBits(stm32.TIM_DIER_UIE) // enable interrupt
|
||||
stm32.TIM7.CR1.SetBits(stm32.TIM_CR1_CEN) // enable timer
|
||||
|
||||
tim7 := interrupt.New(stm32.IRQ_TIM7, handleTIM7)
|
||||
tim7.SetPriority(0xC1)
|
||||
tim7.Enable()
|
||||
}
|
||||
|
||||
var (
|
||||
// tick in milliseconds
|
||||
tickCount timeUnit
|
||||
timerWakeup volatile.Register8
|
||||
)
|
||||
|
||||
const asyncScheduler = false
|
||||
|
||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||
return int64(ticks) * 1000
|
||||
}
|
||||
|
||||
func nanosecondsToTicks(ns int64) timeUnit {
|
||||
return timeUnit(ns / 1000)
|
||||
}
|
||||
|
||||
// sleepTicks should sleep for specific number of microseconds.
|
||||
func sleepTicks(d timeUnit) {
|
||||
timerSleep(uint32(d))
|
||||
}
|
||||
|
||||
// number of ticks (microseconds) since start.
|
||||
func ticks() timeUnit {
|
||||
return tickCount * 1000 // milliseconds to microseconds
|
||||
}
|
||||
|
||||
// ticks are in microseconds
|
||||
func timerSleep(ticks uint32) {
|
||||
timerWakeup.Set(0)
|
||||
|
||||
stm32.TIM3.PSC.Set((PCLK1_FREQ_HZ*2)/10000 - 1) // 8399
|
||||
arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms
|
||||
if arr == 0 {
|
||||
arr = 1 // avoid blocking
|
||||
}
|
||||
stm32.TIM3.ARR.Set(arr)
|
||||
|
||||
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE) // enable interrupt
|
||||
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN) // enable the timer
|
||||
|
||||
// wait for timer
|
||||
for timerWakeup.Get() == 0 {
|
||||
arm.Asm("wfi")
|
||||
}
|
||||
}
|
||||
|
||||
func handleTIM3(interrupt.Interrupt) {
|
||||
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
|
||||
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN) // disable the timer
|
||||
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF) // clear the update flag
|
||||
timerWakeup.Set(1) // flag timer ISR
|
||||
}
|
||||
}
|
||||
|
||||
func handleTIM7(interrupt.Interrupt) {
|
||||
if stm32.TIM7.SR.HasBits(stm32.TIM_SR_UIF) {
|
||||
stm32.TIM7.SR.ClearBits(stm32.TIM_SR_UIF) // clear the update flag
|
||||
tickCount++
|
||||
}
|
||||
}
|
||||
|
||||
func putchar(c byte) {}
|
13
targets/feather-stm32f405.json
Обычный файл
13
targets/feather-stm32f405.json
Обычный файл
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"inherits": ["cortex-m4"],
|
||||
"build-tags": ["feather_stm32f405", "stm32f405", "stm32f4", "stm32"],
|
||||
"cflags": [
|
||||
"-Qunused-arguments"
|
||||
],
|
||||
"linkerscript": "targets/stm32f405.ld",
|
||||
"extra-files": [
|
||||
"src/device/stm32/stm32f405.s"
|
||||
],
|
||||
"flash-method": "command",
|
||||
"flash-command": "dfu-util -a 0 --dfuse-address 0x08000000 -D {hex}"
|
||||
}
|
9
targets/stm32f405.ld
Обычный файл
9
targets/stm32f405.ld
Обычный файл
|
@ -0,0 +1,9 @@
|
|||
MEMORY
|
||||
{
|
||||
FLASH_TEXT (rw) : ORIGIN = 0x08000000, LENGTH = 1M
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
|
||||
}
|
||||
|
||||
_stack_size = 4K;
|
||||
|
||||
INCLUDE "targets/arm.ld"
|
Загрузка…
Создание таблицы
Сослаться в новой задаче