Firmware SDK
twr_gpio.c
1 #include <twr_gpio.h>
2 #include <twr_irq.h>
3 #include <stm32l0xx.h>
4 
5 #define TWR_GPIO_CHANNEL_COUNT 23
6 
7 #define TWR_GPIO_PORT_P0 GPIOA
8 #define TWR_GPIO_PORT_P1 GPIOA
9 #define TWR_GPIO_PORT_P2 GPIOA
10 #define TWR_GPIO_PORT_P3 GPIOA
11 #define TWR_GPIO_PORT_P4 GPIOA
12 #define TWR_GPIO_PORT_P5 GPIOA
13 #define TWR_GPIO_PORT_P6 GPIOB
14 #define TWR_GPIO_PORT_P7 GPIOA
15 #define TWR_GPIO_PORT_P8 GPIOB
16 #define TWR_GPIO_PORT_P9 GPIOB
17 #define TWR_GPIO_PORT_P10 GPIOA
18 #define TWR_GPIO_PORT_P11 GPIOA
19 #define TWR_GPIO_PORT_P12 GPIOB
20 #define TWR_GPIO_PORT_P13 GPIOB
21 #define TWR_GPIO_PORT_P14 GPIOB
22 #define TWR_GPIO_PORT_P15 GPIOB
23 #define TWR_GPIO_PORT_P16 GPIOB
24 #define TWR_GPIO_PORT_P17 GPIOB
25 #define TWR_GPIO_PORT_LED GPIOH
26 #define TWR_GPIO_PORT_BUTTON GPIOA
27 #define TWR_GPIO_PORT_INT GPIOC
28 #define TWR_GPIO_PORT_SCL0 GPIOB
29 #define TWR_GPIO_PORT_SDA0 GPIOB
30 
31 #define TWR_GPIO_POS_P0 0
32 #define TWR_GPIO_POS_P1 1
33 #define TWR_GPIO_POS_P2 2
34 #define TWR_GPIO_POS_P3 3
35 #define TWR_GPIO_POS_P4 4
36 #define TWR_GPIO_POS_P5 5
37 #define TWR_GPIO_POS_P6 1
38 #define TWR_GPIO_POS_P7 6
39 #define TWR_GPIO_POS_P8 0
40 #define TWR_GPIO_POS_P9 2
41 #define TWR_GPIO_POS_P10 10
42 #define TWR_GPIO_POS_P11 9
43 #define TWR_GPIO_POS_P12 14
44 #define TWR_GPIO_POS_P13 15
45 #define TWR_GPIO_POS_P14 13
46 #define TWR_GPIO_POS_P15 12
47 #define TWR_GPIO_POS_P16 8
48 #define TWR_GPIO_POS_P17 9
49 #define TWR_GPIO_POS_LED 1
50 #define TWR_GPIO_POS_BUTTON 8
51 #define TWR_GPIO_POS_INT 13
52 #define TWR_GPIO_POS_SCL0 10
53 #define TWR_GPIO_POS_SDA0 11
54 
55 #define _TWR_GPIO_MODE_MASK 0xf
56 #define _TWR_GPIO_MODE_AF_POS 4
57 #define _twr_gpio_64_bit_pos(__CHANNEL__) (_twr_gpio_32_bit_pos[(__CHANNEL__)] << 1)
58 
59 GPIO_TypeDef * const twr_gpio_port[TWR_GPIO_CHANNEL_COUNT] =
60 {
61  TWR_GPIO_PORT_P0,
62  TWR_GPIO_PORT_P1,
63  TWR_GPIO_PORT_P2,
64  TWR_GPIO_PORT_P3,
65  TWR_GPIO_PORT_P4,
66  TWR_GPIO_PORT_P5,
67  TWR_GPIO_PORT_P6,
68  TWR_GPIO_PORT_P7,
69  TWR_GPIO_PORT_P8,
70  TWR_GPIO_PORT_P9,
71  TWR_GPIO_PORT_P10,
72  TWR_GPIO_PORT_P11,
73  TWR_GPIO_PORT_P12,
74  TWR_GPIO_PORT_P13,
75  TWR_GPIO_PORT_P14,
76  TWR_GPIO_PORT_P15,
77  TWR_GPIO_PORT_P16,
78  TWR_GPIO_PORT_P17,
79  TWR_GPIO_PORT_LED,
80  TWR_GPIO_PORT_BUTTON,
81  TWR_GPIO_PORT_INT,
82  TWR_GPIO_PORT_SCL0,
83  TWR_GPIO_PORT_SDA0
84 };
85 
86 static const uint8_t _twr_gpio_iopenr_mask[TWR_GPIO_CHANNEL_COUNT] =
87 {
88  RCC_IOPENR_GPIOAEN, // P0
89  RCC_IOPENR_GPIOAEN, // P1
90  RCC_IOPENR_GPIOAEN, // P2
91  RCC_IOPENR_GPIOAEN, // P3
92  RCC_IOPENR_GPIOAEN, // P4
93  RCC_IOPENR_GPIOAEN, // P5
94  RCC_IOPENR_GPIOBEN, // P6
95  RCC_IOPENR_GPIOAEN, // P7
96  RCC_IOPENR_GPIOBEN, // P8
97  RCC_IOPENR_GPIOBEN, // P9
98  RCC_IOPENR_GPIOAEN, // P10
99  RCC_IOPENR_GPIOAEN, // P11
100  RCC_IOPENR_GPIOBEN, // P12
101  RCC_IOPENR_GPIOBEN, // P13
102  RCC_IOPENR_GPIOBEN, // P14
103  RCC_IOPENR_GPIOBEN, // P15
104  RCC_IOPENR_GPIOBEN, // P16
105  RCC_IOPENR_GPIOBEN, // P17
106  RCC_IOPENR_GPIOHEN, // LED
107  RCC_IOPENR_GPIOAEN, // BUTTON
108  RCC_IOPENR_GPIOCEN, // INT
109  RCC_IOPENR_GPIOBEN, // SCL0
110  RCC_IOPENR_GPIOBEN, // SDA0
111 };
112 
113 static const uint16_t _twr_gpio_16_bit_pos[TWR_GPIO_CHANNEL_COUNT] =
114 {
115  TWR_GPIO_POS_P0,
116  TWR_GPIO_POS_P1,
117  TWR_GPIO_POS_P2,
118  TWR_GPIO_POS_P3,
119  TWR_GPIO_POS_P4,
120  TWR_GPIO_POS_P5,
121  TWR_GPIO_POS_P6,
122  TWR_GPIO_POS_P7,
123  TWR_GPIO_POS_P8,
124  TWR_GPIO_POS_P9,
125  TWR_GPIO_POS_P10,
126  TWR_GPIO_POS_P11,
127  TWR_GPIO_POS_P12,
128  TWR_GPIO_POS_P13,
129  TWR_GPIO_POS_P14,
130  TWR_GPIO_POS_P15,
131  TWR_GPIO_POS_P16,
132  TWR_GPIO_POS_P17,
133  TWR_GPIO_POS_LED,
134  TWR_GPIO_POS_BUTTON,
135  TWR_GPIO_POS_INT,
136  TWR_GPIO_POS_SCL0,
137  TWR_GPIO_POS_SDA0
138 };
139 
140 static const uint16_t _twr_gpio_32_bit_pos[TWR_GPIO_CHANNEL_COUNT] =
141 {
142  2 * TWR_GPIO_POS_P0,
143  2 * TWR_GPIO_POS_P1,
144  2 * TWR_GPIO_POS_P2,
145  2 * TWR_GPIO_POS_P3,
146  2 * TWR_GPIO_POS_P4,
147  2 * TWR_GPIO_POS_P5,
148  2 * TWR_GPIO_POS_P6,
149  2 * TWR_GPIO_POS_P7,
150  2 * TWR_GPIO_POS_P8,
151  2 * TWR_GPIO_POS_P9,
152  2 * TWR_GPIO_POS_P10,
153  2 * TWR_GPIO_POS_P11,
154  2 * TWR_GPIO_POS_P12,
155  2 * TWR_GPIO_POS_P13,
156  2 * TWR_GPIO_POS_P14,
157  2 * TWR_GPIO_POS_P15,
158  2 * TWR_GPIO_POS_P16,
159  2 * TWR_GPIO_POS_P17,
160  2 * TWR_GPIO_POS_LED,
161  2 * TWR_GPIO_POS_BUTTON,
162  2 * TWR_GPIO_POS_INT,
163  2 * TWR_GPIO_POS_SCL0,
164  2 * TWR_GPIO_POS_SDA0
165 };
166 
167 const uint16_t twr_gpio_16_bit_mask[TWR_GPIO_CHANNEL_COUNT] =
168 {
169  1 << TWR_GPIO_POS_P0,
170  1 << TWR_GPIO_POS_P1,
171  1 << TWR_GPIO_POS_P2,
172  1 << TWR_GPIO_POS_P3,
173  1 << TWR_GPIO_POS_P4,
174  1 << TWR_GPIO_POS_P5,
175  1 << TWR_GPIO_POS_P6,
176  1 << TWR_GPIO_POS_P7,
177  1 << TWR_GPIO_POS_P8,
178  1 << TWR_GPIO_POS_P9,
179  1 << TWR_GPIO_POS_P10,
180  1 << TWR_GPIO_POS_P11,
181  1 << TWR_GPIO_POS_P12,
182  1 << TWR_GPIO_POS_P13,
183  1 << TWR_GPIO_POS_P14,
184  1 << TWR_GPIO_POS_P15,
185  1 << TWR_GPIO_POS_P16,
186  1 << TWR_GPIO_POS_P17,
187  1 << TWR_GPIO_POS_LED,
188  1 << TWR_GPIO_POS_BUTTON,
189  1 << TWR_GPIO_POS_INT,
190  1 << TWR_GPIO_POS_SCL0,
191  1 << TWR_GPIO_POS_SDA0
192 };
193 
194 static const uint32_t _twr_gpio_32_bit_mask[4][TWR_GPIO_CHANNEL_COUNT] =
195 {
196  {
197  0UL,
198  0UL,
199  0UL,
200  0UL,
201  0UL,
202  0UL,
203  0UL,
204  0UL,
205  0UL,
206  0UL,
207  0UL,
208  0UL,
209  0UL,
210  0UL,
211  0UL,
212  0UL,
213  0UL,
214  0UL,
215  0UL,
216  0UL,
217  0UL,
218  0UL,
219  0UL,
220  },
221  {
222  1UL << (2 * TWR_GPIO_POS_P0),
223  1UL << (2 * TWR_GPIO_POS_P1),
224  1UL << (2 * TWR_GPIO_POS_P2),
225  1UL << (2 * TWR_GPIO_POS_P3),
226  1UL << (2 * TWR_GPIO_POS_P4),
227  1UL << (2 * TWR_GPIO_POS_P5),
228  1UL << (2 * TWR_GPIO_POS_P6),
229  1UL << (2 * TWR_GPIO_POS_P7),
230  1UL << (2 * TWR_GPIO_POS_P8),
231  1UL << (2 * TWR_GPIO_POS_P9),
232  1UL << (2 * TWR_GPIO_POS_P10),
233  1UL << (2 * TWR_GPIO_POS_P11),
234  1UL << (2 * TWR_GPIO_POS_P12),
235  1UL << (2 * TWR_GPIO_POS_P13),
236  1UL << (2 * TWR_GPIO_POS_P14),
237  1UL << (2 * TWR_GPIO_POS_P15),
238  1UL << (2 * TWR_GPIO_POS_P16),
239  1UL << (2 * TWR_GPIO_POS_P17),
240  1UL << (2 * TWR_GPIO_POS_LED),
241  1UL << (2 * TWR_GPIO_POS_BUTTON),
242  1UL << (2 * TWR_GPIO_POS_INT),
243  1UL << (2 * TWR_GPIO_POS_SCL0),
244  1UL << (2 * TWR_GPIO_POS_SDA0)
245  },
246  {
247  2UL << (2 * TWR_GPIO_POS_P0),
248  2UL << (2 * TWR_GPIO_POS_P1),
249  2UL << (2 * TWR_GPIO_POS_P2),
250  2UL << (2 * TWR_GPIO_POS_P3),
251  2UL << (2 * TWR_GPIO_POS_P4),
252  2UL << (2 * TWR_GPIO_POS_P5),
253  2UL << (2 * TWR_GPIO_POS_P6),
254  2UL << (2 * TWR_GPIO_POS_P7),
255  2UL << (2 * TWR_GPIO_POS_P8),
256  2UL << (2 * TWR_GPIO_POS_P9),
257  2UL << (2 * TWR_GPIO_POS_P10),
258  2UL << (2 * TWR_GPIO_POS_P11),
259  2UL << (2 * TWR_GPIO_POS_P12),
260  2UL << (2 * TWR_GPIO_POS_P13),
261  2UL << (2 * TWR_GPIO_POS_P14),
262  2UL << (2 * TWR_GPIO_POS_P15),
263  2UL << (2 * TWR_GPIO_POS_P16),
264  2UL << (2 * TWR_GPIO_POS_P17),
265  2UL << (2 * TWR_GPIO_POS_LED),
266  2UL << (2 * TWR_GPIO_POS_BUTTON),
267  2UL << (2 * TWR_GPIO_POS_INT),
268  2UL << (2 * TWR_GPIO_POS_SCL0),
269  2UL << (2 * TWR_GPIO_POS_SDA0)
270  },
271  {
272  3UL << (2 * TWR_GPIO_POS_P0),
273  3UL << (2 * TWR_GPIO_POS_P1),
274  3UL << (2 * TWR_GPIO_POS_P2),
275  3UL << (2 * TWR_GPIO_POS_P3),
276  3UL << (2 * TWR_GPIO_POS_P4),
277  3UL << (2 * TWR_GPIO_POS_P5),
278  3UL << (2 * TWR_GPIO_POS_P6),
279  3UL << (2 * TWR_GPIO_POS_P7),
280  3UL << (2 * TWR_GPIO_POS_P8),
281  3UL << (2 * TWR_GPIO_POS_P9),
282  3UL << (2 * TWR_GPIO_POS_P10),
283  3UL << (2 * TWR_GPIO_POS_P11),
284  3UL << (2 * TWR_GPIO_POS_P12),
285  3UL << (2 * TWR_GPIO_POS_P13),
286  3UL << (2 * TWR_GPIO_POS_P14),
287  3UL << (2 * TWR_GPIO_POS_P15),
288  3UL << (2 * TWR_GPIO_POS_P16),
289  3UL << (2 * TWR_GPIO_POS_P17),
290  3UL << (2 * TWR_GPIO_POS_LED),
291  3UL << (2 * TWR_GPIO_POS_BUTTON),
292  3UL << (2 * TWR_GPIO_POS_INT),
293  3UL << (2 * TWR_GPIO_POS_SCL0),
294  3UL << (2 * TWR_GPIO_POS_SDA0)
295  }
296 };
297 
298 const uint32_t twr_gpio_32_bit_upper_mask[TWR_GPIO_CHANNEL_COUNT] =
299 {
300  (1UL << 16) << TWR_GPIO_POS_P0,
301  (1UL << 16) << TWR_GPIO_POS_P1,
302  (1UL << 16) << TWR_GPIO_POS_P2,
303  (1UL << 16) << TWR_GPIO_POS_P3,
304  (1UL << 16) << TWR_GPIO_POS_P4,
305  (1UL << 16) << TWR_GPIO_POS_P5,
306  (1UL << 16) << TWR_GPIO_POS_P6,
307  (1UL << 16) << TWR_GPIO_POS_P7,
308  (1UL << 16) << TWR_GPIO_POS_P8,
309  (1UL << 16) << TWR_GPIO_POS_P9,
310  (1UL << 16) << TWR_GPIO_POS_P10,
311  (1UL << 16) << TWR_GPIO_POS_P11,
312  (1UL << 16) << TWR_GPIO_POS_P12,
313  (1UL << 16) << TWR_GPIO_POS_P13,
314  (1UL << 16) << TWR_GPIO_POS_P14,
315  (1UL << 16) << TWR_GPIO_POS_P15,
316  (1UL << 16) << TWR_GPIO_POS_P16,
317  (1UL << 16) << TWR_GPIO_POS_P17,
318  (1UL << 16) << TWR_GPIO_POS_LED,
319  (1UL << 16) << TWR_GPIO_POS_BUTTON,
320  (1UL << 16) << TWR_GPIO_POS_INT,
321  (1UL << 16) << TWR_GPIO_POS_SCL0,
322  (1UL << 16) << TWR_GPIO_POS_SDA0
323 };
324 
326 {
327  // Disable interrupts
328  twr_irq_disable();
329 
330  // Enable GPIO clock
331  RCC->IOPENR |= _twr_gpio_iopenr_mask[channel];
332 
333  // Errata workaround
334  RCC->IOPENR;
335 
336  // Enable interrupts
337  twr_irq_enable();
338 }
339 
341 {
342  // Disable interrupts
343  twr_irq_disable();
344 
345  // Read PUPDR register
346  uint32_t pupdr = twr_gpio_port[channel]->PUPDR;
347 
348  // Reset corresponding PUPDR bits
349  pupdr &= ~_twr_gpio_32_bit_mask[3][channel];
350 
351  // Set corresponding PUPDR bits
352  pupdr |= _twr_gpio_32_bit_mask[pull][channel];
353 
354  // Write PUPDR register
355  twr_gpio_port[channel]->PUPDR = pupdr;
356 
357  // Enable interrupts
358  twr_irq_enable();
359 }
360 
362 {
363  // Return pull setting from PUPDR register
364  return (twr_gpio_pull_t) ((twr_gpio_port[channel]->PUPDR >> _twr_gpio_32_bit_pos[channel]) & 3);
365 }
366 
368 {
369  // Disable interrupts
370  twr_irq_disable();
371 
372  // Read OTYPER register
373  uint32_t otyper = twr_gpio_port[channel]->OTYPER;
374 
375  // Read MODER register
376  uint32_t moder = twr_gpio_port[channel]->MODER;
377 
378  // If mode setting is open-drain output...
379  if (mode == TWR_GPIO_MODE_OUTPUT_OD)
380  {
381  // Set corresponding OTYPER bit
382  otyper |= twr_gpio_16_bit_mask[channel];
383 
384  // Override desired mode setting to output
385  mode = TWR_GPIO_MODE_OUTPUT;
386  }
387  else
388  {
389  // Reset corresponding OTYPER bit
390  otyper &= ~twr_gpio_16_bit_mask[channel];
391  }
392 
393  // If mode setting is alternative function ...
394  if((mode & _TWR_GPIO_MODE_MASK) == TWR_GPIO_MODE_ALTERNATE)
395  {
396  // ... write AF number to appropriate pin of appropriate AFR register
397  if(_twr_gpio_16_bit_pos[channel] >= 8)
398  {
399  twr_gpio_port[channel]->AFR[1] &= ~(0x0f << (_twr_gpio_64_bit_pos(channel) - 32));
400  twr_gpio_port[channel]->AFR[1] |= ((uint8_t)mode >> _TWR_GPIO_MODE_AF_POS) << (_twr_gpio_64_bit_pos(channel) - 32);
401  }
402  else
403  {
404  twr_gpio_port[channel]->AFR[0] &= ~(0x0f << _twr_gpio_64_bit_pos(channel));
405  twr_gpio_port[channel]->AFR[0] |= ((uint8_t)mode >> _TWR_GPIO_MODE_AF_POS) << _twr_gpio_64_bit_pos(channel);
406  }
407 
408  // Mask AF number (mode is used as a coordinates in the array below ...)
409  mode &= _TWR_GPIO_MODE_MASK;
410  }
411 
412  // Reset corresponding MODER bits
413  moder &= ~_twr_gpio_32_bit_mask[3][channel];
414 
415  // Set corresponding MODER bits
416  moder |= _twr_gpio_32_bit_mask[mode][channel];
417 
418  // Write OTYPER register
419  twr_gpio_port[channel]->OTYPER = otyper;
420 
421  // Write MODER register
422  twr_gpio_port[channel]->MODER = moder;
423 
424  // Enable interrupts
425  twr_irq_enable();
426 }
427 
429 {
430  // Read mode setting from MODER register
431  twr_gpio_mode_t mode = (twr_gpio_mode_t) ((twr_gpio_port[channel]->MODER >> _twr_gpio_32_bit_pos[channel]) & 3);
432 
433  // If mode setting is output...
434  if (mode == TWR_GPIO_MODE_OUTPUT)
435  {
436  // If TYPER register bit indicates open-drain output...
437  if (((twr_gpio_port[channel]->OTYPER >> _twr_gpio_16_bit_pos[channel]) & 1) != 0)
438  {
439  // Override mode setting to open-drain
441  }
442  }
443 
444  // If mode setting is alternative function ...
445  else if (mode == TWR_GPIO_MODE_ALTERNATE)
446  {
447  // Readout AF number from appropriate AFR
448  if(_twr_gpio_16_bit_pos[channel] >= 8)
449  {
450  mode = (twr_gpio_port[channel]->AFR[1] >> (_twr_gpio_64_bit_pos(channel) - 32)) & 0x0f;
451  }
452  else
453  {
454  mode = (twr_gpio_port[channel]->AFR[0] >> _twr_gpio_64_bit_pos(channel)) & 0x0f;
455  }
456 
457  // Insert number to enumeration
458  mode = (mode << _TWR_GPIO_MODE_AF_POS) | TWR_GPIO_MODE_ALTERNATE;
459  }
460 
461  // Return mode setting
462  return mode;
463 }
464 
466 {
467  // Return GPIO state from IDR register
468  return (twr_gpio_port[channel]->IDR & twr_gpio_16_bit_mask[channel]) != 0 ? 1 : 0;
469 }
470 
471 void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
472 {
473  // Write GPIO state to BSRR register
474  twr_gpio_port[channel]->BSRR = state ? twr_gpio_16_bit_mask[channel] : twr_gpio_32_bit_upper_mask[channel];
475 }
476 
478 {
479  // Return GPIO state from ODR register
480  return (twr_gpio_port[channel]->ODR & twr_gpio_16_bit_mask[channel]) != 0 ? 1 : 0;
481 }
482 
484 {
485  // Disable interrupts
486  twr_irq_disable();
487 
488  // Write ODR register with inverted bit
489  twr_gpio_port[channel]->ODR ^= twr_gpio_16_bit_mask[channel];
490 
491  // Enable interrupts
492  twr_irq_enable();
493 }
twr_gpio_pull_t twr_gpio_get_pull(twr_gpio_channel_t channel)
Get pull-up/pull-down configuration for GPIO channel.
Definition: twr_gpio.c:361
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: twr_gpio.c:471
void twr_gpio_set_pull(twr_gpio_channel_t channel, twr_gpio_pull_t pull)
Set pull-up/pull-down configuration for GPIO channel.
Definition: twr_gpio.c:340
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
twr_gpio_mode_t
GPIO mode of operation.
Definition: twr_gpio.h:103
twr_gpio_channel_t
GPIO channels.
Definition: twr_gpio.h:13
void twr_gpio_toggle_output(twr_gpio_channel_t channel)
Toggle output state for GPIO channel.
Definition: twr_gpio.c:483
int twr_gpio_get_output(twr_gpio_channel_t channel)
Get output state for GPIO channel.
Definition: twr_gpio.c:477
twr_gpio_mode_t twr_gpio_get_mode(twr_gpio_channel_t channel)
Get mode of operation for GPIO channel.
Definition: twr_gpio.c:428
twr_gpio_pull_t
GPIO pull-up/pull-down setting.
Definition: twr_gpio.h:88
int twr_gpio_get_input(twr_gpio_channel_t channel)
Get input state for GPIO channel.
Definition: twr_gpio.c:465
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
@ TWR_GPIO_MODE_OUTPUT
GPIO channel operates as output.
Definition: twr_gpio.h:108
@ TWR_GPIO_MODE_ALTERNATE
GPIO channel operates in alternate mode.
Definition: twr_gpio.h:111
@ TWR_GPIO_MODE_OUTPUT_OD
GPIO channel operates as open-drain output.
Definition: twr_gpio.h:117
void twr_irq_disable(void)
Disable interrupt requests globally (call can be nested)
Definition: twr_irq.c:7
void twr_irq_enable(void)
Enable interrupt requests globally (call can be nested)
Definition: twr_irq.c:21