Skip to content

Commit

Permalink
Merge pull request RIOT-OS#20290 from maribu/drivers/periph/gpio_ll/f…
Browse files Browse the repository at this point in the history
…eatures

drivers/periph_gpio_ll: Fix GPIO_DISCONNECT handling and add compile time feature checks
  • Loading branch information
maribu authored Feb 5, 2024
2 parents 0eddf4a + f10a994 commit 8bf6133
Show file tree
Hide file tree
Showing 19 changed files with 230 additions and 93 deletions.
1 change: 1 addition & 0 deletions cpu/atmega_common/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ FEATURES_PROVIDED += atmega_pcint0
FEATURES_PROVIDED += periph_eeprom
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
FEATURES_PROVIDED += periph_gpio_ll_irq_unmask
Expand Down
10 changes: 10 additions & 0 deletions cpu/atmega_common/include/periph_cpu_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ typedef enum {
GPIO_TRIGGER_LEVEL_HIGH = 0xff, /**< not supported */
} gpio_irq_trig_t;

#define HAVE_GPIO_STATE_T
typedef enum {
GPIO_INPUT,
GPIO_OUTPUT_PUSH_PULL,
GPIO_OUTPUT_OPEN_DRAIN, /**< not supported */
GPIO_OUTPUT_OPEN_SOURCE, /**< not supported */
GPIO_USED_BY_PERIPHERAL, /**< not supported */
GPIO_DISCONNECT = GPIO_INPUT,
} gpio_state_t;

#define HAVE_GPIO_LL_PREPARE_WRITE_ALL_PINS
#define HAVE_GPIO_LL_PREPARE_WRITE

Expand Down
5 changes: 2 additions & 3 deletions cpu/atmega_common/periph/gpio_ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static void _set_dir(gpio_port_t port, uint8_t pin, bool output)
p->ddr |= 1U << pin;
}
else {
p-> ddr &= ~(1U << pin);
p->ddr &= ~(1U << pin);
}
}

Expand All @@ -59,8 +59,7 @@ static void _set_pull_config(gpio_port_t port, uint8_t pin, gpio_pull_t pull)
int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)
{
if ((conf.pull > GPIO_PULL_UP)
|| (conf.state == GPIO_OUTPUT_OPEN_DRAIN)
|| (conf.state == GPIO_OUTPUT_OPEN_SOURCE)) {
|| (conf.state > GPIO_OUTPUT_PUSH_PULL)) {
return -ENOTSUP;
}

Expand Down
7 changes: 7 additions & 0 deletions cpu/efm32/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ FEATURES_PROVIDED += periph_flashpage_in_address_space
FEATURES_PROVIDED += periph_flashpage_pagewise
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_open_drain
FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up
FEATURES_PROVIDED += periph_gpio_ll_open_source
FEATURES_PROVIDED += periph_gpio_ll_open_source_pull_down
FEATURES_PROVIDED += periph_rtt_set_counter
FEATURES_PROVIDED += periph_rtt_overflow
FEATURES_PROVIDED += periph_uart_modecfg
Expand Down
5 changes: 4 additions & 1 deletion cpu/efm32/periph/gpio_ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)

switch (conf.state) {
case GPIO_DISCONNECT:
/* ignoring pull */
mode = gpioModeDisabled;
initial = (conf.pull == GPIO_PULL_UP);
break;
case GPIO_INPUT:
switch (conf.pull) {
Expand Down Expand Up @@ -135,6 +135,9 @@ gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin)
/* Fall-through: There is no error reporting here */
default:
result.state = GPIO_DISCONNECT;
if (GPIO_PinOutGet(port, pin)) {
result.pull = GPIO_PULL_UP;
}
break;
}

Expand Down
5 changes: 5 additions & 0 deletions cpu/esp32/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@ FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_in_address_space
FEATURES_PROVIDED += periph_flashpage_pagewise
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
FEATURES_PROVIDED += periph_gpio_ll_open_drain
FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up
FEATURES_PROVIDED += periph_spi_reconfigure
FEATURES_PROVIDED += puf_sram

Expand Down
4 changes: 4 additions & 0 deletions cpu/gd32v/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ FEATURES_PROVIDED += periph_clic
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_gpio_irq
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
FEATURES_PROVIDED += periph_gpio_ll_open_drain
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtc_mem
FEATURES_PROVIDED += periph_rtt
Expand Down
15 changes: 1 addition & 14 deletions cpu/gd32v/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ typedef union gpio_conf_gd32v gpio_conf_t;
* @ingroup drivers_periph_gpio_ll
*/
union gpio_conf_gd32v {
uint16_t bits; /**< the raw bits */
uint8_t bits; /**< the raw bits */
struct {
/**
* @brief State of the pin
Expand All @@ -259,18 +259,6 @@ union gpio_conf_gd32v {
* 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
*
Expand All @@ -285,7 +273,6 @@ union gpio_conf_gd32v {
* consulted.
*/
bool initial_value : 1;
uint8_t : 7; /*< padding */
};
};

Expand Down
9 changes: 2 additions & 7 deletions cpu/gd32v/periph/gpio_ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)

switch (conf.state) {
case GPIO_DISCONNECT:
*ctrl |= 0x1 << (pos + 2);
pin_used[GPIO_PORT_NUM(port)] &= ~(1 << pin);
if (pin_used[GPIO_PORT_NUM(port)] == 0) {
periph_clk_dis(APB2, (RCU_APB2EN_PAEN_Msk << GPIO_PORT_NUM(port)));
Expand Down Expand Up @@ -121,14 +120,14 @@ gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin)
result.state = GPIO_INPUT;
switch (ctrl) {
case 0:
result.state = GPIO_USED_BY_PERIPHERAL;
result.state = GPIO_DISCONNECT;
break;
case 1:
result.pull = GPIO_FLOATING;
break;
case 2:
result.pull = (((GPIO_Type *)port)->OCTL & (1UL << pin)) ? GPIO_PULL_UP
: GPIO_PULL_DOWN;
: GPIO_PULL_DOWN;
break;
default:
break;
Expand Down Expand Up @@ -173,8 +172,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");
}
}
11 changes: 10 additions & 1 deletion cpu/nrf5x_common/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ FEATURES_PROVIDED += periph_uart_modecfg
FEATURES_PROVIDED += periph_wdt periph_wdt_cb

ifeq (,$(filter nrf5340_app,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_gpio_ll periph_gpio_ll_irq periph_gpio_ll_irq_unmask
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_unmask
FEATURES_PROVIDED += periph_gpio_ll_open_drain
FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up
FEATURES_PROVIDED += periph_gpio_ll_open_source
FEATURES_PROVIDED += periph_gpio_ll_open_source_pull_down
endif

# nRF9160/nRF5340 don't support these drivers right now
Expand Down
3 changes: 3 additions & 0 deletions cpu/sam0_common/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ FEATURES_PROVIDED += periph_flashpage_pagewise
FEATURES_PROVIDED += periph_flashpage_rwee
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
Expand Down
8 changes: 8 additions & 0 deletions cpu/stm32/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@ FEATURES_PROVIDED += periph_rtt_overflow
FEATURES_PROVIDED += periph_uart_modecfg
FEATURES_PROVIDED += periph_uart_nonblocking
FEATURES_PROVIDED += periph_gpio_ll
FEATURES_PROVIDED += periph_gpio_ll_disconnect
FEATURES_PROVIDED += periph_gpio_ll_input_pull_down
FEATURES_PROVIDED += periph_gpio_ll_input_pull_up
FEATURES_PROVIDED += periph_gpio_ll_irq
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
FEATURES_PROVIDED += periph_gpio_ll_open_drain

ifneq (f1,$(CPU_FAM))
FEATURES_PROVIDED += periph_gpio_ll_open_drain_pull_up
endif

ifneq (,$(filter $(CPU_FAM),c0 f0 f1 f3 g0 g4 l0 l1 l4 l5 u5 wb wl))
FEATURES_PROVIDED += periph_flashpage
Expand Down
46 changes: 26 additions & 20 deletions cpu/stm32/include/periph/cpu_gpio_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
*
Expand All @@ -176,7 +183,6 @@ union gpio_conf_stm32 {
* consulted.
*/
bool initial_value : 1;
uint8_t : 7; /*< padding */
};
};

Expand Down
44 changes: 29 additions & 15 deletions cpu/stm32/periph/gpio_ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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");
}
}
Loading

0 comments on commit 8bf6133

Please sign in to comment.