From 1322f404a6531e6bd17bf2d2809f0c800f2d8b27 Mon Sep 17 00:00:00 2001 From: Yusuke Mitsuki Date: Fri, 12 Apr 2019 13:36:14 +0900 Subject: [PATCH] stm32: add support for the STM32F4Discovery Signed-off-by: Yusuke Mitsuki --- .circleci/config.yml | 2 + src/machine/board_stm32f4disco.go | 112 +++++++++++++++ src/machine/machine_stm32.go | 1 + src/machine/machine_stm32f407.go | 220 ++++++++++++++++++++++++++++++ src/runtime/runtime_stm32f407.go | 208 ++++++++++++++++++++++++++++ targets/stm32f407.ld | 10 ++ targets/stm32f4disco.json | 18 +++ 7 files changed, 571 insertions(+) create mode 100644 src/machine/board_stm32f4disco.go create mode 100644 src/machine/machine_stm32f407.go create mode 100644 src/runtime/runtime_stm32f407.go create mode 100644 targets/stm32f407.ld create mode 100644 targets/stm32f4disco.json diff --git a/.circleci/config.yml b/.circleci/config.yml index adb28790..7cf7d18b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -68,6 +68,8 @@ commands: - run: tinygo build -size short -o test.elf -target=pca10056 examples/blinky2 - run: tinygo build -size short -o test.elf -target=itsybitsy-m0 examples/blinky1 - run: tinygo build -size short -o test.elf -target=circuitplay-express examples/blinky1 + - run: tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky1 + - run: tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky2 - run: tinygo build -o wasm.wasm -target=wasm examples/wasm test-linux: parameters: diff --git a/src/machine/board_stm32f4disco.go b/src/machine/board_stm32f4disco.go new file mode 100644 index 00000000..05150cab --- /dev/null +++ b/src/machine/board_stm32f4disco.go @@ -0,0 +1,112 @@ +// +build stm32,stm32f4disco + +package machine + +const ( + PA0 = portA + 0 + PA1 = portA + 1 + PA2 = portA + 2 + PA3 = portA + 3 + PA4 = portA + 4 + PA5 = portA + 5 + PA6 = portA + 6 + PA7 = portA + 7 + PA8 = portA + 8 + PA9 = portA + 9 + PA10 = portA + 10 + PA11 = portA + 11 + PA12 = portA + 12 + PA13 = portA + 13 + PA14 = portA + 14 + PA15 = portA + 15 + + PB0 = portB + 0 + PB1 = portB + 1 + PB2 = portB + 2 + PB3 = portB + 3 + PB4 = portB + 4 + PB5 = portB + 5 + PB6 = portB + 6 + PB7 = portB + 7 + PB8 = portB + 8 + PB9 = portB + 9 + PB10 = portB + 10 + PB11 = portB + 11 + PB12 = portB + 12 + PB13 = portB + 13 + PB14 = portB + 14 + PB15 = portB + 15 + + PC0 = portC + 0 + PC1 = portC + 1 + PC2 = portC + 2 + PC3 = portC + 3 + PC4 = portC + 4 + PC5 = portC + 5 + PC6 = portC + 6 + PC7 = portC + 7 + PC8 = portC + 8 + PC9 = portC + 9 + PC10 = portC + 10 + PC11 = portC + 11 + PC12 = portC + 12 + PC13 = portC + 13 + PC14 = portC + 14 + PC15 = portC + 15 + + PD0 = portD + 0 + PD1 = portD + 1 + PD2 = portD + 2 + PD3 = portD + 3 + PD4 = portD + 4 + PD5 = portD + 5 + PD6 = portD + 6 + PD7 = portD + 7 + PD8 = portD + 8 + PD9 = portD + 9 + PD10 = portD + 10 + PD11 = portD + 11 + PD12 = portD + 12 + PD13 = portD + 13 + PD14 = portD + 14 + PD15 = portD + 15 + + PE0 = portE + 0 + PE1 = portE + 1 + PE2 = portE + 2 + PE3 = portE + 3 + PE4 = portE + 4 + PE5 = portE + 5 + PE6 = portE + 6 + PE7 = portE + 7 + PE8 = portE + 8 + PE9 = portE + 9 + PE10 = portE + 10 + PE11 = portE + 11 + PE12 = portE + 12 + PE13 = portE + 13 + PE14 = portE + 14 + PE15 = portE + 15 + + PH0 = portH + 0 + PH1 = portH + 1 +) + +const ( + LED = LED_BUILTIN + LED1 = LED_GREEN + LED2 = LED_ORANGE + LED3 = LED_RED + LED4 = LED_BLUE + LED_BUILTIN = LED_GREEN + LED_GREEN = PD12 + LED_ORANGE = PD13 + LED_RED = PD14 + LED_BLUE = PD15 +) + +// UART pins +const ( + UART_TX_PIN = PA2 + UART_RX_PIN = PA3 +) diff --git a/src/machine/machine_stm32.go b/src/machine/machine_stm32.go index 6c4b4475..32aa0adc 100644 --- a/src/machine/machine_stm32.go +++ b/src/machine/machine_stm32.go @@ -14,4 +14,5 @@ const ( portE portF portG + portH ) diff --git a/src/machine/machine_stm32f407.go b/src/machine/machine_stm32f407.go new file mode 100644 index 00000000..a41f8d8b --- /dev/null +++ b/src/machine/machine_stm32f407.go @@ -0,0 +1,220 @@ +// +build stm32,stm32f407 + +package machine + +// Peripheral abstraction layer for the stm32. + +import ( + "device/arm" + "device/stm32" +) + +const CPU_FREQUENCY = 168000000 + +const ( + // Mode Flag + GPIO_OUTPUT = 0 + GPIO_INPUT = GPIO_INPUT_PULLDOWN + GPIO_INPUT_FLOATING = 1 + GPIO_INPUT_PULLDOWN = 2 + GPIO_INPUT_PULLUP = 3 + + // for UART + GPIO_UART_TX = 4 + GPIO_UART_RX = 5 + + //GPIOx_MODER + GPIO_MODE_INPUT = 0 + GPIO_MODE_GENERAL_OUTPUT = 1 + GPIO_MODE_ALTERNABTIVE = 2 + GPIO_MODE_ANALOG = 3 + + //GPIOx_OTYPER + GPIO_OUTPUT_MODE_PUSH_PULL = 0 + GPIO_OUTPUT_MODE_OPEN_DRAIN = 1 + + // GPIOx_OSPEEDR + GPIO_SPEED_LOW = 0 + GPIO_SPEED_MID = 1 + GPIO_SPEED_HI = 2 + GPIO_SPEED_VERY_HI = 3 + + // GPIOx_PUPDR + GPIO_FLOATING = 0 + GPIO_PULL_UP = 1 + GPIO_PULL_DOWN = 2 +) + +func (p GPIO) getPort() *stm32.GPIO_Type { + switch p.Pin / 16 { + case 0: + return stm32.GPIOA + case 1: + return stm32.GPIOB + case 2: + return stm32.GPIOC + case 3: + return stm32.GPIOD + case 4: + return stm32.GPIOE + case 5: + return stm32.GPIOF + case 6: + return stm32.GPIOG + case 7: + return stm32.GPIOH + case 8: + return stm32.GPIOI + default: + panic("machine: unknown port") + } +} + +// enableClock enables the clock for this desired GPIO port. +func (p GPIO) enableClock() { + switch p.Pin / 16 { + case 0: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOAEN + case 1: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOBEN + case 2: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOCEN + case 3: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIODEN + case 4: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOEEN + case 5: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOFEN + case 6: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOGEN + case 7: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOHEN + case 8: + stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOIEN + default: + panic("machine: unknown port") + } +} + +// Configure this pin with the given configuration. +func (p GPIO) Configure(config GPIOConfig) { + // Configure the GPIO pin. + p.enableClock() + port := p.getPort() + pin := p.Pin % 16 + pos := pin * 2 + + if config.Mode == GPIO_INPUT_FLOATING { + port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<= 8 { + port.AFRH = stm32.RegValue(uint32(port.AFRH)&^(0xF<> 1) - 1) << 16) | + (1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (PLL_Q << 24) + // Enable main PLL + stm32.RCC.CR |= stm32.RCC_CR_PLLON + // Wait till the main PLL is ready + for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 { + } + // Configure Flash prefetch, Instruction cache, Data cache and wait state + stm32.FLASH.ACR = stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | (5 << stm32.FLASH_ACR_LATENCY_Pos) + // Select the main PLL as system clock source + stm32.RCC.CFGR &^= stm32.RCC_CFGR_SW0 | stm32.RCC_CFGR_SW1 + stm32.RCC.CFGR |= (0x2 << stm32.RCC_CFGR_SW0_Pos) + for (stm32.RCC.CFGR & (0x3 << stm32.RCC_CFGR_SWS0_Pos)) != (0x2 << stm32.RCC_CFGR_SWS0_Pos) { + } + + } else { + // If HSE failed to start up, the application will have wrong clock configuration + for { + } + } + // Enable the CCM RAM clock + stm32.RCC.AHB1ENR |= (1 << 20) + +} + +const tickMicros = 1000 + +var ( + // tick in milliseconds + tickCount timeUnit +) + +//go:volatile +type isrFlag bool + +var timerWakeup isrFlag + +// Enable the TIM3 clock.(sleep count) +func initTIM3() { + stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM3EN + + arm.SetPriority(stm32.IRQ_TIM3, 0xc3) + arm.EnableIRQ(stm32.IRQ_TIM3) +} + +// Enable the TIM7 clock.(tick count) +func initTIM7() { + stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM7EN + + // CK_INT = APB1 x2 = 84mhz + stm32.TIM7.PSC = 84000000/10000 - 1 // 84mhz to 10khz(0.1ms) + stm32.TIM7.ARR = stm32.RegValue(10) - 1 // interrupt per 1ms + + // Enable the hardware interrupt. + stm32.TIM7.DIER |= stm32.TIM_DIER_UIE + + // Enable the timer. + stm32.TIM7.CR1 |= stm32.TIM_CR1_CEN + + arm.SetPriority(stm32.IRQ_TIM7, 0xc1) + arm.EnableIRQ(stm32.IRQ_TIM7) +} + +const asyncScheduler = false + +// sleepTicks should sleep for specific number of microseconds. +func sleepTicks(d timeUnit) { + timerSleep(uint32(d)) +} + +// number of ticks (microseconds) since start. +func ticks() timeUnit { + // milliseconds to microseconds + return tickCount * 1000 +} + +// ticks are in microseconds +func timerSleep(ticks uint32) { + timerWakeup = false + + // CK_INT = APB1 x2 = 84mhz + // prescale counter down from 84mhz to 10khz aka 0.1 ms frequency. + stm32.TIM3.PSC = 84000000/10000 - 1 // 8399 + + // set duty aka duration + arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms + if arr == 0 { + arr = 1 // avoid blocking + } + stm32.TIM3.ARR = stm32.RegValue(arr) + + // Enable the hardware interrupt. + stm32.TIM3.DIER |= stm32.TIM_DIER_UIE + + // Enable the timer. + stm32.TIM3.CR1 |= stm32.TIM_CR1_CEN + + // wait till timer wakes up + for !timerWakeup { + arm.Asm("wfi") + } +} + +//go:export TIM3_IRQHandler +func handleTIM3() { + if (stm32.TIM3.SR & stm32.TIM_SR_UIF) > 0 { + // Disable the timer. + stm32.TIM3.CR1 &^= stm32.TIM_CR1_CEN + + // clear the update flag + stm32.TIM3.SR &^= stm32.TIM_SR_UIF + + // timer was triggered + timerWakeup = true + } +} + +//go:export TIM7_IRQHandler +func handleTIM7() { + if (stm32.TIM7.SR & stm32.TIM_SR_UIF) > 0 { + // clear the update flag + stm32.TIM7.SR &^= stm32.TIM_SR_UIF + tickCount++ + } +} diff --git a/targets/stm32f407.ld b/targets/stm32f407.ld new file mode 100644 index 00000000..2709ca04 --- /dev/null +++ b/targets/stm32f407.ld @@ -0,0 +1,10 @@ + +MEMORY +{ + FLASH_TEXT (rw) : ORIGIN = 0x08000000, LENGTH = 1M + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K +} + +_stack_size = 4K; + +INCLUDE "targets/arm.ld" diff --git a/targets/stm32f4disco.json b/targets/stm32f4disco.json new file mode 100644 index 00000000..67fe7841 --- /dev/null +++ b/targets/stm32f4disco.json @@ -0,0 +1,18 @@ +{ + "inherits": ["cortex-m"], + "llvm-target": "armv7em-none-eabi", + "build-tags": ["stm32f4disco", "stm32f407", "stm32"], + "cflags": [ + "--target=armv7em-none-eabi", + "-Qunused-arguments" + ], + "ldflags": [ + "-T", "targets/stm32f407.ld" + ], + "extra-files": [ + "src/device/stm32/stm32f407.s" + ], + "flash": "openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -c 'program {hex} reset exit'", + "ocd-daemon": ["openocd", "-f", "interface/stlink.cfg", "-f", "target/stm32f4x.cfg"], + "gdb-initial-cmds": ["target remote :3333", "monitor halt", "load", "monitor reset", "c"] +}