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

drivers/periph_gpio_ll: change API to access GPIO ports

The API was based on the assumption that GPIO ports are mapped in memory
sanely, so that a `GPIO_PORT(num)` macro would work allow for constant
folding when `num` is known and still be efficient when it is not.

Some MCUs, however, will need a look up tables to efficiently translate
GPIO port numbers to the port's base address. This will prevent the use
of such a `GPIO_PORT(num)` macro in constant initializers.

As a result, we rather provide `GPIO_PORT_0`, `GPIO_PORT_1`, etc. macros
for each GPIO port present (regardless of MCU naming scheme), as well as
`GPIO_PORT_A`, `GPIO_PORT_B`, etc. macros if (and only if) the MCU port
naming scheme uses letters rather than numbers.

These can be defined as macros to the peripheral base address even when
those are randomly mapped into the address space. In addition, a C
function `gpio_port()` replaces the role of the `GPIO_PORT()` and
`gpio_port_num()` the `GPIO_PORT_NUM()` macro. Those functions will
still be implemented as efficient as possible and will allow constant
folding where it was formerly possible. Hence, there is no downside for
MCUs with sane peripheral memory mapping, but it is highly beneficial
for the crazy ones.

There are also two benefits for the non-crazy MCUs:
1. We can now test for valid port numbers with `#ifdef GPIO_PORT_<NUM>`
    - This directly benefits the test in `tests/periph/gpio_ll`, which
      can now provide a valid GPIO port for each and every board
    - Writing to invalid memory mapped I/O addresses was treated as
      triggering undefined behavior by the compiler and used as a
      optimization opportunity
2. We can now detect at compile time if the naming scheme of the MCU
   uses letters or numbers, and produce more user friendly output.
    - This is directly applied in the test app
This commit is contained in:
Marian Buschsieweke 2024-04-29 13:32:24 +02:00
parent 687a30af33
commit 36e8526046
No known key found for this signature in database
GPG Key ID: 77AA882EC78084E6
24 changed files with 629 additions and 156 deletions

View File

@ -23,7 +23,8 @@
#ifndef STM32_LEDS_H
#define STM32_LEDS_H
/* GPIO_PORT() macro. This define even works when GPIO LL is not in used */
/* Using gpio_ll_arch for the gpio_port() function. This even works when
* GPIO LL is not in used */
#include "gpio_ll_arch.h"
#include "kernel_defines.h"
@ -36,7 +37,7 @@ extern "C" {
* @{
*/
#if defined(LED0_PORT_NUM) && defined (LED0_PIN_NUM)
# define LED0_PORT ((GPIO_TypeDef *)GPIO_PORT(LED0_PORT_NUM))
# define LED0_PORT ((GPIO_TypeDef *)gpio_port(LED0_PORT_NUM))
# define LED0_PIN GPIO_PIN(LED0_PORT_NUM, LED0_PIN_NUM)
# define LED0_MASK (1 << LED0_PIN_NUM)
# if IS_ACTIVE(LED0_IS_INVERTED)
@ -50,7 +51,7 @@ extern "C" {
#endif
#if defined(LED1_PORT_NUM) && defined (LED1_PIN_NUM)
# define LED1_PORT ((GPIO_TypeDef *)GPIO_PORT(LED1_PORT_NUM))
# define LED1_PORT ((GPIO_TypeDef *)gpio_port(LED1_PORT_NUM))
# define LED1_PIN GPIO_PIN(LED1_PORT_NUM, LED1_PIN_NUM)
# define LED1_MASK (1 << LED1_PIN_NUM)
# if IS_ACTIVE(LED1_IS_INVERTED)
@ -64,7 +65,7 @@ extern "C" {
#endif
#if defined(LED2_PORT_NUM) && defined (LED2_PIN_NUM)
# define LED2_PORT ((GPIO_TypeDef *)GPIO_PORT(LED2_PORT_NUM))
# define LED2_PORT ((GPIO_TypeDef *)gpio_port(LED2_PORT_NUM))
# define LED2_PIN GPIO_PIN(LED2_PORT_NUM, LED2_PIN_NUM)
# define LED2_MASK (1 << LED2_PIN_NUM)
# if IS_ACTIVE(LED2_IS_INVERTED)
@ -78,7 +79,7 @@ extern "C" {
#endif
#if defined(LED3_PORT_NUM) && defined (LED3_PIN_NUM)
# define LED3_PORT ((GPIO_TypeDef *)GPIO_PORT(LED3_PORT_NUM))
# define LED3_PORT ((GPIO_TypeDef *)gpio_port(LED3_PORT_NUM))
# define LED3_PIN GPIO_PIN(LED3_PORT_NUM, LED3_PIN_NUM)
# define LED3_MASK (1 << LED3_PIN_NUM)
# if IS_ACTIVE(LED3_IS_INVERTED)
@ -92,7 +93,7 @@ extern "C" {
#endif
#if defined(LED4_PORT_NUM) && defined (LED4_PIN_NUM)
# define LED4_PORT ((GPIO_TypeDef *)GPIO_PORT(LED4_PORT_NUM))
# define LED4_PORT ((GPIO_TypeDef *)gpio_port(LED4_PORT_NUM))
# define LED4_PIN GPIO_PIN(LED4_PORT_NUM, LED4_PIN_NUM)
# define LED4_MASK (1 << LED4_PIN_NUM)
# if IS_ACTIVE(LED4_IS_INVERTED)
@ -106,7 +107,7 @@ extern "C" {
#endif
#if defined(LED5_PORT_NUM) && defined (LED5_PIN_NUM)
# define LED5_PORT ((GPIO_TypeDef *)GPIO_PORT(LED5_PORT_NUM))
# define LED5_PORT ((GPIO_TypeDef *)gpio_port(LED5_PORT_NUM))
# define LED5_PIN GPIO_PIN(LED5_PORT_NUM, LED5_PIN_NUM)
# define LED5_MASK (1 << LED5_PIN_NUM)
# if IS_ACTIVE(LED5_IS_INVERTED)
@ -120,7 +121,7 @@ extern "C" {
#endif
#if defined(LED6_PORT_NUM) && defined (LED6_PIN_NUM)
# define LED6_PORT ((GPIO_TypeDef *)GPIO_PORT(LED6_PORT_NUM))
# define LED6_PORT ((GPIO_TypeDef *)gpio_port(LED6_PORT_NUM))
# define LED6_PIN GPIO_PIN(LED6_PORT_NUM, LED6_PIN_NUM)
# define LED6_MASK (1 << LED6_PIN_NUM)
# if IS_ACTIVE(LED6_IS_INVERTED)
@ -134,7 +135,7 @@ extern "C" {
#endif
#if defined(LED7_PORT_NUM) && defined (LED7_PIN_NUM)
# define LED7_PORT ((GPIO_TypeDef *)GPIO_PORT(LED7_PORT_NUM))
# define LED7_PORT ((GPIO_TypeDef *)gpio_port(LED7_PORT_NUM))
# define LED7_PIN GPIO_PIN(LED7_PORT_NUM, LED7_PIN_NUM)
# define LED7_MASK (1 << LED7_PIN_NUM)
# if IS_ACTIVE(LED7_IS_INVERTED)

View File

@ -57,20 +57,86 @@ extern "C" {
* whenever the port number is known at compile time.
*/
#ifdef PORTH
#define GPIO_PORT(num) \
((num >= PORT_H) ? \
(ATMEGA_GPIO_BASE_H + ((num) - PORT_H) * ATMEGA_GPIO_SIZE) : \
(ATMEGA_GPIO_BASE_A + (num) * ATMEGA_GPIO_SIZE))
#define GPIO_PORT_NUM(port) \
(((port) >= ATMEGA_GPIO_BASE_H) ? \
(((port) - ATMEGA_GPIO_BASE_H) / ATMEGA_GPIO_SIZE + PORT_H) : \
(((port) - ATMEGA_GPIO_BASE_A) / ATMEGA_GPIO_SIZE))
#else
#define GPIO_PORT(num) (ATMEGA_GPIO_BASE_A + (num) * ATMEGA_GPIO_SIZE)
#define GPIO_PORT_NUM(port) (((port) - ATMEGA_GPIO_BASE_A) / ATMEGA_GPIO_SIZE)
#define GPIO_PORT_NUMBERING_ALPHABETIC 1
#ifdef PINA
/* We sadly cannot use PINA, as PINA is technically (in terms of C spec lingo)
* not constant and would trigger:
* initializer element is not constant
* Hence, the defines are a bit more involved to yield proper constants
* suitable for initializers.
*/
# define GPIO_PORT_0 (ATMEGA_GPIO_BASE_A)
#endif
#ifdef PINB
# define GPIO_PORT_1 (ATMEGA_GPIO_BASE_A + 1 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PINC
# define GPIO_PORT_2 (ATMEGA_GPIO_BASE_A + 2 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PIND
# define GPIO_PORT_3 (ATMEGA_GPIO_BASE_A + 3 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PINE
# define GPIO_PORT_4 (ATMEGA_GPIO_BASE_A + 4 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PINF
# define GPIO_PORT_5 (ATMEGA_GPIO_BASE_A + 5 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PING
# define GPIO_PORT_6 (ATMEGA_GPIO_BASE_A + 6 * ATMEGA_GPIO_SIZE)
#endif
/* There is a larger gap between PING and PINH to allow other peripherals to
* also be mapped into the fast I/O memory area. */
#ifdef PINH
# define GPIO_PORT_7 (ATMEGA_GPIO_BASE_H)
#endif
#ifdef PINI
# define GPIO_PORT_8 (ATMEGA_GPIO_BASE_H + 1 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PINJ
# define GPIO_PORT_9 (ATMEGA_GPIO_BASE_H + 2 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PINK
# define GPIO_PORT_10 (ATMEGA_GPIO_BASE_H + 3 * ATMEGA_GPIO_SIZE)
#endif
#ifdef PINL
# define GPIO_PORT_11 (ATMEGA_GPIO_BASE_H + 4 * ATMEGA_GPIO_SIZE)
#endif
static inline gpio_port_t gpio_port(uword_t num)
{
#ifdef PINH
if (num >= PORT_H) {
return ATMEGA_GPIO_BASE_H + ((num - PORT_H) * ATMEGA_GPIO_SIZE);
}
#endif
return ATMEGA_GPIO_BASE_A + (num * ATMEGA_GPIO_SIZE);
}
static inline uword_t gpio_port_num(gpio_port_t port)
{
#ifdef PINH
if ((port) >= ATMEGA_GPIO_BASE_H) {
return (port - ATMEGA_GPIO_BASE_H) / ATMEGA_GPIO_SIZE + PORT_H;
}
#endif
return (port - ATMEGA_GPIO_BASE_A) / ATMEGA_GPIO_SIZE;
}
static inline uword_t gpio_ll_read(gpio_port_t port)
{
atmega_gpio_port_t *p = (void *)port;
@ -158,7 +224,7 @@ static inline void gpio_ll_write(gpio_port_t port, uword_t value)
static inline gpio_port_t gpio_get_port(gpio_t pin)
{
return GPIO_PORT(pin >> 4);
return gpio_port(pin >> 4);
}
static inline uint8_t gpio_get_pin_num(gpio_t pin)

View File

@ -73,16 +73,16 @@ typedef uint8_t gpio_t;
#ifdef GPIO_PORT_DESCENDENT
#ifdef _AVR_ATTINY1634_H_INCLUDED
/* the only one that requires particular treatment! */
#define ATMEGA_GPIO_BASE_A (0x2F)
#define ATMEGA_GPIO_BASE_A 0x2F
#else
/* all other port descendent, including :
- _AVR_IO8534_ (only have port A but with 0x1B address) ;
- _AVR_IOAT94K_H_ (only have ports D and E) ;
- _AVR_IOTN28_H_ (only have ports A and D). */
#define ATMEGA_GPIO_BASE_A (0x39)
#define ATMEGA_GPIO_BASE_A 0x39
#endif /* _AVR_ATTINY1634_H_INCLUDED */
#else /* !GPIO_PORT_DESCENDENT */
#define ATMEGA_GPIO_BASE_A (0x20)
#define ATMEGA_GPIO_BASE_A 0x20
#endif /* GPIO_PORT_DESCENDENT */
/**
* @brief Base of the GPIO port G register as memory address

View File

@ -62,7 +62,7 @@ static void clear_pending_irqs(uint8_t exti)
void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
{
uint8_t exti = atmega_pin2exti(GPIO_PORT_NUM(port), pin);
uint8_t exti = atmega_pin2exti(gpio_port_num(port), pin);
#if defined(EIMSK)
EIMSK &= ~(1 << exti);
#elif defined(GICR)
@ -72,7 +72,7 @@ void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
{
uint8_t exti = atmega_pin2exti(GPIO_PORT_NUM(port), pin);
uint8_t exti = atmega_pin2exti(gpio_port_num(port), pin);
#if defined(EIMSK)
EIMSK |= 1 << exti;
#elif defined(GICR)
@ -82,7 +82,7 @@ void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
void gpio_ll_irq_unmask_and_clear(gpio_port_t port, uint8_t pin)
{
uint8_t exti = atmega_pin2exti(GPIO_PORT_NUM(port), pin);
uint8_t exti = atmega_pin2exti(gpio_port_num(port), pin);
clear_pending_irqs(exti);
#if defined(EIMSK)
EIMSK |= 1 << exti;
@ -118,7 +118,7 @@ static void set_trigger(uint8_t exti, gpio_irq_trig_t trig)
int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig,
gpio_ll_cb_t cb, void *arg)
{
int port_num = GPIO_PORT_NUM(port);
int port_num = gpio_port_num(port);
assert((trig != GPIO_TRIGGER_LEVEL_HIGH) && cb);
if (!atmega_has_pin_exti(port_num, pin)) {
return -ENOTSUP;

View File

@ -48,12 +48,63 @@ extern "C" {
#ifndef DOXYGEN /* hide implementation specific details from Doxygen */
#define GPIO_PORT_NUMBERING_ALPHABETIC 1
/* Note: The pin count may be defined as zero to indicate the port not existing.
* Hence, don't to `#if defined(foo)` but only `#if foo`
*/
#if _GPIO_PORT_A_PIN_COUNT
# define GPIO_PORT_0 0
#endif
#if _GPIO_PORT_B_PIN_COUNT
# define GPIO_PORT_1 1
#endif
#if _GPIO_PORT_C_PIN_COUNT
# define GPIO_PORT_2 2
#endif
#if _GPIO_PORT_D_PIN_COUNT
# define GPIO_PORT_3 3
#endif
#if _GPIO_PORT_E_PIN_COUNT
# define GPIO_PORT_4 4
#endif
#if _GPIO_PORT_F_PIN_COUNT
# define GPIO_PORT_6 6
#endif
#if _GPIO_PORT_G_PIN_COUNT
# define GPIO_PORT_7 7
#endif
#if _GPIO_PORT_H_PIN_COUNT
# define GPIO_PORT_8 8
#endif
#if _GPIO_PORT_I_PIN_COUNT
# define GPIO_PORT_9 9
#endif
#if _GPIO_PORT_J_PIN_COUNT
# define GPIO_PORT_10 10
#endif
#if _GPIO_PORT_K_PIN_COUNT
# define GPIO_PORT_11 11
#endif
/* We could do
*
#define GPIO_PORT(num) (GPIO->P[num])
#define GPIO_PORT_NUM(port) ((port - &GPIO->P))
* static inline gpio_port_t gpio_port(uword_t num)
* {
* return GPIO->P[num];
* }
*
* which forks for some operations, but at latest when _ll_set needs to fan out
* which works for some operations, but at latest when _ll_set needs to fan out
* for some EFM32 families to
*
#if defined(_GPIO_P_DOUTSET_MASK)
@ -78,9 +129,15 @@ extern "C" {
* an implementation for other EFM32 families. For the time being, the
* suboptimal-but-works-for-all version is the best we have.
*/
static inline gpio_port_t gpio_port(uword_t num)
{
return num;
}
#define GPIO_PORT(num) (num)
#define GPIO_PORT_NUM(port) (port)
static inline uword_t gpio_port_num(gpio_port_t port)
{
return port;
}
static inline uword_t gpio_ll_read(gpio_port_t port)
{

View File

@ -32,12 +32,19 @@ extern "C" {
#ifndef DOXYGEN /* hide implementation specific details from Doxygen */
#define GPIO_PORT(num) (num)
#if GPIO_PORT_NUMOF > 1
# define GPIO_PORT_NUM(port) (port)
#else
# define GPIO_PORT_NUM(port) 0
#endif
static inline gpio_port_t gpio_port(uword_t num)
{
return num;
}
static inline uword_t gpio_port_num(gpio_port_t port)
{
if (GPIO_PORT_NUMOF == 1) {
return 0;
}
return port;
}
static inline uword_t gpio_ll_read(gpio_port_t port)
{
@ -45,7 +52,7 @@ static inline uword_t gpio_ll_read(gpio_port_t port)
volatile uword_t *in = (uint32_t *)GPIO_IN_REG;
/* return 0 for unconfigured pins, the current level at the pin otherwise */
#if GPIO_PORT_NUM > 1
if (GPIO_PORT_NUM(port) != 0) {
if (gpio_port_num(port) != 0) {
in = (uint32_t *)GPIO_IN1_REG;
}
#endif
@ -58,7 +65,7 @@ static inline uword_t gpio_ll_read_output(gpio_port_t port)
static_assert(GPIO_PORT_NUMOF < 3);
volatile uword_t *out = (uint32_t *)GPIO_OUT_REG;
#if GPIO_PORT_NUM > 1
if (GPIO_PORT_NUM(port) != 0) {
if (gpio_port_num(port) != 0) {
out = (uint32_t *)GPIO_OUT1_REG;
}
#endif
@ -70,7 +77,7 @@ static inline void gpio_ll_set(gpio_port_t port, uword_t mask)
{
static_assert(GPIO_PORT_NUMOF < 3);
volatile uword_t *out_w1ts = (uint32_t *)GPIO_OUT_W1TS_REG;
if (GPIO_PORT_NUM(port) != 0) {
if (gpio_port_num(port) != 0) {
#if GPIO_PORT_NUM > 1
out_w1ts = (uint32_t)GPIO_OUT1_W1TS;
#endif
@ -83,7 +90,7 @@ static inline void gpio_ll_clear(gpio_port_t port, uword_t mask)
{
static_assert(GPIO_PORT_NUMOF < 3);
volatile uword_t *out_w1tc = (uint32_t *)GPIO_OUT_W1TC_REG;
if (GPIO_PORT_NUM(port) != 0) {
if (gpio_port_num(port) != 0) {
#if GPIO_PORT_NUM > 1
out_w1tc = (uint32_t)GPIO_OUT1_W1TC;
#endif
@ -97,7 +104,7 @@ static inline void gpio_ll_toggle(gpio_port_t port, uword_t mask)
static_assert(GPIO_PORT_NUMOF < 3);
volatile uword_t *out = (uint32_t *)GPIO_OUT_REG;
#if GPIO_PORT_NUM > 1
if (GPIO_PORT_NUM(port) != 0) {
if (gpio_port_num(port) != 0) {
out = (uint32_t *)GPIO_OUT1_REG;
}
#endif
@ -111,7 +118,7 @@ static inline void gpio_ll_write(gpio_port_t port, uword_t value)
static_assert(GPIO_PORT_NUMOF < 3);
volatile uword_t *out = (uint32_t *)GPIO_OUT_REG;
#if GPIO_PORT_NUM > 1
if (GPIO_PORT_NUM(port) != 0) {
if (gpio_port_num(port) != 0) {
out = (uint32_t *)GPIO_OUT1_REG;
}
#endif
@ -120,7 +127,7 @@ static inline void gpio_ll_write(gpio_port_t port, uword_t value)
static inline gpio_port_t gpio_get_port(gpio_t pin)
{
return GPIO_PORT(pin >> 5);
return gpio_port(pin >> 5);
}
static inline uint8_t gpio_get_pin_num(gpio_t pin)

View File

@ -151,8 +151,8 @@ typedef enum {
#if SOC_GPIO_PIN_COUNT > 32
#define GPIO_PORT_NUMOF 2
#define GPIO_PORT_0 GPIO_PORT(0)
#define GPIO_PORT_1 GPIO_PORT(1)
#define GPIO_PORT_0 0
#define GPIO_PORT_1 1
#define GPIO_PORT_0_PIN_NUMOF (32)
#define GPIO_PORT_1_PIN_NUMOF (SOC_GPIO_PIN_COUNT - 32)
#define GPIO_PORT_PIN_NUMOF(p) ((p == GPIO_PORT_0) ? GPIO_PORT_0_PIN_NUMOF \
@ -160,7 +160,7 @@ typedef enum {
#else
#define GPIO_PORT_NUMOF 1
#define GPIO_PORT_0 GPIO_PORT(0)
#define GPIO_PORT_0 0
#define GPIO_PORT_0_PIN_NUMOF (SOC_GPIO_PIN_COUNT)
#define GPIO_PORT_PIN_NUMOF(p) ((p == GPIO_PORT_0) ? GPIO_PORT_0_PIN_NUMOF : 0)

View File

@ -60,7 +60,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)
assert(is_gpio_port_num_valid(port));
assert(pin < GPIO_PORT_PIN_NUMOF(port));
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
gpio_t gpio = GPIO_PIN(gpio_port_num(port), pin);
gpio_config_t cfg = {
.pin_bit_mask = (1ULL << gpio),
@ -168,7 +168,7 @@ gpio_conf_t gpio_ll_query_conf(gpio_port_t port, uint8_t pin)
unsigned state = irq_disable();
result = _gpio_conf[GPIO_PIN(GPIO_PORT_NUM(port), pin)];
result = _gpio_conf[GPIO_PIN(gpio_port_num(port), pin)];
if (result.state == GPIO_INPUT) {
result.initial_value = (gpio_ll_read(port) >> pin) & 1UL;
}

View File

@ -61,10 +61,10 @@ int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig,
unsigned state = irq_disable();
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
gpio_t gpio = GPIO_PIN(gpio_port_num(port), pin);
DEBUG("%s gpio=%u port=%u pin=%u trig=%d cb=%p arg=%p\n",
__func__, gpio, GPIO_PORT_NUM(port), pin, trig, cb, arg);
__func__, gpio, (unsigned)gpio_port_num(port), pin, trig, cb, arg);
/* install GPIO ISR of ESP-IDF if not yet done */
if (!gpio_isr_service_installed &&
@ -113,10 +113,10 @@ int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig,
void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
{
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
gpio_t gpio = GPIO_PIN(gpio_port_num(port), pin);
DEBUG("%s gpio=%u port=%u pin=%u\n",
__func__, gpio, GPIO_PORT_NUM(port), pin);
__func__, gpio, (unsigned)gpio_port_num(port), pin);
if (esp_idf_gpio_intr_disable(gpio) == ESP_OK) {
gpio_int_enabled_table[gpio] = false;
@ -125,7 +125,7 @@ void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
{
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
gpio_t gpio = GPIO_PIN(gpio_port_num(port), pin);
DEBUG("%s gpio=%u port=%u pin=%u\n",
__func__, gpio, port, pin);
@ -137,14 +137,14 @@ void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
void gpio_ll_irq_unmask_and_clear(gpio_port_t port, uint8_t pin)
{
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
gpio_t gpio = GPIO_PIN(gpio_port_num(port), pin);
DEBUG("%s gpio=%u port=%u pin=%u\n",
__func__, gpio, GPIO_PORT_NUM(port), pin);
__func__, gpio, (unsigned)gpio_port_num(port), pin);
volatile uint32_t *status_w1tc = (uint32_t *)GPIO_STATUS_W1TC_REG;
#if GPIO_PORT_NUMOF > 1
if (GPIO_PORT_NUM(port) != 0) {
if (gpio_port_num(port) != 0) {
status_w1tc = (uint32_t *)GPIO_STATUS1_W1TC_REG;
}
#endif

View File

@ -21,7 +21,6 @@
#define GPIO_LL_ARCH_H
#include "architecture.h"
#include "periph/gpio_ll.h"
#include "periph_cpu.h"
#ifdef __cplusplus
@ -35,15 +34,69 @@ extern "C" {
*/
#define GPIO_PORT_NUMOF 5
/**
* @brief Get a GPIO port by number
*/
#define GPIO_PORT(num) (GPIOA_BASE + ((num) << 10))
#define GPIO_PORT_NUMBERING_ALPHABETIC 1
/**
* @brief Get a GPIO port number by gpio_t value
*/
#define GPIO_PORT_NUM(port) (((port) - GPIOA_BASE) >> 10)
#ifdef GPIOA_BASE
# define GPIO_PORT_0 GPIOA_BASE
#endif
#ifdef GPIOB_BASE
# define GPIO_PORT_1 GPIOB_BASE
#endif
#ifdef GPIOC_BASE
# define GPIO_PORT_2 GPIOC_BASE
#endif
#ifdef GPIOD_BASE
# define GPIO_PORT_3 GPIOD_BASE
#endif
#ifdef GPIOE_BASE
# define GPIO_PORT_4 GPIOE_BASE
#endif
#ifdef GPIOF_BASE
# define GPIO_PORT_5 GPIOF_BASE
#endif
#ifdef GPIOG_BASE
# define GPIO_PORT_6 GPIOG_BASE
#endif
#ifdef GPIOH_BASE
# define GPIO_PORT_7 GPIOH_BASE
#endif
#ifdef GPIOI_BASE
# define GPIO_PORT_8 GPIOI_BASE
#endif
#ifdef GPIOJ_BASE
# define GPIO_PORT_9 GPIOJ_BASE
#endif
#ifdef GPIOK_BASE
# define GPIO_PORT_10 GPIOK_BASE
#endif
static inline gpio_port_t gpio_port(uword_t num)
{
#if defined(CPU_FAM_STM32MP1)
return GPIOA_BASE + (num << 12);
#else
return GPIOA_BASE + (num << 10);
#endif
}
static inline uword_t gpio_port_num(gpio_port_t port)
{
#if defined(CPU_FAM_STM32MP1)
return (port - GPIOA_BASE) >> 12;
#else
return (port - GPIOA_BASE) >> 10;
#endif
}
static inline uword_t gpio_ll_read(gpio_port_t port)
{

View File

@ -48,7 +48,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)
unsigned state = irq_disable();
periph_clk_en(APB2, (RCU_APB2EN_PAEN_Msk << GPIO_PORT_NUM(port)));
periph_clk_en(APB2, (RCU_APB2EN_PAEN_Msk << gpio_port_num(port)));
volatile uint32_t *ctrl = (pin < 8) ? &((GPIO_Type *)port)->CTL0
: &((GPIO_Type *)port)->CTL1;
@ -60,13 +60,13 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)
switch (conf.state) {
case GPIO_DISCONNECT:
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)));
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)));
}
break;
case GPIO_INPUT:
pin_used[GPIO_PORT_NUM(port)] |= 1 << pin;
pin_used[gpio_port_num(port)] |= 1 << pin;
if (conf.pull == GPIO_FLOATING) {
*ctrl |= 0x1 << (pos + 2);
}
@ -82,7 +82,7 @@ int gpio_ll_init(gpio_port_t port, uint8_t pin, gpio_conf_t conf)
break;
case GPIO_OUTPUT_PUSH_PULL:
case GPIO_OUTPUT_OPEN_DRAIN:
pin_used[GPIO_PORT_NUM(port)] |= 1 << pin;
pin_used[gpio_port_num(port)] |= 1 << pin;
*ctrl |= (conf.slew_rate + 1) << pos;
*ctrl |= (conf.state == GPIO_OUTPUT_OPEN_DRAIN ? 0x1 : 0x0) << (pos + 2);
if (conf.initial_value) {

View File

@ -78,7 +78,7 @@ static void _gpio_isr(unsigned irqn);
int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig, gpio_ll_cb_t cb, void *arg)
{
unsigned irq_state = irq_disable();
int port_num = GPIO_PORT_NUM(port);
int port_num = gpio_port_num(port);
/* set callback */
_exti_ctx[pin].cb = cb;
@ -177,7 +177,7 @@ static void _gpio_isr(unsigned irqn)
if ((_h_level_triggered & pin_mask) || (_l_level_triggered & pin_mask)) {
/* determine the port of triggered interrupt */
volatile uint32_t *afio_exti_ss = &AFIO->EXTISS0 + (pin >> 2);
gpio_port_t port = GPIO_PORT(((*afio_exti_ss >> ((pin & 0x03) * 4)) & 0xfUL));
gpio_port_t port = gpio_port(((*afio_exti_ss >> ((pin & 0x03) * 4)) & 0xfUL));
/* trigger software interrupt if the pin has the according level */
uint32_t level = gpio_ll_read(port) & pin_mask;

View File

@ -51,16 +51,37 @@ extern "C" {
#endif
#if defined(CPU_FAM_NRF51)
#define GPIO_PORT(num) ((gpio_port_t)NRF_GPIO)
#define GPIO_PORT_NUM(port) 0
#elif defined(NRF_P1)
#define GPIO_PORT(num) ((num) ? (gpio_port_t)NRF_P1 : (gpio_port_t)NRF_P0)
#define GPIO_PORT_NUM(port) ((port == (gpio_port_t)NRF_P1) ? 1 : 0)
# define GPIO_PORT_0 ((gpio_port_t)NRF_GPIO)
#else
#define GPIO_PORT(num) ((gpio_port_t)NRF_P0)
#define GPIO_PORT_NUM(port) 0
# if defined(NRF_P1)
# define GPIO_PORT_1 ((gpio_port_t)NRF_P1)
# endif
# define GPIO_PORT_0 ((gpio_port_t)NRF_P0)
#endif
static inline gpio_port_t gpio_port(uword_t num)
{
(void)num;
#ifdef GPIO_PORT_1
if (num == 1) {
return GPIO_PORT_1;
}
#endif
return GPIO_PORT_0;
}
static inline uword_t gpio_port_num(gpio_port_t port)
{
(void)port;
#ifdef GPIO_PORT_1
if (port == GPIO_PORT_1) {
return 1;
}
#endif
return 0;
}
static inline uword_t gpio_ll_read(gpio_port_t port)
{
NRF_GPIO_Type *p = (NRF_GPIO_Type *)port;
@ -102,10 +123,10 @@ static inline void gpio_ll_write(gpio_port_t port, uword_t value)
static inline gpio_port_t gpio_get_port(gpio_t pin)
{
#if defined(NRF_P1)
return GPIO_PORT(pin >> 5);
return gpio_port(pin >> 5);
#else
(void)pin;
return GPIO_PORT(0);
return GPIO_PORT_0;
#endif
}

View File

@ -128,7 +128,7 @@ int gpio_ll_irq(gpio_port_t port, uint8_t pin,
{
/* param port is not used on nRF5x variants with only one GPIO port */
(void)port;
uint8_t port_num = GPIO_PORT_NUM(port);
uint8_t port_num = gpio_port_num(port);
uint8_t channel = get_channel_for_pin(port_num, pin);
assert((trig != GPIO_TRIGGER_LEVEL_HIGH) && (trig != GPIO_TRIGGER_LEVEL_LOW));
@ -167,7 +167,7 @@ void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
{
/* param port is not used on nRF5x variants with only one GPIO port */
(void)port;
uint8_t port_num = GPIO_PORT_NUM(port);
uint8_t port_num = gpio_port_num(port);
unsigned channel = get_channel_of_pin(port_num, pin);
assert(channel != GPIOTE_CHAN_NUMOF);
if (channel != GPIOTE_CHAN_NUMOF) {
@ -179,7 +179,7 @@ void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
{
/* param port is not used on nRF5x variants with only one GPIO port */
(void)port;
uint8_t port_num = GPIO_PORT_NUM(port);
uint8_t port_num = gpio_port_num(port);
unsigned channel = get_channel_of_pin(port_num, pin);
assert(channel != GPIOTE_CHAN_NUMOF);
if (channel != GPIOTE_CHAN_NUMOF) {
@ -191,7 +191,7 @@ void gpio_ll_irq_unmask_and_clear(gpio_port_t port, uint8_t pin)
{
/* param port is not used on nRF5x variants with only one GPIO port */
(void)port;
uint8_t port_num = GPIO_PORT_NUM(port);
uint8_t port_num = gpio_port_num(port);
unsigned channel = get_channel_of_pin(port_num, pin);
assert(channel != GPIOTE_CHAN_NUMOF);
if (channel != GPIOTE_CHAN_NUMOF) {
@ -204,7 +204,7 @@ void gpio_ll_irq_off(gpio_port_t port, uint8_t pin)
{
/* param port is not used on nRF5x variants with only one GPIO port */
(void)port;
uint8_t port_num = GPIO_PORT_NUM(port);
uint8_t port_num = gpio_port_num(port);
unsigned channel = get_channel_of_pin(port_num, pin);
assert(channel != GPIOTE_CHAN_NUMOF);
if (channel != GPIOTE_CHAN_NUMOF) {

View File

@ -23,7 +23,6 @@
#define GPIO_LL_ARCH_H
#include "architecture.h"
#include "periph/gpio_ll.h"
#include "periph_cpu.h"
#ifdef __cplusplus
@ -48,6 +47,36 @@ extern "C" {
# define GPIO_IOBUS_BASE GPIO_APB_BASE /* no IOBUS present, fall back to APB */
#endif
#define GPIO_PORT_NUMBERING_ALPHABETIC 1
#if PORT_GROUPS >= 1
# define GPIO_PORT_0 ((uintptr_t)&GPIO_IOBUS_BASE->Group[0])
#endif
#if PORT_GROUPS >= 2
# define GPIO_PORT_1 ((uintptr_t)&GPIO_IOBUS_BASE->Group[1])
#endif
#if PORT_GROUPS >= 3
# define GPIO_PORT_2 ((uintptr_t)&GPIO_IOBUS_BASE->Group[2])
#endif
#if PORT_GROUPS >= 4
# define GPIO_PORT_3 ((uintptr_t)&GPIO_IOBUS_BASE->Group[3])
#endif
#if PORT_GROUPS >= 5
# define GPIO_PORT_4 ((uintptr_t)&GPIO_IOBUS_BASE->Group[4])
#endif
#if PORT_GROUPS >= 5
# define GPIO_PORT_4 ((uintptr_t)&GPIO_IOBUS_BASE->Group[4])
#endif
#if PORT_GROUPS >= 6
# define GPIO_PORT_5 ((uintptr_t)&GPIO_IOBUS_BASE->Group[5])
#endif
#if PORT_GROUPS >= 7
# define GPIO_PORT_6 ((uintptr_t)&GPIO_IOBUS_BASE->Group[6])
#endif
#if PORT_GROUPS >= 8
# define GPIO_PORT_7 ((uintptr_t)&GPIO_IOBUS_BASE->Group[7])
#endif
/**
* @brief Get a GPIO port by number
*/
@ -59,6 +88,16 @@ extern "C" {
#define GPIO_PORT_NUM(port) \
(((port) - (uintptr_t)&GPIO_IOBUS_BASE->Group[0]) / sizeof(GPIO_IOBUS_BASE->Group[0]))
static inline gpio_port_t gpio_port(uword_t num)
{
return (uintptr_t)&GPIO_IOBUS_BASE->Group[num];
}
static inline uword_t gpio_port_num(gpio_port_t port)
{
return (port - (uintptr_t)&GPIO_IOBUS_BASE->Group[0]) / sizeof(GPIO_IOBUS_BASE->Group[0]);
}
static inline PortGroup *sam0_gpio_iobus2ap(PortGroup *iobus)
{
const uintptr_t iobus_base = (uintptr_t)GPIO_IOBUS_BASE;

View File

@ -23,7 +23,6 @@
#define GPIO_LL_ARCH_H
#include "architecture.h"
#include "periph/gpio_ll.h"
#include "periph_cpu.h"
#ifdef __cplusplus
@ -32,24 +31,70 @@ extern "C" {
#ifndef DOXYGEN /* hide implementation specific details from Doxygen */
/**
* @brief Get a GPIO port by number
*/
#if defined(CPU_FAM_STM32MP1)
#define GPIO_PORT(num) (GPIOA_BASE + ((num) << 12))
#else
#define GPIO_PORT(num) (GPIOA_BASE + ((num) << 10))
#define GPIO_PORT_NUMBERING_ALPHABETIC 1
#ifdef GPIOA_BASE
# define GPIO_PORT_0 GPIOA_BASE
#endif
/**
* @brief Get a GPIO port number by gpio_t value
*/
#if defined(CPU_FAM_STM32MP1)
#define GPIO_PORT_NUM(port) (((port) - GPIOA_BASE) >> 12)
#else
#define GPIO_PORT_NUM(port) (((port) - GPIOA_BASE) >> 10)
#ifdef GPIOB_BASE
# define GPIO_PORT_1 GPIOB_BASE
#endif
#ifdef GPIOC_BASE
# define GPIO_PORT_2 GPIOC_BASE
#endif
#ifdef GPIOD_BASE
# define GPIO_PORT_3 GPIOD_BASE
#endif
#ifdef GPIOE_BASE
# define GPIO_PORT_4 GPIOE_BASE
#endif
#ifdef GPIOF_BASE
# define GPIO_PORT_5 GPIOF_BASE
#endif
#ifdef GPIOG_BASE
# define GPIO_PORT_6 GPIOG_BASE
#endif
#ifdef GPIOH_BASE
# define GPIO_PORT_7 GPIOH_BASE
#endif
#ifdef GPIOI_BASE
# define GPIO_PORT_8 GPIOI_BASE
#endif
#ifdef GPIOJ_BASE
# define GPIO_PORT_9 GPIOJ_BASE
#endif
#ifdef GPIOK_BASE
# define GPIO_PORT_10 GPIOK_BASE
#endif
static inline gpio_port_t gpio_port(uword_t num)
{
#if defined(CPU_FAM_STM32MP1)
return GPIOA_BASE + (num << 12);
#else
return GPIOA_BASE + (num << 10);
#endif
}
static inline uword_t gpio_port_num(gpio_port_t port)
{
#if defined(CPU_FAM_STM32MP1)
return (port - GPIOA_BASE) >> 12;
#else
return (port - GPIOA_BASE) >> 10;
#endif
}
static inline uword_t gpio_ll_read(gpio_port_t port)
{
GPIO_TypeDef *p = (GPIO_TypeDef *)port;

View File

@ -95,7 +95,7 @@ static inline void print_str(const char *str)
static void _init_clock(gpio_port_t port)
{
periph_clk_en(GPIO_BUS, (GPIOAEN << GPIO_PORT_NUM(port)));
periph_clk_en(GPIO_BUS, (GPIOAEN << gpio_port_num(port)));
#ifdef PORTG_REQUIRES_EXTERNAL_POWER
if (port == (uintptr_t)GPIOG) {
/* Port G requires external power supply */

View File

@ -207,7 +207,7 @@ static uint8_t get_exti_port(uint8_t exti_num)
int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig, gpio_ll_cb_t cb, void *arg)
{
unsigned irq_state = irq_disable();
int port_num = GPIO_PORT_NUM(port);
int port_num = gpio_port_num(port);
/* set callback */
isr_ctx[pin].cb = cb;
@ -297,7 +297,7 @@ void isr_exti(void)
if (level_triggered & (1UL << pin)) {
/* Trading a couple of CPU cycles to not having to store port connected to EXTI in RAM.
* A simple look up table would save ~6 instructions for the cost 64 bytes of RAM. */
gpio_port_t port = GPIO_PORT(get_exti_port(pin));
gpio_port_t port = gpio_port(get_exti_port(pin));
uint32_t actual_level = gpio_ll_read(port) & (1UL << pin);
uint32_t trigger_level = EXTI_REG_RTSR & (1UL << pin);
if (actual_level == trigger_level) {

View File

@ -93,38 +93,63 @@ typedef uintptr_t gpio_port_t;
#define GPIO_PORT_UNDEF UINTPTR_MAX
#endif
#ifdef DOXYGEN
#if defined(DOXYGEN)
/**
* @brief Get the @ref gpio_port_t value of the port identified by @p num
* @brief Indicates whether GPIO ports are enumerated alphabetically (`1`)
* or numerically (`0`).
*
* @note If @p num is a compile time constant, this is guaranteed to be
* suitable for a constant initializer.
*
* Typically this will be something like `(GPIO_BASE_ADDR + num * sizeof(struct
* vendor_gpio_reg))`
* @note You can use both @ref GPIO_PORT_A and @ref GPIO_PORT_0 to refer
* to the first GPIO port in RIOT, regardless of the naming scheme
* used by the MCU the app is compiled for. This macro is useful
* e.g. for pretty-printing.
*/
#define GPIO_PORT(num) implementation_specific
# define GPIO_PORT_NUMBERING_ALPHABETIC implementation_specific
#endif
#ifdef DOXYGEN
/**
* @brief Get the number of the GPIO port belonging to the given @ref
* gpio_port_t value
* @brief Get the @ref gpio_port_t value of the port labeled 0.
*
* @note If @p port is a compile time constant, this is guaranteed to be
* suitable for a constant initializer.
*
* @pre @p port is the return value of @ref GPIO_PORT
*
* For every supported port number *n* the following `assert()` must not blow
* up:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
* assert(n == GPIO_PORT_NUM(GPIO_PORT(n)));
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* @note For MCUs that use letters instead of numbers, this will be an alias
* for @ref GPIO_PORT_A
* @note Some MCUs will not start with Port 0 / Port A, but rather with
* Port 1 (e.g. MSP430) or Port B (e.g. ATmega328P). It will be
* undefined when unavailable
* @note There will also be `GPIO_PORT_1`, `GPIO_PORT_2`, etc. when there
* are corresponding GPIO ports in hardware.
*/
#define GPIO_PORT_NUM(port) implementation_specific
#endif
#define GPIO_PORT_0 implementation_specific
/**
* @brief Get the @ref gpio_port_t value of the port number @p num
* @param[in] num The number of the port to get
* @pre @p num is a valid GPIO port number. An implementation may
* follow the "garbage in, garbage out" philosophy.
*
* @note If the MCU uses an alphabetic naming scheme, number 0 refers
* to port A.
* @warning This may involve accessing a lookup table, prefer e.g. using
* `GPIO_PORT_0` over `gpio_port(0)` if the port number is known
* at compile time.
*/
gpio_port_t gpio_port(uword_t num);
/**
* @brief Get the number of the GPIO port @p port refers to
* @param[in] port The port to get the number of
*
* @pre @p port is a valid GPIO port. An implementation may follow the
* "garbage in, garbage out" philosophy.
* @warning This may involve iterating over a lookup table, prefer using
* e.g. `0` instead of `gpio_port_num(GPIO_PORT_0)` if the port
* number is known at compile time.
*
* In other words `n == gpio_port_num(gpio_port(n))` for every `n` that is
* a valid port number.
*/
uword_t gpio_port_num(gpio_port_t port);
#endif /* DOXYGEN */
#if !defined(HAVE_GPIO_STATE_T) || defined(DOXYGEN)
/**
@ -490,7 +515,7 @@ static const gpio_conf_t gpio_ll_od_pu = {
#endif
/**
* @brief Check if the given number is a valid argument for @ref GPIO_PORT
* @brief Check if the given number is a valid argument for @ref gpio_port
*
* @param[in] num port number to check
* @retval true the MCU used has a GPIO port with that number
@ -868,5 +893,111 @@ static inline void gpio_ll_switch_dir_input(gpio_port_t port, uword_t inputs)
* to be provided */
#include "gpio_ll_arch.h" /* IWYU pragma: export */
#if !defined(DOXYGEN) && !defined(GPIO_PORT_NUMBERING_ALPHABETIC)
# define GPIO_PORT_NUMBERING_ALPHABETIC 0
#endif
/**
* @name GPIO port aliases for alphabetic enumeration
* @{
*/
#if defined(GPIO_PORT_0) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_0`
*/
# define GPIO_PORT_A GPIO_PORT_0
#endif
#if defined(GPIO_PORT_1) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_1`
*/
# define GPIO_PORT_B GPIO_PORT_1
#endif
#if defined(GPIO_PORT_2) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_2`
*/
# define GPIO_PORT_C GPIO_PORT_2
#endif
#if defined(GPIO_PORT_3) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_3`
*/
# define GPIO_PORT_D GPIO_PORT_3
#endif
#if defined(GPIO_PORT_4) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_4`
*/
# define GPIO_PORT_E GPIO_PORT_4
#endif
#if defined(GPIO_PORT_5) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_5`
*/
# define GPIO_PORT_F GPIO_PORT_5
#endif
#if defined(GPIO_PORT_6) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_6`
*/
# define GPIO_PORT_G GPIO_PORT_6
#endif
#if defined(GPIO_PORT_7) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_7`
*/
# define GPIO_PORT_H GPIO_PORT_7
#endif
#if defined(GPIO_PORT_8) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_8`
*/
# define GPIO_PORT_I GPIO_PORT_8
#endif
#if defined(GPIO_PORT_9) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_9`
*/
# define GPIO_PORT_J GPIO_PORT_9
#endif
#if defined(GPIO_PORT_10) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_10`
*/
# define GPIO_PORT_K GPIO_PORT_10
#endif
#if defined(GPIO_PORT_11) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_11`
*/
# define GPIO_PORT_L GPIO_PORT_11
#endif
#if defined(GPIO_PORT_12) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_12`
*/
# define GPIO_PORT_M GPIO_PORT_12
#endif
#if defined(GPIO_PORT_13) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_13`
*/
# define GPIO_PORT_N GPIO_PORT_13
#endif
#if defined(GPIO_PORT_14) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_14`
*/
# define GPIO_PORT_O GPIO_PORT_14
#endif
#if defined(GPIO_PORT_15) || defined(DOXYGEN)
/**
* @brief Alias of `ref GPIO_PORT_15`
*/
# define GPIO_PORT_P GPIO_PORT_15
#endif
/** @} */
#endif /* PERIPH_GPIO_LL_H */
/** @} */

View File

@ -9,7 +9,7 @@ BOARD ?= nucleo-f767zi
#
# Beware: If other pins on the output port are configured as output GPIOs, they
# might be written to during this test.
PORT_OUT ?= 0
#PORT_OUT := 0
PIN_OUT_0 ?= 0
PIN_OUT_1 ?= 1
@ -36,7 +36,10 @@ endif
COMPENSATE_OVERHEAD ?= 1
CFLAGS += -DPORT_OUT=$(PORT_OUT)
ifneq (,$(PORT_OUT))
CFLAGS += -DPORT_OUT=GPIO_PORT_$(PORT_OUT)
CFLAGS += -DPORT_OUT_NUM=$(PORT_OUT)
endif
CFLAGS += -DPIN_OUT_0=$(PIN_OUT_0)
CFLAGS += -DPIN_OUT_1=$(PIN_OUT_1)
CFLAGS += -DCOMPENSATE_OVERHEAD=$(COMPENSATE_OVERHEAD)

View File

@ -30,7 +30,20 @@
#define COMPENSATE_OVERHEAD 1
#endif
static gpio_port_t port_out = GPIO_PORT(PORT_OUT);
#ifndef PORT_OUT
# if defined(GPIO_PORT_0)
# define PORT_OUT GPIO_PORT_0
# define PORT_OUT_NUM 0
# elif defined(GPIO_PORT_1)
# define PORT_OUT GPIO_PORT_1
# define PORT_OUT_NUM 1
# elif defined(GPIO_PORT_2)
# define PORT_OUT GPIO_PORT_2
# define PORT_OUT_NUM 2
# endif
#endif
static gpio_port_t port_out = PORT_OUT;
static void print_summary_compensated(uint_fast16_t loops, uint32_t duration,
uint32_t duration_uncompensated)
@ -124,8 +137,8 @@ int main(void)
puts("\n"
"periph/gpio: Using 2x gpio_set() and 2x gpio_clear()\n"
"---------------------------------------------------");
gpio_t p0 = GPIO_PIN(PORT_OUT, PIN_OUT_0);
gpio_t p1 = GPIO_PIN(PORT_OUT, PIN_OUT_1);
gpio_t p0 = GPIO_PIN(PORT_OUT_NUM, PIN_OUT_0);
gpio_t p1 = GPIO_PIN(PORT_OUT_NUM, PIN_OUT_1);
gpio_init(p0, GPIO_OUT);
gpio_init(p1, GPIO_OUT);
@ -177,8 +190,8 @@ int main(void)
puts("\n"
"periph/gpio: Using 4x gpio_toggle()\n"
"-----------------------------------");
gpio_t p0 = GPIO_PIN(PORT_OUT, PIN_OUT_0);
gpio_t p1 = GPIO_PIN(PORT_OUT, PIN_OUT_1);
gpio_t p0 = GPIO_PIN(PORT_OUT_NUM, PIN_OUT_0);
gpio_t p1 = GPIO_PIN(PORT_OUT_NUM, PIN_OUT_1);
gpio_init(p0, GPIO_OUT);
gpio_init(p1, GPIO_OUT);
@ -230,8 +243,8 @@ int main(void)
puts("\n"
"periph/gpio: Using 4x gpio_write()\n"
"----------------------------------");
gpio_t p0 = GPIO_PIN(PORT_OUT, PIN_OUT_0);
gpio_t p1 = GPIO_PIN(PORT_OUT, PIN_OUT_1);
gpio_t p0 = GPIO_PIN(PORT_OUT_NUM, PIN_OUT_0);
gpio_t p1 = GPIO_PIN(PORT_OUT_NUM, PIN_OUT_1);
gpio_init(p0, GPIO_OUT);
gpio_init(p1, GPIO_OUT);

View File

@ -9,8 +9,8 @@ BOARD ?= nucleo-f767zi
# pins *must* be on the same port, respectively. Connect the first input to the
# first output pin and the second input pin to the second output pin, e.g. using
# jumper wires.
PORT_IN ?= 1
PORT_OUT ?= 1
PORT_IN ?=
PORT_OUT ?=
PIN_IN_0 ?= 0
PIN_IN_1 ?= 1
PIN_OUT_0 ?= 2
@ -38,8 +38,14 @@ USEMODULE += ztimer_usec
include $(RIOTBASE)/Makefile.include
CFLAGS += -DPORT_OUT=$(PORT_OUT)
CFLAGS += -DPORT_IN=$(PORT_IN)
ifneq (,$(PORT_OUT))
CFLAGS += -DPORT_OUT=GPIO_PORT_$(PORT_OUT)
CFLAGS += -DPORT_OUT_NUM=$(PORT_OUT)
endif
ifneq (,$(PORT_IN))
CFLAGS += -DPORT_IN=GPIO_PORT_$(PORT_IN)
CFLAGS += -DPORT_IN_NUM=$(PORT_IN)
endif
CFLAGS += -DPIN_IN_0=$(PIN_IN_0)
CFLAGS += -DPIN_IN_1=$(PIN_IN_1)
CFLAGS += -DPIN_OUT_0=$(PIN_OUT_0)

View File

@ -1,3 +1,4 @@
BOARD_INSUFFICIENT_MEMORY := \
atmega8 \
samd10-xmini \
#

View File

@ -36,9 +36,33 @@
#define LOW_ROM 0
#endif
/* On e.g. ATmega328P the smallest available GPIO Port is GPIO_PORT_1 (GPIOB),
* on others (e.g. nRF51) the highest available GPIO PORT is GPIO_PORT_0.
* So we need the following dance to find a valid GPIO port to allow compile
* testing. Extend the dance as needed, when new MCUs are added */
#if !defined(PORT_OUT)
# if defined(GPIO_PORT_0)
# define PORT_OUT GPIO_PORT_0
# define PORT_OUT_NUM 0
# elif defined(GPIO_PORT_1)
# define PORT_OUT GPIO_PORT_1
# define PORT_OUT_NUM 1
# endif
#endif
#if !defined(PORT_IN)
# if defined(GPIO_PORT_0)
# define PORT_IN GPIO_PORT_0
# define PORT_IN_NUM 0
# elif defined(GPIO_PORT_1)
# define PORT_IN GPIO_PORT_1
# define PORT_IN_NUM 1
# endif
#endif
static const char *noyes[] = { "no", "yes" };
static gpio_port_t port_out = GPIO_PORT(PORT_OUT);
static gpio_port_t port_in = GPIO_PORT(PORT_IN);
static gpio_port_t port_out = PORT_OUT;
static gpio_port_t port_in = PORT_IN;
static const uint64_t mutex_timeout = US_PER_MS;
@ -75,9 +99,15 @@ static void expect_impl(int val, unsigned line)
static void print_cabling(unsigned port1, unsigned pin1,
unsigned port2, unsigned pin2)
{
printf(" P%u.%u (P%c%u) -- P%u.%u (P%c%u)\n",
port1, pin1, 'A' + (char)port1, pin1,
port2, pin2, 'A' + (char)port2, pin2);
if (GPIO_PORT_NUMBERING_ALPHABETIC) {
/* alphabetic naming scheme */
printf(" P%c%u -- P%c%u\n", 'A' + (char)port1, pin1,
'A' + (char)port2, pin2);
}
else {
/* numeric naming scheme */
printf(" P%u.%u -- P%u.%u\n", port1, pin1, port2, pin2);
}
}
static void print_details(void)
@ -86,8 +116,8 @@ static void print_details(void)
"========================\n"
"Cabling:\n"
"(INPUT -- OUTPUT)");
print_cabling(PORT_IN, PIN_IN_0, PORT_OUT, PIN_OUT_0);
print_cabling(PORT_IN, PIN_IN_1, PORT_OUT, PIN_OUT_1);
print_cabling(PORT_IN_NUM, PIN_IN_0, PORT_OUT_NUM, PIN_OUT_0);
print_cabling(PORT_IN_NUM, PIN_IN_1, PORT_OUT_NUM, PIN_OUT_1);
printf("Number of pull resistor values supported: %u\n", GPIO_PULL_NUMOF);
printf("Number of drive strengths supported: %u\n", GPIO_DRIVE_NUMOF);
printf("Number of slew rates supported: %u\n", GPIO_SLEW_NUMOF);
@ -486,8 +516,8 @@ static void test_gpio_ll_init(void)
"\n"
"Testing is_gpio_port_num_valid() is true for PORT_OUT and "
"PORT_IN:");
expect(is_gpio_port_num_valid(PORT_IN));
expect(is_gpio_port_num_valid(PORT_OUT));
expect(is_gpio_port_num_valid(PORT_IN_NUM));
expect(is_gpio_port_num_valid(PORT_OUT_NUM));
/* first, iterate through input configurations and test them one by one */
test_gpio_ll_init_input_configs();