diff --git a/cpu/sam0_common/periph/gpio.c b/cpu/sam0_common/periph/gpio.c index 13fc0bd26e6f..82cc54699eb2 100644 --- a/cpu/sam0_common/periph/gpio.c +++ b/cpu/sam0_common/periph/gpio.c @@ -163,26 +163,33 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) int pin_mask = _pin_mask(pin); /* make sure pin mode is applicable */ - if (mode > 0x7) { + if (mode & ~MODE_PINCFG_MASK) { return -1; } /* set pin direction */ - if (mode & 0x2) { + if (mode & PORT_PINCFG_INEN) { + /* input */ if (IS_ACTIVE(MODULE_PERIPH_GPIO_FAST_READ)) { port->CTRL.reg |= pin_mask; } port->DIRCLR.reg = pin_mask; } else { + /* output */ if (IS_ACTIVE(MODULE_PERIPH_GPIO_FAST_READ)) { port->CTRL.reg &= ~pin_mask; } port->DIRSET.reg = pin_mask; + + /* enable input to read back output level */ + if (IS_ACTIVE(MODULE_PERIPH_GPIO_READ_OUTPUT)) { + mode |= PORT_PINCFG_INEN; + } } /* configure the pin cfg */ - port->PINCFG[pin_pos].reg = (mode & MODE_PINCFG_MASK); + port->PINCFG[pin_pos].reg = mode; /* and set pull-up/pull-down if applicable */ if (mode == GPIO_IN_PU) { @@ -207,11 +214,11 @@ bool gpio_read(gpio_t pin) port = _port(pin); } - if (port->DIR.reg & mask) { - return (port->OUT.reg & mask) ? 1 : 0; - } - else { - return (port->IN.reg & mask) ? 1 : 0; + if (IS_ACTIVE(MODULE_PERIPH_GPIO_READ_OUTPUT) || + !(port->DIR.reg & mask)) { + return port->IN.reg & mask; + } else { + return port->OUT.reg & mask; } } diff --git a/cpu/samd21/Makefile.features b/cpu/samd21/Makefile.features index f7e98954317c..b7378cec6f02 100644 --- a/cpu/samd21/Makefile.features +++ b/cpu/samd21/Makefile.features @@ -1,6 +1,7 @@ CPU_CORE = cortex-m0plus FEATURES_PROVIDED += periph_gpio_fast_read +FEATURES_PROVIDED += periph_gpio_read_output ifeq (,$(filter samd20%,$(CPU_MODEL))) FEATURES_PROVIDED += periph_uart_collision diff --git a/cpu/samd5x/Makefile.features b/cpu/samd5x/Makefile.features index 53a3e99d333f..601326a352da 100644 --- a/cpu/samd5x/Makefile.features +++ b/cpu/samd5x/Makefile.features @@ -3,6 +3,7 @@ CPU_CORE = cortex-m4f FEATURES_PROVIDED += periph_hwrng FEATURES_PROVIDED += backup_ram FEATURES_PROVIDED += cortexm_mpu +FEATURES_PROVIDED += periph_gpio_read_output FEATURES_PROVIDED += periph_gpio_tamper_wake FEATURES_PROVIDED += periph_rtc_mem FEATURES_PROVIDED += periph_spi_on_qspi diff --git a/cpu/saml1x/Makefile.features b/cpu/saml1x/Makefile.features index b46af8aaba1a..0a675825b5ad 100644 --- a/cpu/saml1x/Makefile.features +++ b/cpu/saml1x/Makefile.features @@ -5,6 +5,7 @@ CPU_CORE = cortex-m23 FEATURES_PROVIDED += periph_hwrng FEATURES_PROVIDED += periph_gpio_fast_read +FEATURES_PROVIDED += periph_gpio_read_output FEATURES_PROVIDED += periph_uart_collision include $(RIOTCPU)/sam0_common/Makefile.features diff --git a/cpu/saml21/Makefile.features b/cpu/saml21/Makefile.features index fe77d1c1df7a..b2a0cebc84a0 100644 --- a/cpu/saml21/Makefile.features +++ b/cpu/saml21/Makefile.features @@ -4,6 +4,7 @@ CPU_CORE = cortex-m0plus CPU_MODELS_WITHOUT_HWRNG += samr30% FEATURES_PROVIDED += periph_gpio_fast_read +FEATURES_PROVIDED += periph_gpio_read_output FEATURES_PROVIDED += periph_uart_collision # Low Power SRAM is *not* retained during Backup Sleep. diff --git a/features.yaml b/features.yaml index 7113af63e6c5..fab68b7ccf35 100644 --- a/features.yaml +++ b/features.yaml @@ -512,6 +512,13 @@ groups: Enabling this feature reduces read latency for an increase in power consumption. It affects both the classic GPIO API driver and the GPIO LL driver. + - name: periph_gpio_read_output + help: This feature is currently implemented on Microchip SAM0 based MCUs only. + Enabling this feature makes `gpio_read()` read back the actual pin level + of an output GPIO (instead of just returning the configured level). + This can be used to detect hardware problems (e.g. if a pin is set HIGH but + reads low). + The feature comes at the cost of slightly higher power consumption. groups: - title: Pin Level Peripheral GPIO API diff --git a/makefiles/features_existing.inc.mk b/makefiles/features_existing.inc.mk index 6420ccd089cd..ad8a5c4e2c5a 100644 --- a/makefiles/features_existing.inc.mk +++ b/makefiles/features_existing.inc.mk @@ -185,6 +185,7 @@ FEATURES_EXISTING := \ periph_gpio_ll_open_source \ periph_gpio_ll_open_source_pull_down \ periph_gpio_ll_switch_dir \ + periph_gpio_read_output \ periph_gpio_tamper_wake \ periph_hash_md5 \ periph_hash_sha3_256 \ diff --git a/tests/periph/gpio/Makefile b/tests/periph/gpio/Makefile index 51a7f28e91c6..050b2f93d61e 100644 --- a/tests/periph/gpio/Makefile +++ b/tests/periph/gpio/Makefile @@ -5,6 +5,7 @@ include ../Makefile.periph_common FEATURES_REQUIRED += periph_gpio FEATURES_OPTIONAL += periph_gpio_irq FEATURES_OPTIONAL += periph_gpio_fast_read +FEATURES_OPTIONAL += periph_gpio_read_output FEATURES_OPTIONAL += periph_gpio_tamper_wake USEMODULE += shell_cmds_default