Add example STM32L programs
authorKeith Packard <keithp@keithp.com>
Fri, 16 Mar 2012 21:25:37 +0000 (14:25 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 29 Mar 2012 04:37:02 +0000 (21:37 -0700)
This loads to flash and sends data over the serial link.

Signed-off-by: Keith Packard <keithp@keithp.com>
ao-bringup/stm/Makefile [new file with mode: 0644]
ao-bringup/stm/altos-ram.ld [new file with mode: 0644]
ao-bringup/stm/altos.ld [new file with mode: 0644]
ao-bringup/stm/bringup.c [new file with mode: 0644]
ao-bringup/stm/registers.ld [new file with mode: 0644]

diff --git a/ao-bringup/stm/Makefile b/ao-bringup/stm/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/ao-bringup/stm/altos-ram.ld b/ao-bringup/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/ao-bringup/stm/altos.ld b/ao-bringup/stm/altos.ld
new file mode 100644 (file)
index 0000000..0a25f85
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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
+
+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/ao-bringup/stm/bringup.c b/ao-bringup/stm/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/ao-bringup/stm/registers.ld b/ao-bringup/stm/registers.ld
new file mode 100644 (file)
index 0000000..58204b9
--- /dev/null
@@ -0,0 +1,46 @@
+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;
+