Merge pull request #11494 from haslinghuis/dshot_gpio
[betaflight.git] / src / main / drivers / exti.c
blob7abf7928ca25d26b43bd4742f5b85db77572465d
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
25 #include "platform.h"
27 #ifdef USE_EXTI
29 #include "drivers/nvic.h"
30 #include "io_impl.h"
31 #include "drivers/exti.h"
33 typedef struct {
34 extiCallbackRec_t* handler;
35 } extiChannelRec_t;
37 extiChannelRec_t extiChannelRecs[16];
39 // IRQ grouping, same on F103, F303, F40x, F7xx, H7xx and G4xx.
40 #define EXTI_IRQ_GROUPS 7
41 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
42 static const uint8_t extiGroups[16] = { 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 };
43 static uint8_t extiGroupPriority[EXTI_IRQ_GROUPS];
45 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
46 static const uint8_t extiGroupIRQn[EXTI_IRQ_GROUPS] = {
47 EXTI0_IRQn,
48 EXTI1_IRQn,
49 EXTI2_IRQn,
50 EXTI3_IRQn,
51 EXTI4_IRQn,
52 EXTI9_5_IRQn,
53 EXTI15_10_IRQn
55 #elif defined(STM32F3)
56 static const uint8_t extiGroupIRQn[EXTI_IRQ_GROUPS] = {
57 EXTI0_IRQn,
58 EXTI1_IRQn,
59 EXTI2_TS_IRQn,
60 EXTI3_IRQn,
61 EXTI4_IRQn,
62 EXTI9_5_IRQn,
63 EXTI15_10_IRQn
65 #else
66 # warning "Unknown CPU"
67 #endif
69 static uint32_t triggerLookupTable[] = {
70 #if defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
71 [BETAFLIGHT_EXTI_TRIGGER_RISING] = GPIO_MODE_IT_RISING,
72 [BETAFLIGHT_EXTI_TRIGGER_FALLING] = GPIO_MODE_IT_FALLING,
73 [BETAFLIGHT_EXTI_TRIGGER_BOTH] = GPIO_MODE_IT_RISING_FALLING
74 #elif defined(STM32F1) || defined(STM32F3) || defined(STM32F4)
75 [BETAFLIGHT_EXTI_TRIGGER_RISING] = EXTI_Trigger_Rising,
76 [BETAFLIGHT_EXTI_TRIGGER_FALLING] = EXTI_Trigger_Falling,
77 [BETAFLIGHT_EXTI_TRIGGER_BOTH] = EXTI_Trigger_Rising_Falling
78 #else
79 # warning "Unknown CPU"
80 #endif
83 // Absorb the difference in IMR and PR assignments to registers
85 #if defined(STM32H7)
86 #define EXTI_REG_IMR (EXTI_D1->IMR1)
87 #define EXTI_REG_PR (EXTI_D1->PR1)
88 #elif defined(STM32G4)
89 #define EXTI_REG_IMR (EXTI->IMR1)
90 #define EXTI_REG_PR (EXTI->PR1)
91 #else
92 #define EXTI_REG_IMR (EXTI->IMR)
93 #define EXTI_REG_PR (EXTI->PR)
94 #endif
96 void EXTIInit(void)
98 #if defined(STM32F1)
99 // enable AFIO for EXTI support
100 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
101 #endif
102 #if defined(STM32F3) || defined(STM32F4)
103 /* Enable SYSCFG clock otherwise the EXTI irq handlers are not called */
104 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
105 #ifdef REMAP_TIM16_DMA
106 SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM16, ENABLE);
107 #endif
108 #ifdef REMAP_TIM17_DMA
109 SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM17, ENABLE);
110 #endif
111 #endif
112 memset(extiChannelRecs, 0, sizeof(extiChannelRecs));
113 memset(extiGroupPriority, 0xff, sizeof(extiGroupPriority));
116 void EXTIHandlerInit(extiCallbackRec_t *self, extiHandlerCallback *fn)
118 self->fn = fn;
121 void EXTIConfig(IO_t io, extiCallbackRec_t *cb, int irqPriority, ioConfig_t config, extiTrigger_t trigger)
123 int chIdx = IO_GPIOPinIdx(io);
125 if (chIdx < 0) {
126 return;
129 int group = extiGroups[chIdx];
131 extiChannelRec_t *rec = &extiChannelRecs[chIdx];
132 rec->handler = cb;
134 EXTIDisable(io);
136 #if defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
137 GPIO_InitTypeDef init = {
138 .Pin = IO_Pin(io),
139 .Mode = GPIO_MODE_INPUT | IO_CONFIG_GET_MODE(config) | triggerLookupTable[trigger],
140 .Speed = IO_CONFIG_GET_SPEED(config),
141 .Pull = IO_CONFIG_GET_PULL(config),
143 HAL_GPIO_Init(IO_GPIO(io), &init);
145 if (extiGroupPriority[group] > irqPriority) {
146 extiGroupPriority[group] = irqPriority;
147 HAL_NVIC_SetPriority(extiGroupIRQn[group], NVIC_PRIORITY_BASE(irqPriority), NVIC_PRIORITY_SUB(irqPriority));
148 HAL_NVIC_EnableIRQ(extiGroupIRQn[group]);
150 #else
151 IOConfigGPIO(io, config);
153 #if defined(STM32F10X)
154 GPIO_EXTILineConfig(IO_GPIO_PortSource(io), IO_GPIO_PinSource(io));
155 #elif defined(STM32F303xC)
156 SYSCFG_EXTILineConfig(IO_EXTI_PortSourceGPIO(io), IO_EXTI_PinSource(io));
157 #elif defined(STM32F4)
158 SYSCFG_EXTILineConfig(IO_EXTI_PortSourceGPIO(io), IO_EXTI_PinSource(io));
159 #else
160 # warning "Unknown CPU"
161 #endif
162 uint32_t extiLine = IO_EXTI_Line(io);
164 EXTI_InitTypeDef EXTIInit;
165 EXTIInit.EXTI_Line = extiLine;
166 EXTIInit.EXTI_Mode = EXTI_Mode_Interrupt;
167 EXTIInit.EXTI_Trigger = triggerLookupTable[trigger];
168 EXTIInit.EXTI_LineCmd = ENABLE;
169 EXTI_Init(&EXTIInit);
171 if (extiGroupPriority[group] > irqPriority) {
172 extiGroupPriority[group] = irqPriority;
174 NVIC_InitTypeDef NVIC_InitStructure;
175 NVIC_InitStructure.NVIC_IRQChannel = extiGroupIRQn[group];
176 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIORITY_BASE(irqPriority);
177 NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_PRIORITY_SUB(irqPriority);
178 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
179 NVIC_Init(&NVIC_InitStructure);
181 #endif
184 void EXTIRelease(IO_t io)
186 // don't forget to match cleanup with config
187 EXTIDisable(io);
189 const int chIdx = IO_GPIOPinIdx(io);
191 if (chIdx < 0) {
192 return;
195 extiChannelRec_t *rec = &extiChannelRecs[chIdx];
196 rec->handler = NULL;
199 void EXTIEnable(IO_t io)
201 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
202 uint32_t extiLine = IO_EXTI_Line(io);
204 if (!extiLine) {
205 return;
208 EXTI_REG_IMR |= extiLine;
209 #elif defined(STM32F303xC)
211 int extiLine = IO_EXTI_Line(io);
213 if (extiLine < 0) {
214 return;
217 // assume extiLine < 32 (valid for all EXTI pins)
219 EXTI_REG_IMR |= 1 << extiLine;
220 #else
221 # error "Unknown CPU"
222 #endif
226 void EXTIDisable(IO_t io)
228 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
229 uint32_t extiLine = IO_EXTI_Line(io);
231 if (!extiLine) {
232 return;
235 EXTI_REG_IMR &= ~extiLine;
236 EXTI_REG_PR = extiLine;
237 #elif defined(STM32F303xC)
239 int extiLine = IO_EXTI_Line(io);
241 if (extiLine < 0) {
242 return;
245 // assume extiLine < 32 (valid for all EXTI pins)
247 EXTI_REG_IMR &= ~(1 << extiLine);
248 #else
249 # error "Unknown CPU"
250 #endif
254 #define EXTI_EVENT_MASK 0xFFFF // first 16 bits only, see also definition of extiChannelRecs.
256 void EXTI_IRQHandler(uint32_t mask)
258 uint32_t exti_active = (EXTI_REG_IMR & EXTI_REG_PR) & mask;
260 EXTI_REG_PR = exti_active; // clear pending mask (by writing 1)
262 while (exti_active) {
263 unsigned idx = 31 - __builtin_clz(exti_active);
264 uint32_t mask = 1 << idx;
265 extiChannelRecs[idx].handler->fn(extiChannelRecs[idx].handler);
266 exti_active &= ~mask;
270 #define _EXTI_IRQ_HANDLER(name, mask) \
271 void name(void) { \
272 EXTI_IRQHandler(mask & EXTI_EVENT_MASK); \
274 struct dummy \
275 /**/
278 _EXTI_IRQ_HANDLER(EXTI0_IRQHandler, 0x0001);
279 _EXTI_IRQ_HANDLER(EXTI1_IRQHandler, 0x0002);
280 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
281 _EXTI_IRQ_HANDLER(EXTI2_IRQHandler, 0x0004);
282 #elif defined(STM32F3)
283 _EXTI_IRQ_HANDLER(EXTI2_TS_IRQHandler, 0x0004);
284 #else
285 # warning "Unknown CPU"
286 #endif
287 _EXTI_IRQ_HANDLER(EXTI3_IRQHandler, 0x0008);
288 _EXTI_IRQ_HANDLER(EXTI4_IRQHandler, 0x0010);
289 _EXTI_IRQ_HANDLER(EXTI9_5_IRQHandler, 0x03e0);
290 _EXTI_IRQ_HANDLER(EXTI15_10_IRQHandler, 0xfc00);
292 #endif