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)
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/>.
29 #include "drivers/nvic.h"
31 #include "drivers/exti.h"
34 extiCallbackRec_t
* handler
;
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
] = {
55 #elif defined(STM32F3)
56 static const uint8_t extiGroupIRQn
[EXTI_IRQ_GROUPS
] = {
66 # warning "Unknown CPU"
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
79 # warning "Unknown CPU"
83 // Absorb the difference in IMR and PR assignments to registers
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)
92 #define EXTI_REG_IMR (EXTI->IMR)
93 #define EXTI_REG_PR (EXTI->PR)
99 // enable AFIO for EXTI support
100 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO
, ENABLE
);
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
);
108 #ifdef REMAP_TIM17_DMA
109 SYSCFG_DMAChannelRemapConfig(SYSCFG_DMARemap_TIM17
, ENABLE
);
112 memset(extiChannelRecs
, 0, sizeof(extiChannelRecs
));
113 memset(extiGroupPriority
, 0xff, sizeof(extiGroupPriority
));
116 void EXTIHandlerInit(extiCallbackRec_t
*self
, extiHandlerCallback
*fn
)
121 void EXTIConfig(IO_t io
, extiCallbackRec_t
*cb
, int irqPriority
, ioConfig_t config
, extiTrigger_t trigger
)
123 int chIdx
= IO_GPIOPinIdx(io
);
129 int group
= extiGroups
[chIdx
];
131 extiChannelRec_t
*rec
= &extiChannelRecs
[chIdx
];
134 #if defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
135 GPIO_InitTypeDef init
= {
137 .Mode
= GPIO_MODE_INPUT
| IO_CONFIG_GET_MODE(config
) | triggerLookupTable
[trigger
],
138 .Speed
= IO_CONFIG_GET_SPEED(config
),
139 .Pull
= IO_CONFIG_GET_PULL(config
),
141 HAL_GPIO_Init(IO_GPIO(io
), &init
);
144 if (extiGroupPriority
[group
] > irqPriority
) {
145 extiGroupPriority
[group
] = irqPriority
;
146 HAL_NVIC_SetPriority(extiGroupIRQn
[group
], NVIC_PRIORITY_BASE(irqPriority
), NVIC_PRIORITY_SUB(irqPriority
));
147 HAL_NVIC_EnableIRQ(extiGroupIRQn
[group
]);
150 IOConfigGPIO(io
, config
);
152 #if defined(STM32F10X)
153 GPIO_EXTILineConfig(IO_GPIO_PortSource(io
), IO_GPIO_PinSource(io
));
154 #elif defined(STM32F303xC)
155 SYSCFG_EXTILineConfig(IO_EXTI_PortSourceGPIO(io
), IO_EXTI_PinSource(io
));
156 #elif defined(STM32F4)
157 SYSCFG_EXTILineConfig(IO_EXTI_PortSourceGPIO(io
), IO_EXTI_PinSource(io
));
159 # warning "Unknown CPU"
162 uint32_t extiLine
= IO_EXTI_Line(io
);
164 EXTI_ClearITPendingBit(extiLine
);
166 EXTI_InitTypeDef EXTIInit
;
167 EXTIInit
.EXTI_Line
= extiLine
;
168 EXTIInit
.EXTI_Mode
= EXTI_Mode_Interrupt
;
169 EXTIInit
.EXTI_Trigger
= triggerLookupTable
[trigger
];
170 EXTIInit
.EXTI_LineCmd
= ENABLE
;
171 EXTI_Init(&EXTIInit
);
173 if (extiGroupPriority
[group
] > irqPriority
) {
174 extiGroupPriority
[group
] = irqPriority
;
176 NVIC_InitTypeDef NVIC_InitStructure
;
177 NVIC_InitStructure
.NVIC_IRQChannel
= extiGroupIRQn
[group
];
178 NVIC_InitStructure
.NVIC_IRQChannelPreemptionPriority
= NVIC_PRIORITY_BASE(irqPriority
);
179 NVIC_InitStructure
.NVIC_IRQChannelSubPriority
= NVIC_PRIORITY_SUB(irqPriority
);
180 NVIC_InitStructure
.NVIC_IRQChannelCmd
= ENABLE
;
181 NVIC_Init(&NVIC_InitStructure
);
186 void EXTIRelease(IO_t io
)
188 // don't forget to match cleanup with config
189 EXTIEnable(io
, false);
191 const int chIdx
= IO_GPIOPinIdx(io
);
197 extiChannelRec_t
*rec
= &extiChannelRecs
[chIdx
];
201 void EXTIEnable(IO_t io
, bool enable
)
203 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
204 uint32_t extiLine
= IO_EXTI_Line(io
);
211 EXTI_REG_IMR
|= extiLine
;
213 EXTI_REG_IMR
&= ~extiLine
;
215 #elif defined(STM32F303xC)
217 int extiLine
= IO_EXTI_Line(io
);
223 // assume extiLine < 32 (valid for all EXTI pins)
226 EXTI_REG_IMR
|= 1 << extiLine
;
228 EXTI_REG_IMR
&= ~(1 << extiLine
);
231 # error "Unknown CPU"
235 #define EXTI_EVENT_MASK 0xFFFF // first 16 bits only, see also definition of extiChannelRecs.
237 void EXTI_IRQHandler(uint32_t mask
)
239 uint32_t exti_active
= (EXTI_REG_IMR
& EXTI_REG_PR
) & mask
;
241 EXTI_REG_PR
= exti_active
; // clear pending mask (by writing 1)
243 while (exti_active
) {
244 unsigned idx
= 31 - __builtin_clz(exti_active
);
245 uint32_t mask
= 1 << idx
;
246 extiChannelRecs
[idx
].handler
->fn(extiChannelRecs
[idx
].handler
);
247 exti_active
&= ~mask
;
251 #define _EXTI_IRQ_HANDLER(name, mask) \
253 EXTI_IRQHandler(mask & EXTI_EVENT_MASK); \
259 _EXTI_IRQ_HANDLER(EXTI0_IRQHandler
, 0x0001);
260 _EXTI_IRQ_HANDLER(EXTI1_IRQHandler
, 0x0002);
261 #if defined(STM32F1) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
262 _EXTI_IRQ_HANDLER(EXTI2_IRQHandler
, 0x0004);
263 #elif defined(STM32F3)
264 _EXTI_IRQ_HANDLER(EXTI2_TS_IRQHandler
, 0x0004);
266 # warning "Unknown CPU"
268 _EXTI_IRQ_HANDLER(EXTI3_IRQHandler
, 0x0008);
269 _EXTI_IRQ_HANDLER(EXTI4_IRQHandler
, 0x0010);
270 _EXTI_IRQ_HANDLER(EXTI9_5_IRQHandler
, 0x03e0);
271 _EXTI_IRQ_HANDLER(EXTI15_10_IRQHandler
, 0xfc00);