From: Keith Packard Date: Fri, 16 Mar 2012 21:25:37 +0000 (-0700) Subject: Add example STM32L programs X-Git-Tag: 1.0.9.4~35 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=e2f13aa43ba79becbff6c9bfc18c665a58d96185 Add example STM32L programs This loads to flash and sends data over the serial link. Signed-off-by: Keith Packard --- diff --git a/ao-bringup/stm/Makefile b/ao-bringup/stm/Makefile new file mode 100644 index 00000000..49966a4f --- /dev/null +++ b/ao-bringup/stm/Makefile @@ -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 index 00000000..b8fffedc --- /dev/null +++ b/ao-bringup/stm/altos-ram.ld @@ -0,0 +1,69 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 index 00000000..0a25f853 --- /dev/null +++ b/ao-bringup/stm/altos.ld @@ -0,0 +1,71 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 index 00000000..b6fe458d --- /dev/null +++ b/ao-bringup/stm/bringup.c @@ -0,0 +1,306 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 + +#include +#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 index 00000000..58204b9f --- /dev/null +++ b/ao-bringup/stm/registers.ld @@ -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; +