Add STM platform and stm-bringup demo program
[fw/altos] / src / stm / ao_timer.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; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19
20 static volatile __data uint16_t ao_tick_count;
21
22 uint16_t ao_time(void)
23 {
24         uint16_t        v;
25         ao_arch_critical(
26                 v = ao_tick_count;
27                 );
28         return v;
29 }
30
31 static __xdata uint8_t ao_forever;
32
33 void
34 ao_delay(uint16_t ticks)
35 {
36         ao_alarm(ticks);
37         ao_sleep(&ao_forever);
38 }
39
40 #define T2_CLOCK_DIVISOR        8       /* 24e6/8 = 3e6 */
41 #define T2_SAMPLE_TIME          30000   /* 3e6/30000 = 100 */
42
43 #if HAS_ADC
44 volatile __data uint8_t ao_adc_interval = 1;
45 volatile __data uint8_t ao_adc_count;
46 #endif
47
48 void
49 ao_debug_out(char c);
50
51
52 void tim2_isr(void)
53 {
54         ++ao_tick_count;
55 #if HAS_ADC
56         if (++ao_adc_count == ao_adc_interval) {
57                 ao_adc_count = 0;
58                 ao_adc_poll();
59         }
60 #endif
61 }
62
63 #if HAS_ADC
64 void
65 ao_timer_set_adc_interval(uint8_t interval) __critical
66 {
67         ao_adc_interval = interval;
68         ao_adc_count = 0;
69 }
70 #endif
71
72 void
73 ao_timer_init(void)
74 {
75 }
76
77 void
78 ao_clock_init(void)
79 {
80         uint32_t        cfgr;
81         
82         /* Set flash latency to tolerate 32MHz SYSCLK  -> 1 wait state */
83         uint32_t        acr = STM_FLASH->acr;
84
85         /* Enable 64-bit access and prefetch */
86         acr |= (1 << STM_FLASH_ACR_ACC64) | (1 << STM_FLASH_ACR_PRFEN);
87         STM_FLASH->acr = acr;
88
89         /* Enable 1 wait state so the CPU can run at 32MHz */
90         acr |= (1 << STM_FLASH_ACR_LATENCY);
91         STM_FLASH->acr = acr;
92
93         /* Enable HSI RC clock 16MHz */
94         if (!(STM_RCC->cr & (1 << STM_RCC_CR_HSIRDY))) {
95                 STM_RCC->cr |= (1 << STM_RCC_CR_HSION);
96                 while (!(STM_RCC->cr & (1 << STM_RCC_CR_HSIRDY)))
97                         asm("nop");
98         }
99
100         /* Switch to direct HSI for SYSCLK */
101         if ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
102             (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)) {
103                 cfgr = STM_RCC->cfgr;
104                 cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
105                 cfgr |= (STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW);
106                 STM_RCC->cfgr = cfgr;
107                 while ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
108                        (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS))
109                         asm("nop");
110         }
111
112         /* Disable the PLL */
113         STM_RCC->cr &= ~(1 << STM_RCC_CR_PLLON);
114         while (STM_RCC->cr & (1 << STM_RCC_CR_PLLRDY))
115                 asm("nop");
116         
117         /* PLLVCO to 96MHz (for USB) -> PLLMUL = 6 */
118         cfgr = STM_RCC->cfgr;
119         cfgr &= ~(STM_RCC_CFGR_PLLMUL_MASK << STM_RCC_CFGR_PLLMUL);
120         cfgr |= (STM_RCC_CFGR_PLLMUL_6 << STM_RCC_CFGR_PLLMUL);
121         
122         /* SYSCLK to 32MHz from PLL clock -> PLLDIV = /3 */
123         cfgr &= ~(STM_RCC_CFGR_PLLDIV_MASK << STM_RCC_CFGR_PLLDIV);
124         cfgr |= (STM_RCC_CFGR_PLLDIV_3 << STM_RCC_CFGR_PLLDIV);
125
126         /* PLL source to HSI */
127         cfgr &= ~(1 << STM_RCC_CFGR_PLLSRC);
128
129         STM_RCC->cfgr = cfgr;
130
131         /* Enable the PLL and wait for it */
132         STM_RCC->cr |= (1 << STM_RCC_CR_PLLON);
133         while (!(STM_RCC->cr & (1 << STM_RCC_CR_PLLRDY)))
134                 asm("nop");
135
136         /* Switch to the PLL for the system clock */
137
138         cfgr = STM_RCC->cfgr;
139         cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW);
140         cfgr |= (STM_RCC_CFGR_SW_PLL << STM_RCC_CFGR_SW);
141         STM_RCC->cfgr = cfgr;
142         while ((STM_RCC->cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
143                (STM_RCC_CFGR_SWS_PLL << STM_RCC_CFGR_SWS))
144                 asm("nop");
145
146         /* HCLK to 32MHz -> AHB prescaler = /1 */
147         cfgr = STM_RCC->cfgr;
148         cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
149         cfgr |= (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE);
150         STM_RCC->cfgr = cfgr;
151         while ((STM_RCC->cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) !=
152                (STM_RCC_CFGR_HPRE_DIV_1 << STM_RCC_CFGR_HPRE))
153                 asm ("nop");
154
155         /* PCLK1 to 16MHz -> APB1 Prescaler = 2 */
156         cfgr = STM_RCC->cfgr;
157         cfgr &= ~(STM_RCC_CFGR_PPRE1_MASK << STM_RCC_CFGR_PPRE1);
158         cfgr |= (STM_RCC_CFGR_PPRE1_DIV_2 << STM_RCC_CFGR_PPRE1);
159         STM_RCC->cfgr = cfgr;
160
161         /* PCLK2 to 16MHz -> APB2 Prescaler = 2 */
162         cfgr = STM_RCC->cfgr;
163         cfgr &= ~(STM_RCC_CFGR_PPRE2_MASK << STM_RCC_CFGR_PPRE2);
164         cfgr |= (STM_RCC_CFGR_PPRE2_DIV_2 << STM_RCC_CFGR_PPRE2);
165         STM_RCC->cfgr = cfgr;
166
167 }