mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 04:52:59 +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:
parent
504c169346
commit
2a00ec13e5
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
/**
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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: ");
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user