2 * CMSIS-Driver for GPIO on STM32F411 based on ARM driver template.
5 #include "Driver_GPIO.h"
10 #define GPIO_MAX_PINS 16U
11 #define PIN_IS_AVAILABLE(n) ((n) < GPIO_MAX_PINS)
13 ARM_GPIO_SignalEvent_t g_pin_cb[GPIO_MAX_PINS];
14 ARM_GPIO_EVENT_TRIGGER g_pin_trigger[GPIO_MAX_PINS];
17 dispatch_callback(ARM_GPIO_Pin_t pin)
19 EXTI->PR = (1 << pin);
21 g_pin_cb[pin](pin, g_pin_trigger[pin]);
24 static void gpio_exti_isr_0(void) { dispatch_callback(0); }
26 static void gpio_exti_isr_1(void) { dispatch_callback(1); }
28 static void gpio_exti_isr_2(void) { dispatch_callback(2); }
30 static void gpio_exti_isr_3(void) { dispatch_callback(3); }
32 static void gpio_exti_isr_4(void) { dispatch_callback(4); }
34 static void gpio_exti_isr_9_5(void)
36 uint32_t pending = EXTI->PR;
37 for (ARM_GPIO_Pin_t i = 5; i < 10; i++)
38 if (pending & (1 << i))
42 static void gpio_exti_isr_15_10(void)
44 uint32_t pending = EXTI->PR;
45 for (ARM_GPIO_Pin_t i = 10; i < 16; i++)
46 if (pending & (1 << i))
50 static void assign_exti(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin)
52 // masks from reference manual 7.2.3
53 // SYSCFG external interrupt configuration register
65 SYSCFG->EXTICR[pin / 4] |= (port_mask << 4*(pin % 4));
67 SYSCFG->EXTICR[pin / 4] &= ~(15 << 4*(pin % 4));
72 isr_for_irq(IRQn_Type irq)
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;
88 irq_for_pin(ARM_GPIO_Pin_t pin)
91 return EXTI0_IRQn + pin;
92 if (5 <= pin && pin < 10)
94 return EXTI15_10_IRQn;
99 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
100 ARM_GPIO_DIRECTION direction)
102 int32_t result = ARM_DRIVER_OK;
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
110 if (PIN_IS_AVAILABLE(pin))
116 gpio->MODER &= ~(GPIO_MODER_MODER0_Msk << (pin * 2));
118 case ARM_GPIO_OUTPUT:
120 tmp &= ~(GPIO_MODER_MODER0_Msk << (pin * 2));
121 tmp |= GPIO_MODER_MODER0_0 << (pin * 2);
125 result = ARM_DRIVER_ERROR_PARAMETER;
130 result = ARM_GPIO_ERROR_PIN;
137 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
138 ARM_GPIO_OUTPUT_MODE mode)
140 int32_t result = ARM_DRIVER_OK;
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
146 if (PIN_IS_AVAILABLE(pin))
148 uint32_t pin_mask = 1 << pin;
151 case ARM_GPIO_PUSH_PULL:
152 gpio->OTYPER &= ~pin_mask;
154 case ARM_GPIO_OPEN_DRAIN:
155 gpio->OTYPER |= pin_mask;
158 result = ARM_DRIVER_ERROR_PARAMETER;
163 result = ARM_GPIO_ERROR_PIN;
169 GPIO_SetPullResistor(
170 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
171 ARM_GPIO_PULL_RESISTOR resistor)
173 int32_t result = ARM_DRIVER_OK;
175 // Ref 8.4.4: PUPDR has two bits for each pin, with
176 // 00 = no pull up, no pull down
181 if (PIN_IS_AVAILABLE(pin))
186 case ARM_GPIO_PULL_NONE:
187 // zero out the two bits
188 gpio->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
190 case ARM_GPIO_PULL_UP:
192 tmp &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
193 tmp |= GPIO_PUPDR_PUPD0_0 << (pin * 2);
196 case ARM_GPIO_PULL_DOWN:
198 tmp &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
199 tmp |= GPIO_PUPDR_PUPD0_1 << (pin * 2);
203 result = ARM_DRIVER_ERROR_PARAMETER;
208 result = ARM_GPIO_ERROR_PIN;
214 GPIO_SetEventTrigger(
216 ARM_GPIO_EVENT_TRIGGER trigger)
218 int32_t result = ARM_DRIVER_OK;
220 // SYSCFG_EXTICR1 has four-bit regions:
221 // each EXTIn handles PAn, PBn, PCn, ...
223 if (PIN_IS_AVAILABLE(pin))
225 uint32_t pin_mask = 1 << pin;
227 case ARM_GPIO_TRIGGER_NONE:
228 EXTI->RTSR &= ~pin_mask;
229 EXTI->FTSR &= ~pin_mask;
230 EXTI->IMR &= ~pin_mask;
232 case ARM_GPIO_TRIGGER_RISING_EDGE:
233 EXTI->RTSR |= pin_mask;
234 EXTI->FTSR &= ~pin_mask;
235 EXTI->IMR |= pin_mask;
237 case ARM_GPIO_TRIGGER_FALLING_EDGE:
238 EXTI->RTSR &= ~pin_mask;
239 EXTI->FTSR |= pin_mask;
240 EXTI->IMR |= pin_mask;
242 case ARM_GPIO_TRIGGER_EITHER_EDGE:
243 EXTI->RTSR |= pin_mask;
244 EXTI->FTSR |= pin_mask;
245 EXTI->IMR |= pin_mask;
248 result = ARM_DRIVER_ERROR_PARAMETER;
253 result = ARM_GPIO_ERROR_PIN;
255 if (result == ARM_DRIVER_OK)
256 g_pin_trigger[pin] = trigger;
261 // Setup GPIO Interface
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
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.
274 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
275 ARM_GPIO_SignalEvent_t cb_event)
277 int32_t result = ARM_DRIVER_OK;
279 if (PIN_IS_AVAILABLE(pin))
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);
287 IRQn_Type irq = irq_for_pin(pin);
291 // SYSCFG_EXTICRx can't assign events for
292 // the same pins on multiple ports at once
293 return ARM_DRIVER_ERROR_PARAMETER;
295 g_pin_cb[pin] = cb_event;
296 NVIC_SetVector(irq, isr_for_irq(irq));
298 assign_exti(gpio, pin);
301 g_pin_cb[pin] = NULL;
304 result = ARM_GPIO_ERROR_PIN;
310 GPIO_SetOutput(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin, uint32_t val)
312 if (PIN_IS_AVAILABLE(pin)) {
313 gpio->BSRR = 1 << (val ? pin : 16+pin);
318 GPIO_GetInput(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin)
320 return PIN_IS_AVAILABLE(pin) && (gpio->IDR & (1 << pin));
323 /* Publicly visible parts *******************************************/
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); } \
349 ARM_DRIVER_GPIO Driver_ ## port = { \
351 port ## _SetDirection, \
352 port ## _SetOutputMode, \
353 port ## _SetPullResistor, \
354 port ## _SetEventTrigger, \
355 port ## _SetOutput, \