altos: Switch all tick variables to AO_TICK_TYPE/AO_TICK_SIGNED
[fw/altos] / src / stm-bringup / bringup.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <string.h>
20
21 #include <stdio.h>
22 #include "stm32l.h"
23
24 void delay(void);
25
26 static void
27 set_clock(void)
28 {
29         uint32_t        cfgr;
30         uint32_t        cr;
31         
32         /* Set flash latency to tolerate 32MHz SYSCLK  -> 1 wait state */
33         uint32_t        acr = stm_flash.acr;
34
35         /* Enable 64-bit access and prefetch */
36         acr |= (1 << STM_FLASH_ACR_ACC64) | (1 << STM_FLASH_ACR_PRFEN);
37         stm_flash.acr = acr;
38
39         /* Enable 1 wait state so the CPU can run at 32MHz */
40         /* (haven't managed to run the CPU at 32MHz yet, it's at 16MHz) */
41         acr |= (1 << STM_FLASH_ACR_LATENCY);
42         stm_flash.acr = acr;
43
44         /* HCLK to 16MHz -> AHB prescaler = /1 */
45         cfgr = stm_rcc.cfgr;
46         cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
47         cfgr |= (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE);
48         stm_rcc.cfgr = cfgr;
49         while ((stm_rcc.cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) !=
50                (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE))
51                 asm ("nop");
52 #define STM_AHB_PRESCALER       1
53
54         /* PCLK1 to 16MHz -> APB1 Prescaler = 1 */
55         cfgr = stm_rcc.cfgr;
56         cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1);
57         cfgr |= (STM_RCC_CFGR_PPRE1_DIV_1 << STM_RCC_CFGR_PPRE1);
58         stm_rcc.cfgr = cfgr;
59 #define STM_APB1_PRESCALER      1
60
61         /* PCLK2 to 16MHz -> APB2 Prescaler = 1 */
62         cfgr = stm_rcc.cfgr;
63         cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2);
64         cfgr |= (STM_RCC_CFGR_PPRE2_DIV_1 << STM_RCC_CFGR_PPRE2);
65         stm_rcc.cfgr = cfgr;
66 #define STM_APB2_PRESCALER      1
67
68         /* Enable power interface clock */
69         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
70
71         /* Set voltage range to 1.8V */
72
73         /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
74         while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
75                 asm("nop");
76
77         /* Configure voltage scaling range */
78         cr = stm_pwr.cr;
79         cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS);
80         cr |= (STM_PWR_CR_VOS_1_8 << STM_PWR_CR_VOS);
81         stm_pwr.cr = cr;
82
83         /* poll VOSF bit in PWR_CSR. Wait until it is reset to 0 */
84         while ((stm_pwr.csr & (1 << STM_PWR_CSR_VOSF)) != 0)
85                 asm("nop");
86
87         /* Enable HSI RC clock 16MHz */
88         if (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY))) {
89                 stm_rcc.cr |= (1 << STM_RCC_CR_HSION);
90                 while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY)))
91                         asm("nop");
92         }
93 #define STM_HSI 16000000
94
95         /* Switch to direct HSI for SYSCLK */
96         if ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
97             (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)) {
98                 cfgr = stm_rcc.cfgr;
99                 cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
100                 cfgr |= (STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW);
101                 stm_rcc.cfgr = cfgr;
102                 while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
103                        (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS))
104                         asm("nop");
105         }
106
107         /* Disable the PLL */
108         stm_rcc.cr &= ~(1 << STM_RCC_CR_PLLON);
109         while (stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY))
110                 asm("nop");
111         
112         /* PLLVCO to 96MHz (for USB) -> PLLMUL = 6, PLLDIV = 4 */
113         cfgr = stm_rcc.cfgr;
114         cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
115         cfgr &= ~(STM_RCC_CFGR_PLLDIV_MASK << STM_RCC_CFGR_PLLDIV);
116
117 //      cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
118 //      cfgr |= (STM_RCC_CFGR_PLLDIV_3 << STM_RCC_CFGR_PLLDIV);
119
120         cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
121         cfgr |= (STM_RCC_CFGR_PLLDIV_4 << STM_RCC_CFGR_PLLDIV);
122
123 #define STM_PLLMUL      6
124 #define STM_PLLDIV      4
125
126         /* PLL source to HSI */
127         cfgr &= ~(1 << STM_RCC_CFGR_PLLSRC);
128
129 #define STM_PLLSRC      STM_HSI
130
131         stm_rcc.cfgr = cfgr;
132
133         /* Enable the PLL and wait for it */
134         stm_rcc.cr |= (1 << STM_RCC_CR_PLLON);
135         while (!(stm_rcc.cr & (1 << STM_RCC_CR_PLLRDY)))
136                 asm("nop");
137
138         /* Switch to the PLL for the system clock */
139
140         cfgr = stm_rcc.cfgr;
141         cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
142         cfgr |= (STM_RCC_CFGR_SW_PLL << STM_RCC_CFGR_SW);
143         stm_rcc.cfgr = cfgr;
144         for (;;) {
145                 uint32_t        c, part, mask, val;
146
147                 c = stm_rcc.cfgr;
148                 mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS);
149                 val = (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS);
150                 part = c & mask;
151                 if (part == val)
152                         break;
153         }
154 }
155
156 #define STM_PLLVCO      (STM_PLLSRC * STM_PLLMUL)
157 #define STM_SYSCLK      (STM_PLLVCO / STM_PLLDIV)
158 #define STM_HCLK        (STM_SYSCLK / STM_AHB_PRESCALER)
159 #define STM_APB1        (STM_HCLK / STM_APB1_PRESCALER)
160 #define STM_APB2        (STM_HCLK / STM_APB2_PRESCALER)
161
162 #define BAUD_9600 (STM_APB2 / 9600)
163
164 void
165 set_serial()
166 {
167         uint32_t        moder, afr;
168
169         /* Enable GPIOA */
170         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
171         
172         /* Hook PA9, PA10 to USART1 (AFIO7) */
173         stm_moder_set(&stm_gpioa, 9, STM_MODER_ALTERNATE);
174         stm_moder_set(&stm_gpioa, 10, STM_MODER_ALTERNATE);
175         stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7);
176         stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7);
177
178         /* Enable USART1 */
179         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN);
180         
181         /* 9.6KBps. PCLK1 = 16MHz. OVER8 = 0 */
182
183         /* USARTDIV = PCLK1 / (16 * 9600) = 104.1{6}
184          * round to 104.1875 (1667 / 16)
185          *
186          * actual baud rate = 16e6 / (16 * 104.1875) = 9598Bps
187          */
188
189         stm_usart1.brr = BAUD_9600;
190
191         stm_usart1.cr1 = ((0 << STM_USART_CR1_OVER8) |
192                           (1 << STM_USART_CR1_UE) |
193                           (0 << STM_USART_CR1_M) |
194                           (0 << STM_USART_CR1_WAKE) |
195                           (0 << STM_USART_CR1_PCE) |
196                           (0 << STM_USART_CR1_PS) |
197                           (0 << STM_USART_CR1_PEIE) |
198                           (0 << STM_USART_CR1_TXEIE) |
199                           (0 << STM_USART_CR1_TCIE) |
200                           (0 << STM_USART_CR1_RXNEIE) |
201                           (0 << STM_USART_CR1_IDLEIE) |
202                           (1 << STM_USART_CR1_TE) |
203                           (1 << STM_USART_CR1_RE) |
204                           (0 << STM_USART_CR1_RWU) |
205                           (0 << STM_USART_CR1_SBK));
206
207         stm_usart1.cr2 = ((0 << STM_USART_CR2_LINEN) |
208                           (STM_USART_CR2_STOP_1 << STM_USART_CR2_STOP) |
209                           (0 << STM_USART_CR2_CLKEN) |
210                           (0 << STM_USART_CR2_CPOL) |
211                           (0 << STM_USART_CR2_CPHA) |
212                           (0 << STM_USART_CR2_LBCL) |
213                           (0 << STM_USART_CR2_LBDIE) |
214                           (0 << STM_USART_CR2_LBDL) |
215                           (0 << STM_USART_CR2_ADD));
216
217         stm_usart1.cr3 = ((0 << STM_USART_CR3_ONEBITE) |
218                           (0 << STM_USART_CR3_CTSIE) |
219                           (0 << STM_USART_CR3_CTSE) |
220                           (0 << STM_USART_CR3_RTSE) |
221                           (0 << STM_USART_CR3_DMAT) |
222                           (0 << STM_USART_CR3_DMAR) |
223                           (0 << STM_USART_CR3_SCEN) |
224                           (0 << STM_USART_CR3_NACK) |
225                           (0 << STM_USART_CR3_HDSEL) |
226                           (0 << STM_USART_CR3_IRLP) |
227                           (0 << STM_USART_CR3_IREN) |
228                           (0 << STM_USART_CR3_EIE));
229 }
230
231 void
232 outbyte(char c)
233 {
234         if (c == '\n')
235                 outbyte('\r');
236         while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE)))
237                 ;
238         stm_usart1.dr = c;
239 }
240
241 int putc( int c, FILE * stream ) {
242         outbyte(c);
243 }
244
245 void
246 serial_string(char *string)
247 {
248         char    c;
249
250         while (c = *string++)
251                 outbyte(c);
252 }
253
254 volatile AO_TICK_TYPE   tick_count;
255
256 void
257 stm_tim6_isr(void)
258 {
259         if (stm_tim6.sr & (1 << STM_TIM67_SR_UIF)) {
260                 stm_tim6.sr = 0;
261                 ++tick_count;
262         }
263 }
264
265 #define TIMER_10kHz     (STM_APB1 / 10000)
266
267 void
268 set_timer6(void)
269 {
270         stm_nvic_set_enable(STM_ISR_TIM6_POS);
271         stm_nvic_set_priority(STM_ISR_TIM6_POS, 1);
272
273         /* Turn on timer 6 */
274         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
275
276         stm_tim6.psc = TIMER_10kHz;
277         stm_tim6.arr = 100;
278         stm_tim6.cnt = 0;
279
280         /* Enable update interrupt */
281         stm_tim6.dier = (1 << STM_TIM67_DIER_UIE);
282
283         /* Poke timer to reload values */
284         stm_tim6.egr |= (1 << STM_TIM67_EGR_UG);
285
286         stm_tim6.cr2 = (STM_TIM67_CR2_MMS_RESET << STM_TIM67_CR2_MMS);
287
288         /* And turn it on */
289         stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
290                         (0 << STM_TIM67_CR1_OPM) |
291                         (1 << STM_TIM67_CR1_URS) |
292                         (0 << STM_TIM67_CR1_UDIS) |
293                         (1 << STM_TIM67_CR1_CEN));
294 }
295
296 void
297 main (void)
298 {
299         set_clock();
300         set_serial();
301         set_timer6();
302         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
303         stm_moder_set(&stm_gpiob, 7, STM_MODER_OUTPUT);
304         stm_moder_set(&stm_gpiob, 6, STM_MODER_OUTPUT);
305         for (;;) {
306                 stm_gpiob.odr = (1 << 7);
307                 printf ("hello, ");
308                 delay();
309                 stm_gpiob.odr = (1 << 6);
310                 printf ("world %d\n", tick_count);
311                 delay();
312         }
313 }
314
315 void
316 delay(void)
317 {
318         int i;
319         for (i = 0; i < 1000000; i++)
320                 __asm__ __volatile__ ("nop\n\t":::"memory");
321 }