From: Keith Packard Date: Sat, 17 Mar 2012 03:21:09 +0000 (-0700) Subject: Add STM platform and stm-bringup demo program X-Git-Tag: 1.0.9.4~34 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=9279fd42793123784ce83ca151df6f4630487722 Add STM platform and stm-bringup demo program The stm-bringup doesn't run altos, it just initializes the device and writes stuff over a serial port. Works on the STM32L Discovery board at least, should do stuff on other boards too. Signed-off-by: Keith Packard --- diff --git a/ao-bringup/stm/Makefile b/ao-bringup/stm/Makefile deleted file mode 100644 index 49966a4f..00000000 --- a/ao-bringup/stm/Makefile +++ /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 index b6fe458d..00000000 --- a/ao-bringup/stm/bringup.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * 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/src/stm-bringup/Makefile b/src/stm-bringup/Makefile new file mode 100644 index 00000000..49966a4f --- /dev/null +++ b/src/stm-bringup/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/src/stm-bringup/bringup.c b/src/stm-bringup/bringup.c new file mode 100644 index 00000000..b6fe458d --- /dev/null +++ b/src/stm-bringup/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/src/stm/altos-ram.ld b/src/stm/altos-ram.ld new file mode 100644 index 00000000..b8fffedc --- /dev/null +++ b/src/stm/altos-ram.ld @@ -0,0 +1,69 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K +} + +C_STACK_SIZE = 512; + +INCLUDE registers.ld + +SECTIONS { + . = ORIGIN(ram); + + /* + * Rom contents + */ + + __text_start__ = .; + + .text : { + *(.interrupt) /* Interrupt vectors */ + *(.text) /* Executable code */ + *(.rodata) /* Constants */ + } > ram + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __text_end__ = .; + } > ram + + __data_start__ = .; + + /* Data -- relocated to RAM, but written to ROM + */ + .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) { + *(.data) /* initialized data */ + __data_end__ = .; + __bss_start__ = .; + } >ram + + .bss : { + *(.bss) + *(COMMON) + __bss_end__ = .; + } >ram + + PROVIDE(__stack__ = . + C_STACK_SIZE); + PROVIDE(end = .); + +} + +ENTRY(start); + + diff --git a/src/stm/altos.ld b/src/stm/altos.ld new file mode 100644 index 00000000..4e955666 --- /dev/null +++ b/src/stm/altos.ld @@ -0,0 +1,72 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (!w) : ORIGIN = 0x20000000, LENGTH = 16K +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) +C_STACK_SIZE = 512; + +SECTIONS { + . = ORIGIN(rom); + + /* + * Rom contents + */ + + __text_start__ = .; + + .text : { + *(.interrupt) /* Interrupt vectors */ + *(.text) /* Executable code */ + *(.rodata) /* Constants */ + } > rom + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + __text_end__ = .; + } > rom + + . = ORIGIN(ram); + __data_start__ = .; + + /* Data -- relocated to RAM, but written to ROM + */ + .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) { + *(.data) /* initialized data */ + __data_end__ = .; + __bss_start__ = .; + } >ram + + .bss : { + *(.bss) + *(COMMON) + __bss_end__ = .; + } >ram + + PROVIDE(__stack__ = . + C_STACK_SIZE); + PROVIDE(end = .); + +} + +ENTRY(start); + + diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h new file mode 100644 index 00000000..e6f54fdb --- /dev/null +++ b/src/stm/ao_arch.h @@ -0,0 +1,129 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 +#include + +/* + * STM32L definitions and code fragments for AltOS + */ + +#define AO_STACK_SIZE 256 + +/* Various definitions to make GCC look more like SDCC */ + +#define ao_arch_naked_declare __attribute__((naked)) +#define ao_arch_naked_define +#define __pdata +#define __data +#define __xdata +#define __code const +#define __reentrant +#define __critical +#define __interrupt(n) +#define __at(n) + +#define ao_arch_reboot() /* XXX */ + +#define ao_arch_nop() asm("nop") + +#define ao_arch_interrupt(n) /* nothing */ + +#undef putchar +#undef getchar +#define putchar(c) ao_putchar(c) +#define getchar ao_getchar + +extern void putchar(char c); +extern char getchar(void); +extern void ao_avr_stdio_init(void); + +extern const uint16_t ao_serial_number; + +#define ARM_PUSH32(stack, val) (*(--(stack)) = (val)) + +#define ao_arch_task_members\ + uint32_t *sp; /* saved stack pointer */ + +#define cli() asm("cpsid i") +#define sei() asm("cpsie i") + +#define ao_arch_init_stack(task, start) do { \ + uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); \ + uint16_t a = (uint16_t) start; \ + int i; \ + \ + /* Return address */ \ + ARM_PUSH32(sp, a); \ + \ + /* Invalid link register */ \ + ARM_PUSH32(sp, 0xffffffff); \ + \ + /* Clear register values */ \ + i = 13; \ + while (i--) \ + ARM_PUSH32(sp, 0); \ + \ + /* PSR with interrupts enabled */ \ + ARM_PUSH32(sp, 0x01000000); \ + task->sp = sp; \ +} while (0); + +#define ao_arch_save_regs() do { \ + asm("push {r0-r12,lr}\n"); \ + cli(); \ + asm("mrs r0,psr" "\n\t" "push {r0}"); \ + sei(); \ + } while (0) + +#define ao_arch_save_stack() do { \ + uint32_t sp; \ + asm("mov %0,sp" : "=&r" (sp) ); \ + ao_cur_task->sp = (uint32_t *) (sp); \ + } while (0) + +#define ao_arch_isr_stack() /* nothing */ + +#define ao_arch_cpu_idle() do { \ + asm("wfi"); \ + } while (0) + +#define ao_arch_restore_stack() do { \ + uint32_t sp; \ + sp = (uint32_t) ao_cur_task->sp; \ + cli(); \ + asm("mov sp, %0" : : "r" (sp) ); \ + asm("pop {r0}" "\n\t" "msr psr,r0"); \ + asm("pop {r0-r12,lr}\n"); \ + asm("bx lr"); \ + } while(0) + +#define ao_arch_critical(b) do { cli(); do { b } while (0); sei(); } while (0) + +#define AO_ARM_NUM_ADC 12 + +struct ao_adc { + uint16_t tick; /* tick when the sample was read */ + uint16_t adc[AO_ARM_NUM_ADC]; /* samples */ +}; + + +#endif /* _AO_ARCH_H_ */ + diff --git a/src/stm/ao_interrupt.c b/src/stm/ao_interrupt.c new file mode 100644 index 00000000..6b4a9700 --- /dev/null +++ b/src/stm/ao_interrupt.c @@ -0,0 +1,169 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 + +extern void main(void); +extern char __stack__; +extern char __text_start__, __text_end__; +extern char __data_start__, __data_end__; +extern char __bss_start__, __bss_end__; + +/* Interrupt functions */ + +void stm_halt_isr(void) +{ + for(;;); +} + +void stm_ignore_isr(void) +{ +} + +void start(void) { + memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__); + memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__); + main(); +} + +#define STRINGIFY(x) #x + +#define isr(name) \ + void __attribute__ ((weak)) stm_ ## name ## _isr(void); \ + _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_ignore_isr)) + +#define isr_halt(name) \ + void __attribute__ ((weak)) stm_ ## name ## _isr(void); \ + _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_halt_isr)) + +isr(nmi) +isr_halt(hardfault) +isr_halt(memmanage) +isr_halt(busfault) +isr_halt(usagefault) +isr(svc) +isr(debugmon) +isr(pendsv) +isr(systick) +isr(wwdg) +isr(pvd) +isr(tamper_stamp) +isr(rtc_wkup) +isr(flash) +isr(rcc) +isr(exti0) +isr(exti1) +isr(exti2) +isr(exti3) +isr(exti4) +isr(dma1_channel1) +isr(dma1_channel2) +isr(dma1_channel3) +isr(dma1_channel4) +isr(dma1_channel5) +isr(dma1_channel6) +isr(dma1_channel7) +isr(adc1) +isr(usb_hp) +isr(usb_lp) +isr(dac) +isr(comp) +isr(exti9_5) +isr(lcd) +isr(tim9) +isr(tim10) +isr(tim11) +isr(tim2) +isr(tim3) +isr(tim4) +isr(i2c1_ev) +isr(i2c1_er) +isr(i2c2_ev) +isr(i2c2_er) +isr(spi1) +isr(spi2) +isr(usart1) +isr(usart2) +isr(usart3) +isr(exti15_10) +isr(rtc_alarm) +isr(usb_fs_wkup) +isr(tim6) +isr(tim7) + +#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr + +__attribute__ ((section(".interrupt"))) +const void *stm_interrupt_vector[] = { + [0] = &__stack__, + [1] = start, + i(0x08, nmi), + i(0x0c, hardfault), + i(0x10, memmanage), + i(0x14, busfault), + i(0x18, usagefault), + i(0x2c, svc), + i(0x30, debugmon), + i(0x38, pendsv), + i(0x3c, systick), + i(0x40, wwdg), + i(0x44, pvd), + i(0x48, tamper_stamp), + i(0x4c, rtc_wkup), + i(0x50, flash), + i(0x54, rcc), + i(0x58, exti0), + i(0x5c, exti1), + i(0x60, exti2), + i(0x64, exti3), + i(0x68, exti4), + i(0x6c, dma1_channel1), + i(0x70, dma1_channel2), + i(0x74, dma1_channel3), + i(0x78, dma1_channel4), + i(0x7c, dma1_channel5), + i(0x80, dma1_channel6), + i(0x84, dma1_channel7), + i(0x88, adc1), + i(0x8c, usb_hp), + i(0x90, usb_lp), + i(0x94, dac), + i(0x98, comp), + i(0x9c, exti9_5), + i(0xa0, lcd), + i(0xa4, tim9), + i(0xa8, tim10), + i(0xac, tim11), + i(0xb0, tim2), + i(0xb4, tim3), + i(0xb8, tim4), + i(0xbc, i2c1_ev), + i(0xc0, i2c1_er), + i(0xc4, i2c2_ev), + i(0xc8, i2c2_er), + i(0xcc, spi1), + i(0xd0, spi2), + i(0xd4, usart1), + i(0xd8, usart2), + i(0xdc, usart3), + i(0xe0, exti15_10), + i(0xe4, rtc_alarm), + i(0xe8, usb_fs_wkup), + i(0xec, tim6), + i(0xf0, tim7), +}; diff --git a/src/stm/ao_led.c b/src/stm/ao_led.c new file mode 100644 index 00000000..db65afdf --- /dev/null +++ b/src/stm/ao_led.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +__pdata uint8_t ao_led_enable; + +#define LED_PORT STM_GPIOD + +void +ao_led_on(uint8_t colors) +{ + LED_PORT->odr |= (colors & ao_led_enable); +} + +void +ao_led_off(uint8_t colors) +{ + LED_PORT->odr &= ~(colors & ao_led_enable); +} + +void +ao_led_set(uint8_t colors) +{ + LED_PORT->odr = (LED_PORT->odr & ~(ao_led_enable)) | (colors & ao_led_enable); +} + +void +ao_led_toggle(uint8_t colors) +{ + LED_PORT->odr ^= (colors & ao_led_enable); +} + +void +ao_led_for(uint8_t colors, uint16_t ticks) __reentrant +{ + ao_led_on(colors); + ao_delay(ticks); + ao_led_off(colors); +} + +void +ao_led_init(uint8_t enable) +{ + int bit; + + ao_led_enable = enable; + LED_PORT->odr &= ~enable; + for (bit = 0; bit < 16; bit++) { + if (enable & (1 << bit)) { + stm_moder_set(LED_PORT, bit, STM_MODER_OUTPUT); + stm_otyper_set(LED_PORT, bit, STM_OTYPER_PUSH_PULL); + } + } +} diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c new file mode 100644 index 00000000..dc446120 --- /dev/null +++ b/src/stm/ao_serial_stm.c @@ -0,0 +1,184 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 + +__xdata struct ao_fifo ao_usart1_rx_fifo; +__xdata struct ao_fifo ao_usart1_tx_fifo; + +void +ao_debug_out(char c) +{ + if (c == '\n') + ao_debug_out('\r'); + while (!(STM_USART1->usart_sr & (1 << STM_USART_SR_TXE))); + STM_USART1->usart_dr = c; +} + +#if 0 +static __xdata uint8_t ao_serial_tx1_started; + +static void +ao_serial_tx1_start(void) +{ + if (!ao_fifo_empty(ao_usart1_tx_fifo) && + !ao_serial_tx1_started) + { + ao_serial_tx1_started = 1; + ao_fifo_remove(ao_usart1_tx_fifo, STM_USART1->usart_dr); + } +} + +void usart1_isr(void) +{ + if (STM_USART1->usart_sr & (1 << STM_USART_SR_RXNE)) { + if (!ao_fifo_full(ao_usart1_rx_fifo)) + ao_fifo_insert(ao_usart1_rx_fifo, STM_USART1->usart_dr); + ao_wakeup(&ao_usart1_rx_fifo); +#if USE_SERIAL_STDIN + ao_wakeup(&ao_stdin_ready); +#endif + } + if (STM_USART1->usart_sr & (1 << STM_USART_SR_TXE)) { + ao_serial_tx1_started = 0; + ao_serial_tx1_start(); + ao_wakeup(&ao_usart1_tx_fifo); + } +} + +char +ao_serial_getchar(void) __critical +{ + char c; + cli(); + while (ao_fifo_empty(ao_usart1_rx_fifo)) + ao_sleep(&ao_usart1_rx_fifo); + ao_fifo_remove(ao_usart1_rx_fifo, c); + sei(); + return c; +} + +#if USE_SERIAL_STDIN +char +ao_serial_pollchar(void) __critical +{ + char c; + cli(); + if (ao_fifo_empty(ao_usart1_rx_fifo)) { + sei(); + return AO_READ_AGAIN; + } + ao_fifo_remove(ao_usart1_rx_fifo,c); + sei(); + return c; +} +#endif + +void +ao_serial_putchar(char c) __critical +{ + cli(); + while (ao_fifo_full(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); + ao_fifo_insert(ao_usart1_tx_fifo, c); + ao_serial_tx1_start(); + sei(); +} + +void +ao_serial_drain(void) __critical +{ + cli(); + while (!ao_fifo_empty(ao_usart1_tx_fifo)) + ao_sleep(&ao_usart1_tx_fifo); + sei(); +} + +#endif + +int _write(int file, char *ptr, int len) +{ + int l = len; + while (l--) + ao_debug_out(*ptr++); + return len; +} + +#define F_CPU 24000000 + +static const struct { + uint32_t usart_brr; +} ao_serial_speeds[] = { + [AO_SERIAL_SPEED_4800] = { + (F_CPU * 16) / (16 * 4800) + }, + [AO_SERIAL_SPEED_9600] = { + (F_CPU * 16) / (16 * 9600) + }, + [AO_SERIAL_SPEED_19200] = { + (F_CPU * 16) / (16 * 19200) + }, + [AO_SERIAL_SPEED_57600] = { + (F_CPU * 16) / (16 * 57600) + }, +}; + +void +ao_serial_set_speed(uint8_t speed) +{ +#if 0 + ao_serial_drain(); +#endif + if (speed > AO_SERIAL_SPEED_57600) + return; + STM_USART1->usart_brr = ao_serial_speeds[speed].usart_brr; +} + +void +ao_serial_init(void) +{ + STM_USART1->usart_cr1 = ((0 << STM_USART_CR1_OVER8) | + (1 << STM_USART_CR1_UE) | + (0 << STM_USART_CR1_M) | + (0 << STM_USART_CR1_WAKE) | + (0 << STM_USART_CR1_PCE) | + (0 << STM_USART_CR1_PS) | + (0 << STM_USART_CR1_PEIE) | + (0 << STM_USART_CR1_TXEIE) | /* XXX enable */ + (0 << STM_USART_CR1_TCIE) | + (0 << STM_USART_CR1_RXNEIE) | /* XXX enable */ + (0 << STM_USART_CR1_IDLEIE) | + (1 << STM_USART_CR1_TE) | + (1 << STM_USART_CR1_RE) | + (0 << STM_USART_CR1_RWU) | + (0 << STM_USART_CR1_SBK)); + + STM_USART1->usart_cr2 = 0; + STM_USART1->usart_cr3 = 0; + + /* Pick a 9600 baud rate */ + ao_serial_set_speed(AO_SERIAL_SPEED_9600); + + printf ("serial initialized\n"); +#if 0 +#if USE_SERIAL_STDIN + ao_add_stdio(ao_serial_pollchar, + ao_serial_putchar, + NULL); +#endif +#endif +} diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c new file mode 100644 index 00000000..f253e0c0 --- /dev/null +++ b/src/stm/ao_timer.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2012 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +static volatile __data uint16_t ao_tick_count; + +uint16_t ao_time(void) +{ + uint16_t v; + ao_arch_critical( + v = ao_tick_count; + ); + return v; +} + +static __xdata uint8_t ao_forever; + +void +ao_delay(uint16_t ticks) +{ + ao_alarm(ticks); + ao_sleep(&ao_forever); +} + +#define T2_CLOCK_DIVISOR 8 /* 24e6/8 = 3e6 */ +#define T2_SAMPLE_TIME 30000 /* 3e6/30000 = 100 */ + +#if HAS_ADC +volatile __data uint8_t ao_adc_interval = 1; +volatile __data uint8_t ao_adc_count; +#endif + +void +ao_debug_out(char c); + + +void tim2_isr(void) +{ + ++ao_tick_count; +#if HAS_ADC + if (++ao_adc_count == ao_adc_interval) { + ao_adc_count = 0; + ao_adc_poll(); + } +#endif +} + +#if HAS_ADC +void +ao_timer_set_adc_interval(uint8_t interval) __critical +{ + ao_adc_interval = interval; + ao_adc_count = 0; +} +#endif + +void +ao_timer_init(void) +{ +} + +void +ao_clock_init(void) +{ + uint32_t cfgr; + + /* Set flash latency to tolerate 32MHz SYSCLK -> 1 wait state */ + uint32_t acr = STM_FLASH->acr; + + /* Enable 64-bit access and prefetch */ + acr |= (1 << STM_FLASH_ACR_ACC64) | (1 << STM_FLASH_ACR_PRFEN); + STM_FLASH->acr = acr; + + /* Enable 1 wait state so the CPU can run at 32MHz */ + acr |= (1 << STM_FLASH_ACR_LATENCY); + STM_FLASH->acr = acr; + + /* Enable HSI RC clock 16MHz */ + if (!(STM_RCC->cr & (1 << STM_RCC_CR_HSIRDY))) { + STM_RCC->cr |= (1 << STM_RCC_CR_HSION); + while (!(STM_RCC->cr & (1 << STM_RCC_CR_HSIRDY))) + asm("nop"); + } + + /* Switch to direct HSI for SYSCLK */ + if ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) != + (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)) { + cfgr = STM_RCC->cfgr; + cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW); + cfgr |= (STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW); + STM_RCC->cfgr = cfgr; + while ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) != + (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)) + asm("nop"); + } + + /* Disable the PLL */ + STM_RCC->cr &= ~(1 << STM_RCC_CR_PLLON); + while (STM_RCC->cr & (1 << STM_RCC_CR_PLLRDY)) + asm("nop"); + + /* PLLVCO to 96MHz (for USB) -> PLLMUL = 6 */ + cfgr = STM_RCC->cfgr; + cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL); + cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL); + + /* SYSCLK to 32MHz from PLL clock -> PLLDIV = /3 */ + cfgr &= ~(STM_RCC_CFGR_PLLDIV_MASK << STM_RCC_CFGR_PLLDIV); + cfgr |= (STM_RCC_CFGR_PLLDIV_3 << STM_RCC_CFGR_PLLDIV); + + /* PLL source to HSI */ + cfgr &= ~(1 << STM_RCC_CFGR_PLLSRC); + + STM_RCC->cfgr = cfgr; + + /* Enable the PLL and wait for it */ + STM_RCC->cr |= (1 << STM_RCC_CR_PLLON); + while (!(STM_RCC->cr & (1 << STM_RCC_CR_PLLRDY))) + asm("nop"); + + /* Switch to the PLL for the system clock */ + + cfgr = STM_RCC->cfgr; + cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW); + cfgr |= (STM_RCC_CFGR_SW_PLL << STM_RCC_CFGR_SW); + STM_RCC->cfgr = cfgr; + while ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) != + (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS)) + asm("nop"); + + /* HCLK to 32MHz -> AHB prescaler = /1 */ + cfgr = STM_RCC->cfgr; + cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE); + cfgr |= (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE); + STM_RCC->cfgr = cfgr; + while ((STM_RCC->cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) != + (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE)) + asm ("nop"); + + /* PCLK1 to 16MHz -> APB1 Prescaler = 2 */ + cfgr = STM_RCC->cfgr; + cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1); + cfgr |= (STM_RCC_CFGR_PPRE1_DIV_2 << STM_RCC_CFGR_PPRE1); + STM_RCC->cfgr = cfgr; + + /* PCLK2 to 16MHz -> APB2 Prescaler = 2 */ + cfgr = STM_RCC->cfgr; + cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2); + cfgr |= (STM_RCC_CFGR_PPRE2_DIV_2 << STM_RCC_CFGR_PPRE2); + STM_RCC->cfgr = cfgr; + +} diff --git a/src/stm/registers.ld b/src/stm/registers.ld new file mode 100644 index 00000000..51921444 --- /dev/null +++ b/src/stm/registers.ld @@ -0,0 +1,47 @@ +stm_fsmc = 0xa0000000; +stm_aes = 0x50060000; +stm_dma = 0x40026000; +stm_flash = 0x40023c00; +stm_rcc = 0x40023800; +stm_crc = 0x40023000; +stm_gpioh = 0x40021400; +stm_gpioe = 0x40021000; +stm_gpiod = 0x40020c00; +stm_gpioc = 0x40020800; +stm_gpiob = 0x40020400; +stm_gpioa = 0x40020000; +stm_usart1 = 0x40013800; +stm_spi1 = 0x40013000; +stm_sdio = 0x40012c00; +stm_adc = 0x40012400; +stm_tim11 = 0x40011000; +stm_tim10 = 0x40010c00; +stm_tim9 = 0x40010800; +stm_exti = 0x40010400; +stm_syscfg = 0x40010000; +stm_comp = 0x40007c00; +stm_ri = 0x40007c04; +stm_dac = 0x40007400; +stm_pwr = 0x40007000; +stm_usb_sram = 0x40006000; +stm_usb = 0x40005c00; +stm_i2c2 = 0x40005800; +stm_i2c1 = 0x40005400; +stm_usart5 = 0x40005000; +stm_usart4 = 0x40004c00; +stm_usart3 = 0x40004800; +stm_usart2 = 0x40004400; +stm_spi3 = 0x40003c00; /* docs are broken here */ +stm_spi2 = 0x40003800; /* docs are broken here */ +stm_iwdg = 0x40003000; +stm_wwdg = 0x40002c00; +stm_rtc = 0x40002800; +stm_lcd = 0x40002400; +stm_tim7 = 0x40001400; +stm_tim6 = 0x40001000; +stm_tim5 = 0x40000c00; +stm_tim4 = 0x40000800; +stm_tim3 = 0x40000400; +stm_tim2 = 0x40000000; + +stm_nvic = 0xe000e100; \ No newline at end of file diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h new file mode 100644 index 00000000..c5e2a797 --- /dev/null +++ b/src/stm/stm32l.h @@ -0,0 +1,662 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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 + +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_ */