1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 10:32:44 +01:00

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 <gunar@schorcht.net>
This commit is contained in:
Marian Buschsieweke 2023-12-27 19:37:03 +01:00
parent 504c169346
commit 2a00ec13e5
No known key found for this signature in database
GPG Key ID: 77AA882EC78084E6
14 changed files with 449 additions and 173 deletions

View File

@ -231,14 +231,6 @@ typedef enum {
GPIO_TRIGGER_LEVEL_HIGH = 0xff, /**< not supported */
} gpio_irq_trig_t;
#define HAVE_GPIO_PULL_T
typedef enum {
GPIO_FLOATING = 0,
GPIO_PULL_UP = 1,
GPIO_PULL_DOWN = 0xfe, /*< not supported */
GPIO_PULL_KEEP = 0xff, /*< not supported */
} gpio_pull_t;
#define HAVE_GPIO_LL_PREPARE_WRITE_ALL_PINS
#define HAVE_GPIO_LL_PREPARE_WRITE

View File

@ -84,10 +84,6 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
{
assert(dest);
memset(dest, 0, sizeof(*dest));
/* E.g. the schematics in figure 14-5 in the ATmega328P datasheet shows that
* a Schmitt Trigger is always connected before the digital input signal.
* Let's assume this is also true for all other ATmegas */
dest->schmitt_trigger = true;
if (_is_output(port, pin)) {
dest->state = GPIO_OUTPUT_PUSH_PULL;
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1U;

View File

@ -141,16 +141,5 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
break;
}
/* as good as any */
dest->slew_rate = GPIO_SLEW_FAST;
/* It's always on as long as they're in a mode in which it matters, judging
* from https://www.silabs.com/documents/public/application-notes/an0027.pdf */
dest->schmitt_trigger = true;
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1;
/* Using 'strong' her already as that fits with what the hardware has
* (lowest, low, standard, high) */
dest->drive_strength = GPIO_DRIVE_STRONG;
}

View File

@ -190,7 +190,7 @@ typedef enum {
GPIO_FLOATING = 0,
GPIO_PULL_UP = 1,
GPIO_PULL_DOWN = 2,
GPIO_PULL_KEEP = 0xff /*< not supported */
GPIO_PULL_KEEP = 3 /*< not supported */
} gpio_pull_t;
/**
@ -212,9 +212,64 @@ typedef enum {
#define GPIO_DRIVE_20 GPIO_DRIVE_STRONG /**< 20 mA (default) */
#define GPIO_DRIVE_30 GPIO_DRIVE_STRONGEST /**< 30 mA */
/* END: GPIO LL overwrites */
#define HAVE_GPIO_STATE_T
typedef enum {
GPIO_OUTPUT_PUSH_PULL,
GPIO_OUTPUT_OPEN_DRAIN,
GPIO_OUTPUT_OPEN_SOURCE,
GPIO_INPUT,
GPIO_USED_BY_PERIPHERAL,
GPIO_DISCONNECT,
} gpio_state_t;
#define HAVE_GPIO_CONF_T
typedef union gpio_conf_esp32 gpio_conf_t;
#endif /* ndef DOXYGEN */
/**
* @brief GPIO pin configuration for ESP32/ESP32Cx/ESP32Sx MCUs
* @ingroup drivers_periph_gpio_ll
*/
union gpio_conf_esp32 {
uint8_t bits; /**< the raw bits */
struct {
/**
* @brief State of the pin
*/
gpio_state_t state : 3;
/**
* @brief Pull resistor configuration
*/
gpio_pull_t pull : 2;
/**
* @brief Drive strength of the GPIO
*
* @warning If the requested drive strength is not available, the closest
* fit supported will be configured instead.
*
* This value is ignored when @ref gpio_conf_esp32::state is configured
* to @ref GPIO_INPUT or @ref GPIO_DISCONNECT.
*/
gpio_drive_strength_t drive_strength : 2;
/**
* @brief Initial value of the output
*
* Ignored if @ref gpio_conf_esp32::state is set to @ref GPIO_INPUT or
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
* state, it is guaranteed to directly transition to the given initial
* value.
*
* @ref gpio_ll_query_conf will write the current value of the specified
* pin here, which is read from the input register when the state is
* @ref GPIO_INPUT, otherwise the state from the output register is
* consulted.
*/
bool initial_value : 1;
};
};
/* END: GPIO LL overwrites */
/** @} */
/**

View File

@ -38,6 +38,15 @@
#include "esp_idf_api/gpio.h"
#ifdef MODULE_FMT
#include "fmt.h"
#else
static inline void print_str(const char *str)
{
fputs(str, stdout);
}
#endif
/* variables that have to be used together with periph/gpio */
#ifdef ESP_PM_WUP_PINS
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)
/* since we can't read back the configuration, we have to save it */
_gpio_conf[gpio] = *conf;
_gpio_conf[gpio].schmitt_trigger = false;
if (esp_idf_gpio_config(&cfg) != ESP_OK) {
return -ENOTSUP;
@ -196,3 +204,17 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
}
irq_restore(state);
}
void gpio_ll_print_conf(const gpio_conf_t *conf)
{
static const char *drive_strs[] = {
[GPIO_DRIVE_WEAKEST] = "weakest",
[GPIO_DRIVE_WEAK] = "weak",
[GPIO_DRIVE_STRONG] = "strong",
[GPIO_DRIVE_STRONGEST] = "strongest",
};
gpio_ll_print_conf_common(conf);
print_str(", drive: ");
print_str(drive_strs[conf->drive_strength]);
}

View File

@ -187,6 +187,24 @@ void gpio_init_analog(gpio_t pin);
* public view on type */
#ifndef DOXYGEN
#define HAVE_GPIO_STATE_T
typedef enum {
GPIO_OUTPUT_PUSH_PULL,
GPIO_OUTPUT_OPEN_DRAIN,
GPIO_OUTPUT_OPEN_SOURCE,
GPIO_INPUT,
GPIO_USED_BY_PERIPHERAL,
GPIO_DISCONNECT,
} gpio_state_t;
#define HAVE_GPIO_PULL_T
typedef enum {
GPIO_FLOATING,
GPIO_PULL_UP,
GPIO_PULL_DOWN,
GPIO_PULL_KEEP,
} gpio_pull_t;
#define HAVE_GPIO_PULL_STRENGTH_T
typedef enum {
GPIO_PULL_WEAKEST = 0,
@ -211,8 +229,66 @@ typedef enum {
GPIO_SLEW_FASTEST = 2,
} gpio_slew_t;
#define HAVE_GPIO_CONF_T
typedef union gpio_conf_gd32v gpio_conf_t;
#endif /* !DOXYGEN */
/**
* @brief GPIO pin configuration for GD32V MCUs.
* @ingroup drivers_periph_gpio_ll
*/
union gpio_conf_gd32v {
uint16_t bits; /**< the raw bits */
struct {
/**
* @brief State of the pin
*/
gpio_state_t state : 3;
/**
* @brief Pull resistor configuration
*/
gpio_pull_t pull : 2;
/**
* @brief Configure the slew rate of outputs
*
* @warning If the requested slew rate is not available, the closest fit
* supported will be configured instead.
*
* This value is ignored *unless* @ref gpio_conf_stm32::state is
* configured to @ref GPIO_OUTPUT_PUSH_PULL or @ref GPIO_OUTPUT_OPEN_DRAIN.
*/
gpio_slew_t slew_rate : 2;
/**
* @brief Whether to disable the input Schmitt trigger
*
* @details This could be called `schmitt_trigger` with inverse
* meaning, but the API contract says that additional
* members in the structure should have a sane
* default when zero.
*
* This value is ignored *unless* @ref gpio_conf_stm32::state is
* configured to @ref GPIO_INPUT.
*/
bool schmitt_trigger_disabled : 1;
/**
* @brief Initial value of the output
*
* Ignored if @ref gpio_conf_stm32::state is set to @ref GPIO_INPUT or
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
* state, it is guaranteed to directly transition to the given initial
* value.
*
* @ref gpio_ll_query_conf will write the current value of the specified
* pin here, which is read from the input register when the state is
* @ref GPIO_INPUT, otherwise the state from the output register is
* consulted.
*/
bool initial_value : 1;
uint8_t : 7; /*< padding */
};
};
/**
* @brief Available number of ADC devices
*/

View File

@ -28,6 +28,15 @@
#define ENABLE_DEBUG 0
#include "debug.h"
#ifdef MODULE_FMT
#include "fmt.h"
#else
static inline void print_str(const char *str)
{
fputs(str, stdout);
}
#endif
uint16_t pin_used[GPIO_PORT_NUMOF] = {};
int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf)
@ -152,3 +161,21 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
}
irq_restore(state);
}
void gpio_ll_print_conf(const gpio_conf_t *conf)
{
static const char *slew_strs[] = {
[GPIO_SLEW_SLOWEST] = "slowest",
[GPIO_SLEW_SLOW] = "medium",
[GPIO_SLEW_FASTEST] = "fastest",
"invalid"
};
gpio_ll_print_conf_common(conf);
print_str(", slew: ");
print_str(slew_strs[conf->slew_rate]);
if (conf->schmitt_trigger_disabled) {
print_str(", Schmitt trigger disabled");
}
}

View File

@ -138,12 +138,69 @@ typedef enum {
#define HAVE_GPIO_PULL_T
typedef enum {
GPIO_FLOATING = 0,
GPIO_PULL_UP = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos,
GPIO_PULL_DOWN = GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos,
/* GPIO_PULL_KEEP is not supported by, gpio_ll_init() returns -ENOTSUP */
GPIO_PULL_KEEP = 0xff
GPIO_PULL_UP = GPIO_PIN_CNF_PULL_Pullup,
GPIO_PULL_DOWN = GPIO_PIN_CNF_PULL_Pulldown,
GPIO_PULL_KEEP = 2,
} gpio_pull_t;
#endif /* END: GPIO LL overwrites */
#define HAVE_GPIO_STATE_T
typedef enum {
GPIO_OUTPUT_PUSH_PULL,
GPIO_OUTPUT_OPEN_DRAIN,
GPIO_OUTPUT_OPEN_SOURCE,
GPIO_INPUT,
GPIO_USED_BY_PERIPHERAL,
GPIO_DISCONNECT,
} gpio_state_t;
#define HAVE_GPIO_CONF_T
typedef union gpio_conf_nrf5x gpio_conf_t;
#endif
/**
* @brief GPIO pin configuration for nRF5x MCUs
* @ingroup drivers_periph_gpio_ll
*/
union gpio_conf_nrf5x {
uint8_t bits; /**< the raw bits */
struct {
/**
* @brief State of the pin
*/
gpio_state_t state : 3;
/**
* @brief Pull resistor configuration
*/
gpio_pull_t pull : 2;
/**
* @brief Drive strength of the GPIO
*
* @warning If the requested drive strength is not available, the
* closest fit supported will be configured instead.
*
* This value is ignored when @ref gpio_conf_nrf5x::state is configured
* to @ref GPIO_INPUT or @ref GPIO_DISCONNECT.
*/
gpio_drive_strength_t drive_strength : 1;
/**
* @brief Initial value of the output
*
* Ignored if @ref gpio_conf_nrf5x::state is set to @ref GPIO_INPUT or
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
* state, it is guaranteed to directly transition to the given initial
* value.
*
* @ref gpio_ll_query_conf will write the current value of the specified
* pin here, which is read from the input register when the state is
* @ref GPIO_INPUT, otherwise the state from the output register is
* consulted.
*/
bool initial_value : 1;
uint8_t : 1; /*< padding */
};
};
/* END: GPIO LL overwrites */
#if !defined(DOXYGEN) && (defined(CPU_NRF53) || defined(CPU_NRF9160))
/**

View File

@ -36,13 +36,22 @@
#include "periph_cpu.h"
#include "periph_conf.h"
#ifdef MODULE_FMT
#include "fmt.h"
#else
static inline void print_str(const char *str)
{
fputs(str, stdout);
}
#endif
int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf)
{
if (conf->pull == GPIO_PULL_KEEP) {
return -ENOTSUP;
}
uint32_t pin_cnf = conf->pull;
uint32_t pin_cnf = (unsigned)conf->pull << GPIO_PIN_CNF_PULL_Pos;
switch (conf->state) {
case GPIO_OUTPUT_PUSH_PULL:
/* 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)
* no matches. Assuming Schmitt trigger cannot be disabled for the
* nRF5x MCU.
*/
dest->schmitt_trigger = true;
dest->state = GPIO_INPUT;
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)
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL;
}
}
void gpio_ll_print_conf(const gpio_conf_t *conf)
{
static const char *drive_strs[] = {
[GPIO_DRIVE_WEAK] = "weak",
[GPIO_DRIVE_STRONG] = "strong",
};
gpio_ll_print_conf_common(conf);
print_str(", drive: ");
print_str(drive_strs[conf->drive_strength]);
}

View File

@ -19,6 +19,7 @@
#ifndef PERIPH_CPU_GPIO_LL_H
#define PERIPH_CPU_GPIO_LL_H
#include <stdalign.h>
#include <stdint.h>
#include "periph_cpu.h"
@ -46,8 +47,6 @@ typedef enum {
GPIO_DRIVE_STRONGEST = 0
} gpio_drive_strength_t;
#if defined(GPIO_OSPEEDR_OSPEED0) || defined(GPIO_OSPEEDER_OSPEEDR0) \
|| defined(GPIO_OSPEEDER_OSPEED0) || defined(GPIO_OSPEEDR_OSPEEDR0)
/* Modern STM32 GPIO config registers with the OSPEEDR register support full
* 4 slew rates, legacy STM32F1 style only have three slew rates. We define
* slow and fast to the same value, so that we have three options:
@ -55,11 +54,26 @@ typedef enum {
* 2. SLOW: 10 MHZ
* 3. FAST/FASTEST: 50 MHz
*/
#if defined(GPIO_OSPEEDR_OSPEED0) || defined(GPIO_OSPEEDER_OSPEEDR0) \
|| defined(GPIO_OSPEEDER_OSPEED0) || defined(GPIO_OSPEEDR_OSPEEDR0)
# define STM32_HAS_OSPEED 1
#else
# define STM32_HAS_OSPEED 0
#endif
#define HAVE_GPIO_SLEW_T
#if STM32_HAS_OSPEED
typedef enum {
GPIO_SLEW_SLOWEST = 0,
GPIO_SLEW_SLOW = 1,
GPIO_SLEW_FAST = 2,
GPIO_SLEW_FASTEST = 3,
} gpio_slew_t;
#else
typedef enum {
GPIO_SLEW_SLOWEST = 0,
GPIO_SLEW_SLOW = 0,
GPIO_SLEW_FAST = 1,
GPIO_SLEW_FASTEST = 2,
} gpio_slew_t;
#endif
@ -88,8 +102,84 @@ typedef enum {
GPIO_TRIGGER_LEVEL_LOW = GPIO_TRIGGER_LEVEL | GPIO_TRIGGER_EDGE_FALLING,
} gpio_irq_trig_t;
#define HAVE_GPIO_STATE_T
typedef enum {
GPIO_OUTPUT_PUSH_PULL,
GPIO_OUTPUT_OPEN_DRAIN,
GPIO_OUTPUT_OPEN_SOURCE,
GPIO_INPUT,
GPIO_USED_BY_PERIPHERAL,
GPIO_DISCONNECT,
} gpio_state_t;
#define HAVE_GPIO_PULL_T
typedef enum {
GPIO_FLOATING,
GPIO_PULL_UP,
GPIO_PULL_DOWN,
GPIO_PULL_KEEP,
} gpio_pull_t;
#define HAVE_GPIO_CONF_T
typedef union gpio_conf_stm32 gpio_conf_t;
#endif /* ndef Doxygen */
/**
* @brief GPIO pin configuration for STM32 MCUs.
* @ingroup drivers_periph_gpio_ll
*/
union gpio_conf_stm32 {
uint16_t bits; /**< the raw bits */
struct {
/**
* @brief State of the pin
*/
gpio_state_t state : 3;
/**
* @brief Pull resistor configuration
*/
gpio_pull_t pull : 2;
/**
* @brief Configure the slew rate of outputs
*
* @warning If the requested slew rate is not available, the closest fit
* supported will be configured instead.
*
* This value is ignored *unless* @ref gpio_conf_stm32::state is
* configured to @ref GPIO_OUTPUT_PUSH_PULL or @ref GPIO_OUTPUT_OPEN_DRAIN.
*/
gpio_slew_t slew_rate : 2;
/**
* @brief Whether to disable the input Schmitt trigger
*
* @details This could be called `schmitt_trigger` with inverse
* meaning, but the API contract says that additional
* members in the structure should have a sane
* default when zero.
*
* This value is ignored *unless* @ref gpio_conf_stm32::state is
* configured to @ref GPIO_INPUT.
*/
bool schmitt_trigger_disabled : 1;
/**
* @brief Initial value of the output
*
* Ignored if @ref gpio_conf_stm32::state is set to @ref GPIO_INPUT or
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
* state, it is guaranteed to directly transition to the given initial
* value.
*
* @ref gpio_ll_query_conf will write the current value of the specified
* pin here, which is read from the input register when the state is
* @ref GPIO_INPUT, otherwise the state from the output register is
* consulted.
*/
bool initial_value : 1;
uint8_t : 7; /*< padding */
};
};
#ifdef __cplusplus
}
#endif

View File

@ -35,6 +35,15 @@
#include "bitarithm.h"
#include "periph/gpio_ll.h"
#ifdef MODULE_FMT
#include "fmt.h"
#else
static inline void print_str(const char *str)
{
fputs(str, stdout);
}
#endif
#ifdef RCC_AHBENR_GPIOAEN
# define GPIO_BUS AHB
# define GPIOAEN RCC_AHBENR_GPIOAEN
@ -356,3 +365,28 @@ void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
}
irq_restore(state);
}
void gpio_ll_print_conf(const gpio_conf_t *conf)
{
static const char *slew_strs[] = {
[GPIO_SLEW_SLOWEST] = "slowest",
#if STM32_HAS_OSPEED
[GPIO_SLEW_SLOW] = "slow",
#endif
[GPIO_SLEW_FAST] = "fast",
[GPIO_SLEW_FASTEST] = "fastest",
/* If only three slew rates are supported, a fourth value would be
* representable with the two-bit field. Let's be rather safe than sorry */
#if !STM32_HAS_OSPEED
"invalid"
#endif
};
gpio_ll_print_conf_common(conf);
print_str(", slew: ");
print_str(slew_strs[conf->slew_rate]);
if (conf->schmitt_trigger_disabled) {
print_str(", Schmitt trigger disabled");
}
}

View File

@ -299,7 +299,57 @@ typedef enum {
+ (GPIO_SLEW_SLOW != GPIO_SLEW_FAST) \
+ (GPIO_SLEW_FAST != GPIO_SLEW_FASTEST))
#if !defined(HAVE_GPIO_CONF_T) || defined(DOXYGEN)
/**
* @brief Public members of `gpio_conf_t`
*
* The type `gpio_conf_t` is implementation specific, but will in any case
* be a union of an unsigned integer of implementation defined width named
* `bits` (to access all bits of the configuration in one read/write), and
* an anonymous `struct` to access the actual configuration via its members.
*
* The members given here have to be present in every implementation. Make sure
* to use the `enum` names to assign them, as the actual numeric representation
* again is implementation specific.
*
* It is explicitly intended that code makes use of implementation specific
* extensions to `gpio_conf_t`. However, portable code should be restricted
* to only use the members detailed here and make sure that all other bits
* are initialized with zero.
*/
union gpio_conf_minimal {
uint8_t bits; /**< The raw bits of the configuration */
struct {
/**
* @brief State of the pin
*/
gpio_state_t state : 3;
/**
* @brief Pull resistor configuration
*/
gpio_pull_t pull : 2;
/**
* @brief Initial value of the output
*
* Ignored if @ref gpio_conf_minimal::state is set to @ref GPIO_INPUT or
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
* state, it is guaranteed to directly transition to the given initial
* value.
*
* @ref gpio_ll_query_conf will write the current value of the specified
* pin here, which is read from the input register when the state is
* @ref GPIO_INPUT, otherwise the state from the output register is
* consulted.
*/
bool initial_value : 1;
uint8_t : 2; /*< padding */
};
};
#if !defined(HAVE_GPIO_CONF_T) && !defined(DOXYGEN)
typedef union gpio_conf_minimal gpio_conf_t;
#endif
#ifdef DOXYGEN
/**
* @brief GPIO pin configuration
*
@ -309,75 +359,9 @@ typedef enum {
* initializers or zeroing out the whole contents using `memset()
* before initializing the individual fields.
*
* It is fully valid that an implementation extends this structure with
* additional implementation specific fields. For example, it could be useful
* to also include fields to configure routing of a GPIO pin to other
* peripherals (e.g. for us as an TXD pin of an UART). These implementation
* specific fields **MUST** however have reasonable defaults when initialized
* with zero (e.g. pin is not routed to another peripheral but to be used as
* regular GPIO). For obvious reasons, portable code cannot rely on the
* presence and semantic of any implementation specific fields. Additionally,
* out-of-tree users should not use these fields, as the implementation
* specific fields cannot be considered a stable API.
* See @ref gpio_conf_minimal for the minimal structure fields to expect.
*/
typedef struct {
gpio_state_t state; /**< State of the pin */
gpio_pull_t pull; /**< Pull resistor configuration */
/**
* @brief Configure the slew rate of outputs
*
* @warning If the requested slew rate is not available, the closest fit
* supported will be configured instead.
*
* This value is ignored *unless* @ref gpio_conf_t::state is configured
* to @ref GPIO_OUTPUT_PUSH_PULL or @ref GPIO_OUTPUT_OPEN_DRAIN.
*/
gpio_slew_t slew_rate;
/**
* @brief Whether to enable the input Schmitt trigger
*
* @warning If the requested Schmitt trigger setting is not available, it
* will be ignored.
*
* This value is ignored *unless* @ref gpio_conf_t::state is configured
* to @ref GPIO_INPUT.
*/
bool schmitt_trigger;
/**
* @brief Initial value of the output
*
* Ignored if @ref gpio_conf_t::state is set to @ref GPIO_INPUT or
* @ref GPIO_DISCONNECT. If the pin was previously in a high impedance
* state, it is guaranteed to directly transition to the given initial
* value.
*
* @ref gpio_ll_query_conf will write the current value of the specified
* pin here, which is read from the input register when the state is
* @ref GPIO_INPUT, otherwise the state from the output register is
* consulted.
*/
bool initial_value;
/**
* @brief Strength of the pull up/down resistor
*
* @warning If the requested pull strength is not available, the closest fit
* supported will be configured instead.
*
* This value is ignored when @ref gpio_conf_t::pull is configured to
* @ref GPIO_FLOATING.
*/
gpio_pull_strength_t pull_strength;
/**
* @brief Drive strength of the GPIO
*
* @warning If the requested drive strength is not available, the closest
* fit supported will be configured instead.
*
* This value is ignored when @ref gpio_conf_t::state is configured to
* @ref GPIO_INPUT or @ref GPIO_DISCONNECT.
*/
gpio_drive_strength_t drive_strength;
} gpio_conf_t;
typedef /* implementation specific */ gpio_conf_t;
#endif
/**
@ -488,9 +472,9 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf);
* @pre @p port and @p pin refer to an existing GPIO pin and @p dest can
* be written to. Expect blowing assertions otherwise.
*
* @note @ref gpio_conf_t::initial_value should be set to the current value
* of the pin, so that no shadow log of the initial value is needed to
* consult.
* @note @ref gpio_conf_minimal::initial_value should be set to the current
* value of the pin, so that no shadow log of the initial value is
* needed to consult.
*/
void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin);

View File

@ -32,47 +32,37 @@ static inline void print_str(const char *str)
const gpio_conf_t gpio_ll_in = {
.state = GPIO_INPUT,
.pull = GPIO_FLOATING,
.schmitt_trigger = true,
};
const gpio_conf_t gpio_ll_in_pd = {
.state = GPIO_INPUT,
.pull = GPIO_PULL_DOWN,
.schmitt_trigger = true,
};
const gpio_conf_t gpio_ll_in_pu = {
.state = GPIO_INPUT,
.pull = GPIO_PULL_UP,
.schmitt_trigger = true,
};
const gpio_conf_t gpio_ll_in_pk = {
.state = GPIO_INPUT,
.pull = GPIO_PULL_KEEP,
.schmitt_trigger = true,
};
const gpio_conf_t gpio_ll_out = {
.state = GPIO_OUTPUT_PUSH_PULL,
.drive_strength = GPIO_DRIVE_STRONGEST,
.slew_rate = GPIO_SLEW_FASTEST,
.initial_value = false,
};
const gpio_conf_t gpio_ll_pd = {
.state = GPIO_OUTPUT_OPEN_DRAIN,
.pull = GPIO_FLOATING,
.drive_strength = GPIO_DRIVE_STRONGEST,
.slew_rate = GPIO_SLEW_FASTEST,
.initial_value = true,
};
const gpio_conf_t gpio_ll_pd_pu = {
.state = GPIO_OUTPUT_OPEN_DRAIN,
.pull = GPIO_PULL_UP,
.drive_strength = GPIO_DRIVE_STRONGEST,
.slew_rate = GPIO_SLEW_FASTEST,
.initial_value = true,
};
@ -103,39 +93,6 @@ void gpio_ll_print_conf_common(const gpio_conf_t *conf)
break;
}
if (conf->state != GPIO_INPUT) {
if (GPIO_DRIVE_NUMOF > 1) {
print_str(", drive: ");
if (conf->drive_strength == GPIO_DRIVE_WEAK) {
print_str("weak");
}
else if (conf->drive_strength == GPIO_DRIVE_WEAKEST) {
print_str("weakest");
}
else if (conf->drive_strength == GPIO_DRIVE_STRONG) {
print_str("strong");
}
else {
print_str("strongest");
}
}
if (GPIO_SLEW_NUMOF > 1) {
print_str(", slew: ");
if (conf->slew_rate == GPIO_SLEW_SLOW) {
print_str("slow");
}
else if (conf->slew_rate == GPIO_SLEW_SLOWEST) {
print_str("slowest");
}
else if (conf->slew_rate == GPIO_SLEW_FAST) {
print_str("fast");
}
else {
print_str("fastest");
}
}
}
if (conf->state != GPIO_OUTPUT_PUSH_PULL) {
print_str(", pull: ");
switch (conf->pull) {
@ -153,26 +110,6 @@ void gpio_ll_print_conf_common(const gpio_conf_t *conf)
print_str("keep");
break;
}
if ((conf->pull != GPIO_FLOATING) && (GPIO_PULL_NUMOF > 1)) {
print_str(" (");
if (conf->pull_strength == GPIO_PULL_WEAK) {
print_str("weak");
}
else if (conf->pull_strength == GPIO_PULL_WEAKEST) {
print_str("weakest");
}
else if (conf->pull_strength == GPIO_PULL_STRONG) {
print_str("strong");
}
else {
print_str("strongest");
}
print_str(")");
}
print_str(", schmitt trigger: ");
print_str(off_on[conf->schmitt_trigger]);
}
print_str(", value: ");

View File

@ -157,7 +157,6 @@ int main(void)
"-------------------------------------------------------");
gpio_conf_t conf = {
.state = GPIO_OUTPUT_PUSH_PULL,
.slew_rate = GPIO_SLEW_FASTEST
};
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, &conf));
expect(0 == gpio_ll_init(port_out, PIN_OUT_1, &conf));
@ -211,7 +210,6 @@ int main(void)
"-----------------------------------------");
gpio_conf_t conf = {
.state = GPIO_OUTPUT_PUSH_PULL,
.slew_rate = GPIO_SLEW_FASTEST
};
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, &conf));
expect(0 == gpio_ll_init(port_out, PIN_OUT_1, &conf));
@ -265,7 +263,6 @@ int main(void)
"----------------------------------------");
gpio_conf_t conf = {
.state = GPIO_OUTPUT_PUSH_PULL,
.slew_rate = GPIO_SLEW_FASTEST
};
expect(0 == gpio_ll_init(port_out, PIN_OUT_0, &conf));
expect(0 == gpio_ll_init(port_out, PIN_OUT_1, &conf));