1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/stm32/periph_gpio_ll: Fix and clean up

The separate Schmitt trigger bit in the configuration is dropped, as
the Schmitt trigger is only every disabled when in `GPIO_DISCONNECT`
mode. So no need to encode the same information twice.

The `gpio_state_t` is improved to be a bitmask that holds the
MODER register value and a flag indicating whether open-drain mode
should be enabled.

Finally, `GPIO_DISCONNECT` is implemented. This is done by placing the
GPIO in analog mode, which by disabling the Schmitt trigger reduces
power consumption.
This commit is contained in:
Marian Buschsieweke 2024-01-23 10:59:42 +01:00
parent 447493e719
commit 6028097132
No known key found for this signature in database
GPG Key ID: 77AA882EC78084E6
2 changed files with 55 additions and 35 deletions

View File

@ -102,14 +102,33 @@ typedef enum {
GPIO_TRIGGER_LEVEL_LOW = GPIO_TRIGGER_LEVEL | GPIO_TRIGGER_EDGE_FALLING,
} gpio_irq_trig_t;
/**
* @brief Possible modes to write to the STM32 GPIOx MODER register
*/
typedef enum {
GPIOX_MODER_INPUT = 0x0, /**< Pin is used as input (reset value) */
GPIOX_MODER_OUTPUT = 0x1, /**< Pin is used as output */
GPIOX_MODER_AF = 0x2, /**< Pin is routed to peripheral (alternate function) */
GPIOX_MODER_ANALOG = 0x3, /**< Pin is in analog mode (least current leakage) */
} gpiox_moder_t;
/**
* @brief Check if gpio_state_t requires open drain mode
*/
#define GPIO_STATE_T_OPEN_DRAIN_FLAG 0x4
/**
* @brief Bitmask to extract moder config
*/
#define GPIO_STATE_T_MODER_Msk 0x3
#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_INPUT = GPIOX_MODER_INPUT,
GPIO_OUTPUT_PUSH_PULL = GPIOX_MODER_OUTPUT,
GPIO_OUTPUT_OPEN_DRAIN = GPIOX_MODER_OUTPUT | GPIO_STATE_T_OPEN_DRAIN_FLAG,
GPIO_USED_BY_PERIPHERAL = GPIOX_MODER_AF,
GPIO_DISCONNECT = GPIOX_MODER_ANALOG,
GPIO_OUTPUT_OPEN_SOURCE = 0x7, /**< not supported */
} gpio_state_t;
#define HAVE_GPIO_PULL_T
@ -130,7 +149,7 @@ typedef union gpio_conf_stm32 gpio_conf_t;
* @ingroup drivers_periph_gpio_ll
*/
union gpio_conf_stm32 {
uint16_t bits; /**< the raw bits */
uint8_t bits; /**< the raw bits */
struct {
/**
* @brief State of the pin
@ -150,18 +169,6 @@ union gpio_conf_stm32 {
* 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
*
@ -176,7 +183,6 @@ union gpio_conf_stm32 {
* consulted.
*/
bool initial_value : 1;
uint8_t : 7; /*< padding */
};
};

View File

@ -77,6 +77,22 @@ static inline void print_str(const char *str)
# define GPIOAEN RCC_APB2ENR_IOPAEN
#endif
/* Bitmask to extract a mode field of the mode register "MODER".
* Note: Some families provide both, hence #elif */
#ifdef GPIO_MODER_MODER0_Msk
# define MODE_Msk GPIO_MODER_MODER0_Msk
#elif GPIO_MODER_MODE0_Msk
# define MODE_Msk GPIO_MODER_MODE0_Msk
#endif
/* Number of bits a mode field in the mode register "MODER" is wide.
* Note: Some families provide both, hence #elif */
#ifdef GPIO_MODER_MODER1_Pos
# define MODE_BITS GPIO_MODER_MODER1_Pos
#elif GPIO_MODER_MODE1_Pos
# define MODE_BITS GPIO_MODER_MODE1_Pos
#endif
static void _init_clock(gpio_port_t port)
{
periph_clk_en(GPIO_BUS, (GPIOAEN << GPIO_PORT_NUM(port)));
@ -90,14 +106,12 @@ static void _init_clock(gpio_port_t port)
}
#if defined(GPIO_MODER_MODER0) || defined(GPIO_MODER_MODE0)
static void _set_dir(gpio_port_t port, uint8_t pin, bool output)
static void _set_mode(gpio_port_t port, uint8_t pin, gpiox_moder_t mode)
{
GPIO_TypeDef *p = (void *)port;
uint32_t tmp = p->MODER;
tmp &= ~(0x3 << (2 * pin));
if (output) {
tmp |= 1UL << (2 * pin);
}
tmp &= ~(MODE_Msk << (MODE_BITS * pin));
tmp |= (unsigned)mode << (MODE_BITS * pin);
p->MODER = tmp;
}
#endif
@ -107,15 +121,19 @@ static void _set_dir(gpio_port_t port, uint8_t pin, bool output)
static gpio_state_t _get_state(gpio_port_t port, uint8_t pin)
{
GPIO_TypeDef *p = (void *)port;
uint32_t moder = (p->MODER >> (2 * pin)) & 0x3UL;
gpiox_moder_t moder = (p->MODER >> (MODE_BITS * pin)) & MODE_Msk;
switch (moder) {
case 0:
case GPIOX_MODER_INPUT:
return GPIO_INPUT;
case 1:
case GPIOX_MODER_OUTPUT:
return ((p->OTYPER >> pin) & 0x1UL) ? GPIO_OUTPUT_OPEN_DRAIN
: GPIO_OUTPUT_PUSH_PULL;
case GPIOX_MODER_ANALOG:
return GPIO_DISCONNECT;
default:
case GPIOX_MODER_AF:
return GPIO_USED_BY_PERIPHERAL;
}
return GPIO_USED_BY_PERIPHERAL;
}
#endif
@ -333,10 +351,10 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)
_set_legacy_f1_config(port, pin, conf);
#else
/* modern STM32 style GPIO configuration register layout */
_set_output_type(port, pin, conf.state == GPIO_OUTPUT_OPEN_DRAIN);
_set_output_type(port, pin, conf.state & GPIO_STATE_T_OPEN_DRAIN_FLAG);
_set_pull_config(port, pin, conf.pull);
_set_slew_rate(port, pin, conf.slew_rate);
_set_dir(port, pin, conf.state < GPIO_INPUT);
_set_mode(port, pin, conf.state & GPIO_STATE_T_MODER_Msk);
#endif
irq_restore(state);
@ -386,8 +404,4 @@ void gpio_ll_print_conf(gpio_conf_t conf)
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");
}
}