summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2015-03-29 21:37:03 +0200
committerVegard Storheil Eriksen <zyp@jvnv.net>2016-08-18 23:36:07 +0200
commit7b2d322df819e8a339cdb534e69d8e205765d3b2 (patch)
treec18a85a712285d6f3939113824eb2f2636833992
parent29d8f1b4e89f31e2f3b448c4d40c6c2518629686 (diff)
Added STM32L0 support.
-rw-r--r--build_rules8
-rw-r--r--gpio/gpio.h22
-rw-r--r--i2c/i2c.cpp2
-rw-r--r--interrupt/fault.cpp4
-rw-r--r--interrupt/interrupt.cpp4
-rw-r--r--ld_scripts/arm_flash_ram.ld2
-rw-r--r--ld_scripts/stm32_l0_8.ld6
-rw-r--r--rcc/flash.h19
-rw-r--r--rcc/rcc.h75
-rw-r--r--syscfg/syscfg.h24
-rw-r--r--usart/usart.h5
-rw-r--r--usb/f1_usb.h1
-rw-r--r--usb/l0_usb.h174
-rw-r--r--usb/l0_usb_def.h37
-rw-r--r--usb/usb.h5
15 files changed, 374 insertions, 14 deletions
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 <os/time.h>
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<Interrupt::DMA2_Channel4_5>() __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::NMI>,
interrupt<Interrupt::HardFault>,
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 <stdint.h>
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 <stdint.h>
+
+#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 <stdint.h>
+
+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