From e586c178073b9a0fee90d5fc8e795d266ebd7b7d Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Tue, 7 Aug 2012 16:50:46 +0200 Subject: Initial import. Most sources are split off from suzumebachi project revision 2fc77d2 as is with some path changes. New build rules introduced. --- .gitignore | 1 + SConscript | 7 ++ build_rules | 80 ++++++++++++++++ gpio/gpio.h | 43 +++++++++ gpio/pin.h | 137 ++++++++++++++++++++++++++++ i2c/i2c.cpp | 145 +++++++++++++++++++++++++++++ i2c/i2c.h | 62 +++++++++++++ interrupt/fault.cpp | 41 +++++++++ interrupt/interrupt.cpp | 187 ++++++++++++++++++++++++++++++++++++++ interrupt/interrupt.h | 151 ++++++++++++++++++++++++++++++ ld_scripts/arm_flash_ram.ld | 78 ++++++++++++++++ ld_scripts/stm32_f1_8.ld | 6 ++ ld_scripts/stm32_f1_b.ld | 6 ++ ld_scripts/stm32_f4_e.ld | 7 ++ ld_scripts/stm32_f4_g.ld | 7 ++ os/mutex.h | 42 +++++++++ os/pool.cpp | 5 + os/pool.h | 146 +++++++++++++++++++++++++++++ os/thread.cpp | 4 + os/thread.h | 63 +++++++++++++ os/time.cpp | 3 + os/time.h | 32 +++++++ rcc/flash.cpp | 17 ++++ rcc/flash.h | 30 ++++++ rcc/rcc.cpp | 51 +++++++++++ rcc/rcc.h | 217 ++++++++++++++++++++++++++++++++++++++++++++ spi/spi.h | 31 +++++++ startup/entry.cpp | 63 +++++++++++++ timer/timer.h | 40 ++++++++ usart/usart.cpp | 7 ++ usart/usart.h | 68 ++++++++++++++ usb/usb.h | 93 +++++++++++++++++++ 32 files changed, 1870 insertions(+) create mode 100644 .gitignore create mode 100644 SConscript create mode 100644 build_rules create mode 100644 gpio/gpio.h create mode 100644 gpio/pin.h create mode 100644 i2c/i2c.cpp create mode 100644 i2c/i2c.h create mode 100644 interrupt/fault.cpp create mode 100644 interrupt/interrupt.cpp create mode 100644 interrupt/interrupt.h create mode 100644 ld_scripts/arm_flash_ram.ld create mode 100644 ld_scripts/stm32_f1_8.ld create mode 100644 ld_scripts/stm32_f1_b.ld create mode 100644 ld_scripts/stm32_f4_e.ld create mode 100644 ld_scripts/stm32_f4_g.ld create mode 100644 os/mutex.h create mode 100644 os/pool.cpp create mode 100644 os/pool.h create mode 100644 os/thread.cpp create mode 100644 os/thread.h create mode 100644 os/time.cpp create mode 100644 os/time.h create mode 100644 rcc/flash.cpp create mode 100644 rcc/flash.h create mode 100644 rcc/rcc.cpp create mode 100644 rcc/rcc.h create mode 100644 spi/spi.h create mode 100644 startup/entry.cpp create mode 100644 timer/timer.h create mode 100644 usart/usart.cpp create mode 100644 usart/usart.h create mode 100644 usb/usb.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/SConscript b/SConscript new file mode 100644 index 0000000..5d706af --- /dev/null +++ b/SConscript @@ -0,0 +1,7 @@ +# Don't call this file explicitly, it is called implicitly by the build rules. + +Import('env') + +env.Append( + LIB_SOURCES = Glob('*.cpp') + Glob('*/*.cpp'), +) diff --git a/build_rules b/build_rules new file mode 100644 index 0000000..0040cd7 --- /dev/null +++ b/build_rules @@ -0,0 +1,80 @@ +laks_dir = Dir('.') +ld_dir = Dir('ld_scripts') +main_sconscript = File('SConscript') + +def select_arm(env, family): + env.SetDefault( + TOOLCHAIN = 'arm-none-eabi-', + ) + + env.Replace( + CC = '${TOOLCHAIN}gcc', + CXX = '${TOOLCHAIN}g++', + AS = '${TOOLCHAIN}gcc', + LINK = '${TOOLCHAIN}gcc', + AR = '${TOOLCHAIN}ar', + RANLIB = '${TOOLCHAIN}ranlib', + + CCFLAGS = '-O2 -Wall -ggdb -mcpu=${CPU_FAMILY} -mthumb -ffunction-sections', + CXXFLAGS = '-fno-exceptions -fno-rtti -Wno-pmf-conversions', + ASFLAGS = '-c -x assembler-with-cpp -mcpu=${CPU_FAMILY} -mthumb', + LINKFLAGS = '-Wall -mcpu=${CPU_FAMILY} -mthumb -mhard-float -nostartfiles -Wl,-T${LINK_SCRIPT}', # -Wl,--gc-sections + + CPPPATH = [laks_dir], + LIBPATH = [ld_dir], + + LIB_SOURCES = [], + + CPU_FAMILY = family, + ) + + if family == 'cortex-m4': + env.Append(CCFLAGS = ' -mhard-float') + +def select_stm32(env, variant): + family = variant[5:9] + pin_count = variant[9] + flash = variant[10] + + if family == 'f103': + select_arm(env, 'cortex-m3') + env.Append(CPPDEFINES = ['STM32F1']) + + env['LINK_SCRIPT'] = { + '8': 'stm32_f1_8.ld', + 'b': 'stm32_f1_b.ld', + }[flash] + + elif family in ('f405', 'f407'): + select_arm(env, 'cortex-m4') + env.Append(CPPDEFINES = ['STM32F4']) + + env['LINK_SCRIPT'] = { + 'e': 'stm32_f4_e.ld', + 'g': 'stm32_f4_g.ld', + }[flash] + + else: + print 'Unknown stm32 family: %s' % mcu + Exit(1) + +def SelectMCU(env, mcu): + mcu = mcu.lower() + + if mcu.startswith('stm32'): + select_stm32(env, mcu) + + else: + print 'Unknown MCU: %s' % mcu + Exit(1) + + SConscript(main_sconscript, exports = 'env') + +AddMethod(Environment, SelectMCU) + +def Firmware(env, target, sources): + firmware = env.Program(target, [sources, env['LIB_SOURCES']]) + #env.Depends(firmware, env['LINK_SCRIPT']) # TODO + return firmware + +AddMethod(Environment, Firmware) diff --git a/gpio/gpio.h b/gpio/gpio.h new file mode 100644 index 0000000..324950e --- /dev/null +++ b/gpio/gpio.h @@ -0,0 +1,43 @@ +#ifndef GPIO_H +#define GPIO_H + +struct GPIO_t { + #if defined(STM32F1) + volatile uint32_t CRL; + volatile uint32_t CRH; + volatile uint32_t IDR; + volatile uint32_t ODR; + volatile uint32_t BSRR; + volatile uint32_t BRR; + volatile uint32_t LCKR; + #elif defined(STM32F4) + volatile uint32_t MODER; + volatile uint32_t OTYPER; + volatile uint32_t OSPEEDER; + volatile uint32_t PUPDR; + volatile uint32_t IDR; + volatile uint32_t ODR; + volatile uint32_t BSRR; + volatile uint32_t LCKR; + volatile uint32_t AFRL; + volatile uint32_t AFRH; + #endif +}; + +#if defined(STM32F1) +static GPIO_t& GPIOA = *(GPIO_t*)0x40010800; +static GPIO_t& GPIOB = *(GPIO_t*)0x40010c00; +static GPIO_t& GPIOC = *(GPIO_t*)0x40011000; +#elif defined(STM32F4) +static GPIO_t& GPIOA = *(GPIO_t*)0x40020000; +static GPIO_t& GPIOB = *(GPIO_t*)0x40020400; +static GPIO_t& GPIOC = *(GPIO_t*)0x40020800; +static GPIO_t& GPIOD = *(GPIO_t*)0x40020c00; +static GPIO_t& GPIOE = *(GPIO_t*)0x40021000; +static GPIO_t& GPIOF = *(GPIO_t*)0x40021400; +static GPIO_t& GPIOG = *(GPIO_t*)0x40021800; +static GPIO_t& GPIOH = *(GPIO_t*)0x40021c00; +static GPIO_t& GPIOI = *(GPIO_t*)0x40022000; +#endif + +#endif diff --git a/gpio/pin.h b/gpio/pin.h new file mode 100644 index 0000000..1ad3ca2 --- /dev/null +++ b/gpio/pin.h @@ -0,0 +1,137 @@ +#ifndef PIN_H +#define PIN_H + +#include "gpio.h" + +class Pin { + private: + GPIO_t& g; + int n; + + public: + Pin(GPIO_t& gpio, int pin) : g(gpio), n(pin) {} + + enum Mode { + Input, + Output, + AF, + Analog, + }; + + enum Type { + PushPull, + OpenDrain, + }; + + enum Pull { + PullNone, + PullUp, + PullDown, + }; + + void set_mode(Mode m) { + g.MODER = (g.MODER & ~(3 << (n * 2))) | m << (n * 2); + } + + void set_type(Type t) { + if(t) { + g.OTYPER |= 1 << n; + } else { + g.OTYPER &= ~(1 << n); + } + } + + void set_pull(Pull p) { + g.PUPDR = (g.PUPDR & ~(3 << (n * 2))) | p << (n * 2); + } + + void set_af(int af) { + if(n < 8) { + g.AFRL = (g.AFRL & ~(0xf << (n * 4))) | af << (n * 4); + } else { + g.AFRH = (g.AFRH & ~(0xf << (n * 4 - 32))) | af << (n * 4 - 32); + } + } + + void on() { + g.BSRR = 1 << n; + } + + void off() { + g.BSRR = 1 << 16 << n; + } + + void set(bool value) { + if(value) { + on(); + } else { + off(); + } + } + + bool get() { + return g.IDR & (1 << n); + } + + void toggle() { + set(!(g.ODR & (1 << n))); + } +}; + +static Pin PA0(GPIOA, 0); +static Pin PA1(GPIOA, 1); +static Pin PA2(GPIOA, 2); +static Pin PA3(GPIOA, 3); +static Pin PA4(GPIOA, 4); +static Pin PA5(GPIOA, 5); +static Pin PA6(GPIOA, 6); +static Pin PA7(GPIOA, 7); +static Pin PA8(GPIOA, 8); +static Pin PA9(GPIOA, 9); +static Pin PA10(GPIOA, 10); +static Pin PA11(GPIOA, 11); +static Pin PA12(GPIOA, 12); +static Pin PA13(GPIOA, 13); +static Pin PA14(GPIOA, 14); +static Pin PA15(GPIOA, 15); + +static Pin PB0(GPIOB, 0); +static Pin PB1(GPIOB, 1); +static Pin PB2(GPIOB, 2); +static Pin PB3(GPIOB, 3); +static Pin PB4(GPIOB, 4); +static Pin PB5(GPIOB, 5); +static Pin PB6(GPIOB, 6); +static Pin PB7(GPIOB, 7); +static Pin PB8(GPIOB, 8); +static Pin PB9(GPIOB, 9); +static Pin PB10(GPIOB, 10); +static Pin PB11(GPIOB, 11); +static Pin PB12(GPIOB, 12); +static Pin PB13(GPIOB, 13); +static Pin PB14(GPIOB, 14); +static Pin PB15(GPIOB, 15); + +static Pin PC0(GPIOC, 0); +static Pin PC1(GPIOC, 1); +static Pin PC2(GPIOC, 2); +static Pin PC3(GPIOC, 3); +static Pin PC4(GPIOC, 4); +static Pin PC5(GPIOC, 5); +static Pin PC6(GPIOC, 6); +static Pin PC7(GPIOC, 7); +static Pin PC8(GPIOC, 8); +static Pin PC9(GPIOC, 9); +static Pin PC10(GPIOC, 10); +static Pin PC11(GPIOC, 11); +static Pin PC12(GPIOC, 12); +static Pin PC13(GPIOC, 13); +static Pin PC14(GPIOC, 14); +static Pin PC15(GPIOC, 15); + +static Pin PD12(GPIOD, 12); +static Pin PD13(GPIOD, 13); +static Pin PD14(GPIOD, 14); +static Pin PD15(GPIOD, 15); + +#endif diff --git a/i2c/i2c.cpp b/i2c/i2c.cpp new file mode 100644 index 0000000..a395b13 --- /dev/null +++ b/i2c/i2c.cpp @@ -0,0 +1,145 @@ +#include "i2c.h" + +#include +#include + +#if defined(STM32F1) +I2C_t I2C1(0x40005400, 36000000, Interrupt::I2C1_EV, Interrupt::I2C1_ER); +I2C_t I2C2(0x40005800, 36000000, Interrupt::I2C2_EV, Interrupt::I2C2_ER); +#elif defined(STM32F4) +I2C_t I2C1(0x40005400, 42000000, Interrupt::I2C1_EV, Interrupt::I2C1_ER); +I2C_t I2C2(0x40005800, 42000000, Interrupt::I2C2_EV, Interrupt::I2C2_ER); +//I2C_t I2C3(0x40005c00, 42000000, Interrupt::I2C3_EV, Interrupt::I2C3_ER); +#endif + +void I2C_t::irq_ev() { + uint32_t sr1 = reg.SR1; + reg.SR2; + + // EV5, SB = 1: Start condition sent. + if(sr1 & 0x01) { + // Send address. + reg.DR = (addr << 1) | (writing ? 0 : 1); + } + + // EV6, ADDR = 1: Address sent. + if(sr1 & 0x02) { + if(writing) { + reg.DR = *write_p++; + writing--; + } else { + if(reading > 1) { + reg.CR1 |= 0x400; // Set ACK. + } else { + reg.CR1 |= 0x200; // Set STOP. + } + } + } + + // EV7, RxNE = 1: Receive buffer not empty. + if(sr1 & 0x40) { + *read_p++ = reg.DR; + reading--; + + if(reading == 1) { + // Unset ACK, set STOP. + reg.CR1 = (reg.CR1 & ~0x400) | 0x200; + } + + if(reading == 0) { + busy = 0; + } + } + + //reg.CR1 &= ~0x400; + + // EV8, TxE = 1, BTF = 0: Transmit buffer empty, still writing. + if(sr1 & 0x80 && !(sr1 & 0x04)) { + if(writing) { + // Send data. + reg.DR = *write_p++; + writing--; + } else { + // All data sent. + + if(reading) { + // Send repeat start. + reg.CR1 |= 0x100; + } else { + // Send stop. + reg.CR1 |= 0x200; + busy = 0; + } + } + } +} + +void I2C_t::irq_er() { + handle_error(); +} + +void I2C_t::handle_error() { + reg.SR1; + reg.SR2; + + //while(1); + + reg.SR1 = 0; + + reg.CR1 |= 0x200; + busy = 0; +} + +void I2C_t::enable(Pin& scl, Pin& sda) { + RCC.enable(RCC.I2C1); + asm volatile("nop"); + + scl.set_af(4); + sda.set_af(4); + scl.set_type(Pin::OpenDrain); + sda.set_type(Pin::OpenDrain); + scl.set_mode(Pin::AF); + sda.set_mode(Pin::AF); + + reg.CR1 = 0x8000; + reg.CR1 = 0; + + reg.CR2 = 0x700 | (clk / 1000000); + reg.TRISE = clk / 1000000 + 1; + reg.CCR = clk / 2 / 100000; + + Interrupt::enable(irq_ev_n, &I2C_t::irq_ev, this); + Interrupt::enable(irq_er_n, &I2C_t::irq_er, this); + + reg.CR1 = 1; +} + +void I2C_t::write_reg(uint8_t addr_, uint8_t reg_, uint8_t data) { + addr = addr_; + writing = 2; + reading = 0; + volatile uint8_t buf[] = {reg_, data}; + write_p = buf; + busy = 1; + + reg.CR1 |= 0x100; + + while(busy) { + Thread::yield(); + } +} + +void I2C_t::read_reg(uint8_t addr_, uint8_t reg_, uint8_t len, uint8_t* buf) { + addr = addr_; + writing = 1; + reading = len; + write_p = ®_; + read_p = buf; + busy = 1; + + reg.CR1 |= 0x100; + + while(busy) { + Thread::yield(); + } +} diff --git a/i2c/i2c.h b/i2c/i2c.h new file mode 100644 index 0000000..f4d6949 --- /dev/null +++ b/i2c/i2c.h @@ -0,0 +1,62 @@ +#ifndef I2C_H +#define I2C_H + +#include +#include +#include + +struct I2C_reg_t { + volatile uint32_t CR1; + volatile uint32_t CR2; + volatile uint32_t OAR1; + volatile uint32_t OAR2; + volatile uint32_t DR; + volatile uint32_t SR1; + volatile uint32_t SR2; + volatile uint32_t CCR; + volatile uint32_t TRISE; +}; + +class I2C_t { + private: + volatile uint8_t addr; + volatile uint8_t writing; + volatile uint8_t reading; + volatile uint8_t* write_p; + volatile uint8_t* read_p; + + volatile bool busy; + + public: + I2C_reg_t& reg; + const uint32_t clk; + Interrupt::IRQ irq_ev_n; + Interrupt::IRQ irq_er_n; + + I2C_t(uint32_t reg_addr, uint32_t bus_clk, Interrupt::IRQ ev_n, Interrupt::IRQ er_n) : reg(*(I2C_reg_t*)reg_addr), clk(bus_clk), irq_ev_n(ev_n), irq_er_n(er_n) { + reading = writing = 0; + } + + void irq_ev(); + void irq_er(); + + void handle_error(); + + void enable(Pin& scl, Pin& sda); + + void write_reg(uint8_t addr_, uint8_t reg_, uint8_t data); + void read_reg(uint8_t addr_, uint8_t reg_, uint8_t len, uint8_t* buf); +}; + +#if defined(STM32F1) +extern I2C_t I2C1; +extern I2C_t I2C2; +#elif defined(STM32F4) +extern I2C_t I2C1; +extern I2C_t I2C2; +extern I2C_t I2C3; +#endif + +typedef I2C_t I2C; + +#endif diff --git a/interrupt/fault.cpp b/interrupt/fault.cpp new file mode 100644 index 0000000..016b74b --- /dev/null +++ b/interrupt/fault.cpp @@ -0,0 +1,41 @@ +#include "interrupt.h" +#include +#include + +inline void __attribute__((naked)) switch_context() { + asm volatile ("cpsid i"); + + // Save unsaved registers. + asm volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" ::: "memory"); + + // Store stack pointer for old thread. + asm volatile ("str sp, [%0]" :: "r" (&Thread::active_thread->sp)); + + // Update running thread. + Thread::active_thread = Thread::active_thread->next; + + // Fetch stack pointer for new thread. + asm volatile ("ldr sp, [%0]" :: "r" (&Thread::active_thread->sp)); + + asm volatile ("cpsie i"); + + // Load registers and return. + asm volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" ::: "memory"); +} + +template<> +void interrupt() { + switch_context(); +} + +template<> +void interrupt() { + Time::tick(); +} + +template<> void interrupt() { while(1); } +template<> void interrupt() { while(1); } +template<> void interrupt() { while(1); } +template<> void interrupt() { while(1); } +template<> void interrupt() { while(1); } +template<> void interrupt() { while(1); } diff --git a/interrupt/interrupt.cpp b/interrupt/interrupt.cpp new file mode 100644 index 0000000..cebfed7 --- /dev/null +++ b/interrupt/interrupt.cpp @@ -0,0 +1,187 @@ +#include "interrupt.h" + +namespace Interrupt { + MFP mf_vectors[16 + NUM_IRQs]; +}; + +void entry(); + +void member_function_interrupt_gate() { + uint32_t interrupt_num; + asm ("mrs %0, ipsr" : "=r" (interrupt_num)); + + Interrupt::mf_vectors[interrupt_num].func_p(Interrupt::mf_vectors[interrupt_num].instance_p); +} + +extern "C" void unused_interrupt() { + member_function_interrupt_gate(); + //while(1); +} + +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); +template<> void interrupt() __attribute__ ((weak, alias ("unused_interrupt"))); + +typedef void (*vector_t)(); + +vector_t vectors[] __attribute__((section(".vectors"))) = { + (vector_t)0x20004ffc, + entry, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + 0, + 0, + 0, + 0, + interrupt, + 0, + 0, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + interrupt, + 0, // 60 + 0, // 61 + 0, // 62 + 0, // 63 + 0, // 64 + 0, // 65 + 0, // 66 + 0, // 67 + 0, // 68 + 0, // 69 + 0, // 70 + 0, // 71 + 0, // 72 + 0, // 73 + 0, // 74 + 0, // 75 + 0, // 76 + interrupt<(Interrupt::IRQ)77>, // 77 +}; diff --git a/interrupt/interrupt.h b/interrupt/interrupt.h new file mode 100644 index 0000000..80ccb76 --- /dev/null +++ b/interrupt/interrupt.h @@ -0,0 +1,151 @@ +#ifndef INTERRUPT_H +#define INTERRUPT_H + +#include + +struct NVIC_t { + volatile uint32_t ISER[32]; + volatile uint32_t ICER[32]; + volatile uint32_t ISPR[32]; + volatile uint32_t ICPR[32]; + volatile uint32_t IABR[64]; + volatile uint8_t IPR[2816]; + volatile uint32_t STIR; +}; + +static NVIC_t& NVIC = *(NVIC_t*)0xe000e100; + +struct SCB_t { + volatile uint32_t CPUID; + volatile uint32_t ICSR; + volatile uint32_t VTOR; + volatile uint32_t AIRCR; + volatile uint32_t SCR; + volatile uint32_t CCR; + volatile uint8_t SHPR[12]; + volatile uint32_t SHCSR; + volatile uint32_t CFSR; + volatile uint32_t HFSR; + volatile uint32_t DFSR; + volatile uint32_t MMAR; + volatile uint32_t BFAR; +}; + +static SCB_t& SCB = *(SCB_t*)0xe000ed00; + +namespace Interrupt { + enum Exception { + NMI = 2, + HardFault = 3, + MemManage = 4, + BusFault = 5, + UsageFault = 6, + SVCall = 11, + PendSV = 14, + SysTick = 15 + }; + + enum IRQ { + WWDG, + PVD, + TAMPER, + RTC, + FLASH, + RCC, + EXTI0, + EXTI1, + EXTI2, + EXTI3, + EXTI4, + DMA1_Channel1, + DMA1_Channel2, + DMA1_Channel3, + DMA1_Channel4, + DMA1_Channel5, + DMA1_Channel6, + DMA1_Channel7, + ADC1_2, + USB_HP_CAN_TX, + USB_LP_CAN_RX0, + CAN_RX1, + CAN_SCE, + EXTI9_5, + TIM1_BRK, + TIM1_UP, + TIM1_TRG_COM, + TIM1_CC, + TIM2, + TIM3, + TIM4, + I2C1_EV, + I2C1_ER, + I2C2_EV, + I2C2_ER, + SPI1, + SPI2, + USART1, + USART2, + USART3, + EXTI15_10, + RTCAlarm, + USBWakeup, + TIM8_BRK, + TIM8_UP, + TIM8_TRG_COM, + TIM8_CC, + ADC3, + FSMC, + SDIO, + TIM5, + SPI3, + UART4, + UART5, + TIM6, + TIM7, + DMA2_Channel1, + DMA2_Channel2, + DMA2_Channel3, + DMA2_Channel4_5, + NUM_IRQs + }; + + inline void enable(IRQ n) { + NVIC.ISER[n >> 5] = 1 << (n & 0x1f); + } + + inline void set_priority(Exception n, uint8_t priority) { + SCB.SHPR[n - 4] = priority; + } + + inline void set_priority(IRQ n, uint8_t priority) { + NVIC.IPR[n] = priority; + } + + struct MFP { + void (*func_p)(void*); + void* instance_p; + }; + + extern MFP mf_vectors[]; + + template + inline void set_handler(IRQ n, void (T::*f)(), T* i) { + MFP& mfp = mf_vectors[16 + n]; + mfp.func_p = reinterpret_cast(f); + mfp.instance_p = i; + } + + template + inline void enable(IRQ n, void (T::*f)(), T* i) { + set_handler(n, f, i); + enable(n); + } +}; + +template +void interrupt(); + +template +void interrupt(); + +#endif diff --git a/ld_scripts/arm_flash_ram.ld b/ld_scripts/arm_flash_ram.ld new file mode 100644 index 0000000..4839b16 --- /dev/null +++ b/ld_scripts/arm_flash_ram.ld @@ -0,0 +1,78 @@ +_ram_start = ORIGIN(ram); +_ram_size = LENGTH(ram); +_ram_end = _ram_start + _ram_size; + +SECTIONS { + . = 0; + + .vectors : ALIGN(16) SUBALIGN(16) { + KEEP(*(.vectors)) + } > flash + + .init_array : ALIGN(4) SUBALIGN(4) { + PROVIDE(_init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE(_init_array_end = .); + } > flash + + .fini_array : ALIGN(4) SUBALIGN(4) { + PROVIDE(_fini_array_start = .); + KEEP(*(.fini_array)) + KEEP(*(SORT(.fini_array.*))) + PROVIDE(_fini_array_end = .); + } > flash + + .text : ALIGN(16) SUBALIGN(16) { + *(.text.startup.*) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + *(.glue_7t) + *(.glue_7) + *(.gcc*) + } > flash + + .ARM.extab : { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > flash + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > flash + + .eh_frame_hdr : { + *(.eh_frame_hdr) + } > flash + + .eh_frame : ONLY_IF_RO { + *(.eh_frame) + } > flash + + . = ALIGN(4); + + PROVIDE(_data_rom = .); + + .data : { + PROVIDE(_data_start = .); + *(.data) + . = ALIGN(4); + *(.data.*) + . = ALIGN(4); + *(.ramtext) + . = ALIGN(4); + PROVIDE(_data_end = .); + } > ram AT > flash + + .bss : { + PROVIDE(_bss_start = .); + *(.bss) + . = ALIGN(4); + *(.bss.*) + . = ALIGN(4); + *(COMMON) + . = ALIGN(4); + PROVIDE(_bss_end = .); + } > ram +} diff --git a/ld_scripts/stm32_f1_8.ld b/ld_scripts/stm32_f1_8.ld new file mode 100644 index 0000000..7fd5e59 --- /dev/null +++ b/ld_scripts/stm32_f1_8.ld @@ -0,0 +1,6 @@ +MEMORY { + flash (rx) : org = 0x08000000, len = 128k + ram (rwx) : org = 0x20000000, len = 20k +} + +INCLUDE "arm_flash_ram.ld" diff --git a/ld_scripts/stm32_f1_b.ld b/ld_scripts/stm32_f1_b.ld new file mode 100644 index 0000000..ea0b341 --- /dev/null +++ b/ld_scripts/stm32_f1_b.ld @@ -0,0 +1,6 @@ +MEMORY { + flash (rx) : org = 0x08000000, len = 256k + ram (rwx) : org = 0x20000000, len = 20k +} + +INCLUDE "arm_flash_ram.ld" diff --git a/ld_scripts/stm32_f4_e.ld b/ld_scripts/stm32_f4_e.ld new file mode 100644 index 0000000..b19753c --- /dev/null +++ b/ld_scripts/stm32_f4_e.ld @@ -0,0 +1,7 @@ +MEMORY { + flash (rx) : org = 0x08000000, len = 512k + ram (rwx) : org = 0x20000000, len = 128k + ccm (rwx) : org = 0x10000000, len = 64k +} + +INCLUDE "arm_flash_ram.ld" diff --git a/ld_scripts/stm32_f4_g.ld b/ld_scripts/stm32_f4_g.ld new file mode 100644 index 0000000..6ce322b --- /dev/null +++ b/ld_scripts/stm32_f4_g.ld @@ -0,0 +1,7 @@ +MEMORY { + flash (rx) : org = 0x08000000, len = 1024k + ram (rwx) : org = 0x20000000, len = 128k + ccm (rwx) : org = 0x10000000, len = 64k +} + +INCLUDE "arm_flash_ram.ld" diff --git a/os/mutex.h b/os/mutex.h new file mode 100644 index 0000000..d12331d --- /dev/null +++ b/os/mutex.h @@ -0,0 +1,42 @@ +#ifndef MUTEX_H +#define MUTEX_H + +class Mutex { + private: + uint8_t locked; + public: + Mutex() : locked(0) {} + Mutex(uint8_t l) : locked(l) {} + + bool trylock() { + uint8_t val; + + // Check if mutex is locked. + asm volatile ("ldrexb %0, [%1]" : "=r" (val) : "r" (&locked)); + if(val) { + return false; + } + + // Try taking the lock. + asm volatile ("strexb %0, %1, [%2]" : "=r" (val) : "r" (1), "r" (&locked)); + if(val) { + return false; + } + + asm volatile("dmb"); + return true; + } + + void lock() { + while(!trylock()) { + Thread::yield(); + } + } + + void unlock() { + asm volatile("dmb"); + locked = 0; + } +}; + +#endif diff --git a/os/pool.cpp b/os/pool.cpp new file mode 100644 index 0000000..f059b05 --- /dev/null +++ b/os/pool.cpp @@ -0,0 +1,5 @@ +#include "pool.h" + +void* operator new(unsigned int, char* buf) { + return (void*)buf; +} diff --git a/os/pool.h b/os/pool.h new file mode 100644 index 0000000..1cb0a71 --- /dev/null +++ b/os/pool.h @@ -0,0 +1,146 @@ +#ifndef POOL_H +#define POOL_H + +#include "stdint.h" + +template +class BasePool { + public: + struct Element { + unsigned int use_count; + BasePool* pool; + + char data[sizeof(T)]; + }; + + virtual void free(Element* e) = 0; +}; + +template +class P { + private: + typedef typename BasePool::Element Element; + + Element* e; + + void inc() { + e->use_count++; + } + + void dec() { + e->use_count--; + if(!e->use_count) { + T* p = (T*)e->data; + p->~T(); + e->pool->free(e); + } + } + + public: + P() : e(0) {} + + explicit P(Element* ep) : e(ep) { + inc(); + } + + P(const P& p) : e(p.e) { + inc(); + } + + ~P() { + if(e) { + dec(); + } + } + + void operator=(const P& p) { + if(e) { + dec(); + } + + e = p.e; + + if(e) { + inc(); + } + } + + void reset() { + if(e) { + dec(); + } + + e = 0; + } + + T* operator->() { + return (T*)e->data; + } + + T* operator*() { + return (T*)e->data; + } + + operator bool() { + return bool(e); + } +}; + +template +class Pool : public BasePool { + private: + typedef typename BasePool::Element Element; + + union Node { + Element e; + Node* next; + }; + + Node elements[size]; + + Node* next_free; + + void free(Element* e) { + Node* n = (Node*)e; + + n->next = next_free; + next_free = n; + } + + Element* alloc() { + if(!next_free) { + return 0; + } + + Element* e = &next_free->e; + next_free = next_free->next; + + e->use_count = 0; + e->pool = this; + + return e; + } + + public: + Pool() : next_free(0) { + for(unsigned int i = 0; i < size; i++) { + free(&elements[i].e); + } + } + + P create() { + Element* e = alloc(); + + if(!e) { + return P(); + } + + new (e->data) T; + + return P(e); + } +}; + +void* operator new(unsigned int, char* buf); + +#endif diff --git a/os/thread.cpp b/os/thread.cpp new file mode 100644 index 0000000..426fffd --- /dev/null +++ b/os/thread.cpp @@ -0,0 +1,4 @@ +#include "thread.h" + +Thread Thread::main_thread __attribute__ ((init_priority (1000))); +Thread* Thread::active_thread = &Thread::main_thread; diff --git a/os/thread.h b/os/thread.h new file mode 100644 index 0000000..2213d6f --- /dev/null +++ b/os/thread.h @@ -0,0 +1,63 @@ +#ifndef THREAD_H +#define THREAD_H + +#include + +class Thread { + friend void switch_context(); + + private: + struct int_frame_t { + // Software saved. + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t lr_ex; + + // Hardware saved. + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; + }; + + int_frame_t* sp; + + Thread* next; + + static Thread* active_thread; + static Thread main_thread; + + Thread() : next(this) {} + + public: + Thread(void* stack, uint32_t stack_size, void (*func)()) { + sp = (int_frame_t*)((uint8_t*)stack + stack_size - sizeof(int_frame_t)); + + sp->lr_ex = 0xfffffff9; + + // frame->lr = thread exit handler + sp->pc = (uint32_t)func; + sp->psr = 0x01000000; + } + + void start() { + next = active_thread->next; + active_thread->next = this; + } + + static inline void yield() { + asm volatile("svc 0"); + } +}; + +#endif diff --git a/os/time.cpp b/os/time.cpp new file mode 100644 index 0000000..6c96027 --- /dev/null +++ b/os/time.cpp @@ -0,0 +1,3 @@ +#include "time.h" + +volatile uint32_t Time::systime; diff --git a/os/time.h b/os/time.h new file mode 100644 index 0000000..3533967 --- /dev/null +++ b/os/time.h @@ -0,0 +1,32 @@ +#ifndef TIME_H +#define TIME_H + +#include "thread.h" + +struct STK_t { + volatile uint32_t CTRL; + volatile uint32_t LOAD; + volatile uint32_t VAL; + volatile uint32_t CALIB; +}; + +static STK_t& STK = *(STK_t*)0xe000e010; + +class Time { + private: + static volatile uint32_t systime; + + public: + inline static void tick() { + systime++; + } + + inline static void sleep(uint32_t ms) { + ms += systime; + while(systime < ms) { + Thread::yield(); + } + } +}; + +#endif diff --git a/rcc/flash.cpp b/rcc/flash.cpp new file mode 100644 index 0000000..2b0fb69 --- /dev/null +++ b/rcc/flash.cpp @@ -0,0 +1,17 @@ +#include "flash.h" + +void flash_init() { + #if defined(STM32F1) + + // Set flash latency. + FLASH.ACR = 0x12; + + #elif defined(STM32F4) + + // Set flash latency. + FLASH.ACR = 0x105; + + while(FLASH.ACR != 0x105); + + #endif +} diff --git a/rcc/flash.h b/rcc/flash.h new file mode 100644 index 0000000..30d30a5 --- /dev/null +++ b/rcc/flash.h @@ -0,0 +1,30 @@ +#ifndef FLASH_H +#define FLASH_H + +#include + +struct FLASH_t { + volatile uint32_t ACR; + volatile uint32_t KEYR; + volatile uint32_t OPTKEYR; + volatile uint32_t SR; + volatile uint32_t CR; + #if defined(STM32F1) + volatile uint32_t AR; + volatile uint32_t RESERVED; + volatile uint32_t OBR; + volatile uint32_t WRPR; + #elif defined(STM32F4) + volatile uint32_t OPTCR; + #endif +}; + +#if defined(STM32F1) +static FLASH_t& FLASH = *(FLASH_t*)0x40022000; +#elif defined(STM32F4) +static FLASH_t& FLASH = *(FLASH_t*)0x40023c00; +#endif + +void flash_init(); + +#endif diff --git a/rcc/rcc.cpp b/rcc/rcc.cpp new file mode 100644 index 0000000..57b8f7d --- /dev/null +++ b/rcc/rcc.cpp @@ -0,0 +1,51 @@ +#include "rcc.h" +#include "flash.h" + +void rcc_init() { + // Initialize flash. + flash_init(); + + #if defined(STM32F1) + + // Enable HSE. + RCC.CR |= 0x10000; + while(RCC.CR & 0x20000); + + // Configure and enable PLL. + RCC.CFGR = 0x1d0000; + RCC.CR |= 0x1000000; + while(!(RCC.CR & 0x2000000)); + + // Switch to PLL. + RCC.CFGR |= 0x2; + while(!(RCC.CFGR & 0x8)); + + // Set APB1 prescaler to /2. + RCC.CFGR |= 0x400; + + // Set ADCCLK prescaler to /6. + RCC.CFGR |= 0x8000; + + #elif defined(STM32F4) + + // Enable HSE. + RCC.CR |= 0x10000; + while(!(RCC.CR & 0x20000)); + + // Configure and enable PLL. + RCC.PLLCFGR = 0x20400000 | (7 << 24) | (2 * 168 << 6) | 8; + RCC.CR |= 0x1000000; + while(!(RCC.CR & 0x2000000)); + + // Switch to PLL. + RCC.CFGR |= 0x2; + while(!(RCC.CFGR & 0x8)); + + // Set APB1 prescaler to /4. + RCC.CFGR |= 5 << 10; + + // Set APB2 prescaler to /2. + RCC.CFGR |= 4 << 13; + + #endif +} diff --git a/rcc/rcc.h b/rcc/rcc.h new file mode 100644 index 0000000..4b8d99f --- /dev/null +++ b/rcc/rcc.h @@ -0,0 +1,217 @@ +#ifndef RCC_H +#define RCC_H + +#include + +struct RCC_t { + #if defined(STM32F1) + volatile uint32_t CR; + volatile uint32_t CFGR; + volatile uint32_t CIR; + volatile uint32_t APB2RSTR; + volatile uint32_t APB1RSTR; + volatile uint32_t AHBENR; + volatile uint32_t APB2ENR; + volatile uint32_t APB1ENR; + volatile uint32_t BDCR; + volatile uint32_t CSR; + #elif defined(STM32F4) + volatile uint32_t CR; + volatile uint32_t PLLCFGR; + volatile uint32_t CFGR; + volatile uint32_t CIR; + volatile uint32_t AHB1RSTR; + volatile uint32_t AHB2RSTR; + volatile uint32_t AHB3RSTR; + volatile uint32_t AHB4RSTR; // Reserved + volatile uint32_t APB1RSTR; + volatile uint32_t APB2RSTR; + volatile uint32_t APB3RSTR; // Reserved + volatile uint32_t APB4RSTR; // Reserved + volatile uint32_t AHB1ENR; + volatile uint32_t AHB2ENR; + volatile uint32_t AHB3ENR; + volatile uint32_t AHB4ENR; // Reserved + volatile uint32_t APB1ENR; + volatile uint32_t APB2ENR; + volatile uint32_t APB3ENR; // Reserved + volatile uint32_t APB4ENR; // Reserved + volatile uint32_t AHB1LPENR; + volatile uint32_t AHB2LPENR; + volatile uint32_t AHB3LPENR; + volatile uint32_t AHB4LPENR; // Reserved + volatile uint32_t APB1LPENR; + volatile uint32_t APB2LPENR; + volatile uint32_t APB3LPENR; // Reserved + volatile uint32_t APB4LPENR; // Reserved + volatile uint32_t BDCR; + volatile uint32_t CSR; + volatile uint32_t _1; + volatile uint32_t _2; + volatile uint32_t SSCGR; + volatile uint32_t PLLI2SCFGR; + #endif + + #if defined(STM32F1) + enum AHB_dev { + DMA1 = 1 << 0, + DMA2 = 1 << 1, + SRAM = 1 << 2, + FLITF = 1 << 4, + CRC = 1 << 6, + FSMC = 1 << 8, + SDIO = 1 << 10 + }; + + enum APB1_dev { + TIM2 = 1 << 0, + TIM3 = 1 << 1, + TIM4 = 1 << 2, + TIM5 = 1 << 3, + TIM6 = 1 << 4, + TIM7 = 1 << 5, + TIM12 = 1 << 6, + TIM13 = 1 << 7, + TIM14 = 1 << 8, + WWDG = 1 << 11, + SPI2 = 1 << 14, + SPI3 = 1 << 15, + USART2 = 1 << 17, + USART3 = 1 << 18, + UART4 = 1 << 19, + UART5 = 1 << 20, + I2C1 = 1 << 21, + I2C2 = 1 << 22, + USB = 1 << 23, + CAN = 1 << 25, + BKP = 1 << 27, + PWR = 1 << 28, + DAC = 1 << 29 + }; + + enum APB2_dev { + AFIO = 1 << 0, + IOPA = 1 << 2, + IOPB = 1 << 3, + IOPC = 1 << 4, + IOPD = 1 << 5, + IOPE = 1 << 6, + IOPF = 1 << 7, + IOPG = 1 << 8, + ADC1 = 1 << 9, + ADC2 = 1 << 10, + TIM1 = 1 << 11, + SPI1 = 1 << 12, + TIM8 = 1 << 13, + USART1 = 1 << 14, + ADC3 = 1 << 15, + TIM9 = 1 << 19, + TIM10 = 1 << 20, + TIM11 = 1 << 21 + }; + #elif defined(STM32F4) + enum AHB1_dev { + GPIOA = 1 << 0, + GPIOB = 1 << 1, + GPIOC = 1 << 2, + GPIOD = 1 << 3, + GPIOE = 1 << 4, + GPIOF = 1 << 5, + GPIOG = 1 << 6, + GPIOH = 1 << 7, + GPIOI = 1 << 8, + CRC = 1 << 12, + DMA1 = 1 << 21, + DMA2 = 1 << 22, + ETHMAC = 1 << 25, + OTGHS = 1 << 29, + }; + + enum AHB2_dev { + DCMI = 1 << 0, + CRYP = 1 << 4, + HASH = 1 << 5, + RNG = 1 << 6, + OTGFS = 1 << 7, + }; + + enum AHB3_dev { + FSMC = 1 << 0, + }; + + enum APB1_dev { + TIM2 = 1 << 0, + TIM3 = 1 << 1, + TIM4 = 1 << 2, + TIM5 = 1 << 3, + TIM6 = 1 << 4, + TIM7 = 1 << 5, + TIM12 = 1 << 6, + TIM13 = 1 << 7, + TIM14 = 1 << 8, + WWDG = 1 << 11, + SPI2 = 1 << 14, + SPI3 = 1 << 15, + USART2 = 1 << 17, + USART3 = 1 << 18, + UART4 = 1 << 19, + UART5 = 1 << 20, + I2C1 = 1 << 21, + I2C2 = 1 << 22, + I2C3 = 1 << 23, + CAN1 = 1 << 25, + CAN2 = 1 << 26, + PWR = 1 << 28, + DAC = 1 << 29, + }; + + enum APB2_dev { + TIM1 = 1 << 0, + TIM8 = 1 << 1, + USART1 = 1 << 4, + USART6 = 1 << 5, + ADC = 1 << 8, + SDIO = 1 << 11, + SPI1 = 1 << 12, + SYSCFG = 1 << 14, + TIM9 = 1 << 16, + TIM10 = 1 << 17, + TIM11 = 1 << 18, + }; + #endif + + #if defined(STM32F1) + inline void enable(AHB_dev dev) { + AHBENR |= dev; + } + #elif defined(STM32F4) + inline void enable(AHB1_dev dev) { + AHB1ENR |= dev; + } + + inline void enable(AHB2_dev dev) { + AHB2ENR |= dev; + } + + inline void enable(AHB3_dev dev) { + AHB3ENR |= dev; + } + #endif + inline void enable(APB1_dev dev) { + APB1ENR |= dev; + } + + inline void enable(APB2_dev dev) { + APB2ENR |= dev; + } +}; + +#if defined(STM32F1) +static RCC_t& RCC = *(RCC_t*)0x40021000; +#elif defined(STM32F4) +static RCC_t& RCC = *(RCC_t*)0x40023800; +#endif + +void rcc_init(); + +#endif diff --git a/spi/spi.h b/spi/spi.h new file mode 100644 index 0000000..9f9cf63 --- /dev/null +++ b/spi/spi.h @@ -0,0 +1,31 @@ +#ifndef SPI_H +#define SPI_H + +struct SPI_reg_t { + volatile uint32_t CR1; + volatile uint32_t CR2; + volatile uint32_t SR; + volatile uint32_t DR; + volatile uint32_t CRCPR; + volatile uint32_t RXCRCR; + volatile uint32_t TXCRCR; + volatile uint32_t I2SCFGR; + volatile uint32_t I2SPR; +}; + +class SPI_t { + public: + SPI_reg_t& reg; + + SPI_t(uint32_t reg_addr) : reg(*(SPI_reg_t*)reg_addr) {} +}; + +#if defined(STM32F1) + +#elif defined(STM32F4) +static SPI_t SPI1(0x40013000); +static SPI_t SPI2(0x40003800); +static SPI_t SPI3(0x40003c00); +#endif + +#endif diff --git a/startup/entry.cpp b/startup/entry.cpp new file mode 100644 index 0000000..d7385f8 --- /dev/null +++ b/startup/entry.cpp @@ -0,0 +1,63 @@ +#include +#include + +int main(); + +typedef void (*funcp_t)(); + +// Symbols from linker script. +extern uint32_t _data_rom; +extern uint32_t _data_start; +extern uint32_t _data_end; +extern uint32_t _bss_start; +extern uint32_t _bss_end; +extern funcp_t _init_array_start; +extern funcp_t _init_array_end; +extern funcp_t _fini_array_start; +extern funcp_t _fini_array_end; + +void __attribute__((naked)) entry() { + // Initialize HAL. + rcc_init(); + + // Load .data from rom image. + uint32_t* rp = &_data_rom; + uint32_t* wp = &_data_start; + + while(wp < &_data_end) { + *wp++ = *rp++; + } + + // Clear .bss. + wp = &_bss_start; + + while(wp < &_bss_end) { + *wp++ = 0; + } + + // Call constructors. + funcp_t* fp = &_init_array_start; + + while(fp < &_init_array_end) { + (*fp++)(); + } + + // Call main(). + main(); + + // Call destructors. + fp = &_fini_array_start; + + while(fp < &_fini_array_end) { + (*fp++)(); + } + + // Halt. + while(1); +} + +extern "C" void __cxa_pure_virtual() { + while (1); +} + +void* __dso_handle = 0; diff --git a/timer/timer.h b/timer/timer.h new file mode 100644 index 0000000..f9305de --- /dev/null +++ b/timer/timer.h @@ -0,0 +1,40 @@ +#ifndef TIMER_H +#define TIMER_H + +struct TIM_t { + volatile uint32_t CR1; + volatile uint32_t CR2; + volatile uint32_t SMCR; + volatile uint32_t DIER; + volatile uint32_t SR; + volatile uint32_t EGR; + volatile uint32_t CCMR1; + volatile uint32_t CCMR2; + volatile uint32_t CCER; + volatile uint32_t CNT; + volatile uint32_t PSC; + volatile uint32_t ARR; + volatile uint32_t RCR; + volatile uint32_t CCR1; + volatile uint32_t CCR2; + volatile uint32_t CCR3; + volatile uint32_t CCR4; + volatile uint32_t BDTR; + volatile uint32_t DCR; + volatile uint32_t DMAR; +}; + +#if defined(STM32F1) +static TIM_t& TIM1 = *(TIM_t*)0x40012c00; +static TIM_t& TIM2 = *(TIM_t*)0x40000000; +static TIM_t& TIM3 = *(TIM_t*)0x40000400; +static TIM_t& TIM4 = *(TIM_t*)0x40000800; +static TIM_t& TIM5 = *(TIM_t*)0x40000c00; +static TIM_t& TIM6 = *(TIM_t*)0x40001000; +static TIM_t& TIM7 = *(TIM_t*)0x40001400; +static TIM_t& TIM8 = *(TIM_t*)0x40013400; +#elif defined(STM32F4) +static TIM_t& TIM2 = *(TIM_t*)0x40000000; +#endif + +#endif diff --git a/usart/usart.cpp b/usart/usart.cpp new file mode 100644 index 0000000..61fe393 --- /dev/null +++ b/usart/usart.cpp @@ -0,0 +1,7 @@ +#include "usart.h" + +template<> +void interrupt() { + USART1.recv(); + //GPIOB.ODR ^= 1 << 1; +} diff --git a/usart/usart.h b/usart/usart.h new file mode 100644 index 0000000..38f1879 --- /dev/null +++ b/usart/usart.h @@ -0,0 +1,68 @@ +#ifndef USART_H +#define USART_H + +#include +#include +#include + +struct USART_reg_t { + volatile uint32_t SR; + volatile uint32_t DR; + volatile uint32_t BRR; + volatile uint32_t CR1; + volatile uint32_t CR2; + volatile uint32_t CR3; + volatile uint32_t GTPR; +}; + +class USART_t { + public: + USART_reg_t& reg; + const uint32_t clk; + + USART_t(uint32_t reg_addr, uint32_t bus_clk) : reg(*(USART_reg_t*)reg_addr), clk(bus_clk) {} + + inline void set_baudrate(uint32_t baudrate) { + reg.BRR = clk / baudrate; + } + + inline void enable() { + reg.CR1 = 0x202c; + } + + inline void send(uint8_t data) { + while(!(reg.SR & 0x80)) { + Thread::yield(); + } // Wait for TXE. + + reg.DR = data; + } + + inline uint8_t recv() { + return reg.DR; + } +}; + +#if defined(STM32F1) +static USART_t USART1(0x40013800, 72000000); +static USART_t USART2(0x40004400, 36000000); +static USART_t USART3(0x40004800, 36000000); +#elif defined(STM32F4) +static USART_t USART1(0x40011000, 84000000); +static USART_t USART2(0x40004400, 42000000); +static USART_t USART3(0x40004800, 42000000); +#endif + +inline void usart_enable() { + RCC.enable(RCC.USART1); + USART1.set_baudrate(115200); + USART1.enable(); + + //Interrupt::enable(Interrupt::USART1); +} + +inline void usart_send(uint8_t data) { + USART1.send(data); +} + +#endif diff --git a/usb/usb.h b/usb/usb.h new file mode 100644 index 0000000..c8c550f --- /dev/null +++ b/usb/usb.h @@ -0,0 +1,93 @@ +#ifndef USB_H +#define USB_H + +#include + +struct USB_reg_t { + volatile uint32_t GOTGCTL; + volatile uint32_t GOTGINT; + volatile uint32_t GAHBCFG; + volatile uint32_t GUSBCFG; + volatile uint32_t GRSTCTL; + volatile uint32_t GINTSTS; + volatile uint32_t GINTMSK; + volatile uint32_t GRXSTSR; + volatile uint32_t GRXSTSP; + volatile uint32_t GRXFSIZ; + volatile uint32_t DIEPTXF0; + volatile uint32_t HNPTXSTS; + uint32_t _reserved[2]; + volatile uint32_t GCCFG; + volatile uint32_t CID; + uint32_t _reserved1[48]; + volatile uint32_t HPTXFSIZ; + volatile uint32_t DIEPTXF1; + volatile uint32_t DIEPTXF2; + volatile uint32_t DIEPTXF3; +}; + +struct USB_dev_reg_t { + volatile uint32_t DCFG; + volatile uint32_t DCTL; + volatile uint32_t DSTS; + uint32_t _reserved; + volatile uint32_t DIEPMSK; + volatile uint32_t DOEPMSK; + volatile uint32_t DAINT; + volatile uint32_t DAINTMSK; + uint32_t _reserved1[2]; + volatile uint32_t DVBUSDIS; + volatile uint32_t DVBUSPULSE; + uint32_t _reserved2; + volatile uint32_t DIEPEMPMSK; +}; + +struct USB_dev_iep_reg_t { + volatile uint32_t DIEPCTL; + uint32_t _reserved; + volatile uint32_t DIEPINT; + uint32_t _reserved1; + volatile uint32_t DIEPTSIZ; + uint32_t _reserved2; + volatile uint32_t DTXFSTS; + uint32_t _reserved3; +}; + +struct USB_dev_oep_reg_t { + volatile uint32_t DOEPCTL; + uint32_t _reserved; + volatile uint32_t DOEPINT; + uint32_t _reserved1; + volatile uint32_t DOEPTSIZ; + uint32_t _reserved2[3]; +}; + +union USB_fifo_reg_t { + volatile uint32_t reg; + volatile uint32_t buf[1024]; +}; + +class USB_t { + public: + USB_reg_t& reg; + USB_dev_reg_t& dev_reg; + USB_dev_iep_reg_t* const dev_iep_reg; + USB_dev_oep_reg_t* const dev_oep_reg; + USB_fifo_reg_t* const fifo; + + USB_t(uint32_t reg_addr) : + reg(*(USB_reg_t*)reg_addr), + dev_reg(*(USB_dev_reg_t*)(reg_addr + 0x800)), + dev_iep_reg((USB_dev_iep_reg_t*)(reg_addr + 0x900)), + dev_oep_reg((USB_dev_oep_reg_t*)(reg_addr + 0xb00)), + fifo((USB_fifo_reg_t*)(reg_addr + 0x1000)) {} +}; + +#if defined(STM32F1) + +#elif defined(STM32F4) +static USB_t OTG_FS(0x50000000); +static USB_t OTG_HS(0x40040000); +#endif + +#endif -- cgit v1.2.3