Skip to content

Commit d315010

Browse files
maribugschorcht
andcommitted
drivers/periph/gpio_ll: shrink gpio_conf_t
This commit optimizes the `gpio_conf_t` type in the following regards: - The "base" `gpio_conf_t` is stripped from members that only some platforms support, e.g. drive strength, slew rate, and disabling of the Schmitt Trigger are no longer universally available but platform-specific extensions - The `gpio_conf_t` is now crammed into a bit-field that is 8 bit or 16 bit wide. This allows for storing lots of them e.g. in `driver_foo_params_t` or `uart_conf_t` etc. - A `union` of the `struct` with bit-field members and a `bits` is used to allow accessing all bits in a simple C statement and to ensure alignment for efficient handling of the type Co-authored-by: Gunar Schorcht <[email protected]>
1 parent ec4d1b0 commit d315010

File tree

13 files changed

+328
-175
lines changed

13 files changed

+328
-175
lines changed

cpu/atmega_common/include/periph_cpu_common.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,6 @@ typedef enum {
231231
GPIO_TRIGGER_LEVEL_HIGH = 0xff, /**< not supported */
232232
} gpio_irq_trig_t;
233233

234-
#define HAVE_GPIO_PULL_T
235-
typedef enum {
236-
GPIO_FLOATING = 0,
237-
GPIO_PULL_UP = 1,
238-
GPIO_PULL_DOWN = 0xfe, /*< not supported */
239-
GPIO_PULL_KEEP = 0xff, /*< not supported */
240-
} gpio_pull_t;
241-
242234
#define HAVE_GPIO_LL_PREPARE_WRITE_ALL_PINS
243235
#define HAVE_GPIO_LL_PREPARE_WRITE
244236

cpu/atmega_common/periph/gpio_ll.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,6 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
8484
{
8585
assert(dest);
8686
memset(dest, 0, sizeof(*dest));
87-
/* E.g. the schematics in figure 14-5 in the ATmega328P datasheet shows that
88-
* a Schmitt Trigger is always connected before the digital input signal.
89-
* Let's assume this is also true for all other ATmegas */
90-
dest->schmitt_trigger = true;
9187
if (_is_output(port, pin)) {
9288
dest->state = GPIO_OUTPUT_PUSH_PULL;
9389
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1U;

cpu/efm32/periph/gpio_ll.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,5 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
141141
break;
142142
}
143143

144-
/* as good as any */
145-
dest->slew_rate = GPIO_SLEW_FAST;
146-
147-
/* It's always on as long as they're in a mode in which it matters, judging
148-
* from https://www.silabs.com/documents/public/application-notes/an0027.pdf */
149-
dest->schmitt_trigger = true;
150-
151144
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1;
152-
153-
/* Using 'strong' her already as that fits with what the hardware has
154-
* (lowest, low, standard, high) */
155-
dest->drive_strength = GPIO_DRIVE_STRONG;
156145
}

cpu/esp32/include/periph_cpu.h

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ typedef enum {
190190
GPIO_FLOATING = 0,
191191
GPIO_PULL_UP = 1,
192192
GPIO_PULL_DOWN = 2,
193-
GPIO_PULL_KEEP = 0xff /*< not supported */
193+
GPIO_PULL_KEEP = 3 /*< not supported */
194194
} gpio_pull_t;
195195

196196
/**
@@ -212,9 +212,64 @@ typedef enum {
212212
#define GPIO_DRIVE_20 GPIO_DRIVE_STRONG /**< 20 mA (default) */
213213
#define GPIO_DRIVE_30 GPIO_DRIVE_STRONGEST /**< 30 mA */
214214

215-
/* END: GPIO LL overwrites */
215+
#define HAVE_GPIO_STATE_T
216+
typedef enum {
217+
GPIO_OUTPUT_PUSH_PULL,
218+
GPIO_OUTPUT_OPEN_DRAIN,
219+
GPIO_OUTPUT_OPEN_SOURCE,
220+
GPIO_INPUT,
221+
GPIO_USED_BY_PERIPHERAL,
222+
GPIO_DISCONNECT,
223+
} gpio_state_t;
224+
225+
#define HAVE_GPIO_CONF_T
226+
typedef union gpio_conf_esp32 gpio_conf_t;
216227

217228
#endif /* ndef DOXYGEN */
229+
230+
/**
231+
* @brief GPIO pin configuration for ESP32/ESP32Cx/ESP32Sx MCUs
232+
* @ingroup drivers_periph_gpio_ll
233+
*/
234+
union gpio_conf_esp32 {
235+
uint8_t bits; /**< the raw bits */
236+
struct {
237+
/**
238+
* @brief State of the pin
239+
*/
240+
gpio_state_t state : 3;
241+
/**
242+
* @brief Pull resistor configuration
243+
*/
244+
gpio_pull_t pull : 2;
245+
/**
246+
* @brief Drive strength of the GPIO
247+
*
248+
* @warning If the requested drive strength is not available, the closest
249+
* fit supported will be configured instead.
250+
*
251+
* This value is ignored when @ref gpio_conf_esp32::state is configured
252+
* to @ref GPIO_INPUT or @ref GPIO_DISCONNECT.
253+
*/
254+
gpio_drive_strength_t drive_strength : 2;
255+
/**
256+
* @brief Initial value of the output
257+
*
258+
* Ignored if @ref gpio_conf_esp32::state is set to @ref GPIO_INPUT or
259+
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
260+
* state, it is guaranteed to directly transition to the given initial
261+
* value.
262+
*
263+
* @ref gpio_ll_query_conf will write the current value of the specified
264+
* pin here, which is read from the input register when the state is
265+
* @ref GPIO_INPUT, otherwise the state from the output register is
266+
* consulted.
267+
*/
268+
bool initial_value : 1;
269+
};
270+
};
271+
272+
/* END: GPIO LL overwrites */
218273
/** @} */
219274

220275
/**

cpu/esp32/periph/gpio_ll.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@
3838

3939
#include "esp_idf_api/gpio.h"
4040

41+
#ifdef MODULE_FMT
42+
#include "fmt.h"
43+
#else
44+
static inline void print_str(const char *str)
45+
{
46+
fputs(str, stdout);
47+
}
48+
#endif
49+
4150
/* variables that have to be used together with periph/gpio */
4251
#ifdef ESP_PM_WUP_PINS
4352
extern bool _gpio_pin_pu[GPIO_PIN_NUMOF];
@@ -142,7 +151,6 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf)
142151

143152
/* since we can't read back the configuration, we have to save it */
144153
_gpio_conf[gpio] = *conf;
145-
_gpio_conf[gpio].schmitt_trigger = false;
146154

147155
if (esp_idf_gpio_config(&cfg) != ESP_OK) {
148156
return -ENOTSUP;
@@ -196,3 +204,17 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
196204
}
197205
irq_restore(state);
198206
}
207+
208+
void gpio_ll_print_conf(const gpio_conf_t *conf)
209+
{
210+
static const char *drive_strs[] = {
211+
[GPIO_DRIVE_WEAKEST] = "weakest",
212+
[GPIO_DRIVE_WEAK] = "weak",
213+
[GPIO_DRIVE_STRONG] = "strong",
214+
[GPIO_DRIVE_STRONGEST] = "strongest",
215+
};
216+
217+
gpio_ll_print_conf_common(conf);
218+
print_str(", drive: ");
219+
print_str(drive_strs[conf->drive_strength]);
220+
}

cpu/nrf5x_common/include/periph_cpu_common.h

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,69 @@ typedef enum {
138138
#define HAVE_GPIO_PULL_T
139139
typedef enum {
140140
GPIO_FLOATING = 0,
141-
GPIO_PULL_UP = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos,
142-
GPIO_PULL_DOWN = GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos,
143-
/* GPIO_PULL_KEEP is not supported by, gpio_ll_init() returns -ENOTSUP */
144-
GPIO_PULL_KEEP = 0xff
141+
GPIO_PULL_UP = GPIO_PIN_CNF_PULL_Pullup,
142+
GPIO_PULL_DOWN = GPIO_PIN_CNF_PULL_Pulldown,
143+
GPIO_PULL_KEEP = 2,
145144
} gpio_pull_t;
146-
#endif /* END: GPIO LL overwrites */
145+
146+
#define HAVE_GPIO_STATE_T
147+
typedef enum {
148+
GPIO_OUTPUT_PUSH_PULL,
149+
GPIO_OUTPUT_OPEN_DRAIN,
150+
GPIO_OUTPUT_OPEN_SOURCE,
151+
GPIO_INPUT,
152+
GPIO_USED_BY_PERIPHERAL,
153+
GPIO_DISCONNECT,
154+
} gpio_state_t;
155+
156+
#define HAVE_GPIO_CONF_T
157+
typedef union gpio_conf_nrf5x gpio_conf_t;
158+
159+
#endif
160+
161+
/**
162+
* @brief GPIO pin configuration for nRF5x MCUs
163+
* @ingroup drivers_periph_gpio_ll
164+
*/
165+
union gpio_conf_nrf5x {
166+
uint8_t bits; /**< the raw bits */
167+
struct {
168+
/**
169+
* @brief State of the pin
170+
*/
171+
gpio_state_t state : 3;
172+
/**
173+
* @brief Pull resistor configuration
174+
*/
175+
gpio_pull_t pull : 2;
176+
/**
177+
* @brief Drive strength of the GPIO
178+
*
179+
* @warning If the requested drive strength is not available, the
180+
* closest fit supported will be configured instead.
181+
*
182+
* This value is ignored when @ref gpio_conf_nrf5x::state is configured
183+
* to @ref GPIO_INPUT or @ref GPIO_DISCONNECT.
184+
*/
185+
gpio_drive_strength_t drive_strength : 1;
186+
/**
187+
* @brief Initial value of the output
188+
*
189+
* Ignored if @ref gpio_conf_nrf5x::state is set to @ref GPIO_INPUT or
190+
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
191+
* state, it is guaranteed to directly transition to the given initial
192+
* value.
193+
*
194+
* @ref gpio_ll_query_conf will write the current value of the specified
195+
* pin here, which is read from the input register when the state is
196+
* @ref GPIO_INPUT, otherwise the state from the output register is
197+
* consulted.
198+
*/
199+
bool initial_value : 1;
200+
uint8_t : 1; /*< padding */
201+
};
202+
};
203+
/* END: GPIO LL overwrites */
147204

148205
#if !defined(DOXYGEN) && (defined(CPU_NRF53) || defined(CPU_NRF9160))
149206
/**

cpu/nrf5x_common/periph/gpio_ll.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,22 @@
3636
#include "periph_cpu.h"
3737
#include "periph_conf.h"
3838

39+
#ifdef MODULE_FMT
40+
#include "fmt.h"
41+
#else
42+
static inline void print_str(const char *str)
43+
{
44+
fputs(str, stdout);
45+
}
46+
#endif
47+
3948
int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf)
4049
{
4150
if (conf->pull == GPIO_PULL_KEEP) {
4251
return -ENOTSUP;
4352
}
4453

45-
uint32_t pin_cnf = conf->pull;
54+
uint32_t pin_cnf = (unsigned)conf->pull << GPIO_PIN_CNF_PULL_Pos;
4655
switch (conf->state) {
4756
case GPIO_OUTPUT_PUSH_PULL:
4857
/* INPUT bit needs to be *CLEARED* in input mode, so set to disconnect input buffer */
@@ -115,7 +124,6 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
115124
* no matches. Assuming Schmitt trigger cannot be disabled for the
116125
* nRF5x MCU.
117126
*/
118-
dest->schmitt_trigger = true;
119127
dest->state = GPIO_INPUT;
120128

121129
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
@@ -197,3 +205,15 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
197205
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL;
198206
}
199207
}
208+
209+
void gpio_ll_print_conf(const gpio_conf_t *conf)
210+
{
211+
static const char *drive_strs[] = {
212+
[GPIO_DRIVE_WEAK] = "weak",
213+
[GPIO_DRIVE_STRONG] = "strong",
214+
};
215+
216+
gpio_ll_print_conf_common(conf);
217+
print_str(", drive: ");
218+
print_str(drive_strs[conf->drive_strength]);
219+
}

cpu/stm32/include/periph/cpu_gpio_ll.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef PERIPH_CPU_GPIO_LL_H
2020
#define PERIPH_CPU_GPIO_LL_H
2121

22+
#include <stdalign.h>
2223
#include <stdint.h>
2324
#include "periph_cpu.h"
2425

@@ -88,8 +89,84 @@ typedef enum {
8889
GPIO_TRIGGER_LEVEL_LOW = GPIO_TRIGGER_LEVEL | GPIO_TRIGGER_EDGE_FALLING,
8990
} gpio_irq_trig_t;
9091

92+
#define HAVE_GPIO_STATE_T
93+
typedef enum {
94+
GPIO_OUTPUT_PUSH_PULL,
95+
GPIO_OUTPUT_OPEN_DRAIN,
96+
GPIO_OUTPUT_OPEN_SOURCE,
97+
GPIO_INPUT,
98+
GPIO_USED_BY_PERIPHERAL,
99+
GPIO_DISCONNECT,
100+
} gpio_state_t;
101+
102+
#define HAVE_GPIO_PULL_T
103+
typedef enum {
104+
GPIO_FLOATING,
105+
GPIO_PULL_UP,
106+
GPIO_PULL_DOWN,
107+
GPIO_PULL_KEEP,
108+
} gpio_pull_t;
109+
110+
#define HAVE_GPIO_CONF_T
111+
typedef union gpio_conf_stm32 gpio_conf_t;
112+
91113
#endif /* ndef Doxygen */
92114

115+
/**
116+
* @brief GPIO pin configuration for STM32 MCUs.
117+
* @ingroup drivers_periph_gpio_ll
118+
*/
119+
union gpio_conf_stm32 {
120+
uint16_t bits; /**< the raw bits */
121+
struct {
122+
/**
123+
* @brief State of the pin
124+
*/
125+
gpio_state_t state : 3;
126+
/**
127+
* @brief Pull resistor configuration
128+
*/
129+
gpio_pull_t pull : 2;
130+
/**
131+
* @brief Configure the slew rate of outputs
132+
*
133+
* @warning If the requested slew rate is not available, the closest fit
134+
* supported will be configured instead.
135+
*
136+
* This value is ignored *unless* @ref gpio_conf_stm32::state is
137+
* configured to @ref GPIO_OUTPUT_PUSH_PULL or @ref GPIO_OUTPUT_OPEN_DRAIN.
138+
*/
139+
gpio_slew_t slew_rate : 2;
140+
/**
141+
* @brief Whether to disable the input Schmitt trigger
142+
*
143+
* @details This could be called `schmitt_trigger` with inverse
144+
* meaning, but the API contract says that additional
145+
* members in the structure should have a sane
146+
* default when zero.
147+
*
148+
* This value is ignored *unless* @ref gpio_conf_stm32::state is
149+
* configured to @ref GPIO_INPUT.
150+
*/
151+
bool schmitt_trigger_disabled : 1;
152+
/**
153+
* @brief Initial value of the output
154+
*
155+
* Ignored if @ref gpio_conf_stm32::state is set to @ref GPIO_INPUT or
156+
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
157+
* state, it is guaranteed to directly transition to the given initial
158+
* value.
159+
*
160+
* @ref gpio_ll_query_conf will write the current value of the specified
161+
* pin here, which is read from the input register when the state is
162+
* @ref GPIO_INPUT, otherwise the state from the output register is
163+
* consulted.
164+
*/
165+
bool initial_value : 1;
166+
uint8_t : 7; /*< padding */
167+
};
168+
};
169+
93170
#ifdef __cplusplus
94171
}
95172
#endif

0 commit comments

Comments
 (0)