From ddb22a3c565a8ba0ac3e8b83a8c39333e8bf55ba Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Thu, 20 Aug 2020 12:30:09 +0200 Subject: [PATCH 1/3] sam0_common: Use Single-cycle I/O Port for GPIO when available The Cortex-m0 based ATSAM devices can use the Single-cycle I/O Port for GPIO. This commit modifies the gpio_t type to use this port when available. It is mapped back to the peripheral memory space for configuration access. When it is not available, the _port_iobus() and _port() functions behave identical, which is the case for the samd51. --- cpu/sam0_common/include/periph_cpu_common.h | 2 + cpu/sam0_common/periph/gpio.c | 58 ++++++++++++++++++--- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index a79010a369..a9ec1507f6 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -75,6 +75,8 @@ typedef uint32_t gpio_t; */ #ifdef CPU_FAM_SAML11 #define GPIO_PIN(x, y) (((gpio_t)(&PORT_SEC->Group[x])) | y) +#elif defined(PORT_IOBUS) /* Use IOBUS access when available */ +#define GPIO_PIN(x, y) (((gpio_t)(&PORT_IOBUS->Group[x])) | y) #else #define GPIO_PIN(x, y) (((gpio_t)(&PORT->Group[x])) | y) #endif diff --git a/cpu/sam0_common/periph/gpio.c b/cpu/sam0_common/periph/gpio.c index e3de9c8e7a..7bfa1f9cd4 100644 --- a/cpu/sam0_common/periph/gpio.c +++ b/cpu/sam0_common/periph/gpio.c @@ -21,6 +21,19 @@ * @author Kaspar Schleiser * @author Hauke Petersen * + * The GPIO implementation here support the PERIPH_GPIO_FAST_READ pseudomodule + * on the cortex-m0/m23 based devices. This trades an increase in power + * consumption for a decrease in GPIO pin read latency. Enable this in your + * makefile with: + * + * ``` + * FEATURES_OPTIONAL += periph_gpio_fast_read + * ``` + * + * This switches the GPIO reads to use the Cortex-M0+ single-cycle I/O port + * instead of the regular APB acces. The single-cycle I/O port is always used + * for writes when it is available on the device. + * * @} */ @@ -75,11 +88,29 @@ typedef enum { static gpio_isr_ctx_t gpio_config[NUMOF_IRQS]; #endif /* MODULE_PERIPH_GPIO_IRQ */ -static inline PortGroup *_port(gpio_t pin) +/* The Cortex-m0 based ATSAM devices can use the Single-cycle I/O Port for GPIO. + * When used, the gpio_t is mapped to the IOBUS area and must be mapped back to + * the peripheral memory space for configuration access. When it is not + * available, the _port_iobus() and _port() functions behave identical. + */ +static inline PortGroup *_port_iobus(gpio_t pin) { return (PortGroup *)(pin & ~(0x1f)); } +static inline PortGroup *_port(gpio_t pin) +{ +#ifdef PORT_IOBUS + /* Shift the PortGroup address back from the IOBUS region to the peripheral + * region + */ + return (PortGroup *)((uintptr_t)_port_iobus(pin) - + (uintptr_t)PORT_IOBUS + (uintptr_t)PORT); +#else + return _port_iobus(pin); +#endif +} + static inline int _pin_pos(gpio_t pin) { return (pin & 0x1f); @@ -121,9 +152,15 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) /* set pin direction */ if (mode & 0x2) { + if (IS_ACTIVE(MODULE_PERIPH_GPIO_FAST_READ)) { + port->CTRL.reg |= pin_mask; + } port->DIRCLR.reg = pin_mask; } else { + if (IS_ACTIVE(MODULE_PERIPH_GPIO_FAST_READ)) { + port->CTRL.reg &= ~pin_mask; + } port->DIRSET.reg = pin_mask; } @@ -143,9 +180,16 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) int gpio_read(gpio_t pin) { - PortGroup *port = _port(pin); + PortGroup *port; int mask = _pin_mask(pin); + if (IS_ACTIVE(MODULE_PERIPH_GPIO_FAST_READ)) { + port = _port_iobus(pin); + } + else { + port = _port(pin); + } + if (port->DIR.reg & mask) { return (port->OUT.reg & mask) ? 1 : 0; } @@ -156,25 +200,25 @@ int gpio_read(gpio_t pin) void gpio_set(gpio_t pin) { - _port(pin)->OUTSET.reg = _pin_mask(pin); + _port_iobus(pin)->OUTSET.reg = _pin_mask(pin); } void gpio_clear(gpio_t pin) { - _port(pin)->OUTCLR.reg = _pin_mask(pin); + _port_iobus(pin)->OUTCLR.reg = _pin_mask(pin); } void gpio_toggle(gpio_t pin) { - _port(pin)->OUTTGL.reg = _pin_mask(pin); + _port_iobus(pin)->OUTTGL.reg = _pin_mask(pin); } void gpio_write(gpio_t pin, int value) { if (value) { - _port(pin)->OUTSET.reg = _pin_mask(pin); + _port_iobus(pin)->OUTSET.reg = _pin_mask(pin); } else { - _port(pin)->OUTCLR.reg = _pin_mask(pin); + _port_iobus(pin)->OUTCLR.reg = _pin_mask(pin); } } From 6007a318130bf52a687bb42404601c7b830690c4 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Thu, 10 Sep 2020 21:59:40 +0200 Subject: [PATCH 2/3] sam0: Add periph_gpio_fast_read feature where applicable --- cpu/samd21/Kconfig | 1 + cpu/samd21/Makefile.features | 1 + cpu/saml1x/Kconfig | 1 + cpu/saml1x/Makefile.features | 1 + cpu/saml21/Kconfig | 1 + cpu/saml21/Makefile.features | 2 ++ kconfigs/Kconfig.features | 7 +++++++ 7 files changed, 14 insertions(+) diff --git a/cpu/samd21/Kconfig b/cpu/samd21/Kconfig index e61337f2f5..0b7dfa18a4 100644 --- a/cpu/samd21/Kconfig +++ b/cpu/samd21/Kconfig @@ -10,6 +10,7 @@ config CPU_FAM_SAMD21 select CPU_COMMON_SAM0 select CPU_CORE_CORTEX_M0PLUS select HAS_CPU_SAMD21 + select HAS_PERIPH_GPIO_FAST_READ select HAS_PUF_SRAM ## CPU Models diff --git a/cpu/samd21/Makefile.features b/cpu/samd21/Makefile.features index 0f283eb987..10d35a9472 100644 --- a/cpu/samd21/Makefile.features +++ b/cpu/samd21/Makefile.features @@ -2,5 +2,6 @@ CPU_CORE = cortex-m0plus CPU_FAM = samd21 FEATURES_PROVIDED += puf_sram +FEATURES_PROVIDED += periph_gpio_fast_read -include $(RIOTCPU)/sam0_common/Makefile.features diff --git a/cpu/saml1x/Kconfig b/cpu/saml1x/Kconfig index 0ca51908ba..ee5b1a954a 100644 --- a/cpu/saml1x/Kconfig +++ b/cpu/saml1x/Kconfig @@ -11,6 +11,7 @@ config CPU_COMMON_SAML1X select CPU_CORE_CORTEX_M23 select HAS_CORTEXM_MPU select HAS_CPU_SAML1X + select HAS_PERIPH_GPIO_FAST_READ select HAS_PERIPH_HWRNG config CPU_FAM_SAML10 diff --git a/cpu/saml1x/Makefile.features b/cpu/saml1x/Makefile.features index 2b005dda64..4f0bf86c65 100644 --- a/cpu/saml1x/Makefile.features +++ b/cpu/saml1x/Makefile.features @@ -10,5 +10,6 @@ endif FEATURES_PROVIDED += cortexm_mpu FEATURES_PROVIDED += periph_hwrng +FEATURES_PROVIDED += periph_gpio_fast_read include $(RIOTCPU)/sam0_common/Makefile.features diff --git a/cpu/saml21/Kconfig b/cpu/saml21/Kconfig index e1e694b266..09c0ea649a 100644 --- a/cpu/saml21/Kconfig +++ b/cpu/saml21/Kconfig @@ -11,6 +11,7 @@ config CPU_FAM_SAML21 select CPU_CORE_CORTEX_M0PLUS select HAS_BACKUP_RAM select HAS_CPU_SAML21 + select HAS_PERIPH_GPIO_FAST_READ ## CPU Models config CPU_MODEL_SAML21J18A diff --git a/cpu/saml21/Makefile.features b/cpu/saml21/Makefile.features index 3e4b0d6fa8..7232f9200b 100644 --- a/cpu/saml21/Makefile.features +++ b/cpu/saml21/Makefile.features @@ -4,6 +4,8 @@ CPU_FAM = saml21 # The SAMR30 line of MCUs does not contain a TRNG CPU_MODELS_WITHOUT_HWRNG += samr30% +FEATURES_PROVIDED += periph_gpio_fast_read + # Low Power SRAM is *not* retained during Backup Sleep. # It therefore does not fulfill the requirements of the 'backup_ram' interface. # It can still be used in normal and standby mode, but code that relies on it diff --git a/kconfigs/Kconfig.features b/kconfigs/Kconfig.features index c621830b66..3544bda751 100644 --- a/kconfigs/Kconfig.features +++ b/kconfigs/Kconfig.features @@ -143,6 +143,13 @@ config HAS_PERIPH_GPIO_IRQ Indicates that the GPIO peripheral supports external interrupts is present. +config HAS_PERIPH_GPIO_FAST_READ + bool + help + Indicates that the GPIO peripheral supports a mode in which pin read + operations are faster, usually with a tradeoff against a different + property. + config HAS_PERIPH_HWRNG bool help From 7ef69ae79bf0e6190eb7820972b9d39cd3191014 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Thu, 10 Sep 2020 22:00:46 +0200 Subject: [PATCH 3/3] tests/periph_gpio: Add fast_read feature as optional dependency --- tests/periph_gpio/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/periph_gpio/Makefile b/tests/periph_gpio/Makefile index cdfd9d9950..7733afaaa3 100644 --- a/tests/periph_gpio/Makefile +++ b/tests/periph_gpio/Makefile @@ -2,6 +2,7 @@ include ../Makefile.tests_common FEATURES_REQUIRED = periph_gpio FEATURES_OPTIONAL = periph_gpio_irq +FEATURES_OPTIONAL += periph_gpio_fast_read USEMODULE += shell USEMODULE += shell_commands