[4.4.2] Remove 15 m/s limit on estimated vario (#12788)
[betaflight.git] / src / main / drivers / exti.c
blobb7422e6d072c25694b2ec1cf8dab872b394c28b4
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 #if !defined(SIMULATOR_BUILD)
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 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(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 #else
56 # warning "Unknown CPU"
57 #endif
59 static uint32_t triggerLookupTable[] = {
60 #if defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
61 [BETAFLIGHT_EXTI_TRIGGER_RISING] = GPIO_MODE_IT_RISING,
62 [BETAFLIGHT_EXTI_TRIGGER_FALLING] = GPIO_MODE_IT_FALLING,
63 [BETAFLIGHT_EXTI_TRIGGER_BOTH] = GPIO_MODE_IT_RISING_FALLING
64 #elif defined(STM32F4)
65 [BETAFLIGHT_EXTI_TRIGGER_RISING] = EXTI_Trigger_Rising,
66 [BETAFLIGHT_EXTI_TRIGGER_FALLING] = EXTI_Trigger_Falling,
67 [BETAFLIGHT_EXTI_TRIGGER_BOTH] = EXTI_Trigger_Rising_Falling
68 #else
69 # warning "Unknown CPU"
70 #endif
73 // Absorb the difference in IMR and PR assignments to registers
75 #if defined(STM32H7)
76 #define EXTI_REG_IMR (EXTI_D1->IMR1)
77 #define EXTI_REG_PR (EXTI_D1->PR1)
78 #elif defined(STM32G4)
79 #define EXTI_REG_IMR (EXTI->IMR1)
80 #define EXTI_REG_PR (EXTI->PR1)
81 #else
82 #define EXTI_REG_IMR (EXTI->IMR)
83 #define EXTI_REG_PR (EXTI->PR)
84 #endif
86 void EXTIInit(void)
88 #if defined(STM32F4)
89 /* Enable SYSCFG clock otherwise the EXTI irq handlers are not called */
90 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
91 #ifdef REMAP_TIM16_DMA
92 SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM16, ENABLE);
93 #endif
94 #ifdef REMAP_TIM17_DMA
95 SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM17, ENABLE);
96 #endif
97 #endif
98 memset(extiChannelRecs, 0, sizeof(extiChannelRecs));
99 memset(extiGroupPriority, 0xff, sizeof(extiGroupPriority));
102 void EXTIHandlerInit(extiCallbackRec_t *self, extiHandlerCallback *fn)
104 self->fn = fn;
107 void EXTIConfig(IO_t io, extiCallbackRec_t *cb, int irqPriority, ioConfig_t config, extiTrigger_t trigger)
109 int chIdx = IO_GPIOPinIdx(io);
111 if (chIdx < 0) {
112 return;
115 int group = extiGroups[chIdx];
117 extiChannelRec_t *rec = &extiChannelRecs[chIdx];
118 rec->handler = cb;
120 EXTIDisable(io);
122 #if defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
123 GPIO_InitTypeDef init = {
124 .Pin = IO_Pin(io),
125 .Mode = GPIO_MODE_INPUT | IO_CONFIG_GET_MODE(config) | triggerLookupTable[trigger],
126 .Speed = IO_CONFIG_GET_SPEED(config),
127 .Pull = IO_CONFIG_GET_PULL(config),
129 HAL_GPIO_Init(IO_GPIO(io), &init);
131 if (extiGroupPriority[group] > irqPriority) {
132 extiGroupPriority[group] = irqPriority;
133 HAL_NVIC_SetPriority(extiGroupIRQn[group], NVIC_PRIORITY_BASE(irqPriority), NVIC_PRIORITY_SUB(irqPriority));
134 HAL_NVIC_EnableIRQ(extiGroupIRQn[group]);
136 #else
137 IOConfigGPIO(io, config);
139 #if defined(STM32F4)
140 SYSCFG_EXTILineConfig(IO_EXTI_PortSourceGPIO(io), IO_EXTI_PinSource(io));
141 #else
142 # warning "Unknown CPU"
143 #endif
144 uint32_t extiLine = IO_EXTI_Line(io);
146 EXTI_InitTypeDef EXTIInit;
147 EXTIInit.EXTI_Line = extiLine;
148 EXTIInit.EXTI_Mode = EXTI_Mode_Interrupt;
149 EXTIInit.EXTI_Trigger = triggerLookupTable[trigger];
150 EXTIInit.EXTI_LineCmd = ENABLE;
151 EXTI_Init(&EXTIInit);
153 if (extiGroupPriority[group] > irqPriority) {
154 extiGroupPriority[group] = irqPriority;
156 NVIC_InitTypeDef NVIC_InitStructure;
157 NVIC_InitStructure.NVIC_IRQChannel = extiGroupIRQn[group];
158 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIORITY_BASE(irqPriority);
159 NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_PRIORITY_SUB(irqPriority);
160 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
161 NVIC_Init(&NVIC_InitStructure);
163 #endif
166 void EXTIRelease(IO_t io)
168 // don't forget to match cleanup with config
169 EXTIDisable(io);
171 const int chIdx = IO_GPIOPinIdx(io);
173 if (chIdx < 0) {
174 return;
177 extiChannelRec_t *rec = &extiChannelRecs[chIdx];
178 rec->handler = NULL;
181 void EXTIEnable(IO_t io)
183 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
184 uint32_t extiLine = IO_EXTI_Line(io);
186 if (!extiLine) {
187 return;
190 EXTI_REG_IMR |= extiLine;
191 #else
192 # error "Unknown CPU"
193 #endif
197 void EXTIDisable(IO_t io)
199 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
200 uint32_t extiLine = IO_EXTI_Line(io);
202 if (!extiLine) {
203 return;
206 EXTI_REG_IMR &= ~extiLine;
207 EXTI_REG_PR = extiLine;
208 #else
209 # error "Unknown CPU"
210 #endif
214 #define EXTI_EVENT_MASK 0xFFFF // first 16 bits only, see also definition of extiChannelRecs.
216 void EXTI_IRQHandler(uint32_t mask)
218 uint32_t exti_active = (EXTI_REG_IMR & EXTI_REG_PR) & mask;
220 EXTI_REG_PR = exti_active; // clear pending mask (by writing 1)
222 while (exti_active) {
223 unsigned idx = 31 - __builtin_clz(exti_active);
224 uint32_t mask = 1 << idx;
225 extiChannelRecs[idx].handler->fn(extiChannelRecs[idx].handler);
226 exti_active &= ~mask;
230 #define _EXTI_IRQ_HANDLER(name, mask) \
231 void name(void) { \
232 EXTI_IRQHandler(mask & EXTI_EVENT_MASK); \
234 struct dummy \
235 /**/
238 _EXTI_IRQ_HANDLER(EXTI0_IRQHandler, 0x0001);
239 _EXTI_IRQ_HANDLER(EXTI1_IRQHandler, 0x0002);
240 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
241 _EXTI_IRQ_HANDLER(EXTI2_IRQHandler, 0x0004);
242 #else
243 # warning "Unknown CPU"
244 #endif
245 _EXTI_IRQ_HANDLER(EXTI3_IRQHandler, 0x0008);
246 _EXTI_IRQ_HANDLER(EXTI4_IRQHandler, 0x0010);
247 _EXTI_IRQ_HANDLER(EXTI9_5_IRQHandler, 0x03e0);
248 _EXTI_IRQ_HANDLER(EXTI15_10_IRQHandler, 0xfc00);
250 #endif