]> begriffs open source - cmsis-driver-bare/blob - lib/driver_gpio.c
Get debugging working for gpio demo
[cmsis-driver-bare] / lib / driver_gpio.c
1 /*
2  * CMSIS-Driver for GPIO on STM32F411 based on ARM driver template.
3  */
4
5 #include "Driver_GPIO.h"
6 #include "stm32f4xx.h"
7
8 // #include <assert.h>
9
10 #define GPIO_MAX_PINS           16U
11 #define PIN_IS_AVAILABLE(n)     ((n) < GPIO_MAX_PINS)
12
13 ARM_GPIO_SignalEvent_t g_pin_cb[GPIO_MAX_PINS];
14 ARM_GPIO_EVENT_TRIGGER g_pin_trigger[GPIO_MAX_PINS];
15
16 static void
17 dispatch_callback(ARM_GPIO_Pin_t pin)
18 {
19         EXTI->PR = (1 << pin);
20         if (g_pin_cb[pin])
21                 g_pin_cb[pin](pin, g_pin_trigger[pin]);
22 }
23
24 static void gpio_exti_isr_0(void) { dispatch_callback(0); }
25
26 static void gpio_exti_isr_1(void) { dispatch_callback(1); }
27
28 static void gpio_exti_isr_2(void) { dispatch_callback(2); }
29
30 static void gpio_exti_isr_3(void) { dispatch_callback(3); }
31
32 static void gpio_exti_isr_4(void) { dispatch_callback(4); }
33
34 static void gpio_exti_isr_9_5(void)
35 {
36         uint32_t pending = EXTI->PR;
37         for (ARM_GPIO_Pin_t i = 5; i < 10; i++)
38                 if (pending & (1 << i))
39                         dispatch_callback(i);
40 }
41
42 static void gpio_exti_isr_15_10(void)
43 {
44         uint32_t pending = EXTI->PR;
45         for (ARM_GPIO_Pin_t i = 10; i < 16; i++)
46                 if (pending & (1 << i))
47                         dispatch_callback(i);
48 }
49
50 static void assign_exti(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin)
51 {
52         // masks from reference manual 7.2.3
53         // SYSCFG external interrupt configuration register
54         unsigned port_mask =
55                   gpio == GPIOA ? 0
56                 : gpio == GPIOB ? 1
57                 : gpio == GPIOC ? 2
58                 : gpio == GPIOD ? 3
59                 : gpio == GPIOE ? 4
60                 : gpio == GPIOH ? 7
61                 : 999;
62         if (port_mask != 999)
63         {
64                 if (gpio)
65                         SYSCFG->EXTICR[pin / 4] |=  (port_mask << 4*(pin % 4));
66                 else
67                         SYSCFG->EXTICR[pin / 4] &= ~(15 << 4*(pin % 4));
68         }
69 }
70
71 static uintptr_t
72 isr_for_irq(IRQn_Type irq)
73 {
74         switch (irq)
75         {
76                 case EXTI0_IRQn:     return (uintptr_t)gpio_exti_isr_0;
77                 case EXTI1_IRQn:     return (uintptr_t)gpio_exti_isr_1;
78                 case EXTI2_IRQn:     return (uintptr_t)gpio_exti_isr_2;
79                 case EXTI3_IRQn:     return (uintptr_t)gpio_exti_isr_3;
80                 case EXTI4_IRQn:     return (uintptr_t)gpio_exti_isr_4;
81                 case EXTI9_5_IRQn:   return (uintptr_t)gpio_exti_isr_9_5;
82                 case EXTI15_10_IRQn: return (uintptr_t)gpio_exti_isr_15_10;
83                 default:             return (uintptr_t)NULL;
84         }
85 }
86
87 static IRQn_Type
88 irq_for_pin(ARM_GPIO_Pin_t pin)
89 {
90         if (pin < 5)
91                 return EXTI0_IRQn + pin;
92         if (5 <= pin && pin < 10)
93                 return EXTI9_5_IRQn;
94         return EXTI15_10_IRQn;
95 }
96
97 static int32_t
98 GPIO_SetDirection(
99         GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
100         ARM_GPIO_DIRECTION direction)
101 {
102         int32_t result = ARM_DRIVER_OK;
103
104         // Ref 8.4.1: MODER has two bits for each pin, with
105         // 00: Input (reset state)
106         // 01: General purpose output mode
107         // 10: Alternate function mode
108         // 11: Analog mode
109
110         if (PIN_IS_AVAILABLE(pin))
111         {
112                 uint32_t tmp = 0;
113                 switch (direction)
114                 {
115                         case ARM_GPIO_INPUT:
116                                 gpio->MODER &= ~(GPIO_MODER_MODER0_Msk << (pin * 2));
117                                 break;
118                         case ARM_GPIO_OUTPUT:
119                                 tmp  =   gpio->MODER;
120                                 tmp &= ~(GPIO_MODER_MODER0_Msk << (pin * 2));
121                                 tmp |=   GPIO_MODER_MODER0_0 << (pin * 2);
122                                 gpio->MODER = tmp;
123                                 break;
124                         default:
125                                 result = ARM_DRIVER_ERROR_PARAMETER;
126                                 break;
127                 }
128         }
129         else
130                 result = ARM_GPIO_ERROR_PIN;
131
132         return result;
133 }
134
135 static int32_t
136 GPIO_SetOutputMode(
137         GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
138         ARM_GPIO_OUTPUT_MODE mode)
139 {
140         int32_t result = ARM_DRIVER_OK;
141
142         // Ref 8.4.2: OTYPER has one bit for each pin, with
143         // 0: Output push-pull (reset state)
144         // 1: Output open-drain
145
146         if (PIN_IS_AVAILABLE(pin))
147         {
148                 uint32_t pin_mask = 1 << pin;
149                 switch (mode)
150                 {
151                         case ARM_GPIO_PUSH_PULL:
152                                 gpio->OTYPER &= ~pin_mask;
153                                 break;
154                         case ARM_GPIO_OPEN_DRAIN:
155                                 gpio->OTYPER |=  pin_mask;
156                                 break;
157                         default:
158                                 result = ARM_DRIVER_ERROR_PARAMETER;
159                                 break;
160                 }
161         }
162         else
163                 result = ARM_GPIO_ERROR_PIN;
164
165         return result;
166 }
167
168 static int32_t
169 GPIO_SetPullResistor(
170         GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
171         ARM_GPIO_PULL_RESISTOR resistor)
172 {
173         int32_t result = ARM_DRIVER_OK;
174
175         // Ref 8.4.4: PUPDR has two bits for each pin, with
176         // 00 = no pull up, no pull down
177         // 01 = pull up
178         // 10 = pull down
179         // 11 = reserved
180
181         if (PIN_IS_AVAILABLE(pin))
182         {
183                 uint32_t tmp = 0;
184                 switch (resistor)
185                 {
186                         case ARM_GPIO_PULL_NONE:
187                                 // zero out the two bits
188                                 gpio->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
189                                 break;
190                         case ARM_GPIO_PULL_UP:
191                                 tmp  =   gpio->PUPDR;
192                                 tmp &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
193                                 tmp |=   GPIO_PUPDR_PUPD0_0 << (pin * 2);
194                                 gpio->PUPDR = tmp;
195                                 break;
196                         case ARM_GPIO_PULL_DOWN:
197                                 tmp  =   gpio->PUPDR;
198                                 tmp &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
199                                 tmp |=   GPIO_PUPDR_PUPD0_1 << (pin * 2);
200                                 gpio->PUPDR = tmp;
201                                 break;
202                         default:
203                                 result = ARM_DRIVER_ERROR_PARAMETER;
204                                 break;
205                 }
206         }
207         else
208                 result = ARM_GPIO_ERROR_PIN;
209
210         return result;
211 }
212
213 static int32_t
214 GPIO_SetEventTrigger(
215         ARM_GPIO_Pin_t pin,
216         ARM_GPIO_EVENT_TRIGGER trigger)
217 {
218         int32_t result = ARM_DRIVER_OK;
219
220         // SYSCFG_EXTICR1 has four-bit regions:
221         //  each EXTIn handles PAn, PBn, PCn, ...
222
223         if (PIN_IS_AVAILABLE(pin))
224         {
225                 uint32_t pin_mask = 1 << pin;
226                 switch (trigger) {
227                         case ARM_GPIO_TRIGGER_NONE:
228                                 EXTI->RTSR &= ~pin_mask;
229                                 EXTI->FTSR &= ~pin_mask;
230                                 EXTI->IMR  &= ~pin_mask;
231                                 break;
232                         case ARM_GPIO_TRIGGER_RISING_EDGE:
233                                 EXTI->RTSR |=  pin_mask;
234                                 EXTI->FTSR &= ~pin_mask;
235                                 EXTI->IMR  |=  pin_mask;
236                                 break;
237                         case ARM_GPIO_TRIGGER_FALLING_EDGE:
238                                 EXTI->RTSR &= ~pin_mask;
239                                 EXTI->FTSR |=  pin_mask;
240                                 EXTI->IMR  |=  pin_mask;
241                                 break;
242                         case ARM_GPIO_TRIGGER_EITHER_EDGE:
243                                 EXTI->RTSR |=  pin_mask;
244                                 EXTI->FTSR |=  pin_mask;
245                                 EXTI->IMR  |=  pin_mask;
246                                 break;
247                         default:
248                                 result = ARM_DRIVER_ERROR_PARAMETER;
249                                 break;
250                 }
251         }
252         else
253                 result = ARM_GPIO_ERROR_PIN;
254
255         if (result == ARM_DRIVER_OK)
256                 g_pin_trigger[pin] = trigger;
257
258         return result;
259 }
260
261 // Setup GPIO Interface
262 //
263 // The function ARM_GPIO_Setup sets-up the specified pin
264 // as GPIO with default configuration. Pin is configured
265 // as input without pull-resistor and without event
266 // trigger.
267 //
268 // The parameter cb_event specifies a pointer to the
269 // ARM_GPIO_SignalEvent callback function to register.
270 // Use a NULL pointer when no callback events are
271 // required or to deregister a callback function. 
272 static int32_t
273 GPIO_Setup(
274         GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
275         ARM_GPIO_SignalEvent_t cb_event)
276 {
277         int32_t result = ARM_DRIVER_OK;
278
279         if (PIN_IS_AVAILABLE(pin))
280         {
281                 GPIO_SetPullResistor(gpio, pin, ARM_GPIO_PULL_NONE);
282                 GPIO_SetDirection(gpio, pin, ARM_GPIO_INPUT);
283                 GPIO_SetEventTrigger(pin, ARM_GPIO_TRIGGER_NONE);
284
285                 if (cb_event)
286                 {
287                         IRQn_Type irq = irq_for_pin(pin);
288
289                         if (g_pin_cb[pin])
290                         {
291                                 // SYSCFG_EXTICRx can't assign events for
292                                 // the same pins on multiple ports at once
293                                 return ARM_DRIVER_ERROR_PARAMETER;
294                         }
295                         g_pin_cb[pin] = cb_event;
296                         NVIC_SetVector(irq, isr_for_irq(irq));
297                         NVIC_EnableIRQ(irq);
298                         assign_exti(gpio, pin);
299                 }
300                 else
301                         g_pin_cb[pin] = NULL;
302         }
303         else
304                 result = ARM_GPIO_ERROR_PIN;
305
306         return result;
307 }
308
309 static void
310 GPIO_SetOutput(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin, uint32_t val)
311 {
312         if (PIN_IS_AVAILABLE(pin)) {
313                 gpio->BSRR = 1 << (val ? pin : 16+pin);
314         }
315 }
316
317 static uint32_t
318 GPIO_GetInput(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin)
319 {
320         return PIN_IS_AVAILABLE(pin) && (gpio->IDR & (1 << pin));
321 }
322
323 /* Publicly visible parts *******************************************/
324
325 #define GPIO_PORTS \
326         X(GPIOA) \
327         X(GPIOB) \
328         X(GPIOC) \
329         X(GPIOD) \
330         X(GPIOE) \
331         X(GPIOH)
332
333 #define X(port) \
334         static int32_t  port ## _Setup (ARM_GPIO_Pin_t pin, ARM_GPIO_SignalEvent_t cb_event) { \
335                 return GPIO_Setup(port, pin, cb_event ); } \
336         static int32_t  port ## _SetDirection (ARM_GPIO_Pin_t pin, ARM_GPIO_DIRECTION direction) { \
337                 return GPIO_SetDirection(port, pin, direction); } \
338         static int32_t  port ## _SetOutputMode (ARM_GPIO_Pin_t pin, ARM_GPIO_OUTPUT_MODE mode) { \
339                 return GPIO_SetOutputMode (port, pin, mode); } \
340         static int32_t  port ## _SetPullResistor (ARM_GPIO_Pin_t pin, ARM_GPIO_PULL_RESISTOR resistor) { \
341                 return GPIO_SetPullResistor(port, pin, resistor); } \
342         static int32_t  port ## _SetEventTrigger (ARM_GPIO_Pin_t pin, ARM_GPIO_EVENT_TRIGGER trigger) { \
343                 return GPIO_SetEventTrigger(pin, trigger); } \
344         static void     port ## _SetOutput (ARM_GPIO_Pin_t pin, uint32_t val) { \
345                 GPIO_SetOutput(port, pin, val); } \
346         static uint32_t port ## _GetInput (ARM_GPIO_Pin_t pin) { \
347                 return GPIO_GetInput(port, pin); } \
348         \
349         ARM_DRIVER_GPIO Driver_ ## port = { \
350                 port ## _Setup, \
351                 port ## _SetDirection, \
352                 port ## _SetOutputMode, \
353                 port ## _SetPullResistor, \
354                 port ## _SetEventTrigger, \
355                 port ## _SetOutput, \
356                 port ## _GetInput \
357         };
358
359 GPIO_PORTS
360
361 #undef X
362 #undef GPIO_PORTS