Implement ASSERT() to make debugging easier (#476)
[betaflight.git] / src / main / drivers / exti.c
blob209ac68a30baf6897f6b89b0ced1d7c4e66eeaa4
1 #include <stdbool.h>
2 #include <stdint.h>
3 #include <string.h>
5 #include "platform.h"
6 #include "build/assert.h"
8 #include "nvic.h"
9 #include "io_impl.h"
10 #include "exti.h"
12 #ifdef USE_EXTI
14 typedef struct {
15 extiCallbackRec_t* handler;
16 } extiChannelRec_t;
18 extiChannelRec_t extiChannelRecs[16];
20 // IRQ gouping, same on 103 and 303
21 #define EXTI_IRQ_GROUPS 7
22 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
23 static const uint8_t extiGroups[16] = { 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 };
24 static uint8_t extiGroupPriority[EXTI_IRQ_GROUPS];
26 #if defined(STM32F1) || defined(STM32F4)
27 static const uint8_t extiGroupIRQn[EXTI_IRQ_GROUPS] = {
28 EXTI0_IRQn,
29 EXTI1_IRQn,
30 EXTI2_IRQn,
31 EXTI3_IRQn,
32 EXTI4_IRQn,
33 EXTI9_5_IRQn,
34 EXTI15_10_IRQn
36 #elif defined(STM32F3)
37 static const uint8_t extiGroupIRQn[EXTI_IRQ_GROUPS] = {
38 EXTI0_IRQn,
39 EXTI1_IRQn,
40 EXTI2_TS_IRQn,
41 EXTI3_IRQn,
42 EXTI4_IRQn,
43 EXTI9_5_IRQn,
44 EXTI15_10_IRQn
46 #else
47 # warning "Unknown CPU"
48 #endif
51 void EXTIInit(void)
53 #if defined(STM32F1)
54 // enable AFIO for EXTI support
55 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
56 #endif
57 #if defined(STM32F3) || defined(STM32F4)
58 /* Enable SYSCFG clock otherwise the EXTI irq handlers are not called */
59 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
60 #endif
61 memset(extiChannelRecs, 0, sizeof(extiChannelRecs));
62 memset(extiGroupPriority, 0xff, sizeof(extiGroupPriority));
65 void EXTIHandlerInit(extiCallbackRec_t *self, extiHandlerCallback *fn)
67 self->fn = fn;
70 void EXTIConfig(IO_t io, extiCallbackRec_t *cb, int irqPriority, EXTITrigger_TypeDef trigger)
72 int chIdx;
73 chIdx = IO_GPIOPinIdx(io);
74 if(chIdx < 0)
75 return;
77 // we have only 16 extiChannelRecs
78 ASSERT(chIdx < 16);
80 extiChannelRec_t *rec = &extiChannelRecs[chIdx];
81 int group = extiGroups[chIdx];
83 rec->handler = cb;
84 #if defined(STM32F10X)
85 GPIO_EXTILineConfig(IO_GPIO_PortSource(io), IO_GPIO_PinSource(io));
86 #elif defined(STM32F303xC)
87 SYSCFG_EXTILineConfig(IO_EXTI_PortSourceGPIO(io), IO_EXTI_PinSource(io));
88 #elif defined(STM32F4)
89 SYSCFG_EXTILineConfig(IO_EXTI_PortSourceGPIO(io), IO_EXTI_PinSource(io));
90 #else
91 # warning "Unknown CPU"
92 #endif
93 uint32_t extiLine = IO_EXTI_Line(io);
95 EXTI_ClearITPendingBit(extiLine);
97 EXTI_InitTypeDef EXTIInit;
98 EXTIInit.EXTI_Line = extiLine;
99 EXTIInit.EXTI_Mode = EXTI_Mode_Interrupt;
100 EXTIInit.EXTI_Trigger = trigger;
101 EXTIInit.EXTI_LineCmd = ENABLE;
102 EXTI_Init(&EXTIInit);
104 if(extiGroupPriority[group] > irqPriority) {
105 extiGroupPriority[group] = irqPriority;
107 NVIC_InitTypeDef NVIC_InitStructure;
108 NVIC_InitStructure.NVIC_IRQChannel = extiGroupIRQn[group];
109 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIORITY_BASE(irqPriority);
110 NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_PRIORITY_SUB(irqPriority);
111 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
112 NVIC_Init(&NVIC_InitStructure);
116 void EXTIRelease(IO_t io)
118 // don't forget to match cleanup with config
119 EXTIEnable(io, false);
121 int chIdx;
122 chIdx = IO_GPIOPinIdx(io);
123 if(chIdx < 0)
124 return;
126 // we have only 16 extiChannelRecs
127 ASSERT(chIdx < 16);
129 extiChannelRec_t *rec = &extiChannelRecs[chIdx];
130 rec->handler = NULL;
133 void EXTIEnable(IO_t io, bool enable)
135 #if defined(STM32F1) || defined(STM32F4)
136 uint32_t extiLine = IO_EXTI_Line(io);
137 if(!extiLine)
138 return;
139 if(enable)
140 EXTI->IMR |= extiLine;
141 else
142 EXTI->IMR &= ~extiLine;
143 #elif defined(STM32F303xC)
144 int extiLine = IO_EXTI_Line(io);
145 if(extiLine < 0)
146 return;
147 // assume extiLine < 32 (valid for all EXTI pins)
148 if(enable)
149 EXTI->IMR |= 1 << extiLine;
150 else
151 EXTI->IMR &= ~(1 << extiLine);
152 #else
153 # error "Unsupported target"
154 #endif
157 void EXTI_IRQHandler(void)
159 uint32_t exti_active = EXTI->IMR & EXTI->PR;
161 while(exti_active) {
162 unsigned idx = 31 - __builtin_clz(exti_active);
163 uint32_t mask = 1 << idx;
164 extiChannelRecs[idx].handler->fn(extiChannelRecs[idx].handler);
165 EXTI->PR = mask; // clear pending mask (by writing 1)
166 exti_active &= ~mask;
170 #define _EXTI_IRQ_HANDLER(name) \
171 void name(void) { \
172 EXTI_IRQHandler(); \
174 struct dummy \
175 /**/
178 _EXTI_IRQ_HANDLER(EXTI0_IRQHandler);
179 _EXTI_IRQ_HANDLER(EXTI1_IRQHandler);
180 #if defined(STM32F1)
181 _EXTI_IRQ_HANDLER(EXTI2_IRQHandler);
182 #elif defined(STM32F3) || defined(STM32F4)
183 _EXTI_IRQ_HANDLER(EXTI2_TS_IRQHandler);
184 #else
185 # warning "Unknown CPU"
186 #endif
187 _EXTI_IRQ_HANDLER(EXTI3_IRQHandler);
188 _EXTI_IRQ_HANDLER(EXTI4_IRQHandler);
189 _EXTI_IRQ_HANDLER(EXTI9_5_IRQHandler);
190 _EXTI_IRQ_HANDLER(EXTI15_10_IRQHandler);
192 #endif