From 7b2d322df819e8a339cdb534e69d8e205765d3b2 Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Sun, 29 Mar 2015 21:37:03 +0200 Subject: Added STM32L0 support. --- build_rules | 8 ++ gpio/gpio.h | 22 ++++-- i2c/i2c.cpp | 2 + interrupt/fault.cpp | 4 + interrupt/interrupt.cpp | 4 +- ld_scripts/arm_flash_ram.ld | 2 + ld_scripts/stm32_l0_8.ld | 6 ++ rcc/flash.h | 19 ++++- rcc/rcc.h | 75 ++++++++++++++++++- syscfg/syscfg.h | 24 ++++++ usart/usart.h | 5 +- usb/f1_usb.h | 1 - usb/l0_usb.h | 174 ++++++++++++++++++++++++++++++++++++++++++++ usb/l0_usb_def.h | 37 ++++++++++ usb/usb.h | 5 ++ 15 files changed, 374 insertions(+), 14 deletions(-) create mode 100644 ld_scripts/stm32_l0_8.ld create mode 100644 syscfg/syscfg.h create mode 100644 usb/l0_usb.h create mode 100644 usb/l0_usb_def.h diff --git a/build_rules b/build_rules index 42878b7..6137608 100644 --- a/build_rules +++ b/build_rules @@ -81,6 +81,14 @@ def select_stm32(env, variant): 'g': 'stm32_f4_g.ld', }[flash] + elif family in ('l051', 'l052', 'l053'): + select_arm(env, 'cortex-m0plus') + env.Append(CPPDEFINES = ['STM32L0']) + + env['LINK_SCRIPT'] = { + '8': 'stm32_l0_8.ld', + }[flash] + else: print 'Unknown stm32 family: %s' % family Exit(1) diff --git a/gpio/gpio.h b/gpio/gpio.h index 8a47a46..3ac9b6d 100644 --- a/gpio/gpio.h +++ b/gpio/gpio.h @@ -12,7 +12,7 @@ struct GPIO_reg_t { volatile uint32_t BSRR; volatile uint32_t BRR; volatile uint32_t LCKR; - #elif defined(STM32F3) || defined(STM32F4) + #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) volatile uint32_t MODER; volatile uint32_t OTYPER; volatile uint32_t OSPEEDR; @@ -45,7 +45,7 @@ class GPIO_t { Output = 0x3, AF = 0xb, Analog = 0x0, - #elif defined(STM32F3) || defined(STM32F4) + #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) Input, Output, AF, @@ -78,7 +78,7 @@ class GPIO_t { } else { g.reg.CRH = (g.reg.CRH & ~(0xf << (n * 4 - 32))) | m << (n * 4 - 32); } - #elif defined(STM32F3) || defined(STM32F4) + #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) g.reg.MODER = (g.reg.MODER & ~(3 << (n * 2))) | m << (n * 2); #endif } @@ -86,7 +86,7 @@ class GPIO_t { void set_type(Type t) { #if defined(STM32F1) // TODO: Unified configure() method? - #elif defined(STM32F3) || defined(STM32F4) + #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) if(t) { g.reg.OTYPER |= 1 << n; } else { @@ -98,13 +98,13 @@ class GPIO_t { void set_pull(Pull p) { #if defined(STM32F1) // TODO: Unified configure() method? - #elif defined(STM32F3) || defined(STM32F4) + #elif defined(STM32F3) || defined(STM32F4) || defined(STM32L0) g.reg.PUPDR = (g.reg.PUPDR & ~(3 << (n * 2))) | p << (n * 2); #endif } void set_af(int af) { - #if defined(STM32F3) || defined(STM32F4) + #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) if(n < 8) { g.reg.AFRL = (g.reg.AFRL & ~(0xf << (n * 4))) | af << (n * 4); } else { @@ -114,7 +114,7 @@ class GPIO_t { } void set_speed(Speed s) { - #if defined(STM32F3) || defined(STM32F4) + #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) g.reg.OSPEEDR = (g.reg.OSPEEDR & ~(3 << (n * 2))) | s << (n * 2); #endif } @@ -161,7 +161,7 @@ class GPIO_t { public: constexpr PinArray(const GPIO_t& gpio, int first, int last) : g(gpio), f(first), l(last) {} - #if defined(STM32F3) || defined(STM32F4) + #if defined(STM32F3) || defined(STM32F4) || defined(STM32L0) void set_mode(Pin::Mode m) { g.reg.MODER = (g.reg.MODER & ~mask2()) | ((0x55555555 * m) & mask2()); } @@ -222,6 +222,12 @@ static GPIO_t GPIOF(0x40021400); static GPIO_t GPIOG(0x40021800); static GPIO_t GPIOH(0x40021c00); static GPIO_t GPIOI(0x40022000); +#elif defined(STM32L0) +static GPIO_t GPIOA(0x50000000); +static GPIO_t GPIOB(0x50000400); +static GPIO_t GPIOC(0x50000800); +static GPIO_t GPIOD(0x50000c00); +static GPIO_t GPIOH(0x50001c00); #endif #endif diff --git a/i2c/i2c.cpp b/i2c/i2c.cpp index 6aa25fc..d4a3d3a 100644 --- a/i2c/i2c.cpp +++ b/i2c/i2c.cpp @@ -12,6 +12,7 @@ I2C_t I2C2(0x40005800, 42000000, Interrupt::I2C2_EV, Interrupt::I2C2_ER); //I2C_t I2C3(0x40005c00, 42000000, Interrupt::I2C3_EV, Interrupt::I2C3_ER); #endif +#if defined(STM32F1) || defined(STM32F4) void I2C_t::irq_ev() { uint32_t sr1 = reg.SR1; reg.SR2; @@ -133,3 +134,4 @@ void I2C_t::read_reg(uint8_t addr_, uint8_t reg_, uint8_t len, uint8_t* buf) { Thread::yield(); } } +#endif diff --git a/interrupt/fault.cpp b/interrupt/fault.cpp index 016b74b..0a0410b 100644 --- a/interrupt/fault.cpp +++ b/interrupt/fault.cpp @@ -3,6 +3,8 @@ #include inline void __attribute__((naked)) switch_context() { + #if ! defined(STM32L0) // TODO: cortex-m0/+ unsupported for now. + asm volatile ("cpsid i"); // Save unsaved registers. @@ -21,6 +23,8 @@ inline void __attribute__((naked)) switch_context() { // Load registers and return. asm volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" ::: "memory"); + + #endif } template<> diff --git a/interrupt/interrupt.cpp b/interrupt/interrupt.cpp index 611b09c..ebda829 100644 --- a/interrupt/interrupt.cpp +++ b/interrupt/interrupt.cpp @@ -89,8 +89,10 @@ template<> void interrupt() __attribute__ ((weak, al typedef void (*vector_t)(); +extern uint32_t _ram_end; + vector_t vectors[] __attribute__((section(".vectors"))) = { - (vector_t)0x20004ffc, + (vector_t)&_ram_end, entry, interrupt, interrupt, diff --git a/ld_scripts/arm_flash_ram.ld b/ld_scripts/arm_flash_ram.ld index 9e3f983..34b8a80 100644 --- a/ld_scripts/arm_flash_ram.ld +++ b/ld_scripts/arm_flash_ram.ld @@ -75,4 +75,6 @@ SECTIONS { . = ALIGN(4); PROVIDE(_bss_end = .); } > ram + + PROVIDE(_ram_end = ORIGIN(ram) + LENGTH(ram)); } diff --git a/ld_scripts/stm32_l0_8.ld b/ld_scripts/stm32_l0_8.ld new file mode 100644 index 0000000..289255c --- /dev/null +++ b/ld_scripts/stm32_l0_8.ld @@ -0,0 +1,6 @@ +MEMORY { + flash (rx) : org = 0x08000000, len = 64k + ram (rwx) : org = 0x20000000, len = 8k +} + +INCLUDE "arm_flash_ram.ld" diff --git a/rcc/flash.h b/rcc/flash.h index abb3484..d53fa2c 100644 --- a/rcc/flash.h +++ b/rcc/flash.h @@ -4,18 +4,33 @@ #include struct FLASH_t { + #if defined(STM32F1) || defined(STM32F3) volatile uint32_t ACR; volatile uint32_t KEYR; volatile uint32_t OPTKEYR; volatile uint32_t SR; volatile uint32_t CR; - #if defined(STM32F1) || defined(STM32F3) volatile uint32_t AR; volatile uint32_t RESERVED; volatile uint32_t OBR; volatile uint32_t WRPR; #elif defined(STM32F4) + volatile uint32_t ACR; + volatile uint32_t KEYR; + volatile uint32_t OPTKEYR; + volatile uint32_t SR; + volatile uint32_t CR; volatile uint32_t OPTCR; + #elif defined(STM32L0) + volatile uint32_t ACR; + volatile uint32_t PECR; + volatile uint32_t PDKEYR; + volatile uint32_t PKEYR; + volatile uint32_t PRGKEYR; + volatile uint32_t OPTKEYR; + volatile uint32_t SR; + volatile uint32_t OPTR; + volatile uint32_t WRPROT; #endif }; @@ -23,6 +38,8 @@ struct FLASH_t { static FLASH_t& FLASH = *(FLASH_t*)0x40022000; #elif defined(STM32F4) static FLASH_t& FLASH = *(FLASH_t*)0x40023c00; +#elif defined(STM32L0) +static FLASH_t& FLASH = *(FLASH_t*)0x40022000; #endif void flash_init(); diff --git a/rcc/rcc.h b/rcc/rcc.h index 650e47d..ed8905d 100644 --- a/rcc/rcc.h +++ b/rcc/rcc.h @@ -64,6 +64,28 @@ struct RCC_t { volatile uint32_t _2; volatile uint32_t SSCGR; volatile uint32_t PLLI2SCFGR; + #elif defined(STM32L0) + volatile uint32_t CR; + volatile uint32_t ICSCR; + volatile uint32_t CRRCR; + volatile uint32_t CFGR; + volatile uint32_t CIER; + volatile uint32_t CIFR; + volatile uint32_t CICR; + volatile uint32_t IOPRSTR; + volatile uint32_t AHBRSTR; + volatile uint32_t APB2RSTR; + volatile uint32_t APB1RSTR; + volatile uint32_t IOPENR; + volatile uint32_t AHBENR; + volatile uint32_t APB2ENR; + volatile uint32_t APB1ENR; + volatile uint32_t IOPSMENR; + volatile uint32_t AHBSMENR; + volatile uint32_t APB2SMENR; + volatile uint32_t APB1SMENR; + volatile uint32_t CCIPR; + volatile uint32_t CSR; #endif #if defined(STM32F1) @@ -245,9 +267,53 @@ struct RCC_t { TIM10 = 1 << 17, TIM11 = 1 << 18, }; + #elif defined(STM32L0) + enum AHB_dev { + DMA = 1 << 0, + MIF = 1 << 8, + CRC = 1 << 12, + TOUCH = 1 << 16, + RNG = 1 << 20, + CRYP = 1 << 24, + }; + + enum APB1_dev { + TIM2 = 1 << 0, + TIM6 = 1 << 4, + WWDG = 1 << 11, + SPI2 = 1 << 14, + USART2 = 1 << 17, + LPUART1 = 1 << 18, + I2C1 = 1 << 21, + I2C2 = 1 << 22, + USB = 1 << 23, + CRS = 1 << 27, + PWR = 1 << 28, + DAC = 1 << 29, + LPTIM1 = 1 << 31, + }; + + enum APB2_dev { + SYSCFG = 1 << 0, + TIM21 = 1 << 2, + TIM22 = 1 << 5, + MIFI = 1 << 7, + ADC = 1 << 9, + SPI1 = 1 << 12, + USART1 = 1 << 14, + DBG = 1 << 22, + }; + + enum IOP_dev { + GPIOA = 1 << 0, + GPIOB = 1 << 1, + GPIOC = 1 << 2, + GPIOD = 1 << 3, + GPIOH = 1 << 7, + }; #endif - #if defined(STM32F1) || defined(STM32F3) + #if defined(STM32F1) || defined(STM32F3) || defined(STM32L0) inline void enable(AHB_dev dev) { AHBENR |= dev; } @@ -271,9 +337,14 @@ struct RCC_t { inline void enable(APB2_dev dev) { APB2ENR |= dev; } + #if defined(STM32L0) + inline void enable(IOP_dev dev) { + IOPENR |= dev; + } + #endif }; -#if defined(STM32F1) || defined(STM32F3) +#if defined(STM32F1) || defined(STM32F3) || defined(STM32L0) static RCC_t& RCC = *(RCC_t*)0x40021000; #elif defined(STM32F4) static RCC_t& RCC = *(RCC_t*)0x40023800; diff --git a/syscfg/syscfg.h b/syscfg/syscfg.h new file mode 100644 index 0000000..c29d574 --- /dev/null +++ b/syscfg/syscfg.h @@ -0,0 +1,24 @@ +#ifndef SYSCFG_H +#define SYSCFG_H + +#include + +#if defined(STM32L0) + +struct SYSCFG_t { + volatile uint32_t CFGR1; + volatile uint32_t CFGR2; + volatile uint32_t EXTICR1; + volatile uint32_t EXTICR2; + volatile uint32_t EXTICR3; + volatile uint32_t EXTICR4; + volatile uint32_t COMP1_CTRL; + volatile uint32_t COMP2_CTRL; + volatile uint32_t CFGR3; +}; + +static SYSCFG_t& SYSCFG = *(SYSCFG_t*)0x40010000; + +#endif + +#endif diff --git a/usart/usart.h b/usart/usart.h index c075b9b..f318d3e 100644 --- a/usart/usart.h +++ b/usart/usart.h @@ -15,7 +15,7 @@ struct USART_reg_t { volatile uint32_t CR3; volatile uint32_t GTPR; }; -#elif defined(STM32F3) +#elif defined(STM32F3) || defined(STM32L0) struct USART_reg_t { volatile uint32_t CR1; volatile uint32_t CR2; @@ -51,6 +51,9 @@ static USART_t USART3(0x40004800, 36000000); static USART_t USART1(0x40011000, 84000000); static USART_t USART2(0x40004400, 42000000); static USART_t USART3(0x40004800, 42000000); +#elif defined(STM32L0) +static USART_t USART1(0x40013800, 32000000); +static USART_t USART2(0x40004400, 32000000); #endif #endif diff --git a/usb/f1_usb.h b/usb/f1_usb.h index 166c051..8510bb9 100644 --- a/usb/f1_usb.h +++ b/usb/f1_usb.h @@ -3,7 +3,6 @@ #include "generic.h" #include "f1_usb_def.h" -#include "dwc_otg_def.h" class USB_f1 : public USB_generic { private: diff --git a/usb/l0_usb.h b/usb/l0_usb.h new file mode 100644 index 0000000..243f19b --- /dev/null +++ b/usb/l0_usb.h @@ -0,0 +1,174 @@ +#ifndef L0_USB_H +#define L0_USB_H + +#include "generic.h" +#include "l0_usb_def.h" + +class USB_l0 : public USB_generic { + private: + L0_USB_t& usb; + + uint32_t setupbuf[16]; + + uint32_t buf_end; + + uint8_t pending_addr; + + protected: + virtual void hw_set_address(uint8_t addr) { + usb_rblog.log("SetAddress: %d", addr); + + pending_addr = addr; + } + + virtual void hw_conf_ep(uint8_t ep, EPType type, uint32_t size) { + usb_rblog.log("Configuring EP%02x: size=%d", ep, size); + + uint8_t in = ep & 0x80; + ep &= 0x7f; + + uint32_t old_epr = usb.reg.EPR[ep]; + //uint32_t new_epr = 0x3220; + uint32_t new_epr = 0x8080 | ((type == EPType::Bulk ? 0 : type == EPType::Control ? 1 : type == EPType::Isochronous ? 2 : 3) << 9) | ep; + + if(in || ep == 0) { + usb.bufd[ep].ADDR_TX = buf_end; + buf_end += size; + + new_epr |= (old_epr & 0x0070) ^ 0x0020; + } + + if(!in) { + usb.bufd[ep].ADDR_RX = buf_end; + buf_end += size; + usb.bufd[ep].COUNT_RX = 0x8000 | (1 << 10); + + new_epr |= (old_epr & 0x7000) ^ 0x3000; + } + + usb.reg.EPR[ep] = new_epr; + + usb_rblog.log("EPR: old=%04x, new=%04x", old_epr, usb.reg.EPR[ep]); + } + + virtual void hw_set_stall(uint8_t ep) { + usb_rblog.log("Setting stall on EP %d", ep); + + usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x878f) | 0x2030; + + //otg.dev_iep_reg[ep].DIEPCTL |= (1 << 21); + } + + public: + USB_l0(L0_USB_t& usb_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), usb(usb_periph) {} + + void init() { + usb.reg.CNTR = 3; + Time::sleep(10); + usb.reg.CNTR = 1; + Time::sleep(10); + // Exit power down mode. + usb.reg.CNTR = 0; + } + + void process() { + uint32_t istr = usb.reg.ISTR; + + if(istr & (1 << 10)) { + usb_rblog.log("USB Reset"); + + buf_end = 0x40; + + usb.reg.DADDR = 0x80; + + handle_reset(); + + usb.reg.ISTR = ~(1 << 10); + + return; + } + + if(istr & (1 << 15)) { + usb_rblog.log("USB Transfer: %02x", istr & 0x1f); + + uint32_t ep = istr & 0xf; + uint32_t dir = istr & 0x10; + + usb_rblog.log("EPR%d: %04x", ep, usb.reg.EPR[ep]); + + if(dir) { + // RX. + + usb_rblog.log("RXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_RX, usb.bufd[ep].COUNT_RX); + + uint32_t len = usb.bufd[ep].COUNT_RX & 0x03ff; + + if(usb.reg.EPR[ep] & (1 << 11)) { + usb_rblog.log("SETUP packet received"); + + read(0, setupbuf, 8); + + handle_setup(setupbuf); + + } else { + usb_rblog.log("OUT packet received"); + + handle_out(ep, len); + } + + //usb.reg.EPR[ep] = 0x9280; + //usb.reg.EPR[ep] &= 0x078f; + + usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x078f) | 0x1000; + } else { + // TX. + + usb_rblog.log("TXBUF: ADDR: %04x, COUNT: %04x", usb.bufd[ep].ADDR_TX, usb.bufd[ep].COUNT_TX); + + if(pending_addr) { + usb_rblog.log("Actually changing addr to: %d", pending_addr); + + usb.reg.DADDR = 0x80 | pending_addr; + + pending_addr = 0; + } + + usb.reg.EPR[ep] &= 0x870f; + } + usb_rblog.log("Leaving: EPR%d: %04x", ep, usb.reg.EPR[ep]); + } + } + + virtual bool ep_ready(uint32_t ep) { + return (usb.reg.EPR[ep] & 0x30) == 0x20; + } + + virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { + usb_rblog.log("Writing, ep=%d, len=%d", ep, len); + + uint16_t* p = (uint16_t*)bufp; + uint32_t base = usb.bufd[ep].ADDR_TX >> 1; + + for(uint32_t i = 0; i < len; i += 2) { + usb.buf[base + (i >> 1)] = *p++; + } + + usb.bufd[ep].COUNT_TX = len; + usb.reg.EPR[ep] = (usb.reg.EPR[ep] & 0x870f) | 0x0010; + } + + virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) { + usb_rblog.log("Reading, ep=%d, len=%d", ep, len); + + uint16_t* p = (uint16_t*)bufp; + uint32_t base = usb.bufd[ep].ADDR_RX >> 1; + + for(uint32_t i = 0; i < len; i += 2) { + *p++ = uint16_t(usb.buf[base + (i >> 1)]); + } + + return len; + } +}; + +#endif diff --git a/usb/l0_usb_def.h b/usb/l0_usb_def.h new file mode 100644 index 0000000..b9d8d10 --- /dev/null +++ b/usb/l0_usb_def.h @@ -0,0 +1,37 @@ +#ifndef L0_USB_DEF_H +#define L0_USB_DEF_H + +#include + +class L0_USB_t { + private: + struct L0_USB_reg_t { + volatile uint32_t EPR[16]; + volatile uint32_t CNTR; + volatile uint32_t ISTR; + volatile uint32_t FNR; + volatile uint32_t DADDR; + volatile uint32_t BTABLE; + volatile uint32_t LPMCSR; + volatile uint32_t BCDR; + }; + + struct L0_USB_bufd_t { + volatile uint16_t ADDR_TX; + volatile uint16_t COUNT_TX; + volatile uint16_t ADDR_RX; + volatile uint16_t COUNT_RX; + }; + + public: + L0_USB_reg_t& reg; + L0_USB_bufd_t* bufd; + volatile uint16_t* buf; + + L0_USB_t(uint32_t reg_addr, uint32_t buf_addr) : + reg(*(L0_USB_reg_t*)reg_addr), + bufd((L0_USB_bufd_t*)buf_addr), + buf((volatile uint16_t*)buf_addr) {} +}; + +#endif diff --git a/usb/usb.h b/usb/usb.h index b6a45f2..f37f4a1 100644 --- a/usb/usb.h +++ b/usb/usb.h @@ -12,6 +12,11 @@ static F1_USB_t USB(0x40005c00, 0x40006000); static DWC_OTG_t OTG_FS(0x50000000); static DWC_OTG_t OTG_HS(0x40040000); +#elif defined(STM32L0) +#include "l0_usb.h" + +static L0_USB_t USB(0x40005c00, 0x40006000); + #endif #endif -- cgit v1.2.3