altos/stm32f1: Support timers 2,3,4 for fast timer
[fw/altos] / src / stm32f1 / ao_fast_timer.c
1 /*
2  * Copyright © 2024 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 #if AO_FAST_TIMER == 1
26
27 # define AO_FAST_TIMER_TYPE 18
28 # define stm_tim                stm_tim1
29 # define stm_tim_isr            stm_tim1_up_isr
30 # define STM_ISR_TIM_POS        STM_ISR_TIM1_UP_POS
31 # define STM_RCC_APBENR_TIMEN   STM_RCC_APB2ENR_TIM1EN
32
33 #elif AO_FAST_TIMER == 2
34
35 # define AO_FAST_TIMER_TYPE 234
36 # define stm_tim                stm_tim2
37 # define stm_tim_isr            stm_tim2_isr
38 # define STM_ISR_TIM_POS        STM_ISR_TIM2_POS
39 # define STM_RCC_APBENR_TIMEN   STM_RCC_APB1ENR_TIM2EN
40
41 #elif AO_FAST_TIMER == 3
42
43 # define AO_FAST_TIMER_TYPE 234
44 # define stm_tim                stm_tim3
45 # define stm_tim_isr            stm_tim3_isr
46 # define STM_ISR_TIM_POS        STM_ISR_TIM3_POS
47 # define STM_RCC_APBENR_TIMEN   STM_RCC_APB1ENR_TIM3EN
48
49 #elif AO_FAST_TIMER == 4
50
51 # define AO_FAST_TIMER_TYPE 234
52 # define stm_tim                stm_tim4
53 # define stm_tim_isr            stm_tim4_isr
54 # define STM_ISR_TIM_POS        STM_ISR_TIM4_POS
55 # define STM_RCC_APBENR_TIMEN   STM_RCC_APB1ENR_TIM4EN
56
57 #else
58 #error AO_FAST_TIMER
59 #endif
60
61 #if AO_FAST_TIMER_TYPE == 18
62
63 #define STM_TIM_CR1(cen) ((0 << STM_TIM18_CR1_CKD) |    \
64                           (0 << STM_TIM18_CR1_ARPE) |   \
65                           (0 << STM_TIM18_CR1_CMS) |    \
66                           (0 << STM_TIM18_CR1_DIR) |    \
67                           (0 << STM_TIM18_CR1_OPM) |    \
68                           (1 << STM_TIM18_CR1_URS) |    \
69                           (0 << STM_TIM18_CR1_UDIS) |   \
70                           ((cen) << STM_TIM18_CR1_CEN))
71 #define STM_TIM_SR_UIF          STM_TIM18_SR_UIF
72 #define STM_TIM_DIER_UIE        STM_TIM18_DIER_UIE
73 #define STM_TIM_EGR_UG          STM_TIM18_EGR_UG
74 #define STM_TIM_CR2_MMS         STM_TIM18_CR2_MMS
75 #define STM_TIM_CR2_MMS_RESET   STM_TIM18_CR2_MMS_RESET
76
77 #define AO_TIM_PCLK     AO_PCLK2
78
79 /*
80  * According to the STM clock-configuration, timers 18 run
81  * twice as fast as the APB2 clock *if* the APB2 prescaler
82  * is greater than 1.
83  */
84
85 #if AO_APB2_PRESCALER > 1
86 #define AO_TIM_SCALER 2
87 #else
88 #define AO_TIM_SCALER 1
89 #endif
90
91 #define STM_RCC_APB_TIM stm_rcc.apb2enr
92
93 #elif AO_FAST_TIMER_TYPE == 234
94
95 #define STM_TIM_CR1(cen) ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | \
96                           (0 << STM_TIM234_CR1_ARPE) |                  \
97                           (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | \
98                           (0 << STM_TIM234_CR1_DIR) |                   \
99                           (0 << STM_TIM234_CR1_OPM) |                   \
100                           (0 << STM_TIM234_CR1_URS) |                   \
101                           (0 << STM_TIM234_CR1_UDIS) |                  \
102                           ((cen) << STM_TIM234_CR1_CEN))                \
103
104 #define AO_TIM_PCLK     AO_PCLK1
105
106 /*
107  * According to the STM clock-configuration, timers 234 run
108  * twice as fast as the APB1 clock *if* the APB1 prescaler
109  * is greater than 1.
110  */
111
112 #if AO_APB1_PRESCALER > 1
113 #define AO_TIM_SCALER 2
114 #else
115 #define AO_TIM_SCALER 1
116 #endif
117
118 #define STM_TIM_SR_UIF          STM_TIM234_SR_UIF
119 #define STM_TIM_DIER_UIE        STM_TIM234_DIER_UIE
120 #define STM_TIM_EGR_UG          STM_TIM234_EGR_UG
121 #define STM_TIM_CR2_MMS         STM_TIM234_CR2_MMS
122 #define STM_TIM_CR2_MMS_RESET   STM_TIM234_CR2_MMS_RESET
123
124 #define STM_RCC_APB_TIM stm_rcc.apb1enr
125
126 #endif
127
128 static void
129 ao_fast_timer_enable(void)
130 {
131         stm_tim.cr1 = STM_TIM_CR1(1);
132 }
133
134 static void
135 ao_fast_timer_disable(void)
136 {
137         stm_tim.cr1 = STM_TIM_CR1(0);
138 }
139
140 void
141 ao_fast_timer_on(void (*callback)(void))
142 {
143         ao_fast_timer_callback[ao_fast_timer_count] = callback;
144         if (!ao_fast_timer_count++)
145                 ao_fast_timer_enable();
146 }
147
148 void
149 ao_fast_timer_off(void (*callback)(void))
150 {
151         uint8_t n;
152
153         for (n = 0; n < ao_fast_timer_count; n++)
154                 if (ao_fast_timer_callback[n] == callback) {
155                         for (; n < ao_fast_timer_count-1; n++) {
156                                 ao_fast_timer_callback[n] = ao_fast_timer_callback[n+1];
157                         }
158                         if (!--ao_fast_timer_count)
159                                 ao_fast_timer_disable();
160                         break;
161                 }
162 }
163
164 void stm_tim_isr(void)
165 {
166         uint8_t i;
167         if (stm_tim.sr & (1 << STM_TIM_SR_UIF)) {
168                 stm_tim.sr = 0;
169
170                 for (i = 0; i < ao_fast_timer_count; i++)
171                         (*ao_fast_timer_callback[i])();
172         }
173 }
174
175 #ifndef FAST_TIMER_FREQ
176 #define FAST_TIMER_FREQ 10000
177 #endif
178
179 #define TIMER_FAST      ((AO_TIM_PCLK * AO_TIM_SCALER) / FAST_TIMER_FREQ)
180
181 void
182 ao_fast_timer_init(void)
183 {
184         if (!ao_fast_timer_users) {
185                 stm_nvic_set_enable(STM_ISR_TIM_POS);
186                 stm_nvic_set_priority(STM_ISR_TIM_POS, AO_STM_NVIC_CLOCK_PRIORITY);
187
188                 /* Turn on timer 1 */
189                 STM_RCC_APB_TIM |= (1 << STM_RCC_APBENR_TIMEN);
190
191                 stm_tim.psc = TIMER_FAST;
192                 stm_tim.arr = 9;
193                 stm_tim.cnt = 0;
194
195                 /* Enable update interrupt */
196                 stm_tim.dier = (1 << STM_TIM_DIER_UIE);
197
198                 /* Poke timer to reload values */
199                 stm_tim.egr |= (1 << STM_TIM_EGR_UG);
200
201                 stm_tim.cr2 = (STM_TIM_CR2_MMS_RESET << STM_TIM_CR2_MMS);
202                 ao_fast_timer_disable();
203         }
204         if (ao_fast_timer_users == AO_FAST_TIMER_MAX)
205                 ao_panic(AO_PANIC_FAST_TIMER);
206         ao_fast_timer_users++;
207 }
208