gpio_ll_arch.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2022 Christian Amsüss
3  *
4  * This file is subject to the terms and conditions of the GNU Lesser
5  * General Public License v2.1. See the file LICENSE in the top level
6  * directory for more details.
7  */
8 
9 #pragma once
10 
39 #include "cpu.h"
40 #include "periph_cpu.h"
41 
42 #include "em_gpio.h"
43 
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47 
48 #ifndef DOXYGEN /* hide implementation specific details from Doxygen */
49 
50 #define GPIO_PORT_NUMBERING_ALPHABETIC 1
51 
52 /* Note: The pin count may be defined as zero to indicate the port not existing.
53  * Hence, don't to `#if defined(foo)` but only `#if foo`
54  */
55 #if _GPIO_PORT_A_PIN_COUNT
56 # define GPIO_PORT_0 0
57 #endif
58 
59 #if _GPIO_PORT_B_PIN_COUNT
60 # define GPIO_PORT_1 1
61 #endif
62 
63 #if _GPIO_PORT_C_PIN_COUNT
64 # define GPIO_PORT_2 2
65 #endif
66 
67 #if _GPIO_PORT_D_PIN_COUNT
68 # define GPIO_PORT_3 3
69 #endif
70 
71 #if _GPIO_PORT_E_PIN_COUNT
72 # define GPIO_PORT_4 4
73 #endif
74 
75 #if _GPIO_PORT_F_PIN_COUNT
76 # define GPIO_PORT_6 6
77 #endif
78 
79 #if _GPIO_PORT_G_PIN_COUNT
80 # define GPIO_PORT_7 7
81 #endif
82 
83 #if _GPIO_PORT_H_PIN_COUNT
84 # define GPIO_PORT_8 8
85 #endif
86 
87 #if _GPIO_PORT_I_PIN_COUNT
88 # define GPIO_PORT_9 9
89 #endif
90 
91 #if _GPIO_PORT_J_PIN_COUNT
92 # define GPIO_PORT_10 10
93 #endif
94 
95 #if _GPIO_PORT_K_PIN_COUNT
96 # define GPIO_PORT_11 11
97 #endif
98 
99 /* We could do
100  *
101  * static inline gpio_port_t gpio_port(uword_t num)
102  * {
103  * return GPIO->P[num];
104  * }
105  *
106  * which works for some operations, but at latest when _ll_set needs to fan out
107  * for some EFM32 families to
108  *
109 #if defined(_GPIO_P_DOUTSET_MASK)
110  GPIO->P[port].DOUTSET = pins;
111 #elif defined(GPIO_HAS_SET_CLEAR)
112  GPIO->P_SET[port].DOUT = pins;
113 #else
114  (some bit-banding-style interaction on P)
115 #endif
116  *
117  * that approach becomes an unbearable burden, because P_SET is not necessarily
118  * as large as P, and getting from a P pointer to a P_SET pointer would involve
119  * division and multiplication. Instead, falling back to addressing ports by
120  * their index number, which does require an additional multiplication for most
121  * accesses, but at least does that consistently.
122  *
123  * (It also makes things easier because it allows going through the helper
124  * functions).
125  *
126  * There appears to be one truly viable alternative: implementing gpio_ll only
127  * for those EFM32 that do have DOUTSET etc. in P, with no way of having such
128  * an implementation for other EFM32 families. For the time being, the
129  * suboptimal-but-works-for-all version is the best we have.
130  */
131 static inline gpio_port_t gpio_port(uword_t num)
132 {
133  return num;
134 }
135 
136 static inline uword_t gpio_port_num(gpio_port_t port)
137 {
138  return port;
139 }
140 
141 static inline uword_t gpio_ll_read(gpio_port_t port)
142 {
143  return GPIO_PortInGet(port);
144 }
145 
146 static inline uword_t gpio_ll_read_output(gpio_port_t port)
147 {
148  return GPIO_PortOutGet(port);
149 }
150 
151 static inline void gpio_ll_set(gpio_port_t port, uword_t mask)
152 {
153  GPIO_PortOutSet(port, mask);
154 }
155 
156 static inline void gpio_ll_clear(gpio_port_t port, uword_t mask)
157 {
158  GPIO_PortOutClear(port, mask);
159 }
160 
161 static inline void gpio_ll_toggle(gpio_port_t port, uword_t mask)
162 {
163  GPIO_PortOutToggle(port, mask);
164 }
165 
166 static inline void gpio_ll_write(gpio_port_t port, uword_t value)
167 {
168  GPIO->P[port].DOUT = value;
169 }
170 
171 static inline gpio_port_t gpio_get_port(gpio_t pin)
172 {
173  return (pin >> 4);
174 }
175 
176 static inline uint8_t gpio_get_pin_num(gpio_t pin)
177 {
178  return (pin & 0x0f);
179 }
180 
181 static inline gpio_port_t gpio_port_pack_addr(void *addr)
182 {
183  return (gpio_port_t)addr;
184 }
185 
186 static inline bool is_gpio_port_num_valid(uint_fast8_t num)
187 {
188  return GPIO_PORT_VALID(num);
189 }
190 
191 static inline void * gpio_port_unpack_addr(gpio_port_t port)
192 {
193  if ((port & ~0xff) == 0 && is_gpio_port_num_valid(port)) {
194  return NULL;
195  }
196 
197  return (void *)port;
198 }
199 
200 #endif /* DOXYGEN */
201 #ifdef __cplusplus
202 }
203 #endif
204 
#define GPIO
GPIO register bank.
static uint8_t gpio_get_pin_num(gpio_t pin)
Extract the pin number from a gpio_t
static void * gpio_port_unpack_addr(gpio_port_t port)
Extract a data pointer that was packed by gpio_port_pack_addr.
static void gpio_ll_set(gpio_port_t port, uword_t mask)
Perform an reg |= mask operation on the I/O register of the port.
gpio_port_t gpio_port(uword_t num)
Get the gpio_port_t value of the port number num.
static gpio_port_t gpio_port_pack_addr(void *addr)
Pack a pointer into a gpio_port_t.
static uword_t gpio_ll_read(gpio_port_t port)
Get the current input value of all GPIO pins of the given port as bitmask.
static gpio_port_t gpio_get_port(gpio_t pin)
Extract the gpio_port_t from a gpio_t
uword_t gpio_port_num(gpio_port_t port)
Get the number of the GPIO port port refers to.
static bool is_gpio_port_num_valid(uint_fast8_t num)
Check if the given number is a valid argument for gpio_port.
static uword_t gpio_ll_read_output(gpio_port_t port)
Get the current output value of all GPIO pins of the given port as bitmask.
static void gpio_ll_clear(gpio_port_t port, uword_t mask)
Perform an reg &= ~mask operation on the I/O register of the port.
static void gpio_ll_toggle(gpio_port_t port, uword_t mask)
Perform an reg ^= mask operation on the I/O register of the port.
static void gpio_ll_write(gpio_port_t port, uword_t state)
Perform a masked write operation on the I/O register of the port.
uintptr_t gpio_port_t
GPIO port type.
Definition: gpio_ll.h:95
uint< NUM > _t uword_t
Word sized unsigned integer.
Definition: architecture.h:69
Shared CPU specific definitions for the STM32 family.