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];
15 GPIO_TypeDef *g_pin_gpio[GPIO_MAX_PINS]; // Track which GPIO port owns each pin
18 dispatch_callback(ARM_GPIO_Pin_t pin)
20 // Clear the pending interrupt bit
21 EXTI->PR = (1 << pin);
26 // Determine which event to report
27 ARM_GPIO_EVENT_TRIGGER event = g_pin_trigger[pin];
29 // For either-edge mode, report the specific edge that occurred
30 if (event == ARM_GPIO_TRIGGER_EITHER_EDGE)
32 // Read current pin state to determine which edge occurred
33 // Note: Using direct IDR read instead of GPIO_GetInput() for performance in ISR
34 uint32_t pin_high = g_pin_gpio[pin]->IDR & (1 << pin);
35 event = pin_high ? ARM_GPIO_EVENT_RISING_EDGE : ARM_GPIO_EVENT_FALLING_EDGE;
38 g_pin_cb[pin](pin, event);
41 static void gpio_exti_isr_0(void) { dispatch_callback(0); }
43 static void gpio_exti_isr_1(void) { dispatch_callback(1); }
45 static void gpio_exti_isr_2(void) { dispatch_callback(2); }
47 static void gpio_exti_isr_3(void) { dispatch_callback(3); }
49 static void gpio_exti_isr_4(void) { dispatch_callback(4); }
51 static void gpio_exti_isr_9_5(void)
53 uint32_t pending = EXTI->PR;
54 for (ARM_GPIO_Pin_t i = 5; i < 10; i++)
55 if (pending & (1 << i))
59 static void gpio_exti_isr_15_10(void)
61 uint32_t pending = EXTI->PR;
62 for (ARM_GPIO_Pin_t i = 10; i < 16; i++)
63 if (pending & (1 << i))
67 static void assign_exti(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin)
69 // masks from reference manual 7.2.3
70 // SYSCFG external interrupt configuration register
83 // Clear the 4-bit field first, then set the new port
84 SYSCFG->EXTICR[pin / 4] &= ~(0xF << 4*(pin % 4));
85 SYSCFG->EXTICR[pin / 4] |= (port_mask << 4*(pin % 4));
88 SYSCFG->EXTICR[pin / 4] &= ~(0xF << 4*(pin % 4));
93 isr_for_irq(IRQn_Type irq)
97 case EXTI0_IRQn: return (uintptr_t)gpio_exti_isr_0;
98 case EXTI1_IRQn: return (uintptr_t)gpio_exti_isr_1;
99 case EXTI2_IRQn: return (uintptr_t)gpio_exti_isr_2;
100 case EXTI3_IRQn: return (uintptr_t)gpio_exti_isr_3;
101 case EXTI4_IRQn: return (uintptr_t)gpio_exti_isr_4;
102 case EXTI9_5_IRQn: return (uintptr_t)gpio_exti_isr_9_5;
103 case EXTI15_10_IRQn: return (uintptr_t)gpio_exti_isr_15_10;
104 default: return (uintptr_t)NULL;
109 irq_for_pin(ARM_GPIO_Pin_t pin)
112 return EXTI0_IRQn + pin;
113 if (5 <= pin && pin < 10)
115 return EXTI15_10_IRQn;
120 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
121 ARM_GPIO_DIRECTION direction)
123 int32_t result = ARM_DRIVER_OK;
125 // Ref 8.4.1: MODER has two bits for each pin, with
126 // 00: Input (reset state)
127 // 01: General purpose output mode
128 // 10: Alternate function mode
131 if (PIN_IS_AVAILABLE(pin))
137 gpio->MODER &= ~(GPIO_MODER_MODER0_Msk << (pin * 2));
139 case ARM_GPIO_OUTPUT:
141 tmp &= ~(GPIO_MODER_MODER0_Msk << (pin * 2));
142 tmp |= GPIO_MODER_MODER0_0 << (pin * 2);
146 result = ARM_DRIVER_ERROR_PARAMETER;
151 result = ARM_GPIO_ERROR_PIN;
158 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
159 ARM_GPIO_OUTPUT_MODE mode)
161 int32_t result = ARM_DRIVER_OK;
163 // Ref 8.4.2: OTYPER has one bit for each pin, with
164 // 0: Output push-pull (reset state)
165 // 1: Output open-drain
167 if (PIN_IS_AVAILABLE(pin))
169 uint32_t pin_mask = 1 << pin;
172 case ARM_GPIO_PUSH_PULL:
173 gpio->OTYPER &= ~pin_mask;
175 case ARM_GPIO_OPEN_DRAIN:
176 gpio->OTYPER |= pin_mask;
179 result = ARM_DRIVER_ERROR_PARAMETER;
184 result = ARM_GPIO_ERROR_PIN;
190 GPIO_SetPullResistor(
191 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
192 ARM_GPIO_PULL_RESISTOR resistor)
194 int32_t result = ARM_DRIVER_OK;
196 // Ref 8.4.4: PUPDR has two bits for each pin, with
197 // 00 = no pull up, no pull down
202 if (PIN_IS_AVAILABLE(pin))
207 case ARM_GPIO_PULL_NONE:
208 // zero out the two bits
209 gpio->PUPDR &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
211 case ARM_GPIO_PULL_UP:
213 tmp &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
214 tmp |= GPIO_PUPDR_PUPD0_0 << (pin * 2);
217 case ARM_GPIO_PULL_DOWN:
219 tmp &= ~(GPIO_PUPDR_PUPD0_Msk << (pin * 2));
220 tmp |= GPIO_PUPDR_PUPD0_1 << (pin * 2);
224 result = ARM_DRIVER_ERROR_PARAMETER;
229 result = ARM_GPIO_ERROR_PIN;
235 GPIO_SetEventTrigger(
237 ARM_GPIO_EVENT_TRIGGER trigger)
239 int32_t result = ARM_DRIVER_OK;
241 // SYSCFG_EXTICR1 has four-bit regions:
242 // each EXTIn handles PAn, PBn, PCn, ...
244 if (PIN_IS_AVAILABLE(pin))
246 uint32_t pin_mask = 1 << pin;
248 case ARM_GPIO_TRIGGER_NONE:
249 EXTI->RTSR &= ~pin_mask;
250 EXTI->FTSR &= ~pin_mask;
251 EXTI->IMR &= ~pin_mask;
253 case ARM_GPIO_TRIGGER_RISING_EDGE:
254 EXTI->RTSR |= pin_mask;
255 EXTI->FTSR &= ~pin_mask;
256 EXTI->IMR |= pin_mask;
258 case ARM_GPIO_TRIGGER_FALLING_EDGE:
259 EXTI->RTSR &= ~pin_mask;
260 EXTI->FTSR |= pin_mask;
261 EXTI->IMR |= pin_mask;
263 case ARM_GPIO_TRIGGER_EITHER_EDGE:
264 EXTI->RTSR |= pin_mask;
265 EXTI->FTSR |= pin_mask;
266 EXTI->IMR |= pin_mask;
269 result = ARM_DRIVER_ERROR_PARAMETER;
274 result = ARM_GPIO_ERROR_PIN;
276 if (result == ARM_DRIVER_OK)
277 g_pin_trigger[pin] = trigger;
282 // Setup GPIO Interface
284 // The function ARM_GPIO_Setup sets-up the specified pin
285 // as GPIO with default configuration. Pin is configured
286 // as input without pull-resistor and without event
289 // The parameter cb_event specifies a pointer to the
290 // ARM_GPIO_SignalEvent callback function to register.
291 // Use a NULL pointer when no callback events are
292 // required or to deregister a callback function.
295 GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin,
296 ARM_GPIO_SignalEvent_t cb_event)
298 int32_t result = ARM_DRIVER_OK;
300 if (PIN_IS_AVAILABLE(pin))
302 GPIO_SetPullResistor(gpio, pin, ARM_GPIO_PULL_NONE);
303 GPIO_SetDirection(gpio, pin, ARM_GPIO_INPUT);
304 GPIO_SetEventTrigger(pin, ARM_GPIO_TRIGGER_NONE);
308 IRQn_Type irq = irq_for_pin(pin);
312 // SYSCFG_EXTICRx can't assign events for
313 // the same pins on multiple ports at once
314 return ARM_DRIVER_ERROR_PARAMETER;
316 g_pin_cb[pin] = cb_event;
317 g_pin_gpio[pin] = gpio; // Store GPIO port for this pin
318 NVIC_SetVector(irq, isr_for_irq(irq));
320 assign_exti(gpio, pin);
324 g_pin_cb[pin] = NULL;
325 g_pin_gpio[pin] = NULL;
329 result = ARM_GPIO_ERROR_PIN;
335 GPIO_SetOutput(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin, uint32_t val)
337 if (PIN_IS_AVAILABLE(pin)) {
338 gpio->BSRR = 1 << (val ? pin : 16+pin);
343 GPIO_GetInput(GPIO_TypeDef *gpio, ARM_GPIO_Pin_t pin)
345 return PIN_IS_AVAILABLE(pin) && (gpio->IDR & (1 << pin));
348 /* Publicly visible parts *******************************************/
359 static int32_t port ## _Setup (ARM_GPIO_Pin_t pin, ARM_GPIO_SignalEvent_t cb_event) { \
360 return GPIO_Setup(port, pin, cb_event ); } \
361 static int32_t port ## _SetDirection (ARM_GPIO_Pin_t pin, ARM_GPIO_DIRECTION direction) { \
362 return GPIO_SetDirection(port, pin, direction); } \
363 static int32_t port ## _SetOutputMode (ARM_GPIO_Pin_t pin, ARM_GPIO_OUTPUT_MODE mode) { \
364 return GPIO_SetOutputMode (port, pin, mode); } \
365 static int32_t port ## _SetPullResistor (ARM_GPIO_Pin_t pin, ARM_GPIO_PULL_RESISTOR resistor) { \
366 return GPIO_SetPullResistor(port, pin, resistor); } \
367 static int32_t port ## _SetEventTrigger (ARM_GPIO_Pin_t pin, ARM_GPIO_EVENT_TRIGGER trigger) { \
368 return GPIO_SetEventTrigger(pin, trigger); } \
369 static void port ## _SetOutput (ARM_GPIO_Pin_t pin, uint32_t val) { \
370 GPIO_SetOutput(port, pin, val); } \
371 static uint32_t port ## _GetInput (ARM_GPIO_Pin_t pin) { \
372 return GPIO_GetInput(port, pin); } \
374 ARM_DRIVER_GPIO Driver_ ## port = { \
376 port ## _SetDirection, \
377 port ## _SetOutputMode, \
378 port ## _SetPullResistor, \
379 port ## _SetEventTrigger, \
380 port ## _SetOutput, \