diff options
| author | Keith Packard <keithp@keithp.com> | 2012-03-16 14:25:37 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2012-03-28 21:37:02 -0700 | 
| commit | e2f13aa43ba79becbff6c9bfc18c665a58d96185 (patch) | |
| tree | b0a9ff7f5b94cb96637ce9e9d7938142ce32a5a9 /ao-bringup/stm/bringup.c | |
| parent | 3c7d1f6cfffb43299041f2850a48177f4e9b83a5 (diff) | |
Add example STM32L programs
This loads to flash and sends data over the serial link.
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'ao-bringup/stm/bringup.c')
| -rw-r--r-- | ao-bringup/stm/bringup.c | 306 | 
1 files changed, 306 insertions, 0 deletions
| 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 <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, +}; | 
