ARMEBS4  revision-26.06.2015
stm32_gpio_irq.c
Go to the documentation of this file.
1 /**
2  * \file heivs/stm32_gpio_irq.c
3  * \brief GPIO interrupts
4  * \author marc dot pignat at hevs dot ch
5  */
6 
7 #include "heivs/stm32_gpio_irq.h"
8 #include <stdint.h>
9 #include <stddef.h>
10 #include "stm32/stm32f4xx_rcc.h"
11 #include "stm32/stm32f4xx_misc.h"
12 #include "stm32/stm32f4xx_syscfg.h"
13 #include "stm32/stm32f4xx_exti.h"
14 #include "heivs/bsp.h"
15 
16 struct gpio_irq_handler_t
17 {
18  uint32_t (*handler)(const struct gpio_t *gpio);
19  enum gpio_irq_mode_e mode;
20  struct gpio_t gpio;
21 };
22 
23 static struct gpio_irq_handler_t handlers[16];
24 
25 static uint32_t exti_line(const struct gpio_t *gpio)
26 {
27  return gpio->mask;
28 }
29 
30 static status_e _disable_irq(const struct gpio_t *gpio)
31 {
32  EXTI_InitTypeDef EXTI_InitStructure;
33  EXTI_StructInit(&EXTI_InitStructure);
34  EXTI_InitStructure.EXTI_Line = exti_line(gpio);
35  EXTI_InitStructure.EXTI_LineCmd = DISABLE;
36 
37  EXTI_Init(&EXTI_InitStructure);
38 
39  return NO_ERROR;
40 }
41 
42 static const struct gpio_t NC = GPIO_NC;
43 
44 status_e gpio_irq_disable(const struct gpio_t *gpio)
45 {
46  return gpio_irq_setup(gpio, NULL, GPIO_IRQ_MODE_DISABLED, 0);
47 }
48 
49 static void exti_handler(uint32_t nr)
50 {
51  const struct gpio_t *gpio = &handlers[nr].gpio;
52  EXTI->PR = exti_line(gpio);
53 
54  switch (handlers[nr].mode)
55  {
57  break;
58 
62  handlers[nr].handler(gpio);
63  break;
64 
66  while (!gpio_get(gpio))
67  {
68  if (handlers[nr].handler(gpio))
69  {
70  /* The gpio hasn't moved, but the handler says it's ok*/
71  break;
72  }
73  }
74  break;
75 
77  while (gpio_get(gpio))
78  {
79  if (handlers[nr].handler(gpio))
80  {
81  /* The gpio hasn't moved, but the handler says it's ok*/
82  break;
83  }
84  }
85  break;
86 
87  default:
88  // ERROR_BAD_SWITCH !?!
90  break;
91  }
92 }
93 
94 static void exti0_irq_handler(void)
95 {
96  exti_handler(0);
97 }
98 
99 static void exti1_irq_handler(void)
100 {
101  exti_handler(1);
102 }
103 
104 static void exti2_irq_handler(void)
105 {
106  exti_handler(2);
107 }
108 
109 static void exti3_irq_handler(void)
110 {
111  exti_handler(3);
112 }
113 
114 static void exit4_irq_handler(void)
115 {
116  exti_handler(4);
117 }
118 
119 static void exti9_5_irq_handler(void)
120 {
121  uint32_t i;
122  for (i = 5 ; i <= 9 ; i++)
123  {
124  const struct gpio_t *gpio = &handlers[i].gpio;
125 
126  if (!exti_line(gpio))
127  {
128  continue;
129  }
130 
131  if (EXTI_GetITStatus(exti_line(gpio)))
132  {
133  exti_handler(i);
134  }
135  }
136 }
137 
138 static void exti15_10_irq_handler(void)
139 {
140  uint32_t i;
141  for (i = 10 ; i <= 15 ; i++)
142  {
143  const struct gpio_t *gpio = &handlers[i].gpio;
144 
145  if (!exti_line(gpio))
146  {
147  continue;
148  }
149 
150  if (EXTI_GetITStatus(exti_line(gpio)))
151  {
152  exti_handler(i);
153  }
154  }
155 }
156 
157 struct gpio_exti_map_t
158 {
159  uint32_t irq_nr;
160  void (*handler)(void);
161 };
162 
163 static const struct gpio_exti_map_t map[] =
164 {
165  {.irq_nr = EXTI0_IRQn, .handler = exti0_irq_handler, },
166  {.irq_nr = EXTI1_IRQn, .handler = exti1_irq_handler, },
167  {.irq_nr = EXTI2_IRQn, .handler = exti2_irq_handler, },
168  {.irq_nr = EXTI3_IRQn, .handler = exti3_irq_handler, },
169  {.irq_nr = EXTI4_IRQn, .handler = exit4_irq_handler, },
170  {.irq_nr = EXTI9_5_IRQn, .handler = exti9_5_irq_handler, },
171  {.irq_nr = EXTI9_5_IRQn, .handler = exti9_5_irq_handler, },
172  {.irq_nr = EXTI9_5_IRQn, .handler = exti9_5_irq_handler, },
173  {.irq_nr = EXTI9_5_IRQn, .handler = exti9_5_irq_handler, },
174  {.irq_nr = EXTI9_5_IRQn, .handler = exti9_5_irq_handler, },
175  {.irq_nr = EXTI15_10_IRQn, .handler = exti15_10_irq_handler, },
176  {.irq_nr = EXTI15_10_IRQn, .handler = exti15_10_irq_handler, },
177  {.irq_nr = EXTI15_10_IRQn, .handler = exti15_10_irq_handler, },
178  {.irq_nr = EXTI15_10_IRQn, .handler = exti15_10_irq_handler, },
179  {.irq_nr = EXTI15_10_IRQn, .handler = exti15_10_irq_handler, },
180  {.irq_nr = EXTI15_10_IRQn, .handler = exti15_10_irq_handler, },
181 };
182 
183 status_e gpio_irq_restore(const struct gpio_t *gpio)
184 {
185  switch (handlers[gpio->nr].mode)
186  {
190  return NO_ERROR;
191  break;
192 
194  if (!gpio_get(gpio))
195  {
196  EXTI_GenerateSWInterrupt(exti_line(gpio));
197  return NO_ERROR;
198  }
199  break;
200 
202  if (gpio_get(gpio))
203  {
204  EXTI_GenerateSWInterrupt(exti_line(gpio));
205  return NO_ERROR;
206  }
207  break;
208 
209  default:
210  return ERROR_BAD_SWITCH;
211  break;
212  }
213 
214  return ERROR_BAD_SWITCH;
215 }
216 
217 status_e gpio_irq_setup(const struct gpio_t *gpio, uint32_t (*handler)(const struct gpio_t *gpio), enum gpio_irq_mode_e mode, uint32_t prio)
218 {
219  EXTI_InitTypeDef EXTI_InitStructure;
220  NVIC_InitTypeDef NVIC_InitStructure;
221 
222  // Parameters validation
223  switch (mode)
224  {
226  if (handler != NULL)
227  {
228  return ERROR_BAD_PARAM;
229  }
230  break;
231 
237  break;
238 
239  default:
240  return ERROR_BAD_PARAM;
241  break;
242  }
243 
244  if (gpio->nr >= ARRAY_SIZE(handlers))
245  {
246  return ERROR_BAD_PARAM;
247  }
248 
249  // Disabling ?
250  if (!handler)
251  {
252  status_e status = _disable_irq(gpio);
253  handlers[gpio->nr].mode = GPIO_IRQ_MODE_DISABLED;
254  handlers[gpio->nr].handler = handler;
255  handlers[gpio->nr].gpio = NC;
256 
257  return status;
258  }
259 
260  handlers[gpio->nr].mode = mode;
261  handlers[gpio->nr].handler = handler;
262  handlers[gpio->nr].gpio = *gpio;
263 
264  gpio_setup(gpio);
265 
266  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
267  EXTI_StructInit(&EXTI_InitStructure);
268  EXTI_InitStructure.EXTI_Line = exti_line(gpio);
269  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
270  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
271 
272  switch (mode)
273  {
275  return ERROR_BAD_SWITCH;
276  break;
277 
279  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
280  break;
281 
283  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
284  break;
285 
287  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
288  break;
289 
291  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
292  break;
293 
295  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
296  break;
297 
298  default:
299  return ERROR_BAD_SWITCH;
300  break;
301 
302  }
303 
304  SYSCFG_EXTILineConfig(gpio->ctrl, gpio->nr);
305  EXTI_Init(&EXTI_InitStructure);
306 
307  NVIC_InitStructure.NVIC_IRQChannel = map[gpio->nr].irq_nr;
308 
309  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = prio;
310  NVIC_InitStructure.NVIC_IRQChannelSubPriority = prio;
311  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
312  NVIC_InitStructure.NVIC_Handler = map[gpio->nr].handler;
313  NVIC_Init(&NVIC_InitStructure);
314 
315  // Force pending level interrupts
316  switch (mode)
317  {
319  if (!gpio_get(gpio))
320  {
321  EXTI_GenerateSWInterrupt(exti_line(gpio));
322  }
323  break;
324 
326  if (gpio_get(gpio))
327  {
328  EXTI_GenerateSWInterrupt(exti_line(gpio));
329  }
330  break;
331 
332  default:
333  break;
334  }
335  return NO_ERROR;
336 }
337 
338 
339 
This file contains all the functions prototypes for the RCC firmware library.
FunctionalState EXTI_LineCmd
EXTITrigger_TypeDef EXTI_Trigger
Level low (emulated)
BSP - Board Support Package.
EXTI Init Structure definition.
uint8_t nr
Pin number (0 for GPIOx0, ... , 3 for GPIOx3, ...)
Definition: stm32_gpio.h:99
uint8_t NVIC_IRQChannel
uint8_t ctrl
Controller number (0 for GPIOA, 1 for GPIOB, ...)
Definition: stm32_gpio.h:98
gpio_irq_mode_e
status_e gpio_irq_disable(const struct gpio_t *gpio)
Disable a gpio interrupt.
enum gpio_mode_e mode
mode for instance GPIO_INPUT | GPIO_PULLDOWN
Definition: stm32_gpio.h:101
void bsp_fatal(status_e status)
fatal error
Definition: bsp.c:123
uint8_t NVIC_IRQChannelSubPriority
NVIC Init Structure definition.
static uint32_t gpio_get(const struct gpio_t *gpio)
Get gpio level.
Definition: stm32_gpio.h:219
This file contains all the functions prototypes for the SYSCFG firmware library.
status_e gpio_irq_setup(const struct gpio_t *gpio, uint32_t(*handler)(const struct gpio_t *gpio), enum gpio_irq_mode_e mode, uint32_t prio)
Setup interrupt on GPIO.
#define GPIO_NC
Unconnected pin.
Definition: stm32_gpio.h:110
EXTIMode_TypeDef EXTI_Mode
Parameter unsupported.
Definition: error.h:56
Impossible switch value.
Definition: error.h:63
Level high (emulated)
GPIO control structure.
Definition: stm32_gpio.h:96
FunctionalState NVIC_IRQChannelCmd
uint16_t mask
Pin mask (0x1 for GPIOx0, ... , 0x4 for GPIOx3, ...)
Definition: stm32_gpio.h:100
uint8_t NVIC_IRQChannelPreemptionPriority
status_e gpio_setup(const struct gpio_t *gpio)
Setup a gpio.
Definition: stm32_gpio.c:9
status_e
Known errors.
Definition: error.h:21
#define ARRAY_SIZE(x)
Number of elements in the array.
Definition: utils.h:19
No error.
Definition: error.h:28
GPIO interrupts.
status_e gpio_irq_restore(const struct gpio_t *gpio)
Restore a gpio interrupt.
This file contains all the functions prototypes for the EXTI firmware library.