summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2012-03-16 20:21:09 -0700
committerKeith Packard <keithp@keithp.com>2012-03-28 21:37:02 -0700
commit9279fd42793123784ce83ca151df6f4630487722 (patch)
tree4aa915f83ee5aafbeda8d6df5c32044684e0acae
parente2f13aa43ba79becbff6c9bfc18c665a58d96185 (diff)
Add STM platform and stm-bringup demo program
The stm-bringup doesn't run altos, it just initializes the device and writes stuff over a serial port. Works on the STM32L Discovery board at least, should do stuff on other boards too. Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--src/stm-bringup/Makefile (renamed from ao-bringup/stm/Makefile)0
-rw-r--r--src/stm-bringup/bringup.c (renamed from ao-bringup/stm/bringup.c)0
-rw-r--r--src/stm/altos-ram.ld69
-rw-r--r--src/stm/altos.ld72
-rw-r--r--src/stm/ao_arch.h129
-rw-r--r--src/stm/ao_interrupt.c169
-rw-r--r--src/stm/ao_led.c69
-rw-r--r--src/stm/ao_serial_stm.c184
-rw-r--r--src/stm/ao_timer.c167
-rw-r--r--src/stm/registers.ld47
-rw-r--r--src/stm/stm32l.h662
11 files changed, 1568 insertions, 0 deletions
diff --git a/ao-bringup/stm/Makefile b/src/stm-bringup/Makefile
index 49966a4f..49966a4f 100644
--- a/ao-bringup/stm/Makefile
+++ b/src/stm-bringup/Makefile
diff --git a/ao-bringup/stm/bringup.c b/src/stm-bringup/bringup.c
index b6fe458d..b6fe458d 100644
--- a/ao-bringup/stm/bringup.c
+++ b/src/stm-bringup/bringup.c
diff --git a/src/stm/altos-ram.ld b/src/stm/altos-ram.ld
new file mode 100644
index 00000000..b8fffedc
--- /dev/null
+++ b/src/stm/altos-ram.ld
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+MEMORY {
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
+}
+
+C_STACK_SIZE = 512;
+
+INCLUDE registers.ld
+
+SECTIONS {
+ . = ORIGIN(ram);
+
+ /*
+ * Rom contents
+ */
+
+ __text_start__ = .;
+
+ .text : {
+ *(.interrupt) /* Interrupt vectors */
+ *(.text) /* Executable code */
+ *(.rodata) /* Constants */
+ } > ram
+
+ .ARM.exidx : {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ __text_end__ = .;
+ } > ram
+
+ __data_start__ = .;
+
+ /* Data -- relocated to RAM, but written to ROM
+ */
+ .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
+ *(.data) /* initialized data */
+ __data_end__ = .;
+ __bss_start__ = .;
+ } >ram
+
+ .bss : {
+ *(.bss)
+ *(COMMON)
+ __bss_end__ = .;
+ } >ram
+
+ PROVIDE(__stack__ = . + C_STACK_SIZE);
+ PROVIDE(end = .);
+
+}
+
+ENTRY(start);
+
+
diff --git a/src/stm/altos.ld b/src/stm/altos.ld
new file mode 100644
index 00000000..4e955666
--- /dev/null
+++ b/src/stm/altos.ld
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+MEMORY {
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+ ram (!w) : ORIGIN = 0x20000000, LENGTH = 16K
+}
+
+INCLUDE registers.ld
+
+EXTERN (stm_interrupt_vector)
+C_STACK_SIZE = 512;
+
+SECTIONS {
+ . = ORIGIN(rom);
+
+ /*
+ * Rom contents
+ */
+
+ __text_start__ = .;
+
+ .text : {
+ *(.interrupt) /* Interrupt vectors */
+ *(.text) /* Executable code */
+ *(.rodata) /* Constants */
+ } > rom
+
+ .ARM.exidx : {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ __text_end__ = .;
+ } > rom
+
+ . = ORIGIN(ram);
+ __data_start__ = .;
+
+ /* Data -- relocated to RAM, but written to ROM
+ */
+ .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
+ *(.data) /* initialized data */
+ __data_end__ = .;
+ __bss_start__ = .;
+ } >ram
+
+ .bss : {
+ *(.bss)
+ *(COMMON)
+ __bss_end__ = .;
+ } >ram
+
+ PROVIDE(__stack__ = . + C_STACK_SIZE);
+ PROVIDE(end = .);
+
+}
+
+ENTRY(start);
+
+
diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h
new file mode 100644
index 00000000..e6f54fdb
--- /dev/null
+++ b/src/stm/ao_arch.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <stdio.h>
+#include <stm32l.h>
+
+/*
+ * STM32L definitions and code fragments for AltOS
+ */
+
+#define AO_STACK_SIZE 256
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare __attribute__((naked))
+#define ao_arch_naked_define
+#define __pdata
+#define __data
+#define __xdata
+#define __code const
+#define __reentrant
+#define __critical
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() /* XXX */
+
+#define ao_arch_nop() asm("nop")
+
+#define ao_arch_interrupt(n) /* nothing */
+
+#undef putchar
+#undef getchar
+#define putchar(c) ao_putchar(c)
+#define getchar ao_getchar
+
+extern void putchar(char c);
+extern char getchar(void);
+extern void ao_avr_stdio_init(void);
+
+extern const uint16_t ao_serial_number;
+
+#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
+
+#define ao_arch_task_members\
+ uint32_t *sp; /* saved stack pointer */
+
+#define cli() asm("cpsid i")
+#define sei() asm("cpsie i")
+
+#define ao_arch_init_stack(task, start) do { \
+ uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); \
+ uint16_t a = (uint16_t) start; \
+ int i; \
+ \
+ /* Return address */ \
+ ARM_PUSH32(sp, a); \
+ \
+ /* Invalid link register */ \
+ ARM_PUSH32(sp, 0xffffffff); \
+ \
+ /* Clear register values */ \
+ i = 13; \
+ while (i--) \
+ ARM_PUSH32(sp, 0); \
+ \
+ /* PSR with interrupts enabled */ \
+ ARM_PUSH32(sp, 0x01000000); \
+ task->sp = sp; \
+} while (0);
+
+#define ao_arch_save_regs() do { \
+ asm("push {r0-r12,lr}\n"); \
+ cli(); \
+ asm("mrs r0,psr" "\n\t" "push {r0}"); \
+ sei(); \
+ } while (0)
+
+#define ao_arch_save_stack() do { \
+ uint32_t sp; \
+ asm("mov %0,sp" : "=&r" (sp) ); \
+ ao_cur_task->sp = (uint32_t *) (sp); \
+ } while (0)
+
+#define ao_arch_isr_stack() /* nothing */
+
+#define ao_arch_cpu_idle() do { \
+ asm("wfi"); \
+ } while (0)
+
+#define ao_arch_restore_stack() do { \
+ uint32_t sp; \
+ sp = (uint32_t) ao_cur_task->sp; \
+ cli(); \
+ asm("mov sp, %0" : : "r" (sp) ); \
+ asm("pop {r0}" "\n\t" "msr psr,r0"); \
+ asm("pop {r0-r12,lr}\n"); \
+ asm("bx lr"); \
+ } while(0)
+
+#define ao_arch_critical(b) do { cli(); do { b } while (0); sei(); } while (0)
+
+#define AO_ARM_NUM_ADC 12
+
+struct ao_adc {
+ uint16_t tick; /* tick when the sample was read */
+ uint16_t adc[AO_ARM_NUM_ADC]; /* samples */
+};
+
+
+#endif /* _AO_ARCH_H_ */
+
diff --git a/src/stm/ao_interrupt.c b/src/stm/ao_interrupt.c
new file mode 100644
index 00000000..6b4a9700
--- /dev/null
+++ b/src/stm/ao_interrupt.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "stm32l.h"
+#include <string.h>
+
+extern void main(void);
+extern char __stack__;
+extern char __text_start__, __text_end__;
+extern char __data_start__, __data_end__;
+extern char __bss_start__, __bss_end__;
+
+/* Interrupt functions */
+
+void stm_halt_isr(void)
+{
+ for(;;);
+}
+
+void stm_ignore_isr(void)
+{
+}
+
+void start(void) {
+ memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);
+ memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
+ main();
+}
+
+#define STRINGIFY(x) #x
+
+#define isr(name) \
+ void __attribute__ ((weak)) stm_ ## name ## _isr(void); \
+ _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_ignore_isr))
+
+#define isr_halt(name) \
+ void __attribute__ ((weak)) stm_ ## name ## _isr(void); \
+ _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_halt_isr))
+
+isr(nmi)
+isr_halt(hardfault)
+isr_halt(memmanage)
+isr_halt(busfault)
+isr_halt(usagefault)
+isr(svc)
+isr(debugmon)
+isr(pendsv)
+isr(systick)
+isr(wwdg)
+isr(pvd)
+isr(tamper_stamp)
+isr(rtc_wkup)
+isr(flash)
+isr(rcc)
+isr(exti0)
+isr(exti1)
+isr(exti2)
+isr(exti3)
+isr(exti4)
+isr(dma1_channel1)
+isr(dma1_channel2)
+isr(dma1_channel3)
+isr(dma1_channel4)
+isr(dma1_channel5)
+isr(dma1_channel6)
+isr(dma1_channel7)
+isr(adc1)
+isr(usb_hp)
+isr(usb_lp)
+isr(dac)
+isr(comp)
+isr(exti9_5)
+isr(lcd)
+isr(tim9)
+isr(tim10)
+isr(tim11)
+isr(tim2)
+isr(tim3)
+isr(tim4)
+isr(i2c1_ev)
+isr(i2c1_er)
+isr(i2c2_ev)
+isr(i2c2_er)
+isr(spi1)
+isr(spi2)
+isr(usart1)
+isr(usart2)
+isr(usart3)
+isr(exti15_10)
+isr(rtc_alarm)
+isr(usb_fs_wkup)
+isr(tim6)
+isr(tim7)
+
+#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr
+
+__attribute__ ((section(".interrupt")))
+const void *stm_interrupt_vector[] = {
+ [0] = &__stack__,
+ [1] = start,
+ i(0x08, nmi),
+ i(0x0c, hardfault),
+ i(0x10, memmanage),
+ i(0x14, busfault),
+ i(0x18, usagefault),
+ i(0x2c, svc),
+ i(0x30, debugmon),
+ i(0x38, pendsv),
+ i(0x3c, systick),
+ i(0x40, wwdg),
+ i(0x44, pvd),
+ i(0x48, tamper_stamp),
+ i(0x4c, rtc_wkup),
+ i(0x50, flash),
+ i(0x54, rcc),
+ i(0x58, exti0),
+ i(0x5c, exti1),
+ i(0x60, exti2),
+ i(0x64, exti3),
+ i(0x68, exti4),
+ i(0x6c, dma1_channel1),
+ i(0x70, dma1_channel2),
+ i(0x74, dma1_channel3),
+ i(0x78, dma1_channel4),
+ i(0x7c, dma1_channel5),
+ i(0x80, dma1_channel6),
+ i(0x84, dma1_channel7),
+ i(0x88, adc1),
+ i(0x8c, usb_hp),
+ i(0x90, usb_lp),
+ i(0x94, dac),
+ i(0x98, comp),
+ i(0x9c, exti9_5),
+ i(0xa0, lcd),
+ i(0xa4, tim9),
+ i(0xa8, tim10),
+ i(0xac, tim11),
+ i(0xb0, tim2),
+ i(0xb4, tim3),
+ i(0xb8, tim4),
+ i(0xbc, i2c1_ev),
+ i(0xc0, i2c1_er),
+ i(0xc4, i2c2_ev),
+ i(0xc8, i2c2_er),
+ i(0xcc, spi1),
+ i(0xd0, spi2),
+ i(0xd4, usart1),
+ i(0xd8, usart2),
+ i(0xdc, usart3),
+ i(0xe0, exti15_10),
+ i(0xe4, rtc_alarm),
+ i(0xe8, usb_fs_wkup),
+ i(0xec, tim6),
+ i(0xf0, tim7),
+};
diff --git a/src/stm/ao_led.c b/src/stm/ao_led.c
new file mode 100644
index 00000000..db65afdf
--- /dev/null
+++ b/src/stm/ao_led.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+__pdata uint8_t ao_led_enable;
+
+#define LED_PORT STM_GPIOD
+
+void
+ao_led_on(uint8_t colors)
+{
+ LED_PORT->odr |= (colors & ao_led_enable);
+}
+
+void
+ao_led_off(uint8_t colors)
+{
+ LED_PORT->odr &= ~(colors & ao_led_enable);
+}
+
+void
+ao_led_set(uint8_t colors)
+{
+ LED_PORT->odr = (LED_PORT->odr & ~(ao_led_enable)) | (colors & ao_led_enable);
+}
+
+void
+ao_led_toggle(uint8_t colors)
+{
+ LED_PORT->odr ^= (colors & ao_led_enable);
+}
+
+void
+ao_led_for(uint8_t colors, uint16_t ticks) __reentrant
+{
+ ao_led_on(colors);
+ ao_delay(ticks);
+ ao_led_off(colors);
+}
+
+void
+ao_led_init(uint8_t enable)
+{
+ int bit;
+
+ ao_led_enable = enable;
+ LED_PORT->odr &= ~enable;
+ for (bit = 0; bit < 16; bit++) {
+ if (enable & (1 << bit)) {
+ stm_moder_set(LED_PORT, bit, STM_MODER_OUTPUT);
+ stm_otyper_set(LED_PORT, bit, STM_OTYPER_PUSH_PULL);
+ }
+ }
+}
diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c
new file mode 100644
index 00000000..dc446120
--- /dev/null
+++ b/src/stm/ao_serial_stm.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+__xdata struct ao_fifo ao_usart1_rx_fifo;
+__xdata struct ao_fifo ao_usart1_tx_fifo;
+
+void
+ao_debug_out(char c)
+{
+ if (c == '\n')
+ ao_debug_out('\r');
+ while (!(STM_USART1->usart_sr & (1 << STM_USART_SR_TXE)));
+ STM_USART1->usart_dr = c;
+}
+
+#if 0
+static __xdata uint8_t ao_serial_tx1_started;
+
+static void
+ao_serial_tx1_start(void)
+{
+ if (!ao_fifo_empty(ao_usart1_tx_fifo) &&
+ !ao_serial_tx1_started)
+ {
+ ao_serial_tx1_started = 1;
+ ao_fifo_remove(ao_usart1_tx_fifo, STM_USART1->usart_dr);
+ }
+}
+
+void usart1_isr(void)
+{
+ if (STM_USART1->usart_sr & (1 << STM_USART_SR_RXNE)) {
+ if (!ao_fifo_full(ao_usart1_rx_fifo))
+ ao_fifo_insert(ao_usart1_rx_fifo, STM_USART1->usart_dr);
+ ao_wakeup(&ao_usart1_rx_fifo);
+#if USE_SERIAL_STDIN
+ ao_wakeup(&ao_stdin_ready);
+#endif
+ }
+ if (STM_USART1->usart_sr & (1 << STM_USART_SR_TXE)) {
+ ao_serial_tx1_started = 0;
+ ao_serial_tx1_start();
+ ao_wakeup(&ao_usart1_tx_fifo);
+ }
+}
+
+char
+ao_serial_getchar(void) __critical
+{
+ char c;
+ cli();
+ while (ao_fifo_empty(ao_usart1_rx_fifo))
+ ao_sleep(&ao_usart1_rx_fifo);
+ ao_fifo_remove(ao_usart1_rx_fifo, c);
+ sei();
+ return c;
+}
+
+#if USE_SERIAL_STDIN
+char
+ao_serial_pollchar(void) __critical
+{
+ char c;
+ cli();
+ if (ao_fifo_empty(ao_usart1_rx_fifo)) {
+ sei();
+ return AO_READ_AGAIN;
+ }
+ ao_fifo_remove(ao_usart1_rx_fifo,c);
+ sei();
+ return c;
+}
+#endif
+
+void
+ao_serial_putchar(char c) __critical
+{
+ cli();
+ while (ao_fifo_full(ao_usart1_tx_fifo))
+ ao_sleep(&ao_usart1_tx_fifo);
+ ao_fifo_insert(ao_usart1_tx_fifo, c);
+ ao_serial_tx1_start();
+ sei();
+}
+
+void
+ao_serial_drain(void) __critical
+{
+ cli();
+ while (!ao_fifo_empty(ao_usart1_tx_fifo))
+ ao_sleep(&ao_usart1_tx_fifo);
+ sei();
+}
+
+#endif
+
+int _write(int file, char *ptr, int len)
+{
+ int l = len;
+ while (l--)
+ ao_debug_out(*ptr++);
+ return len;
+}
+
+#define F_CPU 24000000
+
+static const struct {
+ uint32_t usart_brr;
+} ao_serial_speeds[] = {
+ [AO_SERIAL_SPEED_4800] = {
+ (F_CPU * 16) / (16 * 4800)
+ },
+ [AO_SERIAL_SPEED_9600] = {
+ (F_CPU * 16) / (16 * 9600)
+ },
+ [AO_SERIAL_SPEED_19200] = {
+ (F_CPU * 16) / (16 * 19200)
+ },
+ [AO_SERIAL_SPEED_57600] = {
+ (F_CPU * 16) / (16 * 57600)
+ },
+};
+
+void
+ao_serial_set_speed(uint8_t speed)
+{
+#if 0
+ ao_serial_drain();
+#endif
+ if (speed > AO_SERIAL_SPEED_57600)
+ return;
+ STM_USART1->usart_brr = ao_serial_speeds[speed].usart_brr;
+}
+
+void
+ao_serial_init(void)
+{
+ STM_USART1->usart_cr1 = ((0 << STM_USART_CR1_OVER8) |
+ (1 << STM_USART_CR1_UE) |
+ (0 << STM_USART_CR1_M) |
+ (0 << STM_USART_CR1_WAKE) |
+ (0 << STM_USART_CR1_PCE) |
+ (0 << STM_USART_CR1_PS) |
+ (0 << STM_USART_CR1_PEIE) |
+ (0 << STM_USART_CR1_TXEIE) | /* XXX enable */
+ (0 << STM_USART_CR1_TCIE) |
+ (0 << STM_USART_CR1_RXNEIE) | /* XXX enable */
+ (0 << STM_USART_CR1_IDLEIE) |
+ (1 << STM_USART_CR1_TE) |
+ (1 << STM_USART_CR1_RE) |
+ (0 << STM_USART_CR1_RWU) |
+ (0 << STM_USART_CR1_SBK));
+
+ STM_USART1->usart_cr2 = 0;
+ STM_USART1->usart_cr3 = 0;
+
+ /* Pick a 9600 baud rate */
+ ao_serial_set_speed(AO_SERIAL_SPEED_9600);
+
+ printf ("serial initialized\n");
+#if 0
+#if USE_SERIAL_STDIN
+ ao_add_stdio(ao_serial_pollchar,
+ ao_serial_putchar,
+ NULL);
+#endif
+#endif
+}
diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c
new file mode 100644
index 00000000..f253e0c0
--- /dev/null
+++ b/src/stm/ao_timer.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+static volatile __data uint16_t ao_tick_count;
+
+uint16_t ao_time(void)
+{
+ uint16_t v;
+ ao_arch_critical(
+ v = ao_tick_count;
+ );
+ return v;
+}
+
+static __xdata uint8_t ao_forever;
+
+void
+ao_delay(uint16_t ticks)
+{
+ ao_alarm(ticks);
+ ao_sleep(&ao_forever);
+}
+
+#define T2_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */
+#define T2_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */
+
+#if HAS_ADC
+volatile __data uint8_t ao_adc_interval = 1;
+volatile __data uint8_t ao_adc_count;
+#endif
+
+void
+ao_debug_out(char c);
+
+
+void tim2_isr(void)
+{
+ ++ao_tick_count;
+#if HAS_ADC
+ if (++ao_adc_count == ao_adc_interval) {
+ ao_adc_count = 0;
+ ao_adc_poll();
+ }
+#endif
+}
+
+#if HAS_ADC
+void
+ao_timer_set_adc_interval(uint8_t interval) __critical
+{
+ ao_adc_interval = interval;
+ ao_adc_count = 0;
+}
+#endif
+
+void
+ao_timer_init(void)
+{
+}
+
+void
+ao_clock_init(void)
+{
+ uint32_t cfgr;
+
+ /* Set flash latency to tolerate 32MHz SYSCLK -> 1 wait state */
+ uint32_t acr = STM_FLASH->acr;
+
+ /* Enable 64-bit access and prefetch */
+ acr |= (1 << STM_FLASH_ACR_ACC64) | (1 << STM_FLASH_ACR_PRFEN);
+ STM_FLASH->acr = acr;
+
+ /* Enable 1 wait state so the CPU can run at 32MHz */
+ acr |= (1 << STM_FLASH_ACR_LATENCY);
+ STM_FLASH->acr = acr;
+
+ /* Enable HSI RC clock 16MHz */
+ if (!(STM_RCC->cr & (1 << STM_RCC_CR_HSIRDY))) {
+ STM_RCC->cr |= (1 << STM_RCC_CR_HSION);
+ while (!(STM_RCC->cr & (1 << STM_RCC_CR_HSIRDY)))
+ asm("nop");
+ }
+
+ /* Switch to direct HSI for SYSCLK */
+ if ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
+ (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)) {
+ cfgr = STM_RCC->cfgr;
+ cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
+ cfgr |= (STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW);
+ STM_RCC->cfgr = cfgr;
+ while ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
+ (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS))
+ asm("nop");
+ }
+
+ /* Disable the PLL */
+ STM_RCC->cr &= ~(1 << STM_RCC_CR_PLLON);
+ while (STM_RCC->cr & (1 << STM_RCC_CR_PLLRDY))
+ asm("nop");
+
+ /* PLLVCO to 96MHz (for USB) -> PLLMUL = 6 */
+ cfgr = STM_RCC->cfgr;
+ cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
+ cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
+
+ /* SYSCLK to 32MHz from PLL clock -> PLLDIV = /3 */
+ cfgr &= ~(STM_RCC_CFGR_PLLDIV_MASK << STM_RCC_CFGR_PLLDIV);
+ cfgr |= (STM_RCC_CFGR_PLLDIV_3 << STM_RCC_CFGR_PLLDIV);
+
+ /* PLL source to HSI */
+ cfgr &= ~(1 << STM_RCC_CFGR_PLLSRC);
+
+ STM_RCC->cfgr = cfgr;
+
+ /* Enable the PLL and wait for it */
+ STM_RCC->cr |= (1 << STM_RCC_CR_PLLON);
+ while (!(STM_RCC->cr & (1 << STM_RCC_CR_PLLRDY)))
+ asm("nop");
+
+ /* Switch to the PLL for the system clock */
+
+ cfgr = STM_RCC->cfgr;
+ cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
+ cfgr |= (STM_RCC_CFGR_SW_PLL << STM_RCC_CFGR_SW);
+ STM_RCC->cfgr = cfgr;
+ while ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
+ (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS))
+ asm("nop");
+
+ /* HCLK to 32MHz -> AHB prescaler = /1 */
+ cfgr = STM_RCC->cfgr;
+ cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
+ cfgr |= (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE);
+ STM_RCC->cfgr = cfgr;
+ while ((STM_RCC->cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) !=
+ (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE))
+ asm ("nop");
+
+ /* PCLK1 to 16MHz -> APB1 Prescaler = 2 */
+ cfgr = STM_RCC->cfgr;
+ cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1);
+ cfgr |= (STM_RCC_CFGR_PPRE1_DIV_2 << STM_RCC_CFGR_PPRE1);
+ STM_RCC->cfgr = cfgr;
+
+ /* PCLK2 to 16MHz -> APB2 Prescaler = 2 */
+ cfgr = STM_RCC->cfgr;
+ cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2);
+ cfgr |= (STM_RCC_CFGR_PPRE2_DIV_2 << STM_RCC_CFGR_PPRE2);
+ STM_RCC->cfgr = cfgr;
+
+}
diff --git a/src/stm/registers.ld b/src/stm/registers.ld
new file mode 100644
index 00000000..51921444
--- /dev/null
+++ b/src/stm/registers.ld
@@ -0,0 +1,47 @@
+stm_fsmc = 0xa0000000;
+stm_aes = 0x50060000;
+stm_dma = 0x40026000;
+stm_flash = 0x40023c00;
+stm_rcc = 0x40023800;
+stm_crc = 0x40023000;
+stm_gpioh = 0x40021400;
+stm_gpioe = 0x40021000;
+stm_gpiod = 0x40020c00;
+stm_gpioc = 0x40020800;
+stm_gpiob = 0x40020400;
+stm_gpioa = 0x40020000;
+stm_usart1 = 0x40013800;
+stm_spi1 = 0x40013000;
+stm_sdio = 0x40012c00;
+stm_adc = 0x40012400;
+stm_tim11 = 0x40011000;
+stm_tim10 = 0x40010c00;
+stm_tim9 = 0x40010800;
+stm_exti = 0x40010400;
+stm_syscfg = 0x40010000;
+stm_comp = 0x40007c00;
+stm_ri = 0x40007c04;
+stm_dac = 0x40007400;
+stm_pwr = 0x40007000;
+stm_usb_sram = 0x40006000;
+stm_usb = 0x40005c00;
+stm_i2c2 = 0x40005800;
+stm_i2c1 = 0x40005400;
+stm_usart5 = 0x40005000;
+stm_usart4 = 0x40004c00;
+stm_usart3 = 0x40004800;
+stm_usart2 = 0x40004400;
+stm_spi3 = 0x40003c00; /* docs are broken here */
+stm_spi2 = 0x40003800; /* docs are broken here */
+stm_iwdg = 0x40003000;
+stm_wwdg = 0x40002c00;
+stm_rtc = 0x40002800;
+stm_lcd = 0x40002400;
+stm_tim7 = 0x40001400;
+stm_tim6 = 0x40001000;
+stm_tim5 = 0x40000c00;
+stm_tim4 = 0x40000800;
+stm_tim3 = 0x40000400;
+stm_tim2 = 0x40000000;
+
+stm_nvic = 0xe000e100; \ No newline at end of file
diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h
new file mode 100644
index 00000000..c5e2a797
--- /dev/null
+++ b/src/stm/stm32l.h
@@ -0,0 +1,662 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _STM32L_H_
+#define _STM32L_H_
+
+#include <stdint.h>
+
+typedef volatile uint32_t vuint32_t;
+
+struct stm_gpio {
+ vuint32_t moder;
+ vuint32_t otyper;
+ vuint32_t ospeedr;
+ vuint32_t pupdr;
+
+ vuint32_t idr;
+ vuint32_t odr;
+ vuint32_t bsrr;
+ vuint32_t lckr;
+
+ vuint32_t afrl;
+ vuint32_t afrh;
+};
+
+#define STM_MODER_SHIFT(pin) ((pin) << 1)
+#define STM_MODER_MASK 3
+#define STM_MODER_INPUT 0
+#define STM_MODER_OUTPUT 1
+#define STM_MODER_ALTERNATE 2
+#define STM_MODER_ANALOG 3
+
+static inline void
+stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->moder = ((gpio->moder &
+ ~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) |
+ value << STM_MODER_SHIFT(pin));
+}
+
+static inline vuint32_t
+stm_moder_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK;
+}
+
+#define STM_OTYPER_SHIFT(pin) (pin)
+#define STM_OTYPER_MASK 1
+#define STM_OTYPER_PUSH_PULL 0
+#define STM_OTYPER_OPEN_DRAIN 1
+
+static inline void
+stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->otyper = ((gpio->otyper &
+ ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) |
+ value << STM_OTYPER_SHIFT(pin));
+}
+
+static inline vuint32_t
+stm_otyper_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK;
+}
+
+#define STM_OSPEEDR_SHIFT(pin) ((pin) << 1)
+#define STM_OSPEEDR_MASK 3
+#define STM_OSPEEDR_400kHz 0
+#define STM_OSPEEDR_2MHz 1
+#define STM_OSPEEDR_10MHz 2
+#define STM_OSPEEDR_40MHz 3
+
+static inline void
+stm_ospeedr_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->ospeedr = ((gpio->ospeedr &
+ ~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) |
+ value << STM_OSPEEDR_SHIFT(pin));
+}
+
+static inline vuint32_t
+stm_ospeedr_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK;
+}
+
+#define STM_PUPDR_SHIFT(pin) ((pin) << 1)
+#define STM_PUPDR_MASK 3
+#define STM_PUPDR_NONE 0
+#define STM_PUPDR_PULL_UP 1
+#define STM_PUPDR_PULL_DOWN 2
+#define STM_PUPDR_RESERVED 3
+
+static inline void
+stm_pupdr_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->pupdr = ((gpio->pupdr &
+ ~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) |
+ value << STM_PUPDR_SHIFT(pin));
+}
+
+static inline vuint32_t
+stm_pupdr_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK;
+}
+
+#define STM_AFR_SHIFT(pin) ((pin) << 2)
+#define STM_AFR_MASK 0xf
+#define STM_AFR_NONE 0
+#define STM_AFR_AF0 0x0
+#define STM_AFR_AF1 0x1
+#define STM_AFR_AF2 0x2
+#define STM_AFR_AF3 0x3
+#define STM_AFR_AF4 0x4
+#define STM_AFR_AF5 0x5
+#define STM_AFR_AF6 0x6
+#define STM_AFR_AF7 0x7
+#define STM_AFR_AF8 0x8
+#define STM_AFR_AF9 0x9
+#define STM_AFR_AF10 0xa
+#define STM_AFR_AF11 0xb
+#define STM_AFR_AF12 0xc
+#define STM_AFR_AF13 0xd
+#define STM_AFR_AF14 0xe
+#define STM_AFR_AF15 0xf
+
+static inline void
+stm_afr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
+ if (pin < 8)
+ gpio->afrl = ((gpio->afrl &
+ ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) |
+ value << STM_AFR_SHIFT(pin));
+ else {
+ pin -= 8;
+ gpio->afrh = ((gpio->afrh &
+ ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) |
+ value << STM_AFR_SHIFT(pin));
+ }
+}
+
+static inline uint32_t
+stm_afr_get(struct stm_gpio *gpio, int pin) {
+ if (pin < 8)
+ return (gpio->afrl >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK;
+ else {
+ pin -= 8;
+ return (gpio->afrh >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK;
+ }
+}
+
+extern struct stm_gpio stm_gpioa;
+extern struct stm_gpio stm_gpiob;
+extern struct stm_gpio stm_gpioc;
+extern struct stm_gpio stm_gpiod;
+extern struct stm_gpio stm_gpioe;
+extern struct stm_gpio stm_gpioh;
+
+struct stm_usart {
+ vuint32_t sr; /* status register */
+ vuint32_t dr; /* data register */
+ vuint32_t brr; /* baud rate register */
+ vuint32_t cr1; /* control register 1 */
+
+ vuint32_t cr2; /* control register 2 */
+ vuint32_t cr3; /* control register 3 */
+ vuint32_t gtpr; /* guard time and prescaler */
+};
+
+extern struct stm_usart stm_usart1;
+
+#define STM_USART_SR_CTS (9) /* CTS flag */
+#define STM_USART_SR_LBD (8) /* LIN break detection flag */
+#define STM_USART_SR_TXE (7) /* Transmit data register empty */
+#define STM_USART_SR_TC (6) /* Transmission complete */
+#define STM_USART_SR_RXNE (5) /* Read data register not empty */
+#define STM_USART_SR_IDLE (4) /* IDLE line detected */
+#define STM_USART_SR_ORE (3) /* Overrun error */
+#define STM_USART_SR_NF (2) /* Noise detected flag */
+#define STM_USART_SR_FE (1) /* Framing error */
+#define STM_USART_SR_PE (0) /* Parity error */
+
+#define STM_USART_CR1_OVER8 (15) /* Oversampling mode */
+#define STM_USART_CR1_UE (13) /* USART enable */
+#define STM_USART_CR1_M (12) /* Word length */
+#define STM_USART_CR1_WAKE (11) /* Wakeup method */
+#define STM_USART_CR1_PCE (10) /* Parity control enable */
+#define STM_USART_CR1_PS (9) /* Parity selection */
+#define STM_USART_CR1_PEIE (8) /* PE interrupt enable */
+#define STM_USART_CR1_TXEIE (7) /* TXE interrupt enable */
+#define STM_USART_CR1_TCIE (6) /* Transmission complete interrupt enable */
+#define STM_USART_CR1_RXNEIE (5) /* RXNE interrupt enable */
+#define STM_USART_CR1_IDLEIE (4) /* IDLE interrupt enable */
+#define STM_USART_CR1_TE (3) /* Transmitter enable */
+#define STM_USART_CR1_RE (2) /* Receiver enable */
+#define STM_USART_CR1_RWU (1) /* Receiver wakeup */
+#define STM_USART_CR1_SBK (0) /* Send break */
+
+#define STM_USART_CR2_LINEN (14) /* LIN mode enable */
+#define STM_USART_CR2_STOP (12) /* STOP bits */
+#define STM_USART_CR2_STOP_MASK 3
+#define STM_USART_CR2_STOP_1 0
+#define STM_USART_CR2_STOP_0_5 1
+#define STM_USART_CR2_STOP_2 2
+#define STM_USART_CR2_STOP_1_5 3
+
+#define STM_USART_CR2_CLKEN (11) /* Clock enable */
+#define STM_USART_CR2_CPOL (10) /* Clock polarity */
+#define STM_USART_CR2_CPHA (9) /* Clock phase */
+#define STM_USART_CR2_LBCL (8) /* Last bit clock pulse */
+#define STM_USART_CR2_LBDIE (6) /* LIN break detection interrupt enable */
+#define STM_USART_CR2_LBDL (5) /* lin break detection length */
+#define STM_USART_CR2_ADD (0)
+#define STM_USART_CR2_ADD_MASK 0xf
+
+#define STM_USART_CR3_ONEBITE (11) /* One sample bit method enable */
+#define STM_USART_CR3_CTSIE (10) /* CTS interrupt enable */
+#define STM_USART_CR3_CTSE (9) /* CTS enable */
+#define STM_USART_CR3_RTSE (8) /* RTS enable */
+#define STM_USART_CR3_DMAT (7) /* DMA enable transmitter */
+#define STM_USART_CR3_DMAR (6) /* DMA enable receiver */
+#define STM_USART_CR3_SCEN (5) /* Smartcard mode enable */
+#define STM_USART_CR3_NACK (4) /* Smartcard NACK enable */
+#define STM_USART_CR3_HDSEL (3) /* Half-duplex selection */
+#define STM_USART_CR3_IRLP (2) /* IrDA low-power */
+#define STM_USART_CR3_IREN (1) /* IrDA mode enable */
+#define STM_USART_CR3_EIE (0) /* Error interrupt enable */
+
+struct stm_spi {
+};
+
+extern struct stm_spi stm_spi1;
+
+struct stm_tim {
+};
+
+extern struct stm_tim stm_tim9;
+extern struct stm_tim stm_tim10;
+extern struct stm_tim stm_tim11;
+
+/* Flash interface */
+
+struct stm_flash {
+ vuint32_t acr;
+ vuint32_t pecr;
+ vuint32_t pdkeyr;
+ vuint32_t pekeyr;
+
+ vuint32_t prgkeyr;
+ vuint32_t optkeyr;
+ vuint32_t sr;
+ vuint32_t obr;
+
+ vuint32_t wrpr;
+};
+
+extern struct stm_flash stm_flash;
+
+#define STM_FLASH_ACR_RUN_PD (4)
+#define STM_FLASH_ACR_SLEEP_PD (3)
+#define STM_FLASH_ACR_ACC64 (2)
+#define STM_FLASH_ACR_PRFEN (1)
+#define STM_FLASH_ACR_LATENCY (0)
+
+struct stm_rcc {
+ vuint32_t cr;
+ vuint32_t icscr;
+ vuint32_t cfgr;
+ vuint32_t cir;
+
+ vuint32_t ahbrstr;
+ vuint32_t apb2rstr;
+ vuint32_t abp1rstr;
+ vuint32_t ahbenr;
+
+ vuint32_t apb2enr;
+ vuint32_t apb1enr;
+ vuint32_t ahblenr;
+ vuint32_t apb2lpenr;
+
+ vuint32_t apb1lpenr;
+ vuint32_t csr;
+};
+
+extern struct stm_rcc stm_rcc;
+
+#define STM_RCC_CR_RTCPRE (29)
+#define STM_RCC_CR_RTCPRE_HSE_DIV_2 0
+#define STM_RCC_CR_RTCPRE_HSE_DIV_4 1
+#define STM_RCC_CR_RTCPRE_HSE_DIV_8 2
+#define STM_RCC_CR_RTCPRE_HSE_DIV_16 3
+#define STM_RCC_CR_RTCPRE_HSE_MASK 3
+
+#define STM_RCC_CR_CSSON (28)
+#define STM_RCC_CR_PLLRDY (25)
+#define STM_RCC_CR_PLLON (24)
+#define STM_RCC_CR_HSEBYP (18)
+#define STM_RCC_CR_HSERDY (17)
+#define STM_RCC_CR_HSEON (16)
+#define STM_RCC_CR_MSIRDY (9)
+#define STM_RCC_CR_MSION (8)
+#define STM_RCC_CR_HSIRDY (1)
+#define STM_RCC_CR_HSION (0)
+
+#define STM_RCC_CFGR_MCOPRE (28)
+#define STM_RCC_CFGR_MCOPRE_DIV_1 0
+#define STM_RCC_CFGR_MCOPRE_DIV_2 1
+#define STM_RCC_CFGR_MCOPRE_DIV_4 2
+#define STM_RCC_CFGR_MCOPRE_DIV_8 3
+#define STM_RCC_CFGR_MCOPRE_DIV_16 4
+#define STM_RCC_CFGR_MCOPRE_DIV_MASK 7
+
+#define STM_RCC_CFGR_MCOSEL (24)
+#define STM_RCC_CFGR_MCOSEL_DISABLE 0
+#define STM_RCC_CFGR_MCOSEL_SYSCLK 1
+#define STM_RCC_CFGR_MCOSEL_HSI 2
+#define STM_RCC_CFGR_MCOSEL_MSI 3
+#define STM_RCC_CFGR_MCOSEL_HSE 4
+#define STM_RCC_CFGR_MCOSEL_PLL 5
+#define STM_RCC_CFGR_MCOSEL_LSI 6
+#define STM_RCC_CFGR_MCOSEL_LSE 7
+#define STM_RCC_CFGR_MCOSEL_MASK 7
+
+#define STM_RCC_CFGR_PLLDIV (22)
+#define STM_RCC_CFGR_PLLDIV_2 1
+#define STM_RCC_CFGR_PLLDIV_3 2
+#define STM_RCC_CFGR_PLLDIV_4 3
+#define STM_RCC_CFGR_PLLDIV_MASK 3
+
+#define STM_RCC_CFGR_PLLMUL (18)
+#define STM_RCC_CFGR_PLLMUL_3 0
+#define STM_RCC_CFGR_PLLMUL_4 1
+#define STM_RCC_CFGR_PLLMUL_6 2
+#define STM_RCC_CFGR_PLLMUL_8 3
+#define STM_RCC_CFGR_PLLMUL_12 4
+#define STM_RCC_CFGR_PLLMUL_16 5
+#define STM_RCC_CFGR_PLLMUL_24 6
+#define STM_RCC_CFGR_PLLMUL_32 7
+#define STM_RCC_CFGR_PLLMUL_48 8
+#define STM_RCC_CFGR_PLLMUL_MASK 0xf
+
+#define STM_RCC_CFGR_PLLSRC (16)
+
+#define STM_RCC_CFGR_PPRE2 (11)
+#define STM_RCC_CFGR_PPRE2_DIV_1 0
+#define STM_RCC_CFGR_PPRE2_DIV_2 4
+#define STM_RCC_CFGR_PPRE2_DIV_4 5
+#define STM_RCC_CFGR_PPRE2_DIV_8 6
+#define STM_RCC_CFGR_PPRE2_DIV_16 7
+#define STM_RCC_CFGR_PPRE2_MASK 7
+
+#define STM_RCC_CFGR_PPRE1 (8)
+#define STM_RCC_CFGR_PPRE1_DIV_1 0
+#define STM_RCC_CFGR_PPRE1_DIV_2 4
+#define STM_RCC_CFGR_PPRE1_DIV_4 5
+#define STM_RCC_CFGR_PPRE1_DIV_8 6
+#define STM_RCC_CFGR_PPRE1_DIV_16 7
+#define STM_RCC_CFGR_PPRE1_MASK 7
+
+#define STM_RCC_CFGR_HPRE (4)
+#define STM_RCC_CFGR_HPRE_DIV_1 0
+#define STM_RCC_CFGR_HPRE_DIV_2 8
+#define STM_RCC_CFGR_HPRE_DIV_4 9
+#define STM_RCC_CFGR_HPRE_DIV_8 0xa
+#define STM_RCC_CFGR_HPRE_DIV_16 0xb
+#define STM_RCC_CFGR_HPRE_DIV_64 0xc
+#define STM_RCC_CFGR_HPRE_DIV_128 0xd
+#define STM_RCC_CFGR_HPRE_DIV_256 0xe
+#define STM_RCC_CFGR_HPRE_DIV_512 0xf
+#define STM_RCC_CFGR_HPRE_MASK 0xf
+
+#define STM_RCC_CFGR_SWS (2)
+#define STM_RCC_CFGR_SWS_MSI 0
+#define STM_RCC_CFGR_SWS_HSI 1
+#define STM_RCC_CFGR_SWS_HSE 2
+#define STM_RCC_CFGR_SWS_PLL 3
+#define STM_RCC_CFGR_SWS_MASK 3
+
+#define STM_RCC_CFGR_SW (0)
+#define STM_RCC_CFGR_SW_MSI 0
+#define STM_RCC_CFGR_SW_HSI 1
+#define STM_RCC_CFGR_SW_HSE 2
+#define STM_RCC_CFGR_SW_PLL 3
+#define STM_RCC_CFGR_SW_MASK 3
+
+#define STM_RCC_AHBENR_DMA1EN (24)
+#define STM_RCC_AHBENR_FLITFEN (15)
+#define STM_RCC_AHBENR_CRCEN (12)
+#define STM_RCC_AHBENR_GPIOHEN (5)
+#define STM_RCC_AHBENR_GPIOEEN (4)
+#define STM_RCC_AHBENR_GPIODEN (3)
+#define STM_RCC_AHBENR_GPIOCEN (2)
+#define STM_RCC_AHBENR_GPIOBEN (1)
+#define STM_RCC_AHBENR_GPIOAEN (0)
+
+#define STM_RCC_APB2ENR_USART1EN (14)
+#define STM_RCC_APB2ENR_SPI1EN (12)
+#define STM_RCC_APB2ENR_ADC1EN (9)
+#define STM_RCC_APB2ENR_TIM11EN (4)
+#define STM_RCC_APB2ENR_TIM10EN (3)
+#define STM_RCC_APB2ENR_TIM9EN (2)
+#define STM_RCC_APB2ENR_SYSCFGEN (0)
+
+#define STM_RCC_APB1ENR_COMPEN (31)
+#define STM_RCC_APB1ENR_DACEN (29)
+#define STM_RCC_APB1ENR_PWREN (28)
+#define STM_RCC_APB1ENR_USBEN (23)
+#define STM_RCC_APB1ENR_I2C2EN (22)
+#define STM_RCC_APB1ENR_I2C1EN (21)
+#define STM_RCC_APB1ENR_USART3EN (18)
+#define STM_RCC_APB1ENR_USART2EN (17)
+#define STM_RCC_APB1ENR_SPI2EN (14)
+#define STM_RCC_APB1ENR_WWDGEN (11)
+#define STM_RCC_APB1ENR_LCDEN (9)
+#define STM_RCC_APB1ENR_TIM7EN (5)
+#define STM_RCC_APB1ENR_TIM6EN (4)
+#define STM_RCC_APB1ENR_TIM4EN (2)
+#define STM_RCC_APB1ENR_TIM3EN (1)
+#define STM_RCC_APB1ENR_TIM2EN (0)
+
+struct stm_pwr {
+ vuint32_t cr;
+ vuint32_t csr;
+};
+
+extern struct stm_pwr stm_pwr;
+
+#define STM_PWR_CR_LPRUN (14)
+
+#define STM_PWR_CR_VOS (11)
+#define STM_PWR_CR_VOS_1_8 1
+#define STM_PWR_CR_VOS_1_5 2
+#define STM_PWR_CR_VOS_1_2 3
+#define STM_PWR_CR_VOS_MASK 3
+
+#define STM_PWR_CR_FWU (10)
+#define STM_PWR_CR_ULP (9)
+#define STM_PWR_CR_DBP (8)
+
+#define STM_PWR_CR_PLS (5)
+#define STM_PWR_CR_PLS_1_9 0
+#define STM_PWR_CR_PLS_2_1 1
+#define STM_PWR_CR_PLS_2_3 2
+#define STM_PWR_CR_PLS_2_5 3
+#define STM_PWR_CR_PLS_2_7 4
+#define STM_PWR_CR_PLS_2_9 5
+#define STM_PWR_CR_PLS_3_1 6
+#define STM_PWR_CR_PLS_EXT 7
+#define STM_PWR_CR_PLS_MASK 7
+
+#define STM_PWR_CR_PVDE (4)
+#define STM_PWR_CR_CSBF (3)
+#define STM_PWR_CR_CWUF (2)
+#define STM_PWR_CR_PDDS (1)
+#define STM_PWR_CR_LPSDSR (0)
+
+#define STM_PWR_CSR_EWUP3 (10)
+#define STM_PWR_CSR_EWUP2 (9)
+#define STM_PWR_CSR_EWUP1 (8)
+#define STM_PWR_CSR_REGLPF (5)
+#define STM_PWR_CSR_VOSF (4)
+#define STM_PWR_CSR_VREFINTRDYF (3)
+#define STM_PWR_CSR_PVDO (2)
+#define STM_PWR_CSR_SBF (1)
+#define STM_PWR_CSR_WUF (0)
+
+struct stm_tim67 {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ uint32_t _unused_08;
+ vuint32_t dier;
+
+ vuint32_t sr;
+ vuint32_t egr;
+ uint32_t _unused_18;
+ uint32_t _unused_1c;
+
+ uint32_t _unused_20;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+};
+
+extern struct stm_tim67 stm_tim6;
+
+#define STM_TIM67_CR1_ARPE (7)
+#define STM_TIM67_CR1_OPM (3)
+#define STM_TIM67_CR1_URS (2)
+#define STM_TIM67_CR1_UDIS (1)
+#define STM_TIM67_CR1_CEN (0)
+
+#define STM_TIM67_CR2_MMS (4)
+#define STM_TIM67_CR2_MMS_RESET 0
+#define STM_TIM67_CR2_MMS_ENABLE 1
+#define STM_TIM67_CR2_MMS_UPDATE 2
+#define STM_TIM67_CR2_MMS_MASK 7
+
+#define STM_TIM67_DIER_UDE (8)
+#define STM_TIM67_DIER_UIE (0)
+
+#define STM_TIM67_SR_UIF (0)
+
+#define STM_TIM67_EGR_UG (0)
+
+struct stm_nvic {
+ vuint32_t iser[3]; /* 0x000 */
+
+ uint8_t _unused00c[0x080 - 0x00c];
+
+ vuint32_t icer[3]; /* 0x080 */
+
+ uint8_t _unused08c[0x100 - 0x08c];
+
+ vuint32_t ispr[3]; /* 0x100 */
+
+ uint8_t _unused10c[0x180 - 0x10c];
+
+ vuint32_t icpr[3]; /* 0x180 */
+
+ uint8_t _unused18c[0x200 - 0x18c];
+
+ vuint32_t iabr[3]; /* 0x200 */
+
+ uint8_t _unused20c[0x300 - 0x20c];
+
+ vuint32_t ipr[21]; /* 0x300 */
+
+ uint8_t _unused324[0xe00 - 0x324];
+
+ vuint32_t stir; /* 0xe00 */
+};
+
+extern struct stm_nvic stm_nvic;
+
+#define IRQ_REG(irq) ((irq) >> 5)
+#define IRQ_BIT(irq) ((irq) & 0x1f)
+#define IRQ_MASK(irq) (1 << IRQ_BIT(irq))
+#define IRQ_BOOL(v,irq) (((v) >> IRQ_BIT(irq)) & 1)
+
+static inline void
+stm_nvic_set_enable(int irq) {
+ stm_nvic.iser[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_enable(int irq) {
+ stm_nvic.icer[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_enabled(int irq) {
+ return IRQ_BOOL(stm_nvic.iser[IRQ_REG(irq)], irq);
+}
+
+static inline void
+stm_nvic_set_pending(int irq) {
+ stm_nvic.ispr[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_pending(int irq) {
+ stm_nvic.icpr[IRQ_REG(irq)] = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_pending(int irq) {
+ return IRQ_BOOL(stm_nvic.ispr[IRQ_REG(irq)], irq);
+}
+
+static inline int
+stm_nvic_active(int irq) {
+ return IRQ_BOOL(stm_nvic.iabr[IRQ_REG(irq)], irq);
+}
+
+#define IRQ_PRIO_REG(irq) ((irq) >> 2)
+#define IRQ_PRIO_BIT(irq) (((irq) & 3) << 3)
+#define IRQ_PRIO_MASK(irq) (0xff << IRQ_PRIO_BIT(irq))
+
+static inline void
+stm_nvic_set_priority(int irq, uint8_t prio) {
+ int n = IRQ_PRIO_REG(irq);
+ uint32_t v;
+
+ v = stm_nvic.ipr[n];
+ v &= ~IRQ_PRIO_MASK(irq);
+ v |= (prio) << IRQ_PRIO_BIT(irq);
+ stm_nvic.ipr[n] = v;
+}
+
+static inline uint8_t
+stm_nvic_get_priority(int irq) {
+ return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
+}
+
+#define isr(name) void stm_ ## name ## _isr(void);
+
+isr(nmi)
+isr(hardfault)
+isr(memmanage)
+isr(busfault)
+isr(usagefault)
+isr(svc)
+isr(debugmon)
+isr(pendsv)
+isr(systick)
+isr(wwdg)
+isr(pvd)
+isr(tamper_stamp)
+isr(rtc_wkup)
+isr(flash)
+isr(rcc)
+isr(exti0)
+isr(exti1)
+isr(exti2)
+isr(exti3)
+isr(exti4)
+isr(dma1_channel1)
+isr(dma1_channel2)
+isr(dma1_channel3)
+isr(dma1_channel4)
+isr(dma1_channel5)
+isr(dma1_channel6)
+isr(dma1_channel7)
+isr(adc1)
+isr(usb_hp)
+isr(usb_lp)
+isr(dac)
+isr(comp)
+isr(exti9_5)
+isr(lcd)
+isr(tim9)
+isr(tim10)
+isr(tim11)
+isr(tim2)
+isr(tim3)
+isr(tim4)
+isr(i2c1_ev)
+isr(i2c1_er)
+isr(i2c2_ev)
+isr(i2c2_er)
+isr(spi1)
+isr(spi2)
+isr(usart1)
+isr(usart2)
+isr(usart3)
+isr(exti15_10)
+isr(rtc_alarm)
+isr(usb_fs_wkup)
+isr(tim6)
+isr(tim7)
+
+#define STM_ISR_TIM6_POS 43
+
+#undef isr
+
+#endif /* _STM32L_H_ */