Add STM platform and stm-bringup demo program
authorKeith Packard <keithp@keithp.com>
Sat, 17 Mar 2012 03:21:09 +0000 (20:21 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 29 Mar 2012 04:37:02 +0000 (21:37 -0700)
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>
13 files changed:
ao-bringup/stm/Makefile [deleted file]
ao-bringup/stm/bringup.c [deleted file]
src/stm-bringup/Makefile [new file with mode: 0644]
src/stm-bringup/bringup.c [new file with mode: 0644]
src/stm/altos-ram.ld [new file with mode: 0644]
src/stm/altos.ld [new file with mode: 0644]
src/stm/ao_arch.h [new file with mode: 0644]
src/stm/ao_interrupt.c [new file with mode: 0644]
src/stm/ao_led.c [new file with mode: 0644]
src/stm/ao_serial_stm.c [new file with mode: 0644]
src/stm/ao_timer.c [new file with mode: 0644]
src/stm/registers.ld [new file with mode: 0644]
src/stm/stm32l.h [new file with mode: 0644]

diff --git a/ao-bringup/stm/Makefile b/ao-bringup/stm/Makefile
deleted file mode 100644 (file)
index 49966a4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-CC=arm-none-eabi-gcc
-OBJCOPY=arm-none-eabi-objcopy
-
-C_LIB=/local/src/pdclib/pdclib.a
-C_INC=-I/local/src/pdclib/includes -I/local/src/pdclib/internals
-
-DEF_CFLAGS=-g -std=gnu99 -O0 -mlittle-endian -mthumb -ffreestanding -nostdlib -I../../src/stm $(C_INC)
-
-# to run from SRAM
-LD_FLAGS_RAM=-Wl,-Taltos-ram.ld
-LD_FLAGS=-Wl,-Taltos.ld
-
-CFLAGS=$(DEF_CFLAGS) -mcpu=cortex-m3 -DCONFIG_STM32L_DISCOVERY
-
-OBJS=bringup.o
-
-all: bringup-ram.elf bringup.elf
-
-%.bin: %.elf
-       $(OBJCOPY) -O binary $^ $@
-
-bringup.elf: $(OBJS) $(C_LIB) altos.ld
-       $(CC) $(CFLAGS) $(LD_FLAGS) -o $@ $(OBJS) $(C_LIB) -lgcc
-
-bringup-ram.elf: $(OBJS) $(C_LIB) altos-ram.ld
-       $(CC) $(CFLAGS) $(LD_FLAGS_RAM) -o $@ $(OBJS) $(C_LIB) -lgcc
-
-bringup.o: bringup.c
-       $(CC) -c $(CFLAGS) bringup.c
-
-clean:
-       rm -rf *.elf
-       rm -rf *.bin
-
-.PHONY: all clean
diff --git a/ao-bringup/stm/bringup.c b/ao-bringup/stm/bringup.c
deleted file mode 100644 (file)
index b6fe458..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * 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 <string.h>
-
-#include <stdio.h>
-#include "stm32l.h"
-
-void delay(void);
-
-static void
-set_clock(void)
-{
-       uint32_t        cfgr;
-       uint32_t        cr;
-       
-       /* 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 */
-       /* (haven't managed to run the CPU at 32MHz yet, it's at 16MHz) */
-       acr |= (1 << STM_FLASH_ACR_LATENCY);
-       stm_flash.acr = acr;
-
-       /* HCLK to 16MHz -> 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");
-#define STM_AHB_PRESCALER      1
-
-       /* PCLK1 to 16MHz -> APB1 Prescaler = 1 */
-       cfgr = stm_rcc.cfgr;
-       cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1);
-       cfgr |= (STM_RCC_CFGR_PPRE1_DIV_1 << STM_RCC_CFGR_PPRE1);
-       stm_rcc.cfgr = cfgr;
-#define STM_APB1_PRESCALER     1
-
-       /* PCLK2 to 16MHz -> APB2 Prescaler = 1 */
-       cfgr = stm_rcc.cfgr;
-       cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2);
-       cfgr |= (STM_RCC_CFGR_PPRE2_DIV_1 << STM_RCC_CFGR_PPRE2);
-       stm_rcc.cfgr = cfgr;
-#define STM_APB2_PRESCALER     1
-
-       /* Enable power interface clock */
-       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
-
-       /* Set voltage range to 1.8V */
-
-       /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
-       while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
-               asm("nop");
-
-       /* Configure voltage scaling range */
-       cr = stm_pwr.cr;
-       cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS);
-       cr |= (STM_PWR_CR_VOS_1_8 << STM_PWR_CR_VOS);
-       stm_pwr.cr = cr;
-
-       /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
-       while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
-               asm("nop");
-
-       /* 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");
-       }
-#define STM_HSI 16000000
-
-       /* 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, PLLDIV = 4 */
-       cfgr = stm_rcc.cfgr;
-       cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
-       cfgr &= ~(STM_RCC_CFGR_PLLDIV_MASK << STM_RCC_CFGR_PLLDIV);
-
-//     cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
-//     cfgr |= (STM_RCC_CFGR_PLLDIV_3 << STM_RCC_CFGR_PLLDIV);
-
-       cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
-       cfgr |= (STM_RCC_CFGR_PLLDIV_4 << STM_RCC_CFGR_PLLDIV);
-
-#define STM_PLLMUL     6
-#define STM_PLLDIV     4
-
-       /* PLL source to HSI */
-       cfgr &= ~(1 << STM_RCC_CFGR_PLLSRC);
-
-#define STM_PLLSRC     STM_HSI
-
-       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;
-       for (;;) {
-               uint32_t        c, part, mask, val;
-
-               c = stm_rcc.cfgr;
-               mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS);
-               val = (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS);
-               part = c & mask;
-               if (part == val)
-                       break;
-       }
-}
-
-#define STM_PLLVCO     (STM_PLLSRC * STM_PLLMUL)
-#define STM_SYSCLK     (STM_PLLVCO / STM_PLLDIV)
-#define STM_HCLK       (STM_SYSCLK / STM_AHB_PRESCALER)
-#define STM_APB1       (STM_HCLK / STM_APB1_PRESCALER)
-#define STM_APB2       (STM_HCLK / STM_APB2_PRESCALER)
-
-#define BAUD_9600 (STM_APB2 / 9600)
-
-void
-set_serial()
-{
-       uint32_t        moder, afr;
-
-       /* Enable GPIOA */
-       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
-       
-       /* Hook PA9, PA10 to USART1 (AFIO7) */
-       stm_moder_set(&stm_gpioa, 9, STM_MODER_ALTERNATE);
-       stm_moder_set(&stm_gpioa, 10, STM_MODER_ALTERNATE);
-       stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7);
-       stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7);
-
-       /* Enable USART1 */
-       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
-       
-       /* 9.6KBps. PCLK1 = 16MHz. OVER8 = 0 */
-
-       /* USARTDIV = PCLK1 / (16 * 9600) = 104.1{6}
-        * round to 104.1875 (1667 / 16)
-        *
-        * actual baud rate = 16e6 / (16 * 104.1875) = 9598Bps
-        */
-
-       stm_usart1.brr = BAUD_9600;
-
-       stm_usart1.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) |
-                         (0 << STM_USART_CR1_TCIE) |
-                         (0 << STM_USART_CR1_RXNEIE) |
-                         (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.cr2 = ((0 << STM_USART_CR2_LINEN) |
-                         (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) |
-                         (0 << STM_USART_CR2_CLKEN) |
-                         (0 << STM_USART_CR2_CPOL) |
-                         (0 << STM_USART_CR2_CPHA) |
-                         (0 << STM_USART_CR2_LBCL) |
-                         (0 << STM_USART_CR2_LBDIE) |
-                         (0 << STM_USART_CR2_LBDL) |
-                         (0 << STM_USART_CR2_ADD));
-
-       stm_usart1.cr3 = ((0 << STM_USART_CR3_ONEBITE) |
-                         (0 << STM_USART_CR3_CTSIE) |
-                         (0 << STM_USART_CR3_CTSE) |
-                         (0 << STM_USART_CR3_RTSE) |
-                         (0 << STM_USART_CR3_DMAT) |
-                         (0 << STM_USART_CR3_DMAR) |
-                         (0 << STM_USART_CR3_SCEN) |
-                         (0 << STM_USART_CR3_NACK) |
-                         (0 << STM_USART_CR3_HDSEL) |
-                         (0 << STM_USART_CR3_IRLP) |
-                         (0 << STM_USART_CR3_IREN) |
-                         (0 << STM_USART_CR3_EIE));
-}
-
-void
-outbyte(char c)
-{
-       if (c == '\n')
-               outbyte('\r');
-       while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE)))
-               ;
-       stm_usart1.dr = c;
-}
-
-int putc( int c, FILE * stream ) {
-       outbyte(c);
-}
-
-void
-serial_string(char *string)
-{
-       char    c;
-
-       while (c = *string++)
-               outbyte(c);
-}
-
-void
-set_timer6(void)
-{
-       /* Turn on timer 6 */
-       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
-
-       
-}
-
-void
-main (void)
-{
-       set_clock();
-       set_serial();
-       set_timer6();
-       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
-       stm_moder_set(&stm_gpiob, 7, STM_MODER_OUTPUT);
-       stm_moder_set(&stm_gpiob, 6, STM_MODER_OUTPUT);
-       for (;;) {
-               stm_gpiob.odr = (1 << 7);
-               printf ("hello, ");
-               delay();
-               stm_gpiob.odr = (1 << 6);
-               printf ("world\n");
-               delay();
-       }
-}
-
-void
-delay(void)
-{
-       int i;
-       for (i = 0; i < 1000000; i++)
-               __asm__ __volatile__ ("nop\n\t":::"memory");
-}
-
-static int x = 7;
-
-extern char __stack__;
-extern char __text_start__, __text_end__;
-extern char __data_start__, __data_end__;
-extern char __bss_start__, __bss_end__;
-
-void start(void) {
-       memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);
-       memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
-       main();
-}
-
-__attribute__ ((section(".interrupt")))
-static const void *interrupt[] = {
-       &__stack__,
-       start,
-};
diff --git a/src/stm-bringup/Makefile b/src/stm-bringup/Makefile
new file mode 100644 (file)
index 0000000..49966a4
--- /dev/null
@@ -0,0 +1,35 @@
+CC=arm-none-eabi-gcc
+OBJCOPY=arm-none-eabi-objcopy
+
+C_LIB=/local/src/pdclib/pdclib.a
+C_INC=-I/local/src/pdclib/includes -I/local/src/pdclib/internals
+
+DEF_CFLAGS=-g -std=gnu99 -O0 -mlittle-endian -mthumb -ffreestanding -nostdlib -I../../src/stm $(C_INC)
+
+# to run from SRAM
+LD_FLAGS_RAM=-Wl,-Taltos-ram.ld
+LD_FLAGS=-Wl,-Taltos.ld
+
+CFLAGS=$(DEF_CFLAGS) -mcpu=cortex-m3 -DCONFIG_STM32L_DISCOVERY
+
+OBJS=bringup.o
+
+all: bringup-ram.elf bringup.elf
+
+%.bin: %.elf
+       $(OBJCOPY) -O binary $^ $@
+
+bringup.elf: $(OBJS) $(C_LIB) altos.ld
+       $(CC) $(CFLAGS) $(LD_FLAGS) -o $@ $(OBJS) $(C_LIB) -lgcc
+
+bringup-ram.elf: $(OBJS) $(C_LIB) altos-ram.ld
+       $(CC) $(CFLAGS) $(LD_FLAGS_RAM) -o $@ $(OBJS) $(C_LIB) -lgcc
+
+bringup.o: bringup.c
+       $(CC) -c $(CFLAGS) bringup.c
+
+clean:
+       rm -rf *.elf
+       rm -rf *.bin
+
+.PHONY: all clean
diff --git a/src/stm-bringup/bringup.c b/src/stm-bringup/bringup.c
new file mode 100644 (file)
index 0000000..b6fe458
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * 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 <string.h>
+
+#include <stdio.h>
+#include "stm32l.h"
+
+void delay(void);
+
+static void
+set_clock(void)
+{
+       uint32_t        cfgr;
+       uint32_t        cr;
+       
+       /* 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 */
+       /* (haven't managed to run the CPU at 32MHz yet, it's at 16MHz) */
+       acr |= (1 << STM_FLASH_ACR_LATENCY);
+       stm_flash.acr = acr;
+
+       /* HCLK to 16MHz -> 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");
+#define STM_AHB_PRESCALER      1
+
+       /* PCLK1 to 16MHz -> APB1 Prescaler = 1 */
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1);
+       cfgr |= (STM_RCC_CFGR_PPRE1_DIV_1 << STM_RCC_CFGR_PPRE1);
+       stm_rcc.cfgr = cfgr;
+#define STM_APB1_PRESCALER     1
+
+       /* PCLK2 to 16MHz -> APB2 Prescaler = 1 */
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2);
+       cfgr |= (STM_RCC_CFGR_PPRE2_DIV_1 << STM_RCC_CFGR_PPRE2);
+       stm_rcc.cfgr = cfgr;
+#define STM_APB2_PRESCALER     1
+
+       /* Enable power interface clock */
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
+
+       /* Set voltage range to 1.8V */
+
+       /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
+       while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
+               asm("nop");
+
+       /* Configure voltage scaling range */
+       cr = stm_pwr.cr;
+       cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS);
+       cr |= (STM_PWR_CR_VOS_1_8 << STM_PWR_CR_VOS);
+       stm_pwr.cr = cr;
+
+       /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
+       while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
+               asm("nop");
+
+       /* 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");
+       }
+#define STM_HSI 16000000
+
+       /* 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, PLLDIV = 4 */
+       cfgr = stm_rcc.cfgr;
+       cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
+       cfgr &= ~(STM_RCC_CFGR_PLLDIV_MASK << STM_RCC_CFGR_PLLDIV);
+
+//     cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
+//     cfgr |= (STM_RCC_CFGR_PLLDIV_3 << STM_RCC_CFGR_PLLDIV);
+
+       cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
+       cfgr |= (STM_RCC_CFGR_PLLDIV_4 << STM_RCC_CFGR_PLLDIV);
+
+#define STM_PLLMUL     6
+#define STM_PLLDIV     4
+
+       /* PLL source to HSI */
+       cfgr &= ~(1 << STM_RCC_CFGR_PLLSRC);
+
+#define STM_PLLSRC     STM_HSI
+
+       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;
+       for (;;) {
+               uint32_t        c, part, mask, val;
+
+               c = stm_rcc.cfgr;
+               mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS);
+               val = (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS);
+               part = c & mask;
+               if (part == val)
+                       break;
+       }
+}
+
+#define STM_PLLVCO     (STM_PLLSRC * STM_PLLMUL)
+#define STM_SYSCLK     (STM_PLLVCO / STM_PLLDIV)
+#define STM_HCLK       (STM_SYSCLK / STM_AHB_PRESCALER)
+#define STM_APB1       (STM_HCLK / STM_APB1_PRESCALER)
+#define STM_APB2       (STM_HCLK / STM_APB2_PRESCALER)
+
+#define BAUD_9600 (STM_APB2 / 9600)
+
+void
+set_serial()
+{
+       uint32_t        moder, afr;
+
+       /* Enable GPIOA */
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+       
+       /* Hook PA9, PA10 to USART1 (AFIO7) */
+       stm_moder_set(&stm_gpioa, 9, STM_MODER_ALTERNATE);
+       stm_moder_set(&stm_gpioa, 10, STM_MODER_ALTERNATE);
+       stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7);
+       stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7);
+
+       /* Enable USART1 */
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
+       
+       /* 9.6KBps. PCLK1 = 16MHz. OVER8 = 0 */
+
+       /* USARTDIV = PCLK1 / (16 * 9600) = 104.1{6}
+        * round to 104.1875 (1667 / 16)
+        *
+        * actual baud rate = 16e6 / (16 * 104.1875) = 9598Bps
+        */
+
+       stm_usart1.brr = BAUD_9600;
+
+       stm_usart1.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) |
+                         (0 << STM_USART_CR1_TCIE) |
+                         (0 << STM_USART_CR1_RXNEIE) |
+                         (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.cr2 = ((0 << STM_USART_CR2_LINEN) |
+                         (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) |
+                         (0 << STM_USART_CR2_CLKEN) |
+                         (0 << STM_USART_CR2_CPOL) |
+                         (0 << STM_USART_CR2_CPHA) |
+                         (0 << STM_USART_CR2_LBCL) |
+                         (0 << STM_USART_CR2_LBDIE) |
+                         (0 << STM_USART_CR2_LBDL) |
+                         (0 << STM_USART_CR2_ADD));
+
+       stm_usart1.cr3 = ((0 << STM_USART_CR3_ONEBITE) |
+                         (0 << STM_USART_CR3_CTSIE) |
+                         (0 << STM_USART_CR3_CTSE) |
+                         (0 << STM_USART_CR3_RTSE) |
+                         (0 << STM_USART_CR3_DMAT) |
+                         (0 << STM_USART_CR3_DMAR) |
+                         (0 << STM_USART_CR3_SCEN) |
+                         (0 << STM_USART_CR3_NACK) |
+                         (0 << STM_USART_CR3_HDSEL) |
+                         (0 << STM_USART_CR3_IRLP) |
+                         (0 << STM_USART_CR3_IREN) |
+                         (0 << STM_USART_CR3_EIE));
+}
+
+void
+outbyte(char c)
+{
+       if (c == '\n')
+               outbyte('\r');
+       while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE)))
+               ;
+       stm_usart1.dr = c;
+}
+
+int putc( int c, FILE * stream ) {
+       outbyte(c);
+}
+
+void
+serial_string(char *string)
+{
+       char    c;
+
+       while (c = *string++)
+               outbyte(c);
+}
+
+void
+set_timer6(void)
+{
+       /* Turn on timer 6 */
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
+
+       
+}
+
+void
+main (void)
+{
+       set_clock();
+       set_serial();
+       set_timer6();
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+       stm_moder_set(&stm_gpiob, 7, STM_MODER_OUTPUT);
+       stm_moder_set(&stm_gpiob, 6, STM_MODER_OUTPUT);
+       for (;;) {
+               stm_gpiob.odr = (1 << 7);
+               printf ("hello, ");
+               delay();
+               stm_gpiob.odr = (1 << 6);
+               printf ("world\n");
+               delay();
+       }
+}
+
+void
+delay(void)
+{
+       int i;
+       for (i = 0; i < 1000000; i++)
+               __asm__ __volatile__ ("nop\n\t":::"memory");
+}
+
+static int x = 7;
+
+extern char __stack__;
+extern char __text_start__, __text_end__;
+extern char __data_start__, __data_end__;
+extern char __bss_start__, __bss_end__;
+
+void start(void) {
+       memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);
+       memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
+       main();
+}
+
+__attribute__ ((section(".interrupt")))
+static const void *interrupt[] = {
+       &__stack__,
+       start,
+};
diff --git a/src/stm/altos-ram.ld b/src/stm/altos-ram.ld
new file mode 100644 (file)
index 0000000..b8fffed
--- /dev/null
@@ -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 (file)
index 0000000..4e95566
--- /dev/null
@@ -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 (file)
index 0000000..e6f54fd
--- /dev/null
@@ -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 (file)
index 0000000..6b4a970
--- /dev/null
@@ -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 (file)
index 0000000..db65afd
--- /dev/null
@@ -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 (file)
index 0000000..dc44612
--- /dev/null
@@ -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 (file)
index 0000000..f253e0c
--- /dev/null
@@ -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 (file)
index 0000000..5192144
--- /dev/null
@@ -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 (file)
index 0000000..c5e2a79
--- /dev/null
@@ -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_ */