Switch from GPLv2 to GPLv2+
[fw/altos] / src / stm / ao_fast_timer.c
1 /*
2  * Copyright © 2013 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 #include <ao.h>
19 #include <ao_fast_timer.h>
20
21 static void (*ao_fast_timer_callback[AO_FAST_TIMER_MAX])(void);
22 static uint8_t ao_fast_timer_count;
23 static uint8_t ao_fast_timer_users;
24
25 static void
26 ao_fast_timer_enable(void)
27 {
28         stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
29                         (0 << STM_TIM67_CR1_OPM) |
30                         (1 << STM_TIM67_CR1_URS) |
31                         (0 << STM_TIM67_CR1_UDIS) |
32                         (1 << STM_TIM67_CR1_CEN));
33 }
34
35 static void
36 ao_fast_timer_disable(void)
37 {
38         stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
39                         (0 << STM_TIM67_CR1_OPM) |
40                         (1 << STM_TIM67_CR1_URS) |
41                         (0 << STM_TIM67_CR1_UDIS) |
42                         (0 << STM_TIM67_CR1_CEN));
43 }
44
45 void
46 ao_fast_timer_on(void (*callback)(void))
47 {
48         ao_fast_timer_callback[ao_fast_timer_count] = callback;
49         if (!ao_fast_timer_count++)
50                 ao_fast_timer_enable();
51 }
52
53 void
54 ao_fast_timer_off(void (*callback)(void))
55 {
56         uint8_t n;
57
58         for (n = 0; n < ao_fast_timer_count; n++)
59                 if (ao_fast_timer_callback[n] == callback) {
60                         for (; n < ao_fast_timer_count-1; n++) {
61                                 ao_fast_timer_callback[n] = ao_fast_timer_callback[n+1];
62                         }
63                         if (!--ao_fast_timer_count)
64                                 ao_fast_timer_disable();
65                         break;
66                 }
67 }
68
69 void stm_tim6_isr(void)
70 {
71         uint8_t i;
72         if (stm_tim6.sr & (1 << STM_TIM67_SR_UIF)) {
73                 stm_tim6.sr = 0;
74
75                 for (i = 0; i < ao_fast_timer_count; i++)
76                         (*ao_fast_timer_callback[i])();
77         }
78 }
79
80 /*
81  * According to the STM clock-configuration, timers run
82  * twice as fast as the APB1 clock *if* the APB1 prescaler
83  * is greater than 1.
84  */
85
86 #if AO_APB1_PRESCALER > 1
87 #define TIMER_23467_SCALER 2
88 #else
89 #define TIMER_23467_SCALER 1
90 #endif
91
92 #ifndef FAST_TIMER_FREQ
93 #define FAST_TIMER_FREQ 10000
94 #endif
95
96 #define TIMER_FAST      ((AO_PCLK1 * TIMER_23467_SCALER) / FAST_TIMER_FREQ)
97
98 void
99 ao_fast_timer_init(void)
100 {
101         if (!ao_fast_timer_users) {
102                 stm_nvic_set_enable(STM_ISR_TIM6_POS);
103                 stm_nvic_set_priority(STM_ISR_TIM6_POS, AO_STM_NVIC_CLOCK_PRIORITY);
104
105                 /* Turn on timer 6 */
106                 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
107
108                 stm_tim6.psc = TIMER_FAST;
109                 stm_tim6.arr = 9;
110                 stm_tim6.cnt = 0;
111
112                 /* Enable update interrupt */
113                 stm_tim6.dier = (1 << STM_TIM67_DIER_UIE);
114
115                 /* Poke timer to reload values */
116                 stm_tim6.egr |= (1 << STM_TIM67_EGR_UG);
117
118                 stm_tim6.cr2 = (STM_TIM67_CR2_MMS_RESET << STM_TIM67_CR2_MMS);
119                 ao_fast_timer_disable();
120         }
121         if (ao_fast_timer_users == AO_FAST_TIMER_MAX)
122                 ao_panic(AO_PANIC_FAST_TIMER);
123         ao_fast_timer_users++;
124 }
125