From 56ef43158a99ede95597450d115fdcce8666321f Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 08:08:21 +0100 Subject: [PATCH 01/17] drivers/periph/gpio: add comparison functions The extensible GPIO API requires the comparison of structured GPIO types. This means that inline functions must be used instead of direct comparisons. For the migration process, drivers and other modules must first be changed so that they use the inline comparison functions. --- drivers/include/periph/gpio.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/include/periph/gpio.h b/drivers/include/periph/gpio.h index 2d778f8dd19b..852c1f2236a9 100644 --- a/drivers/include/periph/gpio.h +++ b/drivers/include/periph/gpio.h @@ -43,6 +43,11 @@ * definitions in `RIOT/boards/ * /include/periph_conf.h` will define the selected * GPIO pin. * + * @warning The scalar GPIO pin type `gpio_t` is deprecated and will be + * replaced by a structured GPIO pin type in a future GPIO API. Therefore, + * don't use the direct comparison of GPIO pins anymore. Instead, use the + * inline comparison functions @ref gpio_is_equal and @ref gpio_is_undef. + * * # (Low-) Power Implications * * On almost all platforms, we can only control the peripheral power state of @@ -250,6 +255,27 @@ void gpio_toggle(gpio_t pin); */ void gpio_write(gpio_t pin, int value); +/** + * @brief Test if a GPIO pin is equal to another GPIO pin + * + * @param[in] gpio1 First GPIO pin to check + * @param[in] gpio2 Second GPIO pin to check + */ +static inline int gpio_is_equal(gpio_t gpio1, gpio_t gpio2) +{ + return (gpio1 == gpio2); +} + +/** + * @brief Test if a GPIO pin is undefined + * + * @param[in] gpio GPIO pin to check + */ +static inline int gpio_is_undef(gpio_t gpio) +{ + return (gpio == GPIO_UNDEF); +} + #ifdef __cplusplus } #endif From 5e48829bd99edbf1a6b447e84d471e83dce6a0ed Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 12:45:13 +0100 Subject: [PATCH 02/17] drivers: use inline functions for GPIO comparisons The extensible GPIO API requires the comparison of structured GPIO types. This means that inline functions must be used instead of direct comparisons. For the migration process, drivers must first be changed so that they use the inline comparison functions. --- drivers/adcxx1c/adcxx1c.c | 4 ++-- drivers/ads101x/ads101x.c | 2 +- drivers/ccs811/ccs811.c | 18 +++++++++--------- drivers/hd44780/hd44780.c | 8 ++++---- drivers/ili9341/ili9341.c | 2 +- drivers/ina3221/alerts.c | 4 ++-- drivers/itg320x/itg320x.c | 2 +- drivers/ltc4150/ltc4150.c | 8 ++++---- drivers/ltc4150/ltc4150_saul.c | 2 +- drivers/motor_driver/motor_driver.c | 26 +++++++++++++------------- drivers/pca9685/pca9685.c | 6 +++--- drivers/periph_common/spi.c | 2 +- drivers/ph_oem/ph_oem.c | 4 ++-- drivers/ph_oem/ph_oem_saul.c | 2 +- drivers/qmc5883l/qmc5883l.c | 2 +- drivers/rn2xx3/rn2xx3.c | 4 ++-- drivers/sdcard_spi/sdcard_spi.c | 4 ++-- drivers/sds011/sds011.c | 6 +++--- drivers/soft_spi/soft_spi.c | 21 +++++++++++---------- drivers/sx127x/sx127x.c | 12 ++++++------ drivers/tps6274x/tps6274x.c | 8 ++++---- drivers/xbee/xbee.c | 6 +++--- 22 files changed, 77 insertions(+), 76 deletions(-) diff --git a/drivers/adcxx1c/adcxx1c.c b/drivers/adcxx1c/adcxx1c.c index 7416377739d3..ce90e86b9cf0 100644 --- a/drivers/adcxx1c/adcxx1c.c +++ b/drivers/adcxx1c/adcxx1c.c @@ -103,7 +103,7 @@ int adcxx1c_enable_alert(adcxx1c_t *dev, adcxx1c_cb_t cb, void *arg) i2c_acquire(DEV); i2c_read_reg(DEV, ADDR, ADCXX1C_CONF_ADDR, ®, 0); - reg |= (dev->params.alert_pin != GPIO_UNDEF ? ADCXX1C_CONF_ALERT_PIN_EN : 0) + reg |= (!gpio_is_undef(dev->params.alert_pin) ? ADCXX1C_CONF_ALERT_PIN_EN : 0) | ADCXX1C_CONF_ALERT_FLAG_EN; status = i2c_write_reg(DEV, ADDR, ADCXX1C_CONF_ADDR, reg, 0); i2c_release(DEV); @@ -113,7 +113,7 @@ int adcxx1c_enable_alert(adcxx1c_t *dev, adcxx1c_cb_t cb, void *arg) return ADCXX1C_NOI2C; } - if (dev->params.alert_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.alert_pin)) { dev->cb = cb; dev->arg = arg; /* alert active low */ diff --git a/drivers/ads101x/ads101x.c b/drivers/ads101x/ads101x.c index 843df3a6ebd0..1952d7959eac 100644 --- a/drivers/ads101x/ads101x.c +++ b/drivers/ads101x/ads101x.c @@ -159,7 +159,7 @@ int ads101x_enable_alert(ads101x_alert_t *dev, { uint8_t regs[2]; - if (dev->params.alert_pin == GPIO_UNDEF) { + if (gpio_is_undef(dev->params.alert_pin)) { return ADS101X_OK; } diff --git a/drivers/ccs811/ccs811.c b/drivers/ccs811/ccs811.c index 5d4eaa8a54c4..ae2cf279f5ca 100644 --- a/drivers/ccs811/ccs811.c +++ b/drivers/ccs811/ccs811.c @@ -75,7 +75,7 @@ int ccs811_init(ccs811_t *dev, const ccs811_params_t *params) int res = CCS811_OK; - if (dev->params.reset_pin != GPIO_UNDEF && + if (!gpio_is_undef(dev->params.reset_pin) && gpio_init(dev->params.reset_pin, GPIO_OUT) == 0) { DEBUG_DEV("nRESET pin configured", dev); /* enable low active reset signal */ @@ -88,7 +88,7 @@ int ccs811_init(ccs811_t *dev, const ccs811_params_t *params) xtimer_usleep(1000); } - if (dev->params.wake_pin != GPIO_UNDEF && + if (!gpio_is_undef(dev->params.wake_pin) && gpio_init(dev->params.wake_pin, GPIO_OUT) == 0) { gpio_clear(dev->params.wake_pin); DEBUG_DEV("nWAKE pin configured", dev); @@ -208,7 +208,7 @@ int ccs811_set_int_mode(ccs811_t *dev, ccs811_int_mode_t mode) { ASSERT_PARAM(dev != NULL); - if (dev->params.int_pin == GPIO_UNDEF) { + if (gpio_is_undef(dev->params.int_pin)) { DEBUG_DEV("nINT pin not configured", dev); return CCS811_ERROR_NO_INT_PIN; } @@ -365,7 +365,7 @@ int ccs811_power_down (ccs811_t *dev) int res = ccs811_set_mode(dev, CCS811_MODE_IDLE); dev->params.mode = tmp_mode; - if (dev->params.wake_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.wake_pin)) { DEBUG_DEV("Setting nWAKE pin high", dev); gpio_set(dev->params.wake_pin); } @@ -377,7 +377,7 @@ int ccs811_power_up (ccs811_t *dev) { ASSERT_PARAM(dev != NULL); - if (dev->params.wake_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.wake_pin)) { DEBUG_DEV("Setting nWAKE pin low", dev); gpio_clear(dev->params.wake_pin); } @@ -490,7 +490,7 @@ static int _reg_read(const ccs811_t *dev, uint8_t reg, uint8_t *data, uint32_t l } #if MODULE_CCS811_FULL - if (dev->params.wake_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.wake_pin)) { /* wake the sensor with low active WAKE signal */ gpio_clear(dev->params.wake_pin); /* t_WAKE is 50 us */ @@ -502,7 +502,7 @@ static int _reg_read(const ccs811_t *dev, uint8_t reg, uint8_t *data, uint32_t l i2c_release(dev->params.i2c_dev); #if MODULE_CCS811_FULL - if (dev->params.wake_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.wake_pin)) { /* let the sensor enter to sleep mode */ gpio_set(dev->params.wake_pin); /* minimum t_DWAKE is 20 us */ @@ -551,7 +551,7 @@ static int _reg_write(const ccs811_t *dev, uint8_t reg, uint8_t *data, uint32_t } #if MODULE_CCS811_FULL - if (dev->params.wake_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.wake_pin)) { /* wake the sensor with low active WAKE signal */ gpio_clear(dev->params.wake_pin); /* t_WAKE is 50 us */ @@ -568,7 +568,7 @@ static int _reg_write(const ccs811_t *dev, uint8_t reg, uint8_t *data, uint32_t i2c_release(dev->params.i2c_dev); #if MODULE_CCS811_FULL - if (dev->params.wake_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.wake_pin)) { /* let the sensor enter to sleep mode */ gpio_set(dev->params.wake_pin); /* minimum t_DWAKE is 20 us */ diff --git a/drivers/hd44780/hd44780.c b/drivers/hd44780/hd44780.c index d6b767e76f30..d6e2ebac55eb 100644 --- a/drivers/hd44780/hd44780.c +++ b/drivers/hd44780/hd44780.c @@ -72,7 +72,7 @@ static void _send(const hd44780_t *dev, uint8_t value, hd44780_state_t state) { (state == HD44780_ON) ? gpio_set(dev->p.rs) : gpio_clear(dev->p.rs); /* if RW pin is available, set it to LOW */ - if (dev->p.rw != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.rw)) { gpio_clear(dev->p.rw); } /* write data in 8Bit or 4Bit mode */ @@ -110,7 +110,7 @@ int hd44780_init(hd44780_t *dev, const hd44780_params_t *params) } dev->flag = 0; /* set mode depending on configured pins */ - if (dev->p.data[4] != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.data[4])) { dev->flag |= HD44780_8BITMODE; } else { @@ -133,7 +133,7 @@ int hd44780_init(hd44780_t *dev, const hd44780_params_t *params) gpio_init(dev->p.rs, GPIO_OUT); /* RW (read/write) of LCD not required, set it to GPIO_UNDEF */ - if (dev->p.rw != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.rw)) { gpio_init(dev->p.rw, GPIO_OUT); } gpio_init(dev->p.enable, GPIO_OUT); @@ -145,7 +145,7 @@ int hd44780_init(hd44780_t *dev, const hd44780_params_t *params) xtimer_usleep(HD44780_INIT_WAIT_XXL); gpio_clear(dev->p.rs); gpio_clear(dev->p.enable); - if (dev->p.rw != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.rw)) { gpio_clear(dev->p.rw); } /* put the LCD into 4 bit or 8 bit mode */ diff --git a/drivers/ili9341/ili9341.c b/drivers/ili9341/ili9341.c index a441fb2e7065..f00d9ec69820 100644 --- a/drivers/ili9341/ili9341.c +++ b/drivers/ili9341/ili9341.c @@ -96,7 +96,7 @@ int ili9341_init(ili9341_t *dev, const ili9341_params_t *params) return -1; } - if (dev->params->rst_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params->rst_pin)) { gpio_init(dev->params->rst_pin, GPIO_OUT); gpio_clear(dev->params->rst_pin); xtimer_usleep(120 * US_PER_MS); diff --git a/drivers/ina3221/alerts.c b/drivers/ina3221/alerts.c index 68af79396f19..1d60a7be6caa 100644 --- a/drivers/ina3221/alerts.c +++ b/drivers/ina3221/alerts.c @@ -29,7 +29,7 @@ int _ina3221_enable_alert(ina3221_t *dev, ina3221_alert_t alert, if (alert >= INA3221_NUM_ALERTS) { return -ERANGE; } - if (dev->params.upins.apins.alert_pins[alert] == GPIO_UNDEF) { + if (gpio_is_undef(dev->params.upins.apins.alert_pins[alert])) { return -ENOTSUP; } dev->alert_callbacks[alert] = cb; @@ -49,7 +49,7 @@ int _ina3221_disable_alert(ina3221_t *dev, ina3221_alert_t alert) if (alert >= INA3221_NUM_ALERTS) { return -ERANGE; } - if (dev->params.upins.apins.alert_pins[alert] == GPIO_UNDEF) { + if (gpio_is_undef(dev->params.upins.apins.alert_pins[alert])) { return -ENOTSUP; } gpio_irq_disable(dev->params.upins.apins.alert_pins[alert]); diff --git a/drivers/itg320x/itg320x.c b/drivers/itg320x/itg320x.c index d562c08b3b3c..4c5450cac48a 100644 --- a/drivers/itg320x/itg320x.c +++ b/drivers/itg320x/itg320x.c @@ -97,7 +97,7 @@ int itg320x_init(itg320x_t *dev, const itg320x_params_t *params) int itg320x_init_int(const itg320x_t *dev, itg320x_drdy_int_cb_t cb, void *arg) { assert(dev != NULL); - assert(dev->params.int_pin != GPIO_UNDEF); + assert(!gpio_is_undef(dev->params.int_pin)); DEBUG_DEV("cb=%p, arg=%p", dev, cb, arg); diff --git a/drivers/ltc4150/ltc4150.c b/drivers/ltc4150/ltc4150.c index ba9a44bb5b93..c6ff14c80fbb 100644 --- a/drivers/ltc4150/ltc4150.c +++ b/drivers/ltc4150/ltc4150.c @@ -33,7 +33,7 @@ static void pulse_cb(void *_dev) ltc4150_dir_t dir; ltc4150_dev_t *dev = _dev; - if ((dev->params.polarity == GPIO_UNDEF) || + if ((gpio_is_undef(dev->params.polarity)) || (!gpio_read(dev->params.polarity)) ) { dev->discharged++; @@ -66,7 +66,7 @@ int ltc4150_init(ltc4150_dev_t *dev, const ltc4150_params_t *params) memset(dev, 0, sizeof(ltc4150_dev_t)); dev->params = *params; - if (dev->params.shutdown != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.shutdown)) { /* Activate LTC4150 */ if (gpio_init(dev->params.shutdown, GPIO_OUT)) { DEBUG("[ltc4150] Failed to initialize shutdown pin"); @@ -75,7 +75,7 @@ int ltc4150_init(ltc4150_dev_t *dev, const ltc4150_params_t *params) gpio_set(dev->params.shutdown); } - if (dev->params.polarity != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.polarity)) { gpio_mode_t mode = (dev->params.flags & LTC4150_POL_EXT_PULL_UP) ? GPIO_IN : GPIO_IN_PU; if (gpio_init(dev->params.polarity, mode)) { @@ -132,7 +132,7 @@ int ltc4150_shutdown(ltc4150_dev_t *dev) gpio_irq_disable(dev->params.interrupt); - if (dev->params.shutdown != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.shutdown)) { gpio_clear(dev->params.shutdown); } diff --git a/drivers/ltc4150/ltc4150_saul.c b/drivers/ltc4150/ltc4150_saul.c index cfbfd588f9cb..41dcb7efd6ff 100644 --- a/drivers/ltc4150/ltc4150_saul.c +++ b/drivers/ltc4150/ltc4150_saul.c @@ -35,7 +35,7 @@ static int read_charge(const void *_dev, phydat_t *res) res->scale = -3; res->unit = UNIT_COULOMB; temp[0] = temp[2] - temp[1]; - int dim = (dev->params.polarity != GPIO_UNDEF) ? 3 : 1; + int dim = (!gpio_is_undef(dev->params.polarity)) ? 3 : 1; phydat_fit(res, temp, (unsigned)dim); return dim; } diff --git a/drivers/motor_driver/motor_driver.c b/drivers/motor_driver/motor_driver.c index eda143bf4c79..416be9d2734c 100644 --- a/drivers/motor_driver/motor_driver.c +++ b/drivers/motor_driver/motor_driver.c @@ -51,21 +51,21 @@ int motor_driver_init(motor_driver_t motor_driver) } for (uint8_t i = 0; i < motor_driver_conf->nb_motors; i++) { - if ((motor_driver_conf->motors[i].gpio_dir0 != GPIO_UNDEF) + if (!gpio_is_undef(motor_driver_conf->motors[i].gpio_dir0) && (gpio_init(motor_driver_conf->motors[i].gpio_dir0, GPIO_OUT))) { err = EIO; LOG_ERROR("gpio_dir0 init failed\n"); goto motor_init_err; } - if ((motor_driver_conf->motors[i].gpio_dir1_or_brake != GPIO_UNDEF) + if (!gpio_is_undef(motor_driver_conf->motors[i].gpio_dir1_or_brake) && (gpio_init(motor_driver_conf->motors[i].gpio_dir1_or_brake, GPIO_OUT))) { err = EIO; LOG_ERROR("gpio_dir1_or_brake init failed\n"); goto motor_init_err; } - if (motor_driver_conf->motors[i].gpio_enable != GPIO_UNDEF) { + if (!gpio_is_undef(motor_driver_conf->motors[i].gpio_enable)) { if (gpio_init(motor_driver_conf->motors[i].gpio_enable, GPIO_OUT)) { err = EIO; @@ -105,8 +105,8 @@ int motor_set(const motor_driver_t motor_driver, uint8_t motor_id, \ /* Two direction GPIO, handling brake */ if (motor_driver_conf->mode == MOTOR_DRIVER_2_DIRS) { - if ((dev->gpio_dir0 == GPIO_UNDEF) || \ - (dev->gpio_dir1_or_brake == GPIO_UNDEF)) { + if (gpio_is_undef(dev->gpio_dir0) || \ + gpio_is_undef(dev->gpio_dir1_or_brake)) { err = ENODEV; goto motor_set_err; } @@ -124,7 +124,7 @@ int motor_set(const motor_driver_t motor_driver, uint8_t motor_id, \ } /* Single direction GPIO */ else if (motor_driver_conf->mode == MOTOR_DRIVER_1_DIR) { - if (dev->gpio_dir0 == GPIO_UNDEF) { + if (gpio_is_undef(dev->gpio_dir0)) { err = ENODEV; goto motor_set_err; } @@ -141,8 +141,8 @@ int motor_set(const motor_driver_t motor_driver, uint8_t motor_id, \ } /* Single direction GPIO and brake GPIO */ else if (motor_driver_conf->mode == MOTOR_DRIVER_1_DIR_BRAKE) { - if ((dev->gpio_dir0 == GPIO_UNDEF) || \ - (dev->gpio_dir1_or_brake == GPIO_UNDEF)) { + if (gpio_is_undef(dev->gpio_dir0) || \ + gpio_is_undef(dev->gpio_dir1_or_brake)) { err = ENODEV; goto motor_set_err; } @@ -204,8 +204,8 @@ int motor_brake(const motor_driver_t motor_driver, uint8_t motor_id) /* Two direction GPIO, handling brake */ if (motor_driver_conf->mode == MOTOR_DRIVER_2_DIRS) { - if ((dev->gpio_dir0 == GPIO_UNDEF) || \ - (dev->gpio_dir1_or_brake == GPIO_UNDEF)) { + if (gpio_is_undef(dev->gpio_dir0) || \ + gpio_is_undef(dev->gpio_dir1_or_brake)) { err = ENODEV; goto motor_brake_err; } @@ -221,7 +221,7 @@ int motor_brake(const motor_driver_t motor_driver, uint8_t motor_id) } /* Single direction GPIO and brake GPIO */ else if (motor_driver_conf->mode == MOTOR_DRIVER_1_DIR_BRAKE) { - if (dev->gpio_dir1_or_brake == GPIO_UNDEF) { + if (gpio_is_undef(dev->gpio_dir1_or_brake)) { err = ENODEV; goto motor_brake_err; } @@ -256,7 +256,7 @@ void motor_enable(const motor_driver_t motor_driver, uint8_t motor_id) const motor_t *dev = &motor_driver_conf->motors[motor_id]; - assert(dev->gpio_enable != GPIO_UNDEF); + assert(!gpio_is_undef(dev->gpio_enable)); gpio_write(dev->gpio_enable, 1 ^ dev->gpio_enable_invert); } @@ -272,7 +272,7 @@ void motor_disable(const motor_driver_t motor_driver, uint8_t motor_id) const motor_t *dev = &motor_driver_conf->motors[motor_id]; - assert(dev->gpio_enable != GPIO_UNDEF); + assert(!gpio_is_undef(dev->gpio_enable)); gpio_write(dev->gpio_enable, dev->gpio_enable_invert); } diff --git a/drivers/pca9685/pca9685.c b/drivers/pca9685/pca9685.c index 6923a421f3a2..5f86fcbf4871 100644 --- a/drivers/pca9685/pca9685.c +++ b/drivers/pca9685/pca9685.c @@ -104,7 +104,7 @@ int pca9685_init(pca9685_t *dev, const pca9685_params_t *params) DEBUG_DEV("params=%p", dev, params); - if (dev->params.oe_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.oe_pin)) { /* init the pin an disable outputs first */ gpio_init(dev->params.oe_pin, GPIO_OUT); gpio_set(dev->params.oe_pin); @@ -232,7 +232,7 @@ void pca9685_pwm_poweron(pca9685_t *dev) EXEC(_update(dev, PCA9685_REG_MODE1, PCA9685_MODE1_RESTART, 1)); } - if (dev->params.oe_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.oe_pin)) { gpio_clear(dev->params.oe_pin); } @@ -244,7 +244,7 @@ void pca9685_pwm_poweroff(pca9685_t *dev) ASSERT_PARAM(dev != NULL); DEBUG_DEV("", dev); - if (dev->params.oe_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.oe_pin)) { gpio_set(dev->params.oe_pin); } diff --git a/drivers/periph_common/spi.c b/drivers/periph_common/spi.c index 2337be4c0b8f..7b981438e13b 100644 --- a/drivers/periph_common/spi.c +++ b/drivers/periph_common/spi.c @@ -33,7 +33,7 @@ int spi_init_cs(spi_t bus, spi_cs_t cs) if (bus >= SPI_NUMOF) { return SPI_NODEV; } - if ((cs == SPI_CS_UNDEF) || (cs == GPIO_UNDEF)) { + if (gpio_is_equal(cs, SPI_CS_UNDEF) || gpio_is_undef(cs)) { return SPI_NOCS; } diff --git a/drivers/ph_oem/ph_oem.c b/drivers/ph_oem/ph_oem.c index 14f2d6f40032..d57bb8e4b7a4 100644 --- a/drivers/ph_oem/ph_oem.c +++ b/drivers/ph_oem/ph_oem.c @@ -181,7 +181,7 @@ static int _set_interrupt_pin(const ph_oem_t *dev) int ph_oem_enable_interrupt(ph_oem_t *dev, ph_oem_interrupt_pin_cb_t cb, void *arg) { - if (dev->params.interrupt_pin == GPIO_UNDEF) { + if (gpio_is_undef(dev->params.interrupt_pin)) { return PH_OEM_INTERRUPT_GPIO_UNDEF; } @@ -292,7 +292,7 @@ int ph_oem_start_new_reading(const ph_oem_t *dev) /* if interrupt pin is undefined, poll till new reading was taken and stop * device form taking further readings */ - if (dev->params.interrupt_pin == GPIO_UNDEF) { + if (gpio_is_undef(dev->params.interrupt_pin)) { int result = _new_reading_available(dev); if (result < 0) { return result; diff --git a/drivers/ph_oem/ph_oem_saul.c b/drivers/ph_oem/ph_oem_saul.c index bb98cc60f10f..279bf3b1bdfe 100644 --- a/drivers/ph_oem/ph_oem_saul.c +++ b/drivers/ph_oem/ph_oem_saul.c @@ -30,7 +30,7 @@ static int read_ph(const void *dev, phydat_t *res) const ph_oem_t *mydev = dev; uint16_t ph_reading; - if (mydev->params.interrupt_pin != GPIO_UNDEF) { + if (!gpio_is_undef(mydev->params.interrupt_pin)) { puts("interrupt pin not supported with SAUL yet"); return -ENOTSUP; } diff --git a/drivers/qmc5883l/qmc5883l.c b/drivers/qmc5883l/qmc5883l.c index ecb4f1a45fbc..99e5877e3749 100644 --- a/drivers/qmc5883l/qmc5883l.c +++ b/drivers/qmc5883l/qmc5883l.c @@ -178,7 +178,7 @@ int qmc5883l_init_int(const qmc5883l_t *dev, gpio_cb_t cb, void *arg) assert(dev); assert(cb); - if (dev->pin_drdy == GPIO_UNDEF) { + if (gpio_is_undef(dev->pin_drdy)) { return QMC5883L_NOCFG; } if (gpio_init_int(dev->pin_drdy, GPIO_IN, GPIO_RISING, cb, arg) != 0) { diff --git a/drivers/rn2xx3/rn2xx3.c b/drivers/rn2xx3/rn2xx3.c index ce0375677f28..a7578c831cad 100644 --- a/drivers/rn2xx3/rn2xx3.c +++ b/drivers/rn2xx3/rn2xx3.c @@ -144,7 +144,7 @@ void rn2xx3_setup(rn2xx3_t *dev, const rn2xx3_params_t *params) dev->p = *params; /* initialize pins and perform hardware reset */ - if (dev->p.pin_reset != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.pin_reset)) { gpio_init(dev->p.pin_reset, GPIO_OUT); gpio_set(dev->p.pin_reset); } @@ -166,7 +166,7 @@ int rn2xx3_init(rn2xx3_t *dev) } /* if reset pin is connected, do a hardware reset */ - if (dev->p.pin_reset != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.pin_reset)) { gpio_clear(dev->p.pin_reset); xtimer_usleep(RESET_DELAY); gpio_set(dev->p.pin_reset); diff --git a/drivers/sdcard_spi/sdcard_spi.c b/drivers/sdcard_spi/sdcard_spi.c index d650d749cf4f..426e08377eb7 100644 --- a/drivers/sdcard_spi/sdcard_spi.c +++ b/drivers/sdcard_spi/sdcard_spi.c @@ -88,7 +88,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta (gpio_init(card->params.clk, GPIO_OUT) == 0) && (gpio_init(card->params.cs, GPIO_OUT) == 0) && (gpio_init(card->params.miso, GPIO_IN_PU) == 0) && - ( (card->params.power == GPIO_UNDEF) || + ( (gpio_is_undef(card->params.power)) || (gpio_init(card->params.power, GPIO_OUT) == 0)) ) { DEBUG("gpio_init(): [OK]\n"); @@ -101,7 +101,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta case SD_INIT_SPI_POWER_SEQ: DEBUG("SD_INIT_SPI_POWER_SEQ\n"); - if (card->params.power != GPIO_UNDEF) { + if (!gpio_is_undef(card->params.power)) { gpio_write(card->params.power, card->params.power_act_high); xtimer_usleep(SD_CARD_WAIT_AFTER_POWER_UP_US); } diff --git a/drivers/sds011/sds011.c b/drivers/sds011/sds011.c index 06da9d6f6c31..3ae973d9a7e6 100644 --- a/drivers/sds011/sds011.c +++ b/drivers/sds011/sds011.c @@ -192,7 +192,7 @@ int sds011_init(sds011_t *dev, const sds011_params_t *params) { assert((dev != NULL) && (params != NULL) && (params->uart < UART_NUMOF)); - if ((params->pwr_pin != GPIO_UNDEF) && + if ((!gpio_is_undef(params->pwr_pin)) && (gpio_init(params->pwr_pin, GPIO_OUT) != 0)) { return SDS011_ERROR; } @@ -230,7 +230,7 @@ int sds011_register_callback(sds011_t *dev, sds011_callback_t cb, void *ctx) void sds011_power_on(const sds011_t *dev) { assert(dev != NULL); - if(dev->params.pwr_pin != GPIO_UNDEF) { + if(!gpio_is_undef(dev->params.pwr_pin)) { gpio_write(dev->params.pwr_pin, dev->params.pwr_ah); } } @@ -238,7 +238,7 @@ void sds011_power_on(const sds011_t *dev) void sds011_power_off(const sds011_t *dev) { assert(dev != NULL); - if(dev->params.pwr_pin != GPIO_UNDEF) { + if(!gpio_is_undef(dev->params.pwr_pin)) { gpio_write(dev->params.pwr_pin, !dev->params.pwr_ah); } } diff --git a/drivers/soft_spi/soft_spi.c b/drivers/soft_spi/soft_spi.c index 26a54dc01725..a109bba72588 100644 --- a/drivers/soft_spi/soft_spi.c +++ b/drivers/soft_spi/soft_spi.c @@ -63,21 +63,22 @@ void soft_spi_init_pins(soft_spi_t bus) assert(soft_spi_bus_is_valid(bus)); /* check that miso is not mosi is not clk*/ - assert(soft_spi_config[bus].mosi_pin != soft_spi_config[bus].miso_pin); - assert(soft_spi_config[bus].mosi_pin != soft_spi_config[bus].clk_pin); - assert(soft_spi_config[bus].miso_pin != soft_spi_config[bus].clk_pin); + assert(!gpio_is_equal(soft_spi_config[bus].mosi_pin, soft_spi_config[bus].miso_pin)); + assert(!gpio_is_equal(soft_spi_config[bus].mosi_pin, soft_spi_config[bus].clk_pin)); + assert(!gpio_is_equal(soft_spi_config[bus].miso_pin, soft_spi_config[bus].clk_pin)); /* mandatory pins */ - assert((GPIO_UNDEF != soft_spi_config[bus].mosi_pin) || (GPIO_UNDEF != soft_spi_config[bus].miso_pin)); - assert(GPIO_UNDEF != soft_spi_config[bus].clk_pin); + assert(!gpio_is_undef(soft_spi_config[bus].mosi_pin) || + !gpio_is_undef(soft_spi_config[bus].miso_pin)); + assert(!gpio_is_undef(soft_spi_config[bus].clk_pin)); /* initialize clock pin */ gpio_init(soft_spi_config[bus].clk_pin, GPIO_OUT); /* initialize optional pins */ - if (GPIO_UNDEF != soft_spi_config[bus].mosi_pin) { + if (!gpio_is_undef(soft_spi_config[bus].mosi_pin)) { gpio_init(soft_spi_config[bus].mosi_pin, GPIO_OUT); gpio_clear(soft_spi_config[bus].mosi_pin); } - if (GPIO_UNDEF != soft_spi_config[bus].miso_pin) { + if (!gpio_is_undef(soft_spi_config[bus].miso_pin)) { gpio_init(soft_spi_config[bus].mosi_pin, GPIO_IN); } } @@ -90,7 +91,7 @@ int soft_spi_init_cs(soft_spi_t bus, soft_spi_cs_t cs) return SOFT_SPI_NODEV; } - if ((cs != GPIO_UNDEF) && (cs != SOFT_SPI_CS_UNDEF)) { + if (!gpio_is_undef(cs) && !gpio_is_equal(cs, SOFT_SPI_CS_UNDEF)) { DEBUG("Soft SPI set user CS line\n"); gpio_init(cs, GPIO_OUT); gpio_set(cs); @@ -174,14 +175,14 @@ uint8_t soft_spi_transfer_byte(soft_spi_t bus, soft_spi_cs_t cs, bool cont, uint uint8_t retval = 0; /* activate the given chip select line */ - if ((cs != GPIO_UNDEF) && (cs != SOFT_SPI_CS_UNDEF)) { + if (!gpio_is_undef(cs) && !gpio_is_equal(cs, SOFT_SPI_CS_UNDEF)) { gpio_clear((gpio_t)cs); } retval = _transfer_one_byte(bus, out); if (!cont) { - if ((cs != GPIO_UNDEF) && (cs != SOFT_SPI_CS_UNDEF)) { + if (!gpio_is_undef(cs) && !gpio_is_equal(cs, SOFT_SPI_CS_UNDEF)) { gpio_set((gpio_t)cs); } } diff --git a/drivers/sx127x/sx127x.c b/drivers/sx127x/sx127x.c index 91047e1b7003..c8bc530a1760 100644 --- a/drivers/sx127x/sx127x.c +++ b/drivers/sx127x/sx127x.c @@ -104,7 +104,7 @@ int sx127x_reset(const sx127x_t *dev) * 2. Set NReset in Hi-Z state * 3. Wait at least 5 milliseconds */ - if (dev->params.reset_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.reset_pin)) { gpio_init(dev->params.reset_pin, GPIO_OUT); /* set reset pin to the state that triggers manual reset */ @@ -137,7 +137,7 @@ int sx127x_init(sx127x_t *dev) _init_timers(dev); - if (dev->params.reset_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.reset_pin)) { /* reset pin should be left floating during POR */ gpio_init(dev->params.reset_pin, GPIO_IN); @@ -258,7 +258,7 @@ static int _init_gpios(sx127x_t *dev) int res; /* Check if DIO0 pin is defined */ - if (dev->params.dio0_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.dio0_pin)) { res = gpio_init_int(dev->params.dio0_pin, SX127X_DIO_PULL_MODE, GPIO_RISING, sx127x_on_dio0_isr, dev); if (res < 0) { @@ -273,7 +273,7 @@ static int _init_gpios(sx127x_t *dev) } /* Check if DIO1 pin is defined */ - if (dev->params.dio1_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.dio1_pin)) { res = gpio_init_int(dev->params.dio1_pin, SX127X_DIO_PULL_MODE, GPIO_RISING, sx127x_on_dio1_isr, dev); if (res < 0) { @@ -283,7 +283,7 @@ static int _init_gpios(sx127x_t *dev) } /* check if DIO2 pin is defined */ - if (dev->params.dio2_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.dio2_pin)) { res = gpio_init_int(dev->params.dio2_pin, SX127X_DIO_PULL_MODE, GPIO_RISING, sx127x_on_dio2_isr, dev); if (res < 0) { @@ -293,7 +293,7 @@ static int _init_gpios(sx127x_t *dev) } /* check if DIO3 pin is defined */ - if (dev->params.dio3_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.dio3_pin)) { res = gpio_init_int(dev->params.dio3_pin, SX127X_DIO_PULL_MODE, GPIO_RISING, sx127x_on_dio3_isr, dev); if (res < 0) { diff --git a/drivers/tps6274x/tps6274x.c b/drivers/tps6274x/tps6274x.c index 703d55e2bdc4..5ca46b5ef91d 100644 --- a/drivers/tps6274x/tps6274x.c +++ b/drivers/tps6274x/tps6274x.c @@ -31,14 +31,14 @@ int tps6274x_init(tps6274x_t *dev, const tps6274x_params_t *params) dev->params = *params; for (uint8_t i = 0; i < 4; i++) { - if (dev->params.vsel[i] != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.vsel[i])) { ret = gpio_init(dev->params.vsel[i], GPIO_OUT); if(ret < 0) { return TPS6274X_ERR_INIT; } } } - if (dev->params.ctrl_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.ctrl_pin)) { ret = gpio_init(dev->params.ctrl_pin, GPIO_OUT); if(ret < 0) { return TPS6274X_ERR_INIT; @@ -58,7 +58,7 @@ uint16_t tps6274x_switch_voltage(tps6274x_t *dev, uint16_t voltage) uint8_t vsel = (voltage - 1800) / 100; uint8_t vsel_set = 0; for (uint8_t i = 0; i < 4; i++) { - if (dev->params.vsel[i] != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.vsel[i])) { gpio_write(dev->params.vsel[i], (vsel & (0x01 << i))); /* mark pins that could and had to be set */ vsel_set |= vsel & (1 << i); @@ -75,7 +75,7 @@ uint16_t tps6274x_switch_voltage(tps6274x_t *dev, uint16_t voltage) void tps6274x_load_ctrl(tps6274x_t *dev, int status) { - if (dev->params.ctrl_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->params.ctrl_pin)) { gpio_write(dev->params.ctrl_pin, status); } #if ENABLE_DEBUG diff --git a/drivers/xbee/xbee.c b/drivers/xbee/xbee.c index d5e6c403e703..8fad8be981e2 100644 --- a/drivers/xbee/xbee.c +++ b/drivers/xbee/xbee.c @@ -486,11 +486,11 @@ void xbee_setup(xbee_t *dev, const xbee_params_t *params) dev->p = *params; /* initialize pins */ - if (dev->p.pin_reset != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.pin_reset)) { gpio_init(dev->p.pin_reset, GPIO_OUT); gpio_set(dev->p.pin_reset); } - if (dev->p.pin_sleep != GPIO_UNDEF) { + if (!gpio_is_undef(dev->p.pin_sleep)) { gpio_init(dev->p.pin_sleep, GPIO_OUT); gpio_clear(dev->p.pin_sleep); } @@ -588,7 +588,7 @@ int xbee_init(netdev_t *dev) return -ENXIO; } /* if reset pin is connected, do a hardware reset */ - if (xbee->p.pin_reset != GPIO_UNDEF) { + if (!gpio_is_undef(xbee->p.pin_reset)) { gpio_clear(xbee->p.pin_reset); xtimer_usleep(RESET_DELAY); gpio_set(xbee->p.pin_reset); From e79b411bc060065d86db286561c8ab96ac410322 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 12:46:37 +0100 Subject: [PATCH 03/17] pkg: use inline function for GPIO comparison The extensible GPIO API requires the comparison of structured GPIO types. This means that inline functions must be used instead of direct comparisons. For the migration process, packages must first be changed so that they use the inline comparison functions. --- pkg/u8g2/src/csrc/u8x8_riotos.c | 12 ++++++------ pkg/ucglib/src/csrc/ucg_riotos.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/u8g2/src/csrc/u8x8_riotos.c b/pkg/u8g2/src/csrc/u8x8_riotos.c index a7446a39a1d0..2250c4dd5594 100644 --- a/pkg/u8g2/src/csrc/u8x8_riotos.c +++ b/pkg/u8g2/src/csrc/u8x8_riotos.c @@ -70,15 +70,15 @@ static void _enable_pins(const u8x8_riotos_t *u8x8_riot_ptr) return; } - if (u8x8_riot_ptr->pin_cs != GPIO_UNDEF) { + if (!gpio_is_undef(u8x8_riot_ptr->pin_cs)) { gpio_init(u8x8_riot_ptr->pin_cs, GPIO_OUT); } - if (u8x8_riot_ptr->pin_dc != GPIO_UNDEF) { + if (!gpio_is_undef(u8x8_riot_ptr->pin_dc)) { gpio_init(u8x8_riot_ptr->pin_dc, GPIO_OUT); } - if (u8x8_riot_ptr->pin_reset != GPIO_UNDEF) { + if (!gpio_is_undef(u8x8_riot_ptr->pin_reset)) { gpio_init(u8x8_riot_ptr->pin_reset, GPIO_OUT); } } @@ -106,17 +106,17 @@ uint8_t u8x8_gpio_and_delay_riotos(u8x8_t *u8g2, uint8_t msg, uint8_t arg_int, v xtimer_nanosleep(arg_int * 100); break; case U8X8_MSG_GPIO_CS: - if (u8x8_riot_ptr != NULL && u8x8_riot_ptr->pin_cs != GPIO_UNDEF) { + if (u8x8_riot_ptr != NULL && !gpio_is_undef(u8x8_riot_ptr->pin_cs)) { gpio_write(u8x8_riot_ptr->pin_cs, arg_int); } break; case U8X8_MSG_GPIO_DC: - if (u8x8_riot_ptr != NULL && u8x8_riot_ptr->pin_dc != GPIO_UNDEF) { + if (u8x8_riot_ptr != NULL && !gpio_is_undef(u8x8_riot_ptr->pin_dc)) { gpio_write(u8x8_riot_ptr->pin_dc, arg_int); } break; case U8X8_MSG_GPIO_RESET: - if (u8x8_riot_ptr != NULL && u8x8_riot_ptr->pin_reset != GPIO_UNDEF) { + if (u8x8_riot_ptr != NULL && !gpio_is_undef(u8x8_riot_ptr->pin_reset)) { gpio_write(u8x8_riot_ptr->pin_reset, arg_int); } break; diff --git a/pkg/ucglib/src/csrc/ucg_riotos.c b/pkg/ucglib/src/csrc/ucg_riotos.c index bf10f22e754a..38ac98ca828f 100644 --- a/pkg/ucglib/src/csrc/ucg_riotos.c +++ b/pkg/ucglib/src/csrc/ucg_riotos.c @@ -54,7 +54,7 @@ static void ucg_enable_pins(gpio_t *pins, uint32_t pins_enabled) for (i = 0; i < 32; i++) { if (pins_enabled & ((uint32_t)1 << i)) { - if (pins[i] != GPIO_UNDEF) { + if (!gpio_is_undef(pins[i])) { if (i < UCG_PIN_COUNT) { gpio_init(pins[i], GPIO_OUT); } From 7ae64bc4e8f4d6ca7e69b3fcafc9dde2facbef31 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 12:48:48 +0100 Subject: [PATCH 04/17] tests: use inline functions for GPIO comparison The extensible GPIO API requires the comparison of structured GPIO types. This means that inline functions must be used instead of direct comparisons. For the migration process, tests must first be changed so that they use the inline comparison functions. --- tests/driver_ph_oem/main.c | 6 +++--- tests/driver_qmc5883l/main.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/driver_ph_oem/main.c b/tests/driver_ph_oem/main.c index 0bc663051ae3..b0bea3dc53de 100644 --- a/tests/driver_ph_oem/main.c +++ b/tests/driver_ph_oem/main.c @@ -224,7 +224,7 @@ int main(void) } } - if (dev.params.interrupt_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev.params.interrupt_pin)) { /* Setting up and enabling the interrupt pin of the pH OEM */ printf("Enabling interrupt pin... "); if (ph_oem_enable_interrupt(&dev, interrupt_pin_callback, @@ -259,7 +259,7 @@ int main(void) /* blocking for ~420ms till reading is done if no interrupt pin defined */ ph_oem_start_new_reading(&dev); - if (dev.params.interrupt_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev.params.interrupt_pin)) { /* when interrupt is defined, wait for the IRQ to fire and * the event to be posted, so the "reading_available_event_callback" * can be executed after */ @@ -267,7 +267,7 @@ int main(void) ev->handler(ev); } - if (dev.params.interrupt_pin == GPIO_UNDEF) { + if (gpio_is_undef(dev.params.interrupt_pin)) { if (ph_oem_read_ph(&dev, &data) == PH_OEM_OK) { printf("pH value raw: %d\n", data); diff --git a/tests/driver_qmc5883l/main.c b/tests/driver_qmc5883l/main.c index 966c279f3983..b3ab299bc36f 100644 --- a/tests/driver_qmc5883l/main.c +++ b/tests/driver_qmc5883l/main.c @@ -97,7 +97,7 @@ int main(void) } #ifdef MODULE_QMC5883L_INT printf("Mode: "); - if (qmc5883l_params[0].pin_drdy != GPIO_UNDEF) { + if (!gpio_is_undef(qmc5883l_params[0].pin_drdy)) { puts("interrupt driven"); } else { @@ -121,7 +121,7 @@ int main(void) #ifdef MODULE_QMC5883L_INT /* safe a reference to the main thread TCB so we can wait for flags */ - if (qmc5883l_params[0].pin_drdy != GPIO_UNDEF) { + if (!gpio_is_undef(qmc5883l_params[0].pin_drdy)) { _tmain = (thread_t *)thread_get(thread_getpid()); if (qmc5883l_init_int(&_dev, _on_drdy, NULL) != QMC5883L_OK) { From 97ebe6b41fa52f51df0b287b6c5449007ed5fa55 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 5 Dec 2019 11:40:22 +0100 Subject: [PATCH 05/17] drivers/periph: new extendable GPIO API --- Makefile.dep | 5 + drivers/include/periph/gpio.h | 28 +- drivers/include/periph/gpio_ext.h | 774 ++++++++++++++++++++++++++++++ drivers/periph_common/gpio.c | 72 +++ makefiles/pseudomodules.inc.mk | 6 + 5 files changed, 881 insertions(+), 4 deletions(-) create mode 100644 drivers/include/periph/gpio_ext.h create mode 100644 drivers/periph_common/gpio.c diff --git a/Makefile.dep b/Makefile.dep index a9dd641507fd..14b4c2d42a30 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -1011,6 +1011,11 @@ ifneq (,$(filter periph_gpio_irq,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio endif +# Enable optionally periph_gpio_ext when the MCU supports it as feature +ifneq (,$(filter periph_gpio,$(USEMODULE))) + FEATURES_OPTIONAL += periph_gpio_ext +endif + ifneq (,$(filter devfs_hwrng,$(USEMODULE))) FEATURES_REQUIRED += periph_hwrng endif diff --git a/drivers/include/periph/gpio.h b/drivers/include/periph/gpio.h index 852c1f2236a9..ee57430635d1 100644 --- a/drivers/include/periph/gpio.h +++ b/drivers/include/periph/gpio.h @@ -1,16 +1,35 @@ /* * Copyright (C) 2015 Freie Universität Berlin + * 2020 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ +#ifndef PERIPH_GPIO_H +#define PERIPH_GPIO_H + +#ifdef MODULE_PERIPH_GPIO_EXT + +#include "periph/gpio_ext.h" + +#else /* MODULE_PERIPH_GPIO_EXT */ + /** + * @anchor drivers_periph_gpio GPIO * @defgroup drivers_periph_gpio GPIO * @ingroup drivers_periph * @brief Low-level GPIO peripheral driver * + * @note This is the legacy GPIO API. It will be removed once all platforms + * implement the new GPIO API which allows to implement the API for any kind + * of GPIO hardware. The new GPIO API is compatible with this legacy API. + * @warning The scalar GPIO pin type `gpio_t` is deprecated and will be + * replaced by a structured GPIO pin type in the new GPIO API. Therefore, + * don't use the direct comparison of GPIO pins anymore. Instead, use the + * inline comparison functions @ref gpio_is_equal and @ref gpio_is_undef. + * * This is a basic GPIO (General-purpose input/output) interface to allow * platform independent access to a MCU's input/output pins. This interface is * intentionally designed to be as simple as possible, to allow for easy @@ -72,9 +91,6 @@ * @author Hauke Petersen */ -#ifndef PERIPH_GPIO_H -#define PERIPH_GPIO_H - #include #include "periph_cpu.h" @@ -276,9 +292,13 @@ static inline int gpio_is_undef(gpio_t gpio) return (gpio == GPIO_UNDEF); } +/** @} */ + #ifdef __cplusplus } #endif -#endif /* PERIPH_GPIO_H */ /** @} */ + +#endif /* MODULE_PERIPH_GPIO_EXT */ +#endif /* PERIPH_GPIO_H */ diff --git a/drivers/include/periph/gpio_ext.h b/drivers/include/periph/gpio_ext.h new file mode 100644 index 000000000000..0575eed9bb93 --- /dev/null +++ b/drivers/include/periph/gpio_ext.h @@ -0,0 +1,774 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#ifndef PERIPH_GPIO_EXT_H +#define PERIPH_GPIO_EXT_H + +/** + * @defgroup drivers_periph_gpio_ext GPIO + * @ingroup drivers_periph + * @brief GPIO peripheral driver + * + * @note This is the new GPIO API which allows consistent access to any kind + * of GPIO hardware. The GPIO ports of the MCU can thus be extended with GPIO + * extenders and used in the same way. The new GPIO API defines a pin-oriented + * high-level API and a port-oriented low-level API. The high-level API is + * compatible with the legacy GPIO API (@ref drivers_periph_gpio). + * However, it uses the functions of the new low-level API, which must also be + * implemented by the MCU. The new GPIO API can therefore only be used if + * the MCU implements the new low-level API. + * + * The interface provides capabilities to initialize a pin as output-, + * input- and interrupt pin. With the API you can basically set/clear/toggle + * the digital signal at the hardware pin when in output mode. Configured as + * input you can read a digital value that is being applied to the pin + * externally. When initializing an external interrupt pin, you can register + * a callback function that is executed in interrupt context once the interrupt + * condition applies to the pin. Usually you can react to rising or falling + * signal flanks (or both). + * + * In addition the API provides to set standard input/output circuit modes + * such as e.g. internal push-pull configurations. + * + * All modern micro controllers organize their GPIOs in some form of ports, + * often named `PA`, `PB`, `PC`..., or `P0`, `P1`, `P2`..., or similar. Each + * of these ports is then assigned a number of pins, often 8, 16, or 32. A + * hardware pin can thus be described by its port/pin tuple. To access a pin, + * the #GPIO_PIN(port, pin) macro should be used. For example: If your + * platform has a pin PB22, it will be port=1 and pin=22. + * + * ## Implementation + * + * The GPIO interface is divided into a low-level API and a high-level API. + * + * ### Low-Level API + * + * The low-level API provides functions for port-oriented access to the GPIOs. + * It has to be implemented by every hardware component that provides GPIOs. + * The functions of the low-level API are called via a driver of type + * #gpio_driver_t. This driver contains references to these functions of the + * respective hardware component. + * + * Each MCU has to implement this low-level API, see #gpio_driver_t. The MCU + * functions of the low-level API must follow a special naming scheme where + * all function names have the prefix `gpio_cpu_*`. These functions are used + * for the #gpio_cpu_driver, which provides the access to the GPIO ports of + * the MCU. + * + * ### High Level API + * + * The high-level API is used by the application and provides a pin-oriented + * access to the GPIO pins. It uses the functions of the low-level API for + * this purpose. + * + * ### Ports and Port Table + * + * All existing ports of the MCU and the optional GPIO extenders are held + * in a port table #gpio_ports. This table is created automatically from the + * #GPIO_CPU_PORTS and `GPIO_EXT_PORTS` macros. The entries of the port table + * are of type #gpio_port_table_t and contain a port definition of type + * #gpio_port_t. The port definition can be either + * + * - the register address of a MCU port, + * - the address of a device structure of a GPIO extender device or + * - the port number that corresponds to its index in the port table. + * + * The respective implementation of the low-level API determines which + * representation of a port is used. + * + * If GPIO extenders are enabled with module `extend_gpio`, each port table + * entry also includes a reference to a driver of type #gpio_driver_t driver. + * The driver contains the references to the low-level GPIO API functions of + * the respective device and enables access to the GPIO port. In case of CPU + * ports, the driver is set to #gpio_cpu_driver. + * + * ### GPIOs + * + * GPIO pins are of type #gpio_t and are defined as a tuple of the port + * and the pin number of this port. The port is just the address of the + * corresponding entry in the port table #gpio_ports. + * + * GPIOs of type #gpio_t are defined with the #GPIO_PIN(port,pin) macro. + * The #GPIO_UNDEF macro defines a GPIO pin as undefined. + * + * The #GPIO_PORT(gpio) macro can be used to get the corresponding port of + * type #gpio_port_t from the port table for a given GPIO pin of type @ref + * gpio_t. + * + * ### GPIO extender + * + * The use of GPIO extenders is enabled by the `extend_gpio` module. If + * the `extend_gpio` module is enabled, either the board definition or the + * application must provide the configuration of the GPIO extenders in file + * `gpio_ext_conf.h`. For this purpose the macro `GPIO_EXT_PORTS` has to be + * defined. + * + * For example, if a GPIO extender device driver implements the low-level + * functions `foo_gpio_*(foo_gpio_ext_t* dev, ...)`, it can be integrated by + * defining the following configuration + * ``` + * extern foo_gpio_ext_t foo_ext; + * extern foo_gpio_driver_t foo_ext_driver; + * + * #define GPIO_EXT_PORTS \ + * { .port.dev = &foo_ext, .driver = &foo_ext_driver }, \ + * ``` + * See file `tests/periph_gpio_ext` as an example for defining GPIO extender + * configurations. + * + * ## (Low-) Power Implications + * + * On almost all platforms, we can only control the peripheral power state of + * full ports (i.e. groups of pins), but not for single GPIO pins. Together + * with CPU specific alternate function handling for pins used by other + * peripheral drivers, this can make it quite complex to keep track of pins + * that are currently used at a certain moment. To simplify the implementations + * (and ease the memory consumption), we expect ports to be powered on (e.g. + * through peripheral clock gating) when first used and never be powered off + * again. + * + * GPIO driver implementations **should** power on the corresponding port during + * gpio_init() and gpio_init_int(). + * + * For external interrupts to work, some platforms may need to block certain + * power modes (although this is not very likely). This should be done during + * gpio_init_int(). + * + * @{ + * @file + * @brief Low-level GPIO peripheral driver interface definitions + * + * @author Hauke Petersen + * @author Gunar Schorcht + */ + +#include + +#include "gpio_arch.h" /* include architecture specific GPIO definitions */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_GPIO_PIN_T +/** + * @brief GPIO pin number type + */ +typedef uint_fast8_t gpio_pin_t; +#endif + +/** + * @brief Register address type for GPIO ports of the MCU + */ +#ifndef HAVE_GPIO_REG_T +typedef uint32_t gpio_reg_t; +#endif + +/** + * @brief GPIO mask type that corresponds to the supported GPIO port width + * + * This type is used to mask the pins of a GPIO port in various low-level GPIO + * functions. Its size must therefore be the maximum width of all different + * GPIO ports used in the system. For this purpose, each component that + * provides GPIO ports must activate the corresponding pseudomodule + * `gpio_mask_8bit`, `gpio_mask_16bit` or `gpio_mask_32bit` that + * specifies the width of its GPIO ports. + */ +#if defined(MODULE_GPIO_MASK_32BIT) +typedef uint32_t gpio_mask_t; +#elif defined(MODULE_GPIO_MASK_16BIT) +typedef uint16_t gpio_mask_t; +#else +typedef uint8_t gpio_mask_t; +#endif + +/** + * @brief Convert (port, pin) tuple to gpio_t structure + */ +#define GPIO_PIN(x,y) ((gpio_t){ .port = &gpio_ports[x], .pin = y }) + +/** + * @brief Convert GPIO pin to port structure of type gpio_port_t + */ +#define GPIO_PORT(x) (x.port->port) + +/** + * @brief GPIO pin not defined + */ +#define GPIO_PIN_UNDEF ((gpio_pin_t)(UINT_FAST8_MAX)) + +/** + * @brief GPIO not defined + */ +#define GPIO_UNDEF ((gpio_t){ .port = NULL, .pin = GPIO_PIN_UNDEF }) + +#if MODULE_EXTEND_GPIO || DOXYGEN +/** + * @brief Default initializer for driver in gpio_port_table_t + */ +#define GPIO_CPU_PORT(x) ((gpio_port_table_t){ .port.reg = (gpio_reg_t)x, \ + .driver = &gpio_cpu_driver }) +#else +#define GPIO_CPU_PORT(x) ((gpio_port_table_t){ .port.reg = (gpio_reg_t)x }) +#endif + +/** + * @brief Available GPIO modes + * + * Generally, a GPIO can be configured to be input or output. In output mode, a + * pin can further be put into push-pull or open drain configuration. Though + * this is supported by most platforms, this is not always the case, so driver + * implementations may return an error code if a mode is not supported. + */ +#ifndef HAVE_GPIO_MODE_T +typedef enum { + GPIO_IN , /**< configure as input without pull resistor */ + GPIO_IN_PD, /**< configure as input with pull-down resistor */ + GPIO_IN_PU, /**< configure as input with pull-up resistor */ + GPIO_OUT, /**< configure as output in push-pull mode */ + GPIO_OD, /**< configure as output in open-drain mode without + pull resistor */ + GPIO_OD_PU /**< configure as output in open-drain mode with + pull resistor enabled */ +} gpio_mode_t; +#endif + +/** + * @brief Definition of possible active flanks for external interrupt mode + */ +#ifndef HAVE_GPIO_FLANK_T +typedef enum { + GPIO_FALLING = 0, /**< emit interrupt on falling flank */ + GPIO_RISING = 1, /**< emit interrupt on rising flank */ + GPIO_BOTH = 2 /**< emit interrupt on both flanks */ +} gpio_flank_t; +#endif + +/** + * @brief Signature of event callback functions triggered from interrupts + * + * @param[in] arg optional context for the callback + */ +typedef void (*gpio_cb_t)(void *arg); + +/** + * @brief Default interrupt context for GPIO pins + */ +#ifndef HAVE_GPIO_ISR_CTX_T +typedef struct { + gpio_cb_t cb; /**< interrupt callback */ + void *arg; /**< optional argument */ +} gpio_isr_ctx_t; +#endif + +/** + * @brief GPIO port type + * + * A GPIO port allows the access to a number of GPIO pins. It can be either + * + * - the base register address of a MCU GPIO port if all MCU GPIO ports + * follow a consistent address scheme, + * - the port number that corresponds to the index of the entry in the GPIO port + * table #gpio_ports, or + * - the pointer to a device of any type which provides the GPIO pin, + * e.g. a GPIO extender. + * + * Which representation is used is determined by the low-level implementation. + */ +typedef union { + gpio_reg_t reg; /**< register address of a MCU GPIO port */ + uintptr_t num; /**< port number (index in port table #gpio_ports) */ + void* dev; /**< pointer to a device that provides the GPIO port */ +} gpio_port_t; + +/** + * @name Low-level GPIO API + * + * The following function prototypes define the low-level GPIO API + * that have to be implemented by the driver of a GPIO hardware + * device. They are used by high-level GPIO functions `gpio_*`. + * + * The GPIO device driver for a GPIO port contains references to these + * low-level functions. + * + * @note Functions of the low-level API should only be called directly if + * several pins of a GPIO port are to be changed simultaneously using the + * definition of GPIO pin masks of type #gpio_mask_t. + * + * @{ + */ + +/** + * @brief Initialize the given pin as general purpose input or output + * + * @param[in] port port of the GPIO pin to initialize + * @param[in] pin number of the GPIO pin to initialize + * @param[in] mode mode of the pin, see #gpio_mode_t + * + * @return 0 on success + * @return -1 on error + * + * @see gpio_init + */ +typedef int (*gpio_dev_init_t)(gpio_port_t port, uint8_t pin, gpio_mode_t mode); + +#if MODULE_PERIPH_GPIO_IRQ || DOXYGEN + +/** + * @brief Initialize a GPIO pin for external interrupt usage + * + * @param[in] port port of the GPIO pin to initialize + * @param[in] pin number of the GPIO pin to initialize + * @param[in] mode mode of the pin, see #gpio_mode_t + * @param[in] flank define the active flank(s) + * @param[in] cb callback that is called from interrupt context + * @param[in] arg optional argument passed to the callback + * + * @return 0 on success + * @return -1 on error + * + * @see gpio_init_int + */ +typedef int (*gpio_dev_init_int_t)(gpio_port_t port, uint8_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg); + +/** + * @brief Enable GPIO pin interrupt if configured as interrupt source + * + * @param[in] port port of the GPIO pin + * @param[in] pin number of the GPIO pin + * + * @see gpio_irq_enable + */ +typedef void (*gpio_dev_irq_enable_t)(gpio_port_t port, uint8_t pin); + +/** + * @brief Disable GPIO pin interrupt if configured as interrupt source + * + * @param[in] port port of the GPIO pin + * @param[in] pin number of the GPIO pin + * + * @see gpio_irq_disable + */ +typedef void (*gpio_dev_irq_disable_t)(gpio_port_t port, uint8_t pin); + +#endif /* MODULE_PERIPH_GPIO_IRQ || DOXYGEN */ + +/** + * @brief Get current values of all pins of the given GPIO port + * + * @param[in] port GPIO port + * + * @return value of width gpio_mask_t where the bit positions + * represent the current value of the according pin + * (0 when pin is LOW and 1 when pin is HIGH) + */ +typedef gpio_mask_t (*gpio_dev_read_t)(gpio_port_t port); + +/** + * @brief Set the pins of a port defined by the pin mask to HIGH + * + * @param[in] port GPIO port + * @param[in] pins mask of the pins to set + * + * @see gpio_set + */ +typedef void (*gpio_dev_set_t)(gpio_port_t port, gpio_mask_t pins); + +/** + * @brief Set the pins of a port defined by the pin mask to LOW + * + * @param[in] port GPIO port + * @param[in] pins mask of the pins to clear + * + * @see gpio_set + */ +typedef void (*gpio_dev_clear_t)(gpio_port_t port, gpio_mask_t pins); + +/** + * @brief Toggle the value the pins of a port defined by the pin mask + * + * @param[in] port GPIO port + * @param[in] pins mask of the pins to toggle + * + * @see gpio_set + */ +typedef void (*gpio_dev_toggle_t)(gpio_port_t port, gpio_mask_t pins); + +/** + * @brief Set the values of all pins of the given GPIO port + * + * @param[in] port GPIO port + * @param[in] pins values of the pins (according bit is 0 for LOW and 1 for HIGH) + * + * @see gpio_write + */ +typedef void (*gpio_dev_write_t)(gpio_port_t port, gpio_mask_t values); + +/** + * @} + */ + +/** + * @brief GPIO device driver type + * + * GPIO device drivers are used for port-oriented access to GPIO ports. + * gpio_driver_t contains the references to the functions of the low-level + * API, which are implemented by the driver of the hardware component that + * provides a GPIO port. + */ +typedef struct { + gpio_dev_init_t init; /**< see #gpio_dev_init_t */ +#if MODULE_PERIPH_GPIO_IRQ || DOXYGEN + gpio_dev_init_int_t init_int; /**< see #gpio_dev_init_int_t */ + gpio_dev_irq_enable_t irq_enable; /**< see #gpio_dev_irq_enable_t */ + gpio_dev_irq_disable_t irq_disable; /**< see #gpio_dev_irq_disable_t */ +#endif /* MODULE_PERIPH_GPIO_IRQ || DOXYGEN */ + gpio_dev_read_t read; /**< see #gpio_dev_read_t */ + gpio_dev_set_t set; /**< see #gpio_dev_set_t */ + gpio_dev_clear_t clear; /**< see #gpio_dev_clear_t */ + gpio_dev_toggle_t toggle; /**< see #gpio_dev_toggle_t */ + gpio_dev_write_t write; /**< see #gpio_dev_write_t */ +} gpio_driver_t; + +#if MODULE_EXTEND_GPIO || DOXYGEN +/** + * @brief GPIO device driver for MCU GPIO ports. + * + * The GPIO device driver gpio_cpu_driver contains the references to the + * low-level functions `gpio_cpu_*` of the MCU implementation for accessing + * GPIO pins of the MCU GPIO ports. + */ +extern const gpio_driver_t gpio_cpu_driver; +#endif + +/** + * @brief GPIO port table entry type + * + * A GPIO port table entry contains the port of type gpio_port_t. If the + * module `extend_gpio` is enabled, the port table entry additionally + * includes a reference to the driver of the type #gpio_driver_t, which + * implements the low-level GPIO API and realizes the access to the port. + * If the `extend_gpio` module is not enabled, #gpio_cpu_driver is always + * used and this additional reference to the driver is not needed. + * + * The GPIO port table is automatically created from the #GPIO_CPU_PORTS and + * optionally the `GPIO_EXT_PORTS` macro. The #GPIO_CPU_PORTS macro is defined + * by the MCU. The optional `GPIO_EXT_PORTS` macro is defined by the board + * definition or the application according to the GPIO extenders used. + */ +typedef struct { + gpio_port_t port; /**< GPIO port */ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver; /**< associated device driver */ +#endif +} gpio_port_table_t; + +/** + * @brief GPIO port table + * + * The GPIO port table includes an entry of type gpio_port_table_t for each + * existing MCU and GPIO extender ports. It allows the access to a port via + * an index, the GPIO port number. This port number is used in the definition + * of a GPIO pin of type gpio_t. + * + * The GPIO port table is automatically created from the #GPIO_CPU_PORTS and + * optionally the `GPIO_EXT_PORTS` macro. The #GPIO_CPU_PORTS macro is defined + * by the MCU. The optional `GPIO_EXT_PORTS` macro is defined by the board + * definition or the application according to the GPIO extenders used. + * + * The #GPIO_PORT(gpio) macro can be used to get the corresponding port of + * type #gpio_port_t from the port table for a given GPIO pin of type @ref + * gpio_t. + */ +extern const gpio_port_table_t gpio_ports[]; + +/** + * @brief GPIO pin type definition + * + * A GPIO pin is defined by a port that provides the access to the pin and + * the pin number at this port. The port is given by entry in the port table + * #gpio_ports. + */ +typedef struct { + const gpio_port_table_t *port; /**< pointer to the port table entry */ + gpio_pin_t pin; /**< pin number */ +} gpio_t; + +/** + * @name Low-level GPIO API functions for MCU GPIO pins + * + * The following functions correspond exactly to the function prototypes of + * the low-level GPIO API, but follow a special naming scheme that is used to + * automatically create gpio_cpu_driver. These functions have to be implemented + * by each MCU in `cpu/.../periph/gpio.c` for GPIO ports. + * + * They should only be called directly if several pins of a GPIO port are + * to be changed simultaneously using the definition of GPIO pin masks + * of type gpio_mask_t. + * + * The GPIO device driver #gpio_cpu_driver contains references to these + * low-level functions of the MCU implementation. + * + * @see See function prototypes in #gpio_driver_t for detailed information + * about these functions. + * + * @{ + */ +int gpio_cpu_init(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode); +#if MODULE_PERIPH_GPIO_IRQ || DOXYGEN +int gpio_cpu_init_int(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg); +void gpio_cpu_irq_enable(gpio_port_t port, gpio_pin_t pin); +void gpio_cpu_irq_disable(gpio_port_t port, gpio_pin_t pin); +#endif /* MODULE_PERIPH_GPIO_IRQ || DOXYGEN */ +gpio_mask_t gpio_cpu_read(gpio_port_t port); +void gpio_cpu_set(gpio_port_t port, gpio_mask_t pins); +void gpio_cpu_clear(gpio_port_t port, gpio_mask_t pins); +void gpio_cpu_toggle(gpio_port_t port, gpio_mask_t pins); +void gpio_cpu_write(gpio_port_t port, gpio_mask_t values); +/** @} */ + +/** + * @name High-level GPIO API functions + * @{ + */ + +#if MODULE_EXTEND_GPIO || DOXYGEN +/** + * @brief Get the GPIO port driver for a given GPIO + * + * @param[in] gpio GPIO pin + * + * @return GPIO port driver + */ +static inline const gpio_driver_t *gpio_driver_get(gpio_t gpio) +{ + return gpio.port->driver; +} +#endif + +/** + * @brief Initialize the given pin as general purpose input or output + * + * When configured as output, the pin state after initialization is undefined. + * The output pin's state **should** be untouched during the initialization. + * This behavior can however **not be guaranteed** by every platform. + * + * @param[in] gpio GPIO pin to initialize + * @param[in] mode mode of the pin, see #gpio_mode_t + * + * @return 0 on success + * @return -1 on error + */ +static inline int gpio_init(gpio_t gpio, gpio_mode_t mode) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + return driver->init(GPIO_PORT(gpio), gpio.pin, mode); +#else + return gpio_cpu_init(GPIO_PORT(gpio), gpio.pin, mode); +#endif +} + +#if MODULE_PERIPH_GPIO_IRQ || DOXYGEN +/** + * @brief Initialize a GPIO pin for external interrupt usage + * + * The registered callback function will be called in interrupt context every + * time the defined flank(s) are detected. + * + * The interrupt is activated automatically after the initialization. + * + * @note You have to add the module `periph_gpio_irq` to your project to + * enable this function + * + * @param[in] gpio GPIO pin to initialize + * @param[in] mode mode of the pin, see #gpio_mode_t + * @param[in] flank define the active flank(s) + * @param[in] cb callback that is called from interrupt context + * @param[in] arg optional argument passed to the callback + * + * @return 0 on success + * @return -1 on error + */ +static inline int gpio_init_int(gpio_t gpio, gpio_mode_t mode, gpio_flank_t flank, + gpio_cb_t cb, void *arg) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + return driver->init_int(GPIO_PORT(gpio), gpio.pin, mode, flank, cb, arg); +#else + return gpio_cpu_init_int(GPIO_PORT(gpio), gpio.pin, mode, flank, cb, arg); +#endif +} + +/** + * @brief Enable GPIO pin interrupt if configured as interrupt source + * + * @note You have to add the module `periph_gpio_irq` to your project to + * enable this function + * + * @param[in] gpio GPIO pin to enable the interrupt for + */ +static inline void gpio_irq_enable(gpio_t gpio) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + driver->irq_enable(GPIO_PORT(gpio), gpio.pin); +#else + gpio_cpu_irq_enable(GPIO_PORT(gpio), gpio.pin); +#endif +} + +/** + * @brief Disable the GPIO pin interrupt if configured as interrupt source + * + * @note You have to add the module `periph_gpio_irq` to your project to + * enable this function + * + * @param[in] gpio GPIO pin to disable the interrupt for + */ +static inline void gpio_irq_disable(gpio_t gpio) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + driver->irq_disable(GPIO_PORT(gpio), gpio.pin); +#else + gpio_cpu_irq_disable(GPIO_PORT(gpio), gpio.pin); +#endif +} + +#endif /* MODULE_PERIPH_GPIO_IRQ || DOXYGEN */ + +/** + * @brief Get the current value of the given GPIO pin + * + * @param[in] gpio GPIO pin to read + * + * @return 0 when pin is LOW + * @return >0 for HIGH + */ +static inline int gpio_read(gpio_t gpio) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + return driver->read(GPIO_PORT(gpio)) & (1 << gpio.pin); +#else + return gpio_cpu_read(GPIO_PORT(gpio)) & (1 << gpio.pin); +#endif +} + +/** + * @brief Set the given GPIO pin to HIGH + * + * @param[in] gpio GPIO pin to set + */ +static inline void gpio_set(gpio_t gpio) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + driver->set(GPIO_PORT(gpio), (1 << gpio.pin)); +#else + gpio_cpu_set(GPIO_PORT(gpio), (1 << gpio.pin)); +#endif +} + +/** + * @brief Set the given GPIO pin to LOW + * + * @param[in] gpio GPIO pin to clear + */ +static inline void gpio_clear(gpio_t gpio) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + driver->clear(GPIO_PORT(gpio), (1 << gpio.pin)); +#else + gpio_cpu_clear(GPIO_PORT(gpio), (1 << gpio.pin)); +#endif +} + +/** + * @brief Toggle the value of the given GPIO pin + * + * @param[in] gpio GPIO pin to toggle + */ +static inline void gpio_toggle(gpio_t gpio) +{ +#if MODULE_EXTEND_GPIO || DOXYGEN + const gpio_driver_t *driver = gpio_driver_get(gpio); + driver->toggle(GPIO_PORT(gpio), (1 << gpio.pin)); +#else + gpio_cpu_toggle(GPIO_PORT(gpio), (1 << gpio.pin)); +#endif +} + +/** + * @brief Set the given GPIO pin to the given value + * + * @param[in] gpio GPIO pin to set + * @param[in] value value to set the pin to, 0 for LOW, HIGH otherwise + */ +static inline void gpio_write(gpio_t gpio, int value) +{ + if (value) { + gpio_set(gpio); + } else { + gpio_clear(gpio); + } +} + +/** + * @brief Test if a GPIO pin is equal to another GPIO pin + * + * @param[in] gpio1 First GPIO pin to check + * @param[in] gpio2 Second GPIO pin to check + */ +static inline int gpio_is_equal(gpio_t gpio1, gpio_t gpio2) +{ + return (gpio1.port == gpio2.port) && (gpio1.pin == gpio2.pin); +} + +/** + * @brief Test if a GPIO pin is undefined + * + * @param[in] gpio GPIO pin to check + */ +static inline int gpio_is_undef(gpio_t gpio) +{ + return gpio_is_equal(gpio, GPIO_UNDEF); +} + +/** + * @brief Returns the total number of GPIO ports (MCU and other GPIO ports) + * + * return number of GPIO ports + */ +int gpio_port_numof(void); + +/** + * @brief Returns the port number of a given GPIO pin (MCU and other + * GPIO ports) + * + * @param[in] gpio given GPIO pin + * + * return port number for the given GPIO pin + */ +int gpio_port_num(gpio_t gpio); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* PERIPH_GPIO_EXT_H */ diff --git a/drivers/periph_common/gpio.c b/drivers/periph_common/gpio.c new file mode 100644 index 000000000000..88b1f6eaa5c6 --- /dev/null +++ b/drivers/periph_common/gpio.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_periph_gpio + * @{ + * + * @file + * @brief Common GPIO driver functions/definitions + * + * @author Gunar Schorcht + * @} + */ + +#ifdef MODULE_PERIPH_GPIO_EXT + +#include "periph_cpu.h" +#include "periph/gpio.h" + +#ifdef MODULE_EXTEND_GPIO +#include "gpio_ext_conf.h" +#endif + +#ifdef MODULE_EXTEND_GPIO +/* the CPU low level GPIO driver */ +const gpio_driver_t gpio_cpu_driver = { + .init = (gpio_dev_init_t)gpio_cpu_init, +#ifdef MODULE_PERIPH_GPIO_IRQ + .init_int = (gpio_dev_init_int_t)gpio_cpu_init_int, + .irq_enable = (gpio_dev_irq_enable_t)gpio_cpu_irq_enable, + .irq_disable = (gpio_dev_irq_disable_t)gpio_cpu_irq_disable, +#endif /* MODULE_PERIPH_GPIO_IRQ */ + .read = (gpio_dev_read_t)gpio_cpu_read, + .set = (gpio_dev_set_t)gpio_cpu_set, + .clear = (gpio_dev_clear_t)gpio_cpu_clear, + .toggle = (gpio_dev_toggle_t)gpio_cpu_toggle, + .write = (gpio_dev_write_t)gpio_cpu_write, +}; +#endif /* MODULE_EXTEND_GPIO */ + +const gpio_port_table_t gpio_ports[] = { +#if defined(MODULE_PERIPH_GPIO) + GPIO_CPU_PORTS +#endif +#if defined(MODULE_EXTEND_GPIO) && defined(GPIO_EXT_PORTS) + GPIO_EXT_PORTS +#endif +}; + +int gpio_port_numof(void) +{ + return ARRAY_SIZE(gpio_ports); +} + +int gpio_port_num(gpio_t gpio) +{ + for (unsigned i = 0; i < ARRAY_SIZE(gpio_ports); i++) { + if (GPIO_PORT(gpio).dev == gpio_ports[i].port.dev) { + return i; + } + } + return 0; +} + +#else +typedef int dont_be_pedantic; +#endif /* MODULE_PERIPH_GPIO_EXT */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 0bcb61fd26db..4892428e568c 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -42,6 +42,9 @@ PSEUDOMODULES += gnrc_sixlowpan_router_default PSEUDOMODULES += gnrc_sock_async PSEUDOMODULES += gnrc_sock_check_reuse PSEUDOMODULES += gnrc_txtsnd +PSEUDOMODULES += gpio_mask_32bit +PSEUDOMODULES += gpio_mask_16bit +PSEUDOMODULES += gpio_mask_8bit PSEUDOMODULES += heap_cmd PSEUDOMODULES += i2c_scan PSEUDOMODULES += ina3221_alerts @@ -136,6 +139,9 @@ PSEUDOMODULES += mpu9250 PSEUDOMODULES += ina219 PSEUDOMODULES += ina220 +# periph extention interface pseudomodules +PSEUDOMODULES += extend_% + # include variants of mrf24j40 drivers as pseudo modules PSEUDOMODULES += mrf24j40m% From 1ccc76dc14c633f449f9d800b833b086dc31c578 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 22 Feb 2020 15:21:45 +0100 Subject: [PATCH 06/17] drivers: required changes for new GPIO API --- drivers/kw2xrf/kw2xrf_spi.c | 7 ++++++- drivers/soft_spi/include/soft_spi_params.h | 6 +++++- drivers/stmpe811/stmpe811.c | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/kw2xrf/kw2xrf_spi.c b/drivers/kw2xrf/kw2xrf_spi.c index 366375ffeebf..bf71ec3df731 100644 --- a/drivers/kw2xrf/kw2xrf_spi.c +++ b/drivers/kw2xrf/kw2xrf_spi.c @@ -89,9 +89,14 @@ int kw2xrf_spi_init(kw2xrf_t *dev) return 1; } spi_release(SPIDEV); - +#ifndef MODULE_PERIPH_GPIO_EXT DEBUG("[kw2xrf_spi] SPI_DEV(%u) initialized: mode: %u, clk: %u, cs_pin: %u\n", (unsigned)SPIDEV, (unsigned)SPIMODE, (unsigned)SPICLK, (unsigned)CSPIN); +#else + DEBUG("[kw2xrf_spi] SPI_DEV(%u) initialized: mode: %u, clk: %u, cs_pin: GPIO_PIN(%d,%d)\n", + (unsigned)SPIDEV, (unsigned)SPIMODE, (unsigned)SPICLK, + gpio_port_num(CSPIN), CSPIN.pin); +#endif return 0; } diff --git a/drivers/soft_spi/include/soft_spi_params.h b/drivers/soft_spi/include/soft_spi_params.h index fd3d7bb55e64..c45873d93fac 100644 --- a/drivers/soft_spi/include/soft_spi_params.h +++ b/drivers/soft_spi/include/soft_spi_params.h @@ -34,11 +34,15 @@ extern "C" { #ifndef SOFT_SPI_PARAM_CLK #define SOFT_SPI_PARAM_CLK (GPIO_PIN(0, 1)) #endif +#ifndef SOFT_SPI_PARAM_MODE +#define SOFT_SPI_PARAM_MODE (SOFT_SPI_MODE_0) +#endif #ifndef SOFT_SPI_PARAMS #define SOFT_SPI_PARAMS { .miso_pin = SOFT_SPI_PARAM_MISO, \ .mosi_pin = SOFT_SPI_PARAM_MOSI, \ - .clk_pin = SOFT_SPI_PARAM_CLK } + .clk_pin = SOFT_SPI_PARAM_CLK, \ + .soft_spi_mode = SOFT_SPI_PARAM_MODE } #endif /** diff --git a/drivers/stmpe811/stmpe811.c b/drivers/stmpe811/stmpe811.c index a04a2b0810cf..5dbc5ee73b46 100644 --- a/drivers/stmpe811/stmpe811.c +++ b/drivers/stmpe811/stmpe811.c @@ -160,7 +160,7 @@ int stmpe811_init(stmpe811_t *dev, const stmpe811_params_t * params, touch_event /* clear interrupt status */ _clear_interrupt_status(dev); - if ((dev->params.int_pin != GPIO_UNDEF) && cb) { + if (!gpio_is_undef(dev->params.int_pin) && cb) { DEBUG("[stmpe811] init: configuring touchscreen interrupt\n"); gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_RISING, cb, arg); From 9590cf4ba5c054ed4d105c20939766bcd3f0b12c Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 22 Feb 2020 15:53:45 +0100 Subject: [PATCH 07/17] tests: required changes for new GPIO API --- tests/driver_pir/main.c | 5 +++++ tests/periph_gpio/main.c | 9 +++++---- tests/pkg_semtech-loramac/Makefile | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/driver_pir/main.c b/tests/driver_pir/main.c index 63736db54d79..903dcefe648d 100644 --- a/tests/driver_pir/main.c +++ b/tests/driver_pir/main.c @@ -62,7 +62,12 @@ void* pir_handler(void *arg) int main(void) { puts("PIR motion sensor test application\n"); +#ifndef MODULE_PERIPH_GPIO_EXT printf("Initializing PIR sensor at GPIO_%ld... ", (long)PIR_PARAM_GPIO); +#else + printf("Initializing PIR sensor at GPIO_PIN(%d, %d) ... ", + gpio_port_num(PIR_PARAM_GPIO), PIR_PARAM_GPIO.pin); +#endif if (pir_init(&dev, &pir_params[0]) == 0) { puts("[OK]\n"); } diff --git a/tests/periph_gpio/main.c b/tests/periph_gpio/main.c index f882c609b7fc..e83a6bf6a6b9 100644 --- a/tests/periph_gpio/main.c +++ b/tests/periph_gpio/main.c @@ -31,7 +31,8 @@ #ifdef MODULE_PERIPH_GPIO_IRQ static void cb(void *arg) { - printf("INT: external interrupt from pin %i\n", (int)arg); + printf("INT: external interrupt from GPIO_PIN(%i, %i)\n", + (int)arg >> 8, (int)arg & 0xff); } #endif @@ -143,7 +144,7 @@ static int init_int(int argc, char **argv) } } - if (gpio_init_int(GPIO_PIN(po, pi), mode, flank, cb, (void *)pi) < 0) { + if (gpio_init_int(GPIO_PIN(po, pi), mode, flank, cb, (void *)((po << 8) + pi)) < 0) { printf("error: init_int of GPIO_PIN(%i, %i) failed\n", po, pi); return 1; } @@ -201,10 +202,10 @@ static int read(int argc, char **argv) pin = atoi(argv[2]); if (gpio_read(GPIO_PIN(port, pin))) { - printf("GPIO_PIN(%i.%02i) is HIGH\n", port, pin); + printf("GPIO_PIN(%i, %i) is HIGH\n", port, pin); } else { - printf("GPIO_PIN(%i.%02i) is LOW\n", port, pin); + printf("GPIO_PIN(%i, %i) is LOW\n", port, pin); } return 0; diff --git a/tests/pkg_semtech-loramac/Makefile b/tests/pkg_semtech-loramac/Makefile index 25ab1ecdf5d1..ec3db28d87ab 100644 --- a/tests/pkg_semtech-loramac/Makefile +++ b/tests/pkg_semtech-loramac/Makefile @@ -5,7 +5,9 @@ include ../Makefile.tests_common BOARD_WITHOUT_LORAMAC_RX := \ arduino-mega2560 \ i-nucleo-lrwan1 \ + nucleo-l053r8\ stm32f0discovery \ + stm32l0538-disco \ waspmote-pro \ LORA_DRIVER ?= sx1276 From b5218ca3090480c1d0c64c781630d3b5888cac75 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 5 Dec 2019 11:42:52 +0100 Subject: [PATCH 08/17] cpu/stm32*: changes for new GPIO API --- cpu/stm32_common/Makefile.dep | 3 + cpu/stm32_common/Makefile.features | 2 +- cpu/stm32_common/include/gpio_arch.h | 34 ++++ cpu/stm32_common/include/gpio_arch_common.h | 129 ++++++++++++++ cpu/stm32_common/include/periph_cpu_common.h | 120 ++------------ cpu/stm32_common/periph/can.c | 4 +- cpu/stm32_common/periph/eth.c | 1 + cpu/stm32_common/periph/gpio.c | 166 +++++++++---------- cpu/stm32_common/periph/i2c_2.c | 4 +- cpu/stm32_common/periph/pwm.c | 6 +- cpu/stm32_common/periph/qdec.c | 2 +- cpu/stm32_common/periph/spi.c | 24 +-- cpu/stm32_common/periph/uart.c | 10 +- cpu/stm32f0/include/periph_cpu.h | 12 ++ cpu/stm32f1/include/periph_cpu.h | 13 ++ cpu/stm32f2/include/periph_cpu.h | 17 +- cpu/stm32f3/include/periph_cpu.h | 14 ++ cpu/stm32f4/include/periph_cpu.h | 17 +- cpu/stm32f7/include/periph_cpu.h | 19 ++- cpu/stm32l0/include/periph_cpu.h | 14 ++ cpu/stm32l1/include/periph_cpu.h | 14 ++ cpu/stm32l1/periph/adc.c | 3 +- cpu/stm32l4/include/periph_cpu.h | 15 ++ 23 files changed, 411 insertions(+), 232 deletions(-) create mode 100644 cpu/stm32_common/include/gpio_arch.h create mode 100644 cpu/stm32_common/include/gpio_arch_common.h diff --git a/cpu/stm32_common/Makefile.dep b/cpu/stm32_common/Makefile.dep index 2a2c82fa341d..d626dabf7b42 100644 --- a/cpu/stm32_common/Makefile.dep +++ b/cpu/stm32_common/Makefile.dep @@ -7,3 +7,6 @@ USEMODULE += stm32_common stm32_common_periph ifneq (,$(filter periph_usbdev,$(FEATURES_USED))) USEMODULE += xtimer endif + +# 16 bit GPIO pin mask required +USEMODULE += gpio_mask_16bit diff --git a/cpu/stm32_common/Makefile.features b/cpu/stm32_common/Makefile.features index 5b3085628cf1..5660d175065b 100644 --- a/cpu/stm32_common/Makefile.features +++ b/cpu/stm32_common/Makefile.features @@ -1,5 +1,5 @@ FEATURES_PROVIDED += periph_cpuid -FEATURES_PROVIDED += periph_gpio periph_gpio_irq +FEATURES_PROVIDED += periph_gpio periph_gpio_irq periph_gpio_ext FEATURES_PROVIDED += puf_sram FEATURES_PROVIDED += periph_uart_modecfg FEATURES_PROVIDED += periph_wdt diff --git a/cpu/stm32_common/include/gpio_arch.h b/cpu/stm32_common/include/gpio_arch.h new file mode 100644 index 000000000000..5b6b88c81815 --- /dev/null +++ b/cpu/stm32_common/include/gpio_arch.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32_common + * @{ + * + * @file + * @brief CPU specific GPIO definitions for the STM32 family + * + * @author Gunar Schorcht + */ + +#ifndef GPIO_ARCH_H +#define GPIO_ARCH_H + +#include "gpio_arch_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* GPIO_ARCH_H */ +/** @} */ diff --git a/cpu/stm32_common/include/gpio_arch_common.h b/cpu/stm32_common/include/gpio_arch_common.h new file mode 100644 index 000000000000..a5f78c3ec2a8 --- /dev/null +++ b/cpu/stm32_common/include/gpio_arch_common.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * 2017 OTA keys S.A. + * 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32_common + * @{ + * + * @file + * @brief Shared CPU specific GPIO definitions for the STM32 family + * + * @author Hauke Petersen + * @author Vincent Dupont + * @author Gunar Schorcht + */ + +#ifndef GPIO_ARCH_COMMON_H +#define GPIO_ARCH_COMMON_H + +#include "cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Define a magic number that tells us to use hardware chip select + * + * We use a random value here, that does clearly differentiate from any possible + * GPIO pin number. + */ +#define SPI_HWCS_MASK (0x80) + +/** + * @brief Override the default SPI hardware chip select access macro + * + * Since the CPU does only support one single hardware chip select line, we can + * detect the usage of non-valid lines by comparing to SPI_HWCS_MASK. + */ +#define SPI_HWCS(x) ((gpio_t){ .port = NULL, .pin = SPI_HWCS_MASK | x }) + +/** + * @brief Test whether a GPIO pin is defined as SPI hardware chip select + */ +#define SPI_HWCS_IS(x) (x.port == NULL && ((x.pin & SPI_HWCS_MASK) == SPI_HWCS_MASK)) + +/** + * @brief Available MUX values for configuring a pin's alternate function + */ +typedef enum { +#ifdef CPU_FAM_STM32F1 + GPIO_AF_OUT_PP = 0xb, /**< alternate function output - push-pull */ + GPIO_AF_OUT_OD = 0xf, /**< alternate function output - open-drain */ +#else + GPIO_AF0 = 0, /**< use alternate function 0 */ + GPIO_AF1, /**< use alternate function 1 */ + GPIO_AF2, /**< use alternate function 2 */ + GPIO_AF3, /**< use alternate function 3 */ + GPIO_AF4, /**< use alternate function 4 */ + GPIO_AF5, /**< use alternate function 5 */ + GPIO_AF6, /**< use alternate function 6 */ + GPIO_AF7, /**< use alternate function 7 */ +#ifndef CPU_FAM_STM32F0 + GPIO_AF8, /**< use alternate function 8 */ + GPIO_AF9, /**< use alternate function 9 */ + GPIO_AF10, /**< use alternate function 10 */ + GPIO_AF11, /**< use alternate function 11 */ + GPIO_AF12, /**< use alternate function 12 */ + GPIO_AF13, /**< use alternate function 13 */ + GPIO_AF14, /**< use alternate function 14 */ + GPIO_AF15 /**< use alternate function 15 */ +#endif +#endif +} gpio_af_t; + +#ifndef CPU_FAM_STM32F1 +/** + * @brief Generate GPIO mode bitfields + * + * We use 5 bit to encode the mode: + * - bit 0+1: pin mode (input / output) + * - bit 2+3: pull resistor configuration + * - bit 4: output type (0: push-pull, 1: open-drain) + */ +#define GPIO_MODE(io, pr, ot) ((io << 0) | (pr << 2) | (ot << 4)) + +#ifndef DOXYGEN + +/** + * @brief Override GPIO mode options + * @{ + */ +#define HAVE_GPIO_MODE_T +typedef enum { + GPIO_IN = GPIO_MODE(0, 0, 0), /**< input w/o pull R */ + GPIO_IN_PD = GPIO_MODE(0, 2, 0), /**< input with pull-down */ + GPIO_IN_PU = GPIO_MODE(0, 1, 0), /**< input with pull-up */ + GPIO_OUT = GPIO_MODE(1, 0, 0), /**< push-pull output */ + GPIO_OD = GPIO_MODE(1, 0, 1), /**< open-drain w/o pull R */ + GPIO_OD_PU = GPIO_MODE(1, 1, 1) /**< open-drain with pull-up */ +} gpio_mode_t; +/** @} */ + +/** + * @brief Override flank configuration values + * @{ + */ +#define HAVE_GPIO_FLANK_T +typedef enum { + GPIO_RISING = 1, /**< emit interrupt on rising flank */ + GPIO_FALLING = 2, /**< emit interrupt on falling flank */ + GPIO_BOTH = 3 /**< emit interrupt on both flanks */ +} gpio_flank_t; +/** @} */ +#endif /* ndef DOXYGEN */ +#endif /* ndef CPU_FAM_STM32F1 */ + +#ifdef __cplusplus +} +#endif + +#endif /* GPIO_ARCH_COMMON_H */ +/** @} */ diff --git a/cpu/stm32_common/include/periph_cpu_common.h b/cpu/stm32_common/include/periph_cpu_common.h index 9507935a01d1..96e4ae458fef 100644 --- a/cpu/stm32_common/include/periph_cpu_common.h +++ b/cpu/stm32_common/include/periph_cpu_common.h @@ -22,6 +22,7 @@ #define PERIPH_CPU_COMMON_H #include "cpu.h" +#include "periph/gpio.h" #ifdef __cplusplus extern "C" { @@ -49,6 +50,11 @@ extern "C" { */ #define CPUID_LEN (12U) +/** + * @brief Base register address for MCU GPIO port for all STM32-based CPUs. + */ +#define GPIO_CPU_PORT_ADDR(port) (GPIOA_BASE + (port << 10)) + /** * @brief We provide our own pm_off() function for all STM32-based CPUs */ @@ -140,42 +146,6 @@ typedef enum { #endif } bus_t; -#ifndef DOXYGEN -/** - * @brief Overwrite the default gpio_t type definition - * @{ - */ -#define HAVE_GPIO_T -typedef uint32_t gpio_t; -/** @} */ -#endif - -/** - * @brief Definition of a fitting UNDEF value - */ -#define GPIO_UNDEF (0xffffffff) - -/** - * @brief Define a CPU specific GPIO pin generator macro - */ -#define GPIO_PIN(x, y) ((GPIOA_BASE + (x << 10)) | y) - -/** - * @brief Define a magic number that tells us to use hardware chip select - * - * We use a random value here, that does clearly differentiate from any possible - * GPIO_PIN(x) value. - */ -#define SPI_HWCS_MASK (0xffffff00) - -/** - * @brief Override the default SPI hardware chip select access macro - * - * Since the CPU does only support one single hardware chip select line, we can - * detect the usage of non-valid lines by comparing to SPI_HWCS_VALID. - */ -#define SPI_HWCS(x) (SPI_HWCS_MASK | x) - /** * @name Use the shared I2C functions * @{ @@ -191,76 +161,6 @@ typedef uint32_t gpio_t; #endif /** @} */ -/** - * @brief Available MUX values for configuring a pin's alternate function - */ -typedef enum { -#ifdef CPU_FAM_STM32F1 - GPIO_AF_OUT_PP = 0xb, /**< alternate function output - push-pull */ - GPIO_AF_OUT_OD = 0xf, /**< alternate function output - open-drain */ -#else - GPIO_AF0 = 0, /**< use alternate function 0 */ - GPIO_AF1, /**< use alternate function 1 */ - GPIO_AF2, /**< use alternate function 2 */ - GPIO_AF3, /**< use alternate function 3 */ - GPIO_AF4, /**< use alternate function 4 */ - GPIO_AF5, /**< use alternate function 5 */ - GPIO_AF6, /**< use alternate function 6 */ - GPIO_AF7, /**< use alternate function 7 */ -#ifndef CPU_FAM_STM32F0 - GPIO_AF8, /**< use alternate function 8 */ - GPIO_AF9, /**< use alternate function 9 */ - GPIO_AF10, /**< use alternate function 10 */ - GPIO_AF11, /**< use alternate function 11 */ - GPIO_AF12, /**< use alternate function 12 */ - GPIO_AF13, /**< use alternate function 13 */ - GPIO_AF14, /**< use alternate function 14 */ - GPIO_AF15 /**< use alternate function 15 */ -#endif -#endif -} gpio_af_t; - -#ifndef CPU_FAM_STM32F1 -/** - * @brief Generate GPIO mode bitfields - * - * We use 5 bit to encode the mode: - * - bit 0+1: pin mode (input / output) - * - bit 2+3: pull resistor configuration - * - bit 4: output type (0: push-pull, 1: open-drain) - */ -#define GPIO_MODE(io, pr, ot) ((io << 0) | (pr << 2) | (ot << 4)) - -#ifndef DOXYGEN -/** - * @brief Override GPIO mode options - * @{ - */ -#define HAVE_GPIO_MODE_T -typedef enum { - GPIO_IN = GPIO_MODE(0, 0, 0), /**< input w/o pull R */ - GPIO_IN_PD = GPIO_MODE(0, 2, 0), /**< input with pull-down */ - GPIO_IN_PU = GPIO_MODE(0, 1, 0), /**< input with pull-up */ - GPIO_OUT = GPIO_MODE(1, 0, 0), /**< push-pull output */ - GPIO_OD = GPIO_MODE(1, 0, 1), /**< open-drain w/o pull R */ - GPIO_OD_PU = GPIO_MODE(1, 1, 1) /**< open-drain with pull-up */ -} gpio_mode_t; -/** @} */ - -/** - * @brief Override flank configuration values - * @{ - */ -#define HAVE_GPIO_FLANK_T -typedef enum { - GPIO_RISING = 1, /**< emit interrupt on rising flank */ - GPIO_FALLING = 2, /**< emit interrupt on falling flank */ - GPIO_BOTH = 3 /**< emit interrupt on both flanks */ -} gpio_flank_t; -/** @} */ -#endif /* ndef DOXYGEN */ -#endif /* ndef CPU_FAM_STM32F1 */ - #ifdef MODULE_PERIPH_DMA /** * @brief DMA configuration @@ -666,17 +566,17 @@ void periph_clk_dis(bus_t bus, uint32_t mask); /** * @brief Configure the alternate function for the given pin * - * @param[in] pin pin to configure + * @param[in] gpio gpio to configure * @param[in] af alternate function to use */ -void gpio_init_af(gpio_t pin, gpio_af_t af); +void gpio_init_af(gpio_t gpio, gpio_af_t af); /** * @brief Configure the given pin to be used as ADC input * - * @param[in] pin pin to configure + * @param[in] gpio gpio to configure */ -void gpio_init_analog(gpio_t pin); +void gpio_init_analog(gpio_t gpio); #ifdef MODULE_PERIPH_DMA /** diff --git a/cpu/stm32_common/periph/can.c b/cpu/stm32_common/periph/can.c index 28ad426d3af3..e8cbc68bb536 100644 --- a/cpu/stm32_common/periph/can.c +++ b/cpu/stm32_common/periph/can.c @@ -243,11 +243,11 @@ void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin, void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin) #endif { - if (dev->tx_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->tx_pin)) { gpio_init(dev->tx_pin, GPIO_IN); gpio_init_analog(dev->tx_pin); } - if (dev->rx_pin != GPIO_UNDEF) { + if (!gpio_is_undef(dev->rx_pin)) { gpio_init(dev->rx_pin, GPIO_IN); gpio_init_analog(dev->rx_pin); } diff --git a/cpu/stm32_common/periph/eth.c b/cpu/stm32_common/periph/eth.c index c5c4aea11c43..4f2bd73b12a0 100644 --- a/cpu/stm32_common/periph/eth.c +++ b/cpu/stm32_common/periph/eth.c @@ -26,6 +26,7 @@ #include "net/ethernet.h" #include "periph/gpio.h" +#include "periph_conf.h" #define ENABLE_DEBUG (0) #include "debug.h" diff --git a/cpu/stm32_common/periph/gpio.c b/cpu/stm32_common/periph/gpio.c index dd232d7482b4..ac2da13323cd 100644 --- a/cpu/stm32_common/periph/gpio.c +++ b/cpu/stm32_common/periph/gpio.c @@ -47,176 +47,145 @@ static gpio_isr_ctx_t isr_ctx[EXTI_NUMOF]; #endif /* MODULE_PERIPH_GPIO_IRQ */ /** - * @brief Extract the port base address from the given pin identifier - */ -static inline GPIO_TypeDef *_port(gpio_t pin) -{ - return (GPIO_TypeDef *)(pin & ~(0x0f)); -} - -/** - * @brief Extract the port number form the given identifier + * @brief Extract the port number form the given device address * * The port number is extracted by looking at bits 10, 11, 12, 13 of the base * register addresses. */ -static inline int _port_num(gpio_t pin) +static inline int _port_num(gpio_port_t port) { - return ((pin >> 10) & 0x0f); + return ((port.reg >> 10) & 0x0f); } /** - * @brief Extract the pin number from the last 4 bit of the pin identifier + * @brief Convert port register address to port register structure */ -static inline int _pin_num(gpio_t pin) +static inline GPIO_TypeDef *_port(gpio_port_t port) { - return (pin & 0x0f); + return (GPIO_TypeDef *)port.reg; } -int gpio_init(gpio_t pin, gpio_mode_t mode) +int gpio_cpu_init(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode) { - GPIO_TypeDef *port = _port(pin); - int pin_num = _pin_num(pin); - /* enable clock */ #if defined(CPU_FAM_STM32F0) || defined (CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L1) - periph_clk_en(AHB, (RCC_AHBENR_GPIOAEN << _port_num(pin))); + periph_clk_en(AHB, (RCC_AHBENR_GPIOAEN << _port_num(port))); #elif defined (CPU_FAM_STM32L0) - periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(pin))); + periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(port))); #elif defined (CPU_FAM_STM32L4) - periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(pin))); + periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(port))); #ifdef PWR_CR2_IOSV - if (port == GPIOG) { + if (_port(port) == GPIOG) { /* Port G requires external power supply */ periph_clk_en(APB1, RCC_APB1ENR1_PWREN); PWR->CR2 |= PWR_CR2_IOSV; } #endif /* PWR_CR2_IOSV */ #else - periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(pin))); + periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(port))); #endif - /* set mode */ - port->MODER &= ~(0x3 << (2 * pin_num)); - port->MODER |= ((mode & 0x3) << (2 * pin_num)); + _port(port)->MODER &= ~(0x3 << (pin << 1)); + _port(port)->MODER |= ((mode & 0x3) << (pin << 1)); /* set pull resistor configuration */ - port->PUPDR &= ~(0x3 << (2 * pin_num)); - port->PUPDR |= (((mode >> 2) & 0x3) << (2 * pin_num)); + _port(port)->PUPDR &= ~(0x3 << (pin << 1)); + _port(port)->PUPDR |= (((mode >> 2) & 0x3) << (pin << 1)); /* set output mode */ - port->OTYPER &= ~(1 << pin_num); - port->OTYPER |= (((mode >> 4) & 0x1) << pin_num); + _port(port)->OTYPER &= ~(1 << pin); + _port(port)->OTYPER |= (((mode >> 4) & 0x1) << pin); /* set pin speed to maximum */ - port->OSPEEDR |= (3 << (2 * pin_num)); + _port(port)->OSPEEDR |= (3 << (pin << 1)); return 0; } -void gpio_init_af(gpio_t pin, gpio_af_t af) +void gpio_init_af(gpio_t gpio, gpio_af_t af) { - GPIO_TypeDef *port = _port(pin); - uint32_t pin_num = _pin_num(pin); + GPIO_TypeDef *port = _port(GPIO_PORT(gpio)); + gpio_pin_t pin = gpio.pin; /* set pin to AF mode */ - port->MODER &= ~(3 << (2 * pin_num)); - port->MODER |= (2 << (2 * pin_num)); + port->MODER &= ~(3 << (pin << 1)); + port->MODER |= (2 << (pin << 1)); /* set selected function */ - port->AFR[(pin_num > 7) ? 1 : 0] &= ~(0xf << ((pin_num & 0x07) * 4)); - port->AFR[(pin_num > 7) ? 1 : 0] |= (af << ((pin_num & 0x07) * 4)); + port->AFR[(pin > 7) ? 1 : 0] &= ~(0xf << ((pin & 0x07) << 2)); + port->AFR[(pin > 7) ? 1 : 0] |= (af << ((pin & 0x07) << 2)); } -void gpio_init_analog(gpio_t pin) +void gpio_init_analog(gpio_t gpio) { /* enable clock, needed as this function can be used without calling * gpio_init first */ #if defined(CPU_FAM_STM32F0) || defined (CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L1) - periph_clk_en(AHB, (RCC_AHBENR_GPIOAEN << _port_num(pin))); + periph_clk_en(AHB, (RCC_AHBENR_GPIOAEN << _port_num(GPIO_PORT(gpio)))); #elif defined (CPU_FAM_STM32L0) - periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(pin))); + periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(GPIO_PORT(gpio)))); #elif defined (CPU_FAM_STM32L4) - periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(pin))); + periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(GPIO_PORT(gpio)))); #else - periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(pin))); + periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(GPIO_PORT(gpio)))); #endif /* set to analog mode */ - _port(pin)->MODER |= (0x3 << (2 * _pin_num(pin))); -} - -void gpio_irq_enable(gpio_t pin) -{ - EXTI->IMR |= (1 << _pin_num(pin)); -} - -void gpio_irq_disable(gpio_t pin) -{ - EXTI->IMR &= ~(1 << _pin_num(pin)); + _port(GPIO_PORT(gpio))->MODER |= (0x3 << ((uint32_t)gpio.pin << 1)); } -int gpio_read(gpio_t pin) +gpio_mask_t gpio_cpu_read(gpio_port_t port) { - return (_port(pin)->IDR & (1 << _pin_num(pin))); + return _port(port)->IDR; } -void gpio_set(gpio_t pin) +void gpio_cpu_set(gpio_port_t port, gpio_mask_t pins) { - _port(pin)->BSRR = (1 << _pin_num(pin)); + _port(port)->BSRR = pins; } -void gpio_clear(gpio_t pin) +void gpio_cpu_clear(gpio_port_t port, gpio_mask_t pins) { - _port(pin)->BSRR = (1 << (_pin_num(pin) + 16)); + _port(port)->BSRR = ((uint32_t)pins << 16); } -void gpio_toggle(gpio_t pin) +void gpio_cpu_toggle(gpio_port_t port, gpio_mask_t pins) { - if (gpio_read(pin)) { - gpio_clear(pin); - } else { - gpio_set(pin); - } + _port(port)->ODR = _port(port)->ODR ^ pins; } -void gpio_write(gpio_t pin, int value) +void gpio_cpu_write(gpio_port_t port, gpio_mask_t values) { - if (value) { - gpio_set(pin); - } else { - gpio_clear(pin); - } + _port(port)->ODR = values; } #ifdef MODULE_PERIPH_GPIO_IRQ -int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, - gpio_cb_t cb, void *arg) +int gpio_cpu_init_int(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg) { - int pin_num = _pin_num(pin); - int port_num = _port_num(pin); + int port_num = _port_num(port); /* set callback */ - isr_ctx[pin_num].cb = cb; - isr_ctx[pin_num].arg = arg; + isr_ctx[pin].cb = cb; + isr_ctx[pin].arg = arg; /* enable clock of the SYSCFG module for EXTI configuration */ periph_clk_en(APB2, RCC_APB2ENR_SYSCFGEN); /* initialize pin as input */ - gpio_init(pin, mode); + gpio_cpu_init(port, pin, mode); /* enable global pin interrupt */ #if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) - if (pin_num < 2) { + if (pin < 2) { NVIC_EnableIRQ(EXTI0_1_IRQn); } - else if (pin_num < 4) { + else if (pin < 4) { NVIC_EnableIRQ(EXTI2_3_IRQn); } else { NVIC_EnableIRQ(EXTI4_15_IRQn); } #else - if (pin_num < 5) { - NVIC_EnableIRQ(EXTI0_IRQn + pin_num); + if (pin < 5) { + NVIC_EnableIRQ(EXTI0_IRQn + pin); } - else if (pin_num < 10) { + else if (pin < 10) { NVIC_EnableIRQ(EXTI9_5_IRQn); } else { @@ -224,21 +193,34 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, } #endif /* configure the active flank */ - EXTI->RTSR &= ~(1 << pin_num); - EXTI->RTSR |= ((flank & 0x1) << pin_num); - EXTI->FTSR &= ~(1 << pin_num); - EXTI->FTSR |= ((flank >> 1) << pin_num); + EXTI->RTSR &= ~(1 << pin); + EXTI->RTSR |= ((flank & 0x1) << pin); + EXTI->FTSR &= ~(1 << pin); + EXTI->FTSR |= ((flank >> 1) << pin); /* enable specific pin as exti sources */ - SYSCFG->EXTICR[pin_num >> 2] &= ~(0xf << ((pin_num & 0x03) * 4)); - SYSCFG->EXTICR[pin_num >> 2] |= (port_num << ((pin_num & 0x03) * 4)); + SYSCFG->EXTICR[pin >> 2] &= ~(0xf << ((pin & 0x03) * 4)); + SYSCFG->EXTICR[pin >> 2] |= (port_num << ((pin & 0x03) * 4)); /* clear any pending requests */ - EXTI->PR = (1 << pin_num); + EXTI->PR = (1 << pin); /* unmask the pins interrupt channel */ - EXTI->IMR |= (1 << pin_num); + EXTI->IMR |= (1 << pin); return 0; } + +void gpio_cpu_irq_enable(gpio_port_t port, gpio_pin_t pin) +{ + (void)port; + EXTI->IMR |= (1 << pin); +} + +void gpio_cpu_irq_disable(gpio_port_t port, gpio_pin_t pin) +{ + (void)port; + EXTI->IMR &= ~(1 << pin); +} + void isr_exti(void) { /* only generate interrupts against lines which have their IMR set */ diff --git a/cpu/stm32_common/periph/i2c_2.c b/cpu/stm32_common/periph/i2c_2.c index 8cb037b4d41a..4f2b953ec2eb 100644 --- a/cpu/stm32_common/periph/i2c_2.c +++ b/cpu/stm32_common/periph/i2c_2.c @@ -114,8 +114,8 @@ static void _init_pins(i2c_t dev) gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU); #ifdef CPU_FAM_STM32F1 /* This is needed in case the remapped pins are used */ - if (i2c_config[dev].scl_pin == GPIO_PIN(PORT_B, 8) || - i2c_config[dev].sda_pin == GPIO_PIN(PORT_B, 9)) { + if (gpio_is_equal(i2c_config[dev].scl_pin, GPIO_PIN(PORT_B, 8)) || + gpio_is_equal(i2c_config[dev].sda_pin, GPIO_PIN(PORT_B, 9))) { /* The remapping periph clock must first be enabled */ RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; /* Then the remap can occur */ diff --git a/cpu/stm32_common/periph/pwm.c b/cpu/stm32_common/periph/pwm.c index 7d1a358e36c5..cc351e26ef51 100644 --- a/cpu/stm32_common/periph/pwm.c +++ b/cpu/stm32_common/periph/pwm.c @@ -58,7 +58,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) /* configure the used pins */ unsigned i = 0; - while ((i < TIMER_CHAN) && (pwm_config[pwm].chan[i].pin != GPIO_UNDEF)) { + while ((i < TIMER_CHAN) && !gpio_is_undef(pwm_config[pwm].chan[i].pin)) { gpio_init(pwm_config[pwm].chan[i].pin, GPIO_OUT); gpio_init_af(pwm_config[pwm].chan[i].pin, pwm_config[pwm].af); i++; @@ -103,7 +103,7 @@ uint8_t pwm_channels(pwm_t pwm) assert(pwm < PWM_NUMOF); unsigned i = 0; - while ((i < TIMER_CHAN) && (pwm_config[pwm].chan[i].pin != GPIO_UNDEF)) { + while ((i < TIMER_CHAN) && !gpio_is_undef(pwm_config[pwm].chan[i].pin)) { i++; } return (uint8_t)i; @@ -113,7 +113,7 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value) { assert((pwm < PWM_NUMOF) && (channel < TIMER_CHAN) && - (pwm_config[pwm].chan[channel].pin != GPIO_UNDEF)); + !gpio_is_undef(pwm_config[pwm].chan[channel].pin)); /* norm value to maximum possible value */ if (value > dev(pwm)->ARR) { diff --git a/cpu/stm32_common/periph/qdec.c b/cpu/stm32_common/periph/qdec.c index 1b4b56d5d15a..20373b8a078c 100644 --- a/cpu/stm32_common/periph/qdec.c +++ b/cpu/stm32_common/periph/qdec.c @@ -96,7 +96,7 @@ int32_t qdec_init(qdec_t qdec, qdec_mode_t mode, qdec_cb_t cb, void *arg) /* Configure the used pins */ i = 0; - while ((i < QDEC_CHAN) && (qdec_config[qdec].chan[i].pin != GPIO_UNDEF)) { + while ((i < QDEC_CHAN) && !gpio_is_undef(qdec_config[qdec].chan[i].pin)) { gpio_init(qdec_config[qdec].chan[i].pin, GPIO_IN); gpio_init_af(qdec_config[qdec].chan[i].pin, qdec_config[qdec].af); i++; diff --git a/cpu/stm32_common/periph/spi.c b/cpu/stm32_common/periph/spi.c index ba09d3447f88..de464d81895c 100644 --- a/cpu/stm32_common/periph/spi.c +++ b/cpu/stm32_common/periph/spi.c @@ -92,13 +92,13 @@ int spi_init_cs(spi_t bus, spi_cs_t cs) if (bus >= SPI_NUMOF) { return SPI_NODEV; } - if (cs == SPI_CS_UNDEF || - (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) { + if (gpio_is_equal(cs, SPI_CS_UNDEF) || + (SPI_HWCS_IS(cs) && !gpio_is_equal(cs, SPI_HWCS(0)))) { return SPI_NOCS; } - if (cs == SPI_HWCS_MASK) { - if (spi_config[bus].cs_pin == GPIO_UNDEF) { + if (gpio_is_equal(cs, SPI_HWCS(0))) { + if (gpio_is_undef(spi_config[bus].cs_pin)) { return SPI_NOCS; } #ifdef CPU_FAM_STM32F1 @@ -109,8 +109,8 @@ int spi_init_cs(spi_t bus, spi_cs_t cs) #endif } else { - gpio_init((gpio_t)cs, GPIO_OUT); - gpio_set((gpio_t)cs); + gpio_init(cs, GPIO_OUT); + gpio_set(cs); } return SPI_OK; @@ -151,7 +151,7 @@ int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) /* enable device */ uint8_t br = spi_divtable[spi_config[bus].apbbus][clk]; dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR); - if (cs != SPI_HWCS_MASK) { + if (!SPI_HWCS_IS(cs)) { dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI); } else { @@ -274,8 +274,8 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, /* active the given chip select line */ dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */ - if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) { - gpio_clear((gpio_t)cs); + if (!SPI_HWCS_IS(cs) && !gpio_is_equal(cs, SPI_CS_UNDEF)) { + gpio_clear(cs); } #ifdef MODULE_PERIPH_DMA @@ -291,10 +291,10 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, #endif /* release the chip select if not specified differently */ - if ((!cont) && (cs != SPI_CS_UNDEF)) { + if ((!cont) && (!gpio_is_equal(cs, SPI_CS_UNDEF))) { dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */ - if (cs != SPI_HWCS_MASK) { - gpio_set((gpio_t)cs); + if (!SPI_HWCS_IS(cs)) { + gpio_set(cs); } } } diff --git a/cpu/stm32_common/periph/uart.c b/cpu/stm32_common/periph/uart.c index 4f79f6a87dca..f0a7de8a7052 100644 --- a/cpu/stm32_common/periph/uart.c +++ b/cpu/stm32_common/periph/uart.c @@ -78,7 +78,7 @@ static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate); #ifdef MODULE_STM32_PERIPH_UART_HW_FC static inline void uart_init_rts_pin(uart_t uart) { - if (uart_config[uart].rts_pin != GPIO_UNDEF) { + if (!gpio_is_undef(uart_config[uart].rts_pin)) { gpio_init(uart_config[uart].rts_pin, GPIO_OUT); #ifdef CPU_FAM_STM32F1 gpio_init_af(uart_config[uart].rts_pin, GPIO_AF_OUT_PP); @@ -90,7 +90,7 @@ static inline void uart_init_rts_pin(uart_t uart) static inline void uart_init_cts_pin(uart_t uart) { - if (uart_config[uart].cts_pin != GPIO_UNDEF) { + if (!gpio_is_undef(uart_config[uart].cts_pin)) { gpio_init(uart_config[uart].cts_pin, GPIO_IN); #ifndef CPU_FAM_STM32F1 gpio_init_af(uart_config[uart].cts_pin, uart_config[uart].cts_af); @@ -188,10 +188,10 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) } #ifdef MODULE_STM32_PERIPH_UART_HW_FC - if (uart_config[uart].cts_pin != GPIO_UNDEF) { + if (!gpio_is_undef(uart_config[uart].cts_pin)) { dev(uart)->CR3 |= USART_CR3_CTSE; } - if (uart_config[uart].rts_pin != GPIO_UNDEF) { + if (!gpio_is_undef(uart_config[uart].rts_pin)) { dev(uart)->CR3 |= USART_CR3_RTSE; } #endif @@ -386,7 +386,7 @@ void uart_poweroff(uart_t uart) #ifdef MODULE_STM32_PERIPH_UART_HW_FC /* the uart peripheral does not put RTS high from hardware when * UE flag is cleared, so we need to do this manually */ - if (uart_config[uart].rts_pin != GPIO_UNDEF) { + if (!gpio_is_undef(uart_config[uart].rts_pin)) { gpio_init(uart_config[uart].rts_pin, GPIO_OUT); gpio_set(uart_config[uart].rts_pin); } diff --git a/cpu/stm32f0/include/periph_cpu.h b/cpu/stm32f0/include/periph_cpu.h index 1bed660526c8..0d5eb835090b 100644 --- a/cpu/stm32f0/include/periph_cpu.h +++ b/cpu/stm32f0/include/periph_cpu.h @@ -40,8 +40,20 @@ enum { PORT_D = 3, /**< port D */ PORT_E = 4, /**< port E */ PORT_F = 5, /**< port F */ + GPIO_EXT_PORT = 6 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32F0 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), + #ifndef DOXYGEN /** * @brief Override ADC resolution values diff --git a/cpu/stm32f1/include/periph_cpu.h b/cpu/stm32f1/include/periph_cpu.h index 872cf42edfae..86213347163f 100644 --- a/cpu/stm32f1/include/periph_cpu.h +++ b/cpu/stm32f1/include/periph_cpu.h @@ -122,8 +122,21 @@ enum { PORT_E = 4, /**< port E */ PORT_F = 5, /**< port F */ PORT_G = 6, /**< port G */ + GPIO_EXT_PORT = 7 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32F1 familiy as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_A) }, \ + { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_B) }, \ + { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_C) }, \ + { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_D) }, \ + { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_E) }, \ + { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_F) }, \ + { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_G) }, + /** * @brief ADC channel configuration data */ diff --git a/cpu/stm32f2/include/periph_cpu.h b/cpu/stm32f2/include/periph_cpu.h index ea0b1428115f..d0ba16d6983e 100644 --- a/cpu/stm32f2/include/periph_cpu.h +++ b/cpu/stm32f2/include/periph_cpu.h @@ -44,9 +44,24 @@ enum { PORT_F = 5, /**< port F */ PORT_G = 6, /**< port G */ PORT_H = 7, /**< port H */ - PORT_I = 8 /**< port I */ + PORT_I = 8, /**< port I */ + GPIO_EXT_PORT = 9 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32F2 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_G)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_H)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_I)), + /** * @brief Available number of ADC devices */ diff --git a/cpu/stm32f3/include/periph_cpu.h b/cpu/stm32f3/include/periph_cpu.h index e63b1d5aeef4..8d3ad9f9cc4b 100644 --- a/cpu/stm32f3/include/periph_cpu.h +++ b/cpu/stm32f3/include/periph_cpu.h @@ -42,8 +42,22 @@ enum { PORT_F = 5, /**< port F */ PORT_G = 6, /**< port G */ PORT_H = 7, /**< port H */ + GPIO_EXT_PORT = 8 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32F3 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_G)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_H)), + #ifdef __cplusplus } #endif diff --git a/cpu/stm32f4/include/periph_cpu.h b/cpu/stm32f4/include/periph_cpu.h index 5faead9535bf..357ab3551eae 100644 --- a/cpu/stm32f4/include/periph_cpu.h +++ b/cpu/stm32f4/include/periph_cpu.h @@ -42,9 +42,24 @@ enum { PORT_F = 5, /**< port F */ PORT_G = 6, /**< port G */ PORT_H = 7, /**< port H */ - PORT_I = 8 /**< port I */ + PORT_I = 8, /**< port I */ + GPIO_EXT_PORT = 9 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32F4 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_G)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_H)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_I)), + /** * @brief Available number of ADC devices */ diff --git a/cpu/stm32f7/include/periph_cpu.h b/cpu/stm32f7/include/periph_cpu.h index c9eb8d752c5e..795df2ba0cdc 100644 --- a/cpu/stm32f7/include/periph_cpu.h +++ b/cpu/stm32f7/include/periph_cpu.h @@ -50,9 +50,26 @@ enum { PORT_H = 7, /**< port H */ PORT_I = 8, /**< port I */ PORT_J = 9, /**< port J */ - PORT_K = 10 /**< port K */ + PORT_K = 10, /**< port K */ + GPIO_EXT_PORT = 11 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32F7 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_G)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_H)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_I)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_J)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_K)), + #ifdef __cplusplus } #endif diff --git a/cpu/stm32l0/include/periph_cpu.h b/cpu/stm32l0/include/periph_cpu.h index 7e88ef945ed8..e3795e8232bf 100644 --- a/cpu/stm32l0/include/periph_cpu.h +++ b/cpu/stm32l0/include/periph_cpu.h @@ -43,8 +43,22 @@ enum { PORT_D = 3, /**< port D */ PORT_E = 4, /**< port E */ PORT_H = 7, /**< port H */ + GPIO_EXT_PORT = 8 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32L0 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(0), \ + GPIO_CPU_PORT(0), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_H)), + #ifndef DOXYGEN /** * @brief Override ADC resolution values diff --git a/cpu/stm32l1/include/periph_cpu.h b/cpu/stm32l1/include/periph_cpu.h index d2c48c3862e3..b41d62cda325 100644 --- a/cpu/stm32l1/include/periph_cpu.h +++ b/cpu/stm32l1/include/periph_cpu.h @@ -49,8 +49,22 @@ enum { PORT_F = 6, /**< port F */ PORT_G = 7, /**< port G */ PORT_H = 5, /**< port H */ + GPIO_EXT_PORT = 8 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32L1 family as GPIO device definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_H)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_G)), + /** * @brief ADC channel configuration data */ diff --git a/cpu/stm32l1/periph/adc.c b/cpu/stm32l1/periph/adc.c index 8cebee2fc9e9..acf6406b53ba 100644 --- a/cpu/stm32l1/periph/adc.c +++ b/cpu/stm32l1/periph/adc.c @@ -112,8 +112,9 @@ int adc_init(adc_t line) prep(); /* configure the pin */ - if ((adc_config[line].pin != GPIO_UNDEF)) + if (!gpio_is_undef(adc_config[line].pin)) { gpio_init_analog(adc_config[line].pin); + } /* set ADC clock prescaler */ ADC->CCR &= ~ADC_CCR_ADCPRE; diff --git a/cpu/stm32l4/include/periph_cpu.h b/cpu/stm32l4/include/periph_cpu.h index 48c37fb04484..31ac9a77a4cc 100644 --- a/cpu/stm32l4/include/periph_cpu.h +++ b/cpu/stm32l4/include/periph_cpu.h @@ -44,8 +44,23 @@ enum { PORT_G = 6, /**< port G */ PORT_H = 7, /**< port H */ PORT_I = 8, /**< port I */ + GPIO_EXT_PORT = 9 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the STM32L4 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_G)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_H)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_I)), + /** * @brief Available number of ADC devices */ From 6833cf050e9d6ec4d4ec3481e0195b2ce8a8bdf2 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 16:53:14 +0100 Subject: [PATCH 09/17] cpu/stm32f1: changes for new GPIO API The changes in `cpu/stm32f1` depend on `cpu/stm_common` and are not compilable separately. --- cpu/stm32f1/include/gpio_arch.h | 92 ++++++++++++++++++++ cpu/stm32f1/include/periph_cpu.h | 72 ++-------------- cpu/stm32f1/periph/gpio.c | 141 ++++++++++++------------------- 3 files changed, 155 insertions(+), 150 deletions(-) create mode 100644 cpu/stm32f1/include/gpio_arch.h diff --git a/cpu/stm32f1/include/gpio_arch.h b/cpu/stm32f1/include/gpio_arch.h new file mode 100644 index 000000000000..531d4e525a4e --- /dev/null +++ b/cpu/stm32f1/include/gpio_arch.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015-2016 Freie Universität Berlin + * 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_stm32f1 + * @{ + * + * @file + * @brief CPU specific GPIO definitions for STMF1 family + * + * @author Hauke Petersen + * @author Gunar Schorcht + */ + +#ifndef GPIO_ARCH_H +#define GPIO_ARCH_H + +#include "cpu.h" +#include "gpio_arch_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Generate GPIO mode bitfields + * + * We use 4 bit to determine the pin functions: + * - bit 4: ODR value + * - bit 2+3: in/out + * - bit 1: PU enable + * - bit 2: OD enable + */ +#define GPIO_MODE(mode, cnf, odr) (mode | (cnf << 2) | (odr << 4)) + +#ifndef DOXYGEN +/** + * @brief Override GPIO mode options + * + * We use 4 bit to encode CNF and MODE. + * @{ + */ +#define HAVE_GPIO_MODE_T +typedef enum { + GPIO_IN = GPIO_MODE(0, 1, 0), /**< input w/o pull R */ + GPIO_IN_PD = GPIO_MODE(0, 2, 0), /**< input with pull-down */ + GPIO_IN_PU = GPIO_MODE(0, 2, 1), /**< input with pull-up */ + GPIO_OUT = GPIO_MODE(3, 0, 0), /**< push-pull output */ + GPIO_OD = GPIO_MODE(3, 1, 0), /**< open-drain w/o pull R */ + GPIO_OD_PU = (0xff) /**< not supported by HW */ +} gpio_mode_t; +/** @} */ +#endif /* ndef DOXYGEN */ + +/** + * @brief Override values for pull register configuration + * @{ + */ +#define HAVE_GPIO_PP_T +typedef enum { + GPIO_NOPULL = 4, /**< do not use internal pull resistors */ + GPIO_PULLUP = 9, /**< enable internal pull-up resistor */ + GPIO_PULLDOWN = 8 /**< enable internal pull-down resistor */ +} gpio_pp_t; +/** @} */ + +#ifndef DOXYGEN +/** + * @brief Override flank configuration values + * @{ + */ +#define HAVE_GPIO_FLANK_T +typedef enum { + GPIO_RISING = 1, /**< emit interrupt on rising flank */ + GPIO_FALLING = 2, /**< emit interrupt on falling flank */ + GPIO_BOTH = 3 /**< emit interrupt on both flanks */ +} gpio_flank_t; +/** @} */ +#endif /* ndef DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* GPIO_ARCH_H */ +/** @} */ diff --git a/cpu/stm32f1/include/periph_cpu.h b/cpu/stm32f1/include/periph_cpu.h index 86213347163f..fa4106aba07e 100644 --- a/cpu/stm32f1/include/periph_cpu.h +++ b/cpu/stm32f1/include/periph_cpu.h @@ -45,17 +45,6 @@ extern "C" { */ #define TIMER_MAXVAL (0xffff) -/** - * @brief Generate GPIO mode bitfields - * - * We use 4 bit to determine the pin functions: - * - bit 4: ODR value - * - bit 2+3: in/out - * - bit 1: PU enable - * - bit 2: OD enable - */ -#define GPIO_MODE(mode, cnf, odr) (mode | (cnf << 2) | (odr << 4)) - /** * @brief Define the number of available PM modes */ @@ -66,51 +55,6 @@ extern "C" { */ #define PM_STOP_CONFIG (PWR_CR_LPDS) -#ifndef DOXYGEN -/** - * @brief Override GPIO mode options - * - * We use 4 bit to encode CNF and MODE. - * @{ - */ -#define HAVE_GPIO_MODE_T -typedef enum { - GPIO_IN = GPIO_MODE(0, 1, 0), /**< input w/o pull R */ - GPIO_IN_PD = GPIO_MODE(0, 2, 0), /**< input with pull-down */ - GPIO_IN_PU = GPIO_MODE(0, 2, 1), /**< input with pull-up */ - GPIO_OUT = GPIO_MODE(3, 0, 0), /**< push-pull output */ - GPIO_OD = GPIO_MODE(3, 1, 0), /**< open-drain w/o pull R */ - GPIO_OD_PU = (0xff) /**< not supported by HW */ -} gpio_mode_t; -/** @} */ -#endif /* ndef DOXYGEN */ - -/** - * @brief Override values for pull register configuration - * @{ - */ -#define HAVE_GPIO_PP_T -typedef enum { - GPIO_NOPULL = 4, /**< do not use internal pull resistors */ - GPIO_PULLUP = 9, /**< enable internal pull-up resistor */ - GPIO_PULLDOWN = 8 /**< enable internal pull-down resistor */ -} gpio_pp_t; -/** @} */ - -#ifndef DOXYGEN -/** - * @brief Override flank configuration values - * @{ - */ -#define HAVE_GPIO_FLANK_T -typedef enum { - GPIO_RISING = 1, /**< emit interrupt on rising flank */ - GPIO_FALLING = 2, /**< emit interrupt on falling flank */ - GPIO_BOTH = 3 /**< emit interrupt on both flanks */ -} gpio_flank_t; -/** @} */ -#endif /* ndef DOXYGEN */ - /** * @brief Available ports on the STM32F1 family */ @@ -126,16 +70,16 @@ enum { }; /** - * @brief Available ports on the STM32F1 familiy as GPIO register definitions + * @brief Available ports on the STM32F1 family as GPIO register definitions */ #define GPIO_CPU_PORTS \ - { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_A) }, \ - { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_B) }, \ - { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_C) }, \ - { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_D) }, \ - { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_E) }, \ - { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_F) }, \ - { .port.reg = (gpio_reg_t)GPIO_CPU_PORT_ADDR(PORT_G) }, + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_A)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_B)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_C)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_D)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_E)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_F)), \ + GPIO_CPU_PORT(GPIO_CPU_PORT_ADDR(PORT_G)), /** * @brief ADC channel configuration data diff --git a/cpu/stm32f1/periph/gpio.c b/cpu/stm32f1/periph/gpio.c index 1d0cec0a3168..b555dd2c4796 100644 --- a/cpu/stm32f1/periph/gpio.c +++ b/cpu/stm32f1/periph/gpio.c @@ -48,184 +48,153 @@ static gpio_isr_ctx_t exti_ctx[GPIO_ISR_CHAN_NUMOF]; #endif /* MODULE_PERIPH_GPIO_IRQ */ /** - * @brief Extract the pin's port base address from the given pin identifier + * @brief Convert port register address to port register structure */ -static inline GPIO_TypeDef *_port(gpio_t pin) +static inline GPIO_TypeDef *_port(gpio_port_t port) { - return (GPIO_TypeDef *)(pin & ~(0x0f)); + return (GPIO_TypeDef *)port.reg; } /** - * @brief Extract the port number from the given pin identifier + * @brief Extract the port number from the given device address * * Isolating bits 10 to 13 of the port base addresses leads to unique port * numbers. */ -static inline int _port_num(gpio_t pin) +static inline int _port_num(gpio_port_t port) { - return (((pin >> 10) & 0x0f) - 2); + return (((port.reg >> 10) & 0x0f) - 2); } -/** - * @brief Get the pin number from the pin identifier, encoded in the LSB 4 bit - */ -static inline int _pin_num(gpio_t pin) -{ - return (pin & 0x0f); -} - - -int gpio_init(gpio_t pin, gpio_mode_t mode) +int gpio_cpu_init(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode) { - GPIO_TypeDef *port = _port(pin); - int pin_num = _pin_num(pin); - /* open-drain output with pull-up is not supported */ if (mode == GPIO_OD_PU) { return -1; } /* enable the clock for the selected port */ - periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin))); + periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(port))); #ifdef BOARD_NUCLEO_F103RB /* disable the default SWJ RST mode to allow using the pin as IO this may also work on other f103 based boards but it was only tested on nucleo-f103rb */ - if ((pin_num == 4) && _port_num(pin)) { + if ((pin == 4) && _port_num(port)) { RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_NOJNTRST; } #endif /* set pin mode */ - port->CR[pin_num >> 3] &= ~(0xf << ((pin_num & 0x7) * 4)); - port->CR[pin_num >> 3] |= ((mode & MODE_MASK) << ((pin_num & 0x7) * 4)); + _port(port)->CR[pin >> 3] &= ~(0xf << ((pin & 0x7) * 4)); + _port(port)->CR[pin >> 3] |= ((mode & MODE_MASK) << ((pin & 0x7) * 4)); /* set ODR */ if (mode == GPIO_IN_PU) - port->ODR |= 1 << pin_num; + _port(port)->ODR |= 1 << pin; else - port->ODR &= ~(1 << pin_num); + _port(port)->ODR &= ~(1 << pin); return 0; /* all OK */ } -void gpio_init_af(gpio_t pin, gpio_af_t af) +void gpio_init_af(gpio_t gpio, gpio_af_t af) { - int pin_num = _pin_num(pin); - GPIO_TypeDef *port = _port(pin); + int pin_num = gpio.pin; + GPIO_TypeDef *port = _port(GPIO_PORT(gpio)); /* enable the clock for the selected port */ - periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin))); + periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(GPIO_PORT(gpio)))); /* configure the pin */ port->CR[pin_num >> 3] &= ~(0xf << ((pin_num & 0x7) * 4)); port->CR[pin_num >> 3] |= (af << ((pin_num & 0x7) * 4)); } -void gpio_init_analog(gpio_t pin) +void gpio_init_analog(gpio_t gpio) { + GPIO_TypeDef *port = _port(GPIO_PORT(gpio)); + /* enable the GPIO port RCC */ - periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin))); + periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(GPIO_PORT(gpio)))); /* map the pin as analog input */ - int pin_num = _pin_num(pin); - _port(pin)->CR[pin_num >= 8] &= ~(0xfl << (4 * (pin_num - ((pin_num >= 8) * 8)))); + port->CR[gpio.pin >= 8] &= ~(0xfl << (4 * (gpio.pin - ((gpio.pin >= 8) * 8)))); } -int gpio_read(gpio_t pin) +gpio_mask_t gpio_cpu_read(gpio_port_t port) { - GPIO_TypeDef *port = _port(pin); - int pin_num = _pin_num(pin); - - if (port->CR[pin_num >> 3] & (0x3 << ((pin_num & 0x7) << 2))) { - /* pin is output */ - return (port->ODR & (1 << pin_num)); - } - else { - /* or input */ - return (port->IDR & (1 << pin_num)); - } + return _port(port)->IDR; } -void gpio_set(gpio_t pin) +void gpio_cpu_set(gpio_port_t port, gpio_mask_t pins) { - _port(pin)->BSRR = (1 << _pin_num(pin)); + _port(port)->BSRR = pins; } -void gpio_clear(gpio_t pin) +void gpio_cpu_clear(gpio_port_t port, gpio_mask_t pins) { - _port(pin)->BRR = (1 << _pin_num(pin)); + _port(port)->BSRR = ((uint32_t)pins << 16); } -void gpio_toggle(gpio_t pin) +void gpio_cpu_toggle(gpio_port_t port, gpio_mask_t pins) { - if (gpio_read(pin)) { - gpio_clear(pin); - } - else { - gpio_set(pin); - } + _port(port)->ODR = _port(port)->ODR ^ pins; } -void gpio_write(gpio_t pin, int value) +void gpio_cpu_write(gpio_port_t port, gpio_mask_t values) { - if (value) { - _port(pin)->BSRR = (1 << _pin_num(pin)); - } - else { - _port(pin)->BRR = (1 << _pin_num(pin)); - } + _port(port)->ODR = values; } #ifdef MODULE_PERIPH_GPIO_IRQ -int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, - gpio_cb_t cb, void *arg) +int gpio_cpu_init_int(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg) { - int pin_num = _pin_num(pin); - /* disable interrupts on the channel we want to edit (just in case) */ - EXTI->IMR &= ~(1 << pin_num); + EXTI->IMR &= ~(1 << pin); /* configure pin as input */ - gpio_init(pin, mode); + gpio_cpu_init(port, pin, mode); /* set callback */ - exti_ctx[pin_num].cb = cb; - exti_ctx[pin_num].arg = arg; + exti_ctx[pin].cb = cb; + exti_ctx[pin].arg = arg; /* enable alternate function clock for the GPIO module */ periph_clk_en(APB2, RCC_APB2ENR_AFIOEN); /* configure the EXTI channel */ - AFIO->EXTICR[pin_num >> 2] &= ~(0xf << ((pin_num & 0x3) * 4)); - AFIO->EXTICR[pin_num >> 2] |= (_port_num(pin) << ((pin_num & 0x3) * 4)); + AFIO->EXTICR[pin >> 2] &= ~(0xf << ((pin & 0x3) * 4)); + AFIO->EXTICR[pin >> 2] |= (_port_num(port) << ((pin & 0x3) * 4)); /* configure the active flank */ - EXTI->RTSR &= ~(1 << pin_num); - EXTI->RTSR |= ((flank & 0x1) << pin_num); - EXTI->FTSR &= ~(1 << pin_num); - EXTI->FTSR |= ((flank >> 1) << pin_num); + EXTI->RTSR &= ~(1 << pin); + EXTI->RTSR |= ((flank & 0x1) << pin); + EXTI->FTSR &= ~(1 << pin); + EXTI->FTSR |= ((flank >> 1) << pin); /* active global interrupt for the selected port */ - if (pin_num < 5) { - NVIC_EnableIRQ(EXTI0_IRQn + pin_num); + if (pin < 5) { + NVIC_EnableIRQ(EXTI0_IRQn + pin); } - else if (pin_num < 10) { + else if (pin < 10) { NVIC_EnableIRQ(EXTI9_5_IRQn); } else { NVIC_EnableIRQ(EXTI15_10_IRQn); } /* clear event mask */ - EXTI->EMR &= ~(1 << pin_num); + EXTI->EMR &= ~(1 << pin); /* unmask the pins interrupt channel */ - EXTI->IMR |= (1 << pin_num); + EXTI->IMR |= (1 << pin); return 0; } -void gpio_irq_enable(gpio_t pin) +void gpio_cpu_irq_enable(gpio_port_t port, gpio_pin_t pin) { - EXTI->IMR |= (1 << _pin_num(pin)); + (void)port; + EXTI->IMR |= (1 << pin); } -void gpio_irq_disable(gpio_t pin) +void gpio_cpu_irq_disable(gpio_port_t port, gpio_pin_t pin) { - EXTI->IMR &= ~(1 << _pin_num(pin)); + (void)port; + EXTI->IMR &= ~(1 << pin); } void isr_exti(void) From 9352d64aad78f204e3cc912e2f3cf09c82421b0d Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 22 Feb 2020 15:20:23 +0100 Subject: [PATCH 10/17] cpu/stm32l4: changes for new GPIO API --- cpu/stm32l4/periph/adc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpu/stm32l4/periph/adc.c b/cpu/stm32l4/periph/adc.c index 3a567fd484fd..0e33fb64b707 100644 --- a/cpu/stm32l4/periph/adc.c +++ b/cpu/stm32l4/periph/adc.c @@ -92,15 +92,15 @@ static inline void done(adc_t line) */ static inline GPIO_TypeDef *_port(gpio_t pin) { - return (GPIO_TypeDef *)(pin & ~(0x0f)); + return (GPIO_TypeDef *)(GPIO_PORT(pin).reg); } /** * @brief Extract the pin number from the last 4 bit of the pin identifier */ -static inline int _pin_num(gpio_t pin) +static inline int _pin_num(gpio_t gpio) { - return (pin & 0x0f); + return (gpio.pin & 0x0f); } int adc_init(adc_t line) From df98b470b8f229e7cf0b663d7c71904c499327c4 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 15:23:09 +0100 Subject: [PATCH 11/17] boards/stm32*: changes for the new GPIO API --- boards/b-l072z-lrwan1/include/board.h | 1 + boards/b-l475e-iot01a/include/board.h | 1 + boards/common/nucleo64/include/board.h | 4 ++-- boards/lobaro-lorabox/include/board.h | 2 ++ boards/nz32-sc151/include/sx127x_params.h | 5 ++++- boards/p-l496g-cell02/include/board.h | 1 + boards/pyboard/include/board.h | 1 + boards/stm32f030f4-demo/include/board.h | 2 ++ boards/stm32f0discovery/include/board.h | 1 + boards/stm32f3discovery/include/board.h | 1 + boards/stm32l0538-disco/include/board.h | 1 + boards/stm32l476g-disco/include/board.h | 1 + boards/ublox-c030-u201/include/board.h | 1 + 13 files changed, 19 insertions(+), 3 deletions(-) diff --git a/boards/b-l072z-lrwan1/include/board.h b/boards/b-l072z-lrwan1/include/board.h index 5478d2b78f27..90a4b72b65aa 100644 --- a/boards/b-l072z-lrwan1/include/board.h +++ b/boards/b-l072z-lrwan1/include/board.h @@ -22,6 +22,7 @@ #include #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/b-l475e-iot01a/include/board.h b/boards/b-l475e-iot01a/include/board.h index d12a9b06b262..01765614dac4 100644 --- a/boards/b-l475e-iot01a/include/board.h +++ b/boards/b-l475e-iot01a/include/board.h @@ -22,6 +22,7 @@ #include #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/common/nucleo64/include/board.h b/boards/common/nucleo64/include/board.h index 83ab8d62fa03..4c7afe60e7d5 100644 --- a/boards/common/nucleo64/include/board.h +++ b/boards/common/nucleo64/include/board.h @@ -77,9 +77,9 @@ static const motor_driver_config_t motor_driver_config[] = { .motors = { { .pwm_channel = 0, - .gpio_enable = 0, + .gpio_enable = GPIO_UNDEF, .gpio_dir0 = ARDUINO_PIN_15, - .gpio_dir1_or_brake = 0, + .gpio_dir1_or_brake = GPIO_UNDEF, .gpio_dir_reverse = 0, .gpio_enable_invert = 0, .gpio_brake_invert = 0, diff --git a/boards/lobaro-lorabox/include/board.h b/boards/lobaro-lorabox/include/board.h index 803bc9535fb8..1ce0f0ba8e09 100644 --- a/boards/lobaro-lorabox/include/board.h +++ b/boards/lobaro-lorabox/include/board.h @@ -20,6 +20,8 @@ #ifndef BOARD_H #define BOARD_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/boards/nz32-sc151/include/sx127x_params.h b/boards/nz32-sc151/include/sx127x_params.h index 2e4a9543fdb0..1efdbcc6d73b 100644 --- a/boards/nz32-sc151/include/sx127x_params.h +++ b/boards/nz32-sc151/include/sx127x_params.h @@ -37,7 +37,10 @@ static const sx127x_params_t sx127x_params[] = .dio0_pin = GPIO_PIN(PORT_B, 0), .dio1_pin = GPIO_PIN(PORT_B, 1), .dio2_pin = GPIO_PIN(PORT_C, 6), - .dio3_pin = GPIO_PIN(PORT_A, 10) + .dio3_pin = GPIO_PIN(PORT_A, 10), + .dio4_pin = GPIO_UNDEF, + .dio5_pin = GPIO_UNDEF, + .paselect = SX127X_PA_RFO } }; diff --git a/boards/p-l496g-cell02/include/board.h b/boards/p-l496g-cell02/include/board.h index be91f01f6dc6..ce76c6aa0868 100644 --- a/boards/p-l496g-cell02/include/board.h +++ b/boards/p-l496g-cell02/include/board.h @@ -22,6 +22,7 @@ #include #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/pyboard/include/board.h b/boards/pyboard/include/board.h index 7a7d5a2441ec..f4497cd6a16d 100644 --- a/boards/pyboard/include/board.h +++ b/boards/pyboard/include/board.h @@ -24,6 +24,7 @@ #include #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/stm32f030f4-demo/include/board.h b/boards/stm32f030f4-demo/include/board.h index dcf94554bc97..00f0ec274c00 100644 --- a/boards/stm32f030f4-demo/include/board.h +++ b/boards/stm32f030f4-demo/include/board.h @@ -24,6 +24,8 @@ #ifndef BOARD_H #define BOARD_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/boards/stm32f0discovery/include/board.h b/boards/stm32f0discovery/include/board.h index f2c75db863ba..7b9a021bc7d5 100644 --- a/boards/stm32f0discovery/include/board.h +++ b/boards/stm32f0discovery/include/board.h @@ -21,6 +21,7 @@ #define BOARD_H #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/stm32f3discovery/include/board.h b/boards/stm32f3discovery/include/board.h index 0015094e2fe6..326c08529ca7 100644 --- a/boards/stm32f3discovery/include/board.h +++ b/boards/stm32f3discovery/include/board.h @@ -21,6 +21,7 @@ #define BOARD_H #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/stm32l0538-disco/include/board.h b/boards/stm32l0538-disco/include/board.h index 45d811290518..3f016e846b46 100644 --- a/boards/stm32l0538-disco/include/board.h +++ b/boards/stm32l0538-disco/include/board.h @@ -20,6 +20,7 @@ #define BOARD_H #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/stm32l476g-disco/include/board.h b/boards/stm32l476g-disco/include/board.h index edddb5cfc87d..c887dd337030 100644 --- a/boards/stm32l476g-disco/include/board.h +++ b/boards/stm32l476g-disco/include/board.h @@ -24,6 +24,7 @@ #include #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/ublox-c030-u201/include/board.h b/boards/ublox-c030-u201/include/board.h index 90449132cb67..cb7b2777e839 100644 --- a/boards/ublox-c030-u201/include/board.h +++ b/boards/ublox-c030-u201/include/board.h @@ -24,6 +24,7 @@ #include #include "cpu.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { From b836cfb52c1bceefe51da83bee7060d12ba30597 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 17:31:18 +0100 Subject: [PATCH 12/17] boards/stm32f1: changes for new GPIO API --- boards/common/blxxxpill/include/board_common.h | 2 ++ boards/maple-mini/include/board.h | 2 ++ boards/opencm904/include/board.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/boards/common/blxxxpill/include/board_common.h b/boards/common/blxxxpill/include/board_common.h index a405eadd8cfc..c28aa3a22740 100644 --- a/boards/common/blxxxpill/include/board_common.h +++ b/boards/common/blxxxpill/include/board_common.h @@ -24,6 +24,8 @@ #ifndef BOARD_COMMON_H #define BOARD_COMMON_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/boards/maple-mini/include/board.h b/boards/maple-mini/include/board.h index 924075b6caa3..30eebfba7aed 100644 --- a/boards/maple-mini/include/board.h +++ b/boards/maple-mini/include/board.h @@ -20,6 +20,8 @@ #ifndef BOARD_H #define BOARD_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/boards/opencm904/include/board.h b/boards/opencm904/include/board.h index f927ce4cede2..be9f0f4bc891 100644 --- a/boards/opencm904/include/board.h +++ b/boards/opencm904/include/board.h @@ -20,6 +20,8 @@ #ifndef BOARD_H #define BOARD_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif From 2f833c16fdf6febc5f0e1064df81ee99aeeb5669 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 13:29:15 +0100 Subject: [PATCH 13/17] cpu/atmega*: changes for new GPIO API --- cpu/atmega1281/include/periph_cpu.h | 13 +++ cpu/atmega1284p/include/periph_cpu.h | 17 ++-- cpu/atmega128rfa1/include/periph_cpu.h | 23 +++-- cpu/atmega2560/include/periph_cpu.h | 39 ++++++--- cpu/atmega256rfr2/include/periph_cpu.h | 23 +++-- cpu/atmega328p/include/periph_cpu.h | 17 ++-- cpu/atmega32u4/include/periph_cpu.h | 14 ++- cpu/atmega_common/Makefile.dep | 3 + cpu/atmega_common/Makefile.features | 2 +- cpu/atmega_common/include/atmega_gpio.h | 50 +++++------ cpu/atmega_common/include/gpio_arch.h | 67 ++++++++++++++ cpu/atmega_common/include/periph_cpu_common.h | 41 +-------- cpu/atmega_common/periph/gpio.c | 87 +++++++++---------- cpu/atmega_common/periph/pwm.c | 16 ++-- cpu/atmega_common/periph/spi.c | 4 +- drivers/ws281x/atmega.c | 6 +- 16 files changed, 264 insertions(+), 158 deletions(-) create mode 100644 cpu/atmega_common/include/gpio_arch.h diff --git a/cpu/atmega1281/include/periph_cpu.h b/cpu/atmega1281/include/periph_cpu.h index 07ebe56a75fd..4da17364f6c6 100644 --- a/cpu/atmega1281/include/periph_cpu.h +++ b/cpu/atmega1281/include/periph_cpu.h @@ -40,8 +40,21 @@ enum { PORT_E = 4, /**< port E */ PORT_F = 5, /**< port F */ PORT_G = 6, /**< port G */ + GPIO_EXT_PORT = 7 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the ATmega1281 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(0x22), /* port A */ \ + GPIO_CPU_PORT(0x25), /* port B */ \ + GPIO_CPU_PORT(0x28), /* port C */ \ + GPIO_CPU_PORT(0x2b), /* port D */ \ + GPIO_CPU_PORT(0x2e), /* port E */ \ + GPIO_CPU_PORT(0x31), /* port F */ \ + GPIO_CPU_PORT(0x34), /* port G */ + /** * @brief Available external interrupt pins on the ATmega1281 family * diff --git a/cpu/atmega1284p/include/periph_cpu.h b/cpu/atmega1284p/include/periph_cpu.h index e61349c6e45a..2bb516e8daf8 100644 --- a/cpu/atmega1284p/include/periph_cpu.h +++ b/cpu/atmega1284p/include/periph_cpu.h @@ -29,11 +29,6 @@ extern "C" { #endif -/** - * @brief Define a CPU specific GPIO pin generator macro - */ -#define GPIO_PIN(x, y) ((x << 4) | y) - /** * @brief Available ports on the ATmega1284p family */ @@ -41,9 +36,19 @@ enum { PORT_A = 0, /**< port A */ PORT_B = 1, /**< port B */ PORT_C = 2, /**< port C */ - PORT_D = 3 /**< port D */ + PORT_D = 3, /**< port D */ + GPIO_EXT_PORT = 4 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the ATmega1284p family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(0x22), /* port A */ \ + GPIO_CPU_PORT(0x25), /* port B */ \ + GPIO_CPU_PORT(0x28), /* port C */ \ + GPIO_CPU_PORT(0x2b), /* port D */ + /** * @brief Available external interrupt pins on the ATmega1284p family * diff --git a/cpu/atmega128rfa1/include/periph_cpu.h b/cpu/atmega128rfa1/include/periph_cpu.h index 9cfa5ae6c07c..585057f7b284 100644 --- a/cpu/atmega128rfa1/include/periph_cpu.h +++ b/cpu/atmega128rfa1/include/periph_cpu.h @@ -32,14 +32,27 @@ extern "C" { * @{ */ enum { - PORT_B = 1, /**< port B */ - PORT_D = 3, /**< port D */ - PORT_E = 4, /**< port E */ - PORT_F = 5, /**< port F */ - PORT_G = 6, /**< port G */ + PORT_B = 1, /**< port B */ + PORT_D = 3, /**< port D */ + PORT_E = 4, /**< port E */ + PORT_F = 5, /**< port F */ + PORT_G = 6, /**< port G */ + GPIO_EXT_PORT = 7 /**< first GPIO extender port */ }; /** @} */ +/** + * @brief Available ports on the ATmega128rfa1 MCU as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(0 ), /* n/a */ \ + GPIO_CPU_PORT(0x25), /* port B */ \ + GPIO_CPU_PORT(0 ), /* n/a */ \ + GPIO_CPU_PORT(0x2b), /* port D */ \ + GPIO_CPU_PORT(0x2e), /* port E */ \ + GPIO_CPU_PORT(0x31), /* port F */ \ + GPIO_CPU_PORT(0x34), /* port G */ + /** * @brief Available external interrupt pins on the ATmega128rfa1 MCU * diff --git a/cpu/atmega2560/include/periph_cpu.h b/cpu/atmega2560/include/periph_cpu.h index 2002edc28cb1..d7950a31901b 100644 --- a/cpu/atmega2560/include/periph_cpu.h +++ b/cpu/atmega2560/include/periph_cpu.h @@ -31,19 +31,36 @@ extern "C" { * @brief Available ports on the ATmega2560 family */ enum { - PORT_A = 0, /**< port A */ - PORT_B = 1, /**< port B */ - PORT_C = 2, /**< port C */ - PORT_D = 3, /**< port D */ - PORT_E = 4, /**< port E */ - PORT_F = 5, /**< port F */ - PORT_G = 6, /**< port G */ - PORT_H = 7, /**< port H */ - PORT_J = 8, /**< port J */ - PORT_K = 9, /**< port K */ - PORT_L = 10 /**< port L */ + PORT_A = 0, /**< port A */ + PORT_B = 1, /**< port B */ + PORT_C = 2, /**< port C */ + PORT_D = 3, /**< port D */ + PORT_E = 4, /**< port E */ + PORT_F = 5, /**< port F */ + PORT_G = 6, /**< port G */ + PORT_H = 7, /**< port H */ + PORT_J = 8, /**< port J */ + PORT_K = 9, /**< port K */ + PORT_L = 10, /**< port L */ + GPIO_EXT_PORT = 11 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the ATmega2560 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(0x22), /* port A */ \ + GPIO_CPU_PORT(0x25), /* port B */ \ + GPIO_CPU_PORT(0x28), /* port C */ \ + GPIO_CPU_PORT(0x2b), /* port D */ \ + GPIO_CPU_PORT(0x2e), /* port E */ \ + GPIO_CPU_PORT(0x31), /* port F */ \ + GPIO_CPU_PORT(0x34), /* port G */ \ + GPIO_CPU_PORT(0x102), /* port H */ \ + GPIO_CPU_PORT(0x105), /* port J */ \ + GPIO_CPU_PORT(0x108), /* port K */ \ + GPIO_CPU_PORT(0x10b), /* port L */ + /** * @brief Available external interrupt pins on the ATmega2560 family * diff --git a/cpu/atmega256rfr2/include/periph_cpu.h b/cpu/atmega256rfr2/include/periph_cpu.h index 49d1305e3490..a1433301bc20 100644 --- a/cpu/atmega256rfr2/include/periph_cpu.h +++ b/cpu/atmega256rfr2/include/periph_cpu.h @@ -32,14 +32,27 @@ extern "C" { * @{ */ enum { - PORT_B = 1, /**< port B */ - PORT_D = 3, /**< port D */ - PORT_E = 4, /**< port E */ - PORT_F = 5, /**< port F */ - PORT_G = 6, /**< port G */ + PORT_B = 1, /**< port B */ + PORT_D = 3, /**< port D */ + PORT_E = 4, /**< port E */ + PORT_F = 5, /**< port F */ + PORT_G = 6, /**< port G */ + GPIO_EXT_PORT = 7 /**< first GPIO extender port */ }; /** @} */ +/** + * @brief Available ports on the ATmega256rfr2 MCU as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(0 ), /* n/a */ \ + GPIO_CPU_PORT(0x25), /* port B */ \ + GPIO_CPU_PORT(0 ), /* n/a */ \ + GPIO_CPU_PORT(0x2b), /* port D */ \ + GPIO_CPU_PORT(0x2e), /* port E */ \ + GPIO_CPU_PORT(0x31), /* port F */ \ + GPIO_CPU_PORT(0x34), /* port G */ + /** * @brief Available external interrupt pins on the ATmega256rfr family * diff --git a/cpu/atmega328p/include/periph_cpu.h b/cpu/atmega328p/include/periph_cpu.h index ac4be4cd09ce..29a8b59ab2b5 100644 --- a/cpu/atmega328p/include/periph_cpu.h +++ b/cpu/atmega328p/include/periph_cpu.h @@ -27,20 +27,25 @@ extern "C" { #endif -/** - * @brief Define a CPU specific GPIO pin generator macro - */ -#define GPIO_PIN(x, y) ((x << 4) | y) - /** * @brief Available ports on the ATmega328p family */ enum { PORT_B = 1, /**< port B */ PORT_C = 2, /**< port C */ - PORT_D = 3 /**< port D */ + PORT_D = 3, /**< port D */ + GPIO_EXT_PORT = 4 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the ATmega328p family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(0 ), /* n/a */ \ + GPIO_CPU_PORT(0x25), /* port B */ \ + GPIO_CPU_PORT(0x28), /* port C */ \ + GPIO_CPU_PORT(0x2b), /* port D */ + /** * @brief Available external interrupt pins on the ATmega328p family * diff --git a/cpu/atmega32u4/include/periph_cpu.h b/cpu/atmega32u4/include/periph_cpu.h index 603ef706255c..ad1fc495490f 100644 --- a/cpu/atmega32u4/include/periph_cpu.h +++ b/cpu/atmega32u4/include/periph_cpu.h @@ -34,9 +34,21 @@ enum { PORT_C = 2, /**< port C */ PORT_D = 3, /**< port D */ PORT_E = 4, /**< port E */ - PORT_F = 5 /**< port F */ + PORT_F = 5, /**< port F */ + GPIO_EXT_PORT = 6 /**< first GPIO extender port */ }; +/** + * @brief Available ports on the ATmega32u4 family as GPIO register definitions + */ +#define GPIO_CPU_PORTS \ + GPIO_CPU_PORT(0 ), /* n/a */ \ + GPIO_CPU_PORT(0x25), /* port B */ \ + GPIO_CPU_PORT(0x28), /* port C */ \ + GPIO_CPU_PORT(0x2b), /* port D */ \ + GPIO_CPU_PORT(0x2e), /* port E */ \ + GPIO_CPU_PORT(0x31), /* port F */ + /** * @brief Available external interrupt pins on the ATmega32u4 family * diff --git a/cpu/atmega_common/Makefile.dep b/cpu/atmega_common/Makefile.dep index 33fa82c5cfa5..e4aefb34add9 100644 --- a/cpu/atmega_common/Makefile.dep +++ b/cpu/atmega_common/Makefile.dep @@ -7,6 +7,9 @@ USEMODULE += atmega_common # peripheral drivers are linked into the final binary USEMODULE += atmega_common_periph +# 8 bit GPIO pin mask required +USEMODULE += gpio_mask_8bit + # the atmel port uses stdio_uart USEMODULE += stdio_uart diff --git a/cpu/atmega_common/Makefile.features b/cpu/atmega_common/Makefile.features index 7067896b24fb..1c6980c7188d 100644 --- a/cpu/atmega_common/Makefile.features +++ b/cpu/atmega_common/Makefile.features @@ -2,7 +2,7 @@ FEATURES_PROVIDED += arch_8bit FEATURES_PROVIDED += arch_avr8 FEATURES_PROVIDED += atmega_pcint0 FEATURES_PROVIDED += periph_eeprom -FEATURES_PROVIDED += periph_gpio periph_gpio_irq +FEATURES_PROVIDED += periph_gpio periph_gpio_irq periph_gpio_ext FEATURES_PROVIDED += periph_pm FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_wdt diff --git a/cpu/atmega_common/include/atmega_gpio.h b/cpu/atmega_common/include/atmega_gpio.h index f4befd77192a..771b0bf94f3b 100644 --- a/cpu/atmega_common/include/atmega_gpio.h +++ b/cpu/atmega_common/include/atmega_gpio.h @@ -43,55 +43,55 @@ extern "C" { #define ATMEGA_GPIO_OFFSET_PIN_PORT (0x02) #define ATMEGA_GPIO_OFFSET_PIN_PIN (0x03) + /** * @brief Extract the pin number of the given pin */ -static inline uint8_t atmega_pin_num(gpio_t pin) +static inline uint8_t atmega_pin_num(gpio_pin_t pin) { - return (pin & 0x0f); + return (pin & 0x07); } /** - * @brief Extract the port number of the given pin + * @brief Generate the PORTx address of the give port. */ -static inline uint8_t atmega_port_num(gpio_t pin) +static inline gpio_reg_t atmega_port_addr(gpio_port_t port) { - return (pin >> 4) & 0x0f; + return port.reg; } /** - * @brief Generate the PORTx address of the give pin. + * @brief Generate the DDRx address of the given port. */ -static inline uint16_t atmega_port_addr(gpio_t pin) +static inline gpio_reg_t atmega_ddr_addr(gpio_port_t port) { - uint8_t port_num = atmega_port_num(pin); - uint16_t port_addr = port_num * ATMEGA_GPIO_OFFSET_PIN_PIN; - - port_addr += ATMEGA_GPIO_BASE_PORT_A; - port_addr += ATMEGA_GPIO_OFFSET_PIN_PORT; - -#if defined (PORTG) - if (port_num > PORT_G) { - port_addr += ATMEGA_GPIO_OFFSET_PORT_H; - } -#endif - return port_addr; + return (atmega_port_addr(port) - 0x01); } /** - * @brief Generate the DDRx address of the given pin + * @brief Generate the PINx address of the given port. */ -static inline uint16_t atmega_ddr_addr(gpio_t pin) +static inline gpio_reg_t atmega_pin_addr(gpio_port_t port) { - return (atmega_port_addr(pin) - 0x01); + return (atmega_port_addr(port) - 0x02); } /** - * @brief Generate the PINx address of the given pin. + * @brief Generate the port number of the given port */ -static inline uint16_t atmega_pin_addr(gpio_t pin) +static inline uint8_t atmega_port_num(gpio_port_t port) { - return (atmega_port_addr(pin) - 0x02); + gpio_reg_t port_addr = atmega_port_addr(port); + +#ifdef PORTG + if (port_addr > ATMEGA_GPIO_OFFSET_PORT_H) { + port_addr -= ATMEGA_GPIO_OFFSET_PORT_H; + } +#endif + port_addr -= ATMEGA_GPIO_OFFSET_PIN_PORT; + port_addr -= ATMEGA_GPIO_BASE_PORT_A; + + return port_addr / ATMEGA_GPIO_OFFSET_PIN_PIN; } #ifdef __cplusplus diff --git a/cpu/atmega_common/include/gpio_arch.h b/cpu/atmega_common/include/gpio_arch.h new file mode 100644 index 000000000000..51e298c1c316 --- /dev/null +++ b/cpu/atmega_common/include/gpio_arch.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 HAW Hamburg + * 2016 Freie Universität Berlin + * 2016 INRIA + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_atmega_common + * @{ + * + * @file + * @brief CPU specific definitions for GPIOs + * + * @author René Herthel + * @author Hauke Petersen + * @author Francisco Acosta + */ + +#ifndef GPIO_ARCH_H +#define GPIO_ARCH_H + +#include "cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN + +/** + * @brief Override register address type for GPIO ports of the MCU + * + * The size of this type must match the size of a pointer to distinguish + * between MCU GPIO register addresses and pointers on GPIO devices. + */ +#define HAVE_GPIO_REG_T +typedef uint16_t gpio_reg_t; + +/** + * @brief Override the GPIO flanks + * + * This device has an additional mode in which the interrupt is triggered + * when the pin is low. + * + * Enumeration order is important, do not modify. + * @{ + */ +#define HAVE_GPIO_FLANK_T +typedef enum { + GPIO_LOW, /**< emit interrupt when pin low */ + GPIO_BOTH, /**< emit interrupt on both flanks */ + GPIO_FALLING, /**< emit interrupt on falling flank */ + GPIO_RISING, /**< emit interrupt on rising flank */ +} gpio_flank_t; +/** @} */ +#endif /* ndef DOXYGEN */ + +#ifdef __cplusplus +} +#endif + +#endif /* GPIO_ARCH_H */ +/** @} */ diff --git a/cpu/atmega_common/include/periph_cpu_common.h b/cpu/atmega_common/include/periph_cpu_common.h index 7f798d7e2bd3..107f9e94d30b 100644 --- a/cpu/atmega_common/include/periph_cpu_common.h +++ b/cpu/atmega_common/include/periph_cpu_common.h @@ -24,6 +24,7 @@ #define PERIPH_CPU_COMMON_H #include "cpu.h" +#include "periph/gpio.h" #ifdef __cplusplus extern "C" { @@ -36,46 +37,6 @@ extern "C" { #define CPUID_LEN (4U) /** @} */ -#ifndef DOXYGEN -/** - * @brief Overwrite the default gpio_t type definition - * @{ - */ -#define HAVE_GPIO_T -typedef uint8_t gpio_t; -/** @} */ -#endif - -/** - * @brief Definition of a fitting UNDEF value - */ -#define GPIO_UNDEF (0xff) - -/** - * @brief Define a CPU specific GPIO pin generator macro - */ -#define GPIO_PIN(x, y) ((x << 4) | y) - -#ifndef DOXYGEN -/** - * @brief Override the GPIO flanks - * - * This device has an additional mode in which the interrupt is triggered - * when the pin is low. - * - * Enumeration order is important, do not modify. - * @{ - */ -#define HAVE_GPIO_FLANK_T -typedef enum { - GPIO_LOW, /**< emit interrupt when pin low */ - GPIO_BOTH, /**< emit interrupt on both flanks */ - GPIO_FALLING, /**< emit interrupt on falling flank */ - GPIO_RISING, /**< emit interrupt on rising flank */ -} gpio_flank_t; -/** @} */ -#endif /* ndef DOXYGEN */ - /** * @brief Use some common SPI functions * @{ diff --git a/cpu/atmega_common/periph/gpio.c b/cpu/atmega_common/periph/gpio.c index ba7b46200451..d0212bc63b08 100644 --- a/cpu/atmega_common/periph/gpio.c +++ b/cpu/atmega_common/periph/gpio.c @@ -150,21 +150,21 @@ static gpio_isr_ctx_pcint_t pcint_config[8 * PCINT_NUM_BANKS]; #endif /* MODULE_PERIPH_GPIO_IRQ */ -int gpio_init(gpio_t pin, gpio_mode_t mode) +int gpio_cpu_init(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode) { uint8_t pin_mask = (1 << atmega_pin_num(pin)); switch (mode) { case GPIO_OUT: - _SFR_MEM8(atmega_ddr_addr(pin)) |= pin_mask; + _SFR_MEM8(atmega_ddr_addr(port)) |= pin_mask; break; case GPIO_IN: - _SFR_MEM8(atmega_ddr_addr(pin)) &= ~pin_mask; - _SFR_MEM8(atmega_port_addr(pin)) &= ~pin_mask; + _SFR_MEM8(atmega_ddr_addr(port)) &= ~pin_mask; + _SFR_MEM8(atmega_port_addr(port)) &= ~pin_mask; break; case GPIO_IN_PU: - _SFR_MEM8(atmega_ddr_addr(pin)) &= ~pin_mask; - _SFR_MEM8(atmega_port_addr(pin)) |= pin_mask; + _SFR_MEM8(atmega_ddr_addr(port)) &= ~pin_mask; + _SFR_MEM8(atmega_port_addr(port)) |= pin_mask; break; default: return -1; @@ -173,50 +173,44 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) return 0; } -int gpio_read(gpio_t pin) +gpio_mask_t gpio_cpu_read(gpio_port_t port) { - return (_SFR_MEM8(atmega_pin_addr(pin)) & (1 << atmega_pin_num(pin))); + return _SFR_MEM8(atmega_pin_addr(port)); } -void gpio_set(gpio_t pin) +void gpio_cpu_set(gpio_port_t port, gpio_mask_t pins) { - _SFR_MEM8(atmega_port_addr(pin)) |= (1 << atmega_pin_num(pin)); + _SFR_MEM8(atmega_port_addr(port)) |= pins; } -void gpio_clear(gpio_t pin) +void gpio_cpu_clear(gpio_port_t port, gpio_mask_t pins) { - _SFR_MEM8(atmega_port_addr(pin)) &= ~(1 << atmega_pin_num(pin)); + _SFR_MEM8(atmega_port_addr(port)) &= ~pins; } -void gpio_toggle(gpio_t pin) +void gpio_cpu_toggle(gpio_port_t port, gpio_mask_t pins) { - if (gpio_read(pin)) { - gpio_clear(pin); - } - else { - gpio_set(pin); - } + /* + * According to the data sheet, writing a one to PIN toggles the bit in + * the PORT register, independent on the value of DDR. + */ + _SFR_MEM8(atmega_pin_addr(port)) = _SFR_MEM8(atmega_ddr_addr(port)) & pins; } -void gpio_write(gpio_t pin, int value) +void gpio_cpu_write(gpio_port_t port, gpio_mask_t values) { - if (value) { - gpio_set(pin); - } - else { - gpio_clear(pin); - } + _SFR_MEM8(atmega_port_addr(port)) &= _SFR_MEM8(atmega_ddr_addr(port)) & values; } #ifdef MODULE_PERIPH_GPIO_IRQ -static inline int8_t _int_num(gpio_t pin) +static inline int8_t _int_num(gpio_port_t port, gpio_pin_t pin) { uint8_t num; const gpio_t ext_ints[GPIO_EXT_INT_NUMOF] = CPU_ATMEGA_EXT_INTS; /* find pin in ext_ints array to get the interrupt number */ for (num = 0; num < GPIO_EXT_INT_NUMOF; num++) { - if (pin == ext_ints[num]) { + if (port.dev == GPIO_PORT(ext_ints[num]).dev && pin == ext_ints[num].pin) { return num; } } @@ -225,15 +219,16 @@ static inline int8_t _int_num(gpio_t pin) } #ifdef ENABLE_PCINT -static inline int pcint_init_int(gpio_t pin, gpio_mode_t mode, - gpio_flank_t flank, +static inline int pcint_init_int(gpio_port_t port, gpio_pin_t pin, + gpio_mode_t mode, gpio_flank_t flank, gpio_cb_t cb, void *arg) { int8_t offset = -1; uint8_t pin_num = atmega_pin_num(pin); for (unsigned i = 0; i < ARRAY_SIZE(pcint_mapping); i++) { - if (pin != GPIO_UNDEF && pin == pcint_mapping[i]) { + if (port.dev != NULL && pin != GPIO_PIN_UNDEF && + port.dev == GPIO_PORT(pcint_mapping[i]).dev && pin == pcint_mapping[i].pin) { offset = i; break; } @@ -255,7 +250,7 @@ static inline int pcint_init_int(gpio_t pin, gpio_mode_t mode, pcint_config[offset].cb = cb; /* init gpio */ - gpio_init(pin, mode); + gpio_cpu_init(port, pin, mode); /* configure pcint */ cli(); switch (bank) { @@ -288,7 +283,7 @@ static inline int pcint_init_int(gpio_t pin, gpio_mode_t mode, break; } /* As ports are mixed in a bank (e.g. PCINT0), we can only save a single bit here! */ - uint8_t port_value = (_SFR_MEM8(atmega_pin_addr( pin ))); + uint8_t port_value = (_SFR_MEM8(atmega_pin_addr( port ))); uint8_t pin_mask = (1 << pin_num); uint8_t pin_value = ((port_value & pin_mask) != 0); if (pin_value) { @@ -302,10 +297,10 @@ static inline int pcint_init_int(gpio_t pin, gpio_mode_t mode, } #endif /* ENABLE_PCINT */ -int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, - gpio_cb_t cb, void *arg) +int gpio_cpu_init_int(gpio_port_t port, gpio_pin_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg) { - int8_t int_num = _int_num(pin); + int8_t int_num = _int_num(port, pin); /* mode not supported */ if ((mode != GPIO_IN) && (mode != GPIO_IN_PU)) { @@ -316,7 +311,7 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, if (int_num < 0) { #ifdef ENABLE_PCINT /* If pin change interrupts are enabled, enable mask and interrupt */ - return pcint_init_int(pin, mode, flank, cb, arg); + return pcint_init_int(port, pin, mode, flank, cb, arg); #else return -1; #endif /* ENABLE_PCINT */ @@ -327,7 +322,7 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, return -1; } - gpio_init(pin, mode); + gpio_cpu_init(port, pin, mode); /* clear global interrupt flag */ cli(); @@ -358,15 +353,17 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, return 0; } -void gpio_irq_enable(gpio_t pin) +void gpio_cpu_irq_enable(gpio_port_t port, gpio_pin_t pin) { - EIFR |= (1 << _int_num(pin)); - EIMSK |= (1 << _int_num(pin)); + int8_t num = _int_num(port, pin); + EIFR |= (1 << num); + EIMSK |= (1 << num); } -void gpio_irq_disable(gpio_t pin) +void gpio_cpu_irq_disable(gpio_port_t port, gpio_pin_t pin) { - EIMSK &= ~(1 << _int_num(pin)); + (void)port; + EIMSK &= ~(1 << _int_num(port, pin)); } static inline void irq_handler(uint8_t int_num) @@ -390,9 +387,9 @@ static inline void pcint_handler(uint8_t bank, uint8_t enabled_pcints) /* get pin from mapping (assumes 8 entries per bank!) */ gpio_t pin = pcint_mapping[bank * 8 + idx]; /* re-construct mask from pin */ - uint8_t pin_mask = (1 << (atmega_pin_num(pin))); + uint8_t pin_mask = (1 << (atmega_pin_num(pin.pin))); uint8_t idx_mask = (1 << idx); - uint8_t port_value = (_SFR_MEM8(atmega_pin_addr( pin ))); + uint8_t port_value = (_SFR_MEM8(atmega_pin_addr(GPIO_PORT(pin)))); uint8_t pin_value = ((port_value & pin_mask) != 0); uint8_t old_state = ((pcint_state[bank] & idx_mask) != 0); gpio_isr_ctx_pcint_t *conf = &pcint_config[bank * 8 + idx]; diff --git a/cpu/atmega_common/periph/pwm.c b/cpu/atmega_common/periph/pwm.c index 21b5d93e71ed..cf554c8df77a 100644 --- a/cpu/atmega_common/periph/pwm.c +++ b/cpu/atmega_common/periph/pwm.c @@ -64,7 +64,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) /* only left implemented, max resolution 256 */ assert(dev < PWM_NUMOF && mode == PWM_LEFT && res <= 256); /* resolution != 256 only valid if ch0 not used */ - assert(!(res != 256 && pwm_conf[dev].pin_ch[0] != GPIO_UNDEF)); + assert(!(res != 256 && !gpio_is_undef(pwm_conf[dev].pin_ch[0]))); /* disable PWM */ pwm_conf[dev].dev->CRA = 0x00; @@ -92,7 +92,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) res -= 1; /* configure pins and resolution. Output must be low at initialization. * Force the pin low to avoid flickering. */ - if (pwm_conf[dev].pin_ch[0] != GPIO_UNDEF) { + if (!gpio_is_undef(pwm_conf[dev].pin_ch[0])) { gpio_init(pwm_conf[dev].pin_ch[0], GPIO_OUT); gpio_clear(pwm_conf[dev].pin_ch[0]); } @@ -101,7 +101,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) pwm_conf[dev].dev->OCR[0] = (uint8_t)res; } - if (pwm_conf[dev].pin_ch[1] != GPIO_UNDEF) { + if (!gpio_is_undef(pwm_conf[dev].pin_ch[1])) { gpio_init(pwm_conf[dev].pin_ch[1], GPIO_OUT); gpio_clear(pwm_conf[dev].pin_ch[1]); } @@ -122,8 +122,8 @@ uint8_t pwm_channels(pwm_t dev) /* a pwm with no channels enabled makes no sense. Assume at least one is * enabled */ - if (pwm_conf[dev].pin_ch[0] == GPIO_UNDEF || - pwm_conf[dev].pin_ch[1] == GPIO_UNDEF) { + if (gpio_is_undef(pwm_conf[dev].pin_ch[0]) || + gpio_is_undef(pwm_conf[dev].pin_ch[1])) { return 1; } @@ -132,7 +132,7 @@ uint8_t pwm_channels(pwm_t dev) void pwm_set(pwm_t dev, uint8_t ch, uint16_t value) { - assert(dev < PWM_NUMOF && ch <= 1 && pwm_conf[dev].pin_ch[ch] != GPIO_UNDEF); + assert(dev < PWM_NUMOF && ch <= 1 && !gpio_is_undef(pwm_conf[dev].pin_ch[ch])); /* output flickers when duty cycle is 0 or 100%. Simply force the pin * low or high respectively to have a clean output. */ @@ -178,11 +178,11 @@ void pwm_poweroff(pwm_t dev) power_timer0_disable(); } - if (pwm_conf[dev].pin_ch[0] != GPIO_UNDEF) { + if (!gpio_is_undef(pwm_conf[dev].pin_ch[0])) { gpio_clear(pwm_conf[dev].pin_ch[0]); } - if (pwm_conf[dev].pin_ch[1] != GPIO_UNDEF) { + if (!gpio_is_undef(pwm_conf[dev].pin_ch[1])) { gpio_clear(pwm_conf[dev].pin_ch[1]); } } diff --git a/cpu/atmega_common/periph/spi.c b/cpu/atmega_common/periph/spi.c index bbb023015cfb..3e224b8abae8 100644 --- a/cpu/atmega_common/periph/spi.c +++ b/cpu/atmega_common/periph/spi.c @@ -117,7 +117,7 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, assert(out_buf || in_buf); - if (cs != SPI_CS_UNDEF) { + if (!gpio_is_equal(cs, SPI_CS_UNDEF)) { gpio_clear((gpio_t)cs); } @@ -131,7 +131,7 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, } } - if ((!cont) && (cs != SPI_CS_UNDEF)) { + if ((!cont) && !gpio_is_equal(cs, SPI_CS_UNDEF)) { gpio_set((gpio_t)cs); } } diff --git a/drivers/ws281x/atmega.c b/drivers/ws281x/atmega.c index b549d39812a1..f367190e8c22 100644 --- a/drivers/ws281x/atmega.c +++ b/drivers/ws281x/atmega.c @@ -85,13 +85,13 @@ void ws281x_write_buffer(ws281x_t *dev, const void *buf, size_t size) assert(dev); const uint8_t *pos = buf; const uint8_t *end = pos + size; - uint16_t port_addr = atmega_port_addr(dev->params.pin); + uint16_t port_addr = atmega_port_addr(dev->params.pin.port); uint8_t mask_on, mask_off; { uint8_t port_state = _SFR_MEM8(port_addr); - mask_on = port_state | (1 << atmega_pin_num(dev->params.pin)); - mask_off = port_state & ~(1 << atmega_pin_num(dev->params.pin)); + mask_on = port_state | (1 << atmega_pin_num(dev->params.pin.pin)); + mask_off = port_state & ~(1 << atmega_pin_num(dev->params.pin.pin)); } #if (CLOCK_CORECLOCK >= 7500000U) && (CLOCK_CORECLOCK <= 8500000U) From 1c36f923662a0c13de24a5b838212e025a37994c Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 17 Jan 2020 15:26:45 +0100 Subject: [PATCH 14/17] boards/atmega*: changes for new GPIO API --- boards/atmega256rfr2-xpro/include/board.h | 9 +++++---- boards/avr-rss2/include/board.h | 1 + boards/mega-xplained/include/board.h | 18 +++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/boards/atmega256rfr2-xpro/include/board.h b/boards/atmega256rfr2-xpro/include/board.h index 7e4edde9fa41..4f6b57987563 100644 --- a/boards/atmega256rfr2-xpro/include/board.h +++ b/boards/atmega256rfr2-xpro/include/board.h @@ -20,6 +20,7 @@ #define BOARD_H #include "cpu.h" +#include "periph_cpu.h" #include "periph/gpio.h" #ifdef __cplusplus @@ -48,10 +49,10 @@ extern "C" { */ #define LED0_PIN GPIO_PIN(PORT_B, 4) #define LED0_MODE GPIO_OUT -#define LED0_ENABLE_PORT DDRB |= LED0_PIN -#define LED0_ON PORTB |= LED0_PIN -#define LED0_OFF PORTB &= ~LED0_PIN -#define LED0_TOGGLE PORTB ^= LED0_PIN +#define LED0_ENABLE_PORT DDRB |= LED0_PIN.pin +#define LED0_ON PORTB |= LED0_PIN.pin +#define LED0_OFF PORTB &= ~LED0_PIN.pin +#define LED0_TOGGLE PORTB ^= LED0_PIN.pin /** @} */ /** diff --git a/boards/avr-rss2/include/board.h b/boards/avr-rss2/include/board.h index 4f625eaeec2b..9e3ec8e98cd8 100644 --- a/boards/avr-rss2/include/board.h +++ b/boards/avr-rss2/include/board.h @@ -22,6 +22,7 @@ #include "cpu.h" #include "periph/gpio.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" { diff --git a/boards/mega-xplained/include/board.h b/boards/mega-xplained/include/board.h index e79f4ef13e0d..4d15ead102c9 100644 --- a/boards/mega-xplained/include/board.h +++ b/boards/mega-xplained/include/board.h @@ -79,15 +79,15 @@ extern "C" { * @{ */ /* LED0,2 currently unsupported due to lack of GPIO_OD support */ -#define LED1_ENABLE_PORT DDRB |= LED1_PIN -#define LED1_ON PORTB |= LED1_PIN -#define LED1_OFF PORTB &= ~LED1_PIN -#define LED1_TOGGLE PORTB ^= LED1_PIN - -#define LED3_ENABLE_PORT DDRB |= LED3_PIN -#define LED3_ON PORTB |= LED3_PIN -#define LED3_OFF PORTB &= ~LED3_PIN -#define LED3_TOGGLE PORTB ^= LED3_PIN +#define LED1_ENABLE_PORT DDRB |= LED1_PIN.pin +#define LED1_ON PORTB |= LED1_PIN.pin +#define LED1_OFF PORTB &= ~LED1_PIN.pin +#define LED1_TOGGLE PORTB ^= LED1_PIN.pin + +#define LED3_ENABLE_PORT DDRB |= LED3_PIN.pin +#define LED3_ON PORTB |= LED3_PIN.pin +#define LED3_OFF PORTB &= ~LED3_PIN.pin +#define LED3_TOGGLE PORTB ^= LED3_PIN.pin /** @} */ /** From 5d6567db97bb7cec03d8f5f4ee66904dc83934dc Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 18 Jan 2020 16:21:13 +0100 Subject: [PATCH 15/17] drivers/ws281x: change for new GPIO API --- drivers/ws281x/atmega.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ws281x/atmega.c b/drivers/ws281x/atmega.c index f367190e8c22..312935493c71 100644 --- a/drivers/ws281x/atmega.c +++ b/drivers/ws281x/atmega.c @@ -85,7 +85,7 @@ void ws281x_write_buffer(ws281x_t *dev, const void *buf, size_t size) assert(dev); const uint8_t *pos = buf; const uint8_t *end = pos + size; - uint16_t port_addr = atmega_port_addr(dev->params.pin.port); + uint16_t port_addr = atmega_port_addr(GPIO_PORT(dev->params.pin)); uint8_t mask_on, mask_off; { @@ -95,7 +95,7 @@ void ws281x_write_buffer(ws281x_t *dev, const void *buf, size_t size) } #if (CLOCK_CORECLOCK >= 7500000U) && (CLOCK_CORECLOCK <= 8500000U) - const uint8_t port_num = atmega_port_num(dev->params.pin); + const uint8_t port_num = atmega_port_num(GPIO_PORT(dev->params.pin)); switch (port_num) { case PORT_B: while (pos < end) { From 07e9dd4cfe3763811b2004229d7ed3622593c4e7 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 24 Jan 2020 15:26:58 +0100 Subject: [PATCH 16/17] doc: fix doxygen warning for new GPIO API --- doc/doxygen/riot.doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/doxygen/riot.doxyfile b/doc/doxygen/riot.doxyfile index 0bbe5fcc40eb..d1b1324c4637 100644 --- a/doc/doxygen/riot.doxyfile +++ b/doc/doxygen/riot.doxyfile @@ -2360,7 +2360,7 @@ PLANTUML_JAR_PATH = # Minimum value: 0, maximum value: 10000, default value: 50. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_GRAPH_MAX_NODES = 200 +DOT_GRAPH_MAX_NODES = 300 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # generated by dot. A depth value of 3 means that only nodes reachable from the From 23783b746f956f14905380b258e1665afb2d986c Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 22 Feb 2020 12:49:27 +0100 Subject: [PATCH 17/17] tests: test application for gpio extension --- tests/periph_gpio_ext/Makefile | 16 ++ tests/periph_gpio_ext/Makefile.ci | 8 + tests/periph_gpio_ext/bar_gpio_ext.c | 100 ++++++++ tests/periph_gpio_ext/bar_gpio_ext.h | 65 +++++ tests/periph_gpio_ext/foo_gpio_ext.c | 100 ++++++++ tests/periph_gpio_ext/foo_gpio_ext.h | 65 +++++ tests/periph_gpio_ext/gpio_ext_conf.c | 38 +++ tests/periph_gpio_ext/gpio_ext_conf.h | 59 +++++ tests/periph_gpio_ext/main.c | 343 ++++++++++++++++++++++++++ tests/periph_gpio_ext/tests/01-run.py | 78 ++++++ 10 files changed, 872 insertions(+) create mode 100644 tests/periph_gpio_ext/Makefile create mode 100644 tests/periph_gpio_ext/Makefile.ci create mode 100644 tests/periph_gpio_ext/bar_gpio_ext.c create mode 100644 tests/periph_gpio_ext/bar_gpio_ext.h create mode 100644 tests/periph_gpio_ext/foo_gpio_ext.c create mode 100644 tests/periph_gpio_ext/foo_gpio_ext.h create mode 100644 tests/periph_gpio_ext/gpio_ext_conf.c create mode 100644 tests/periph_gpio_ext/gpio_ext_conf.h create mode 100644 tests/periph_gpio_ext/main.c create mode 100755 tests/periph_gpio_ext/tests/01-run.py diff --git a/tests/periph_gpio_ext/Makefile b/tests/periph_gpio_ext/Makefile new file mode 100644 index 000000000000..762f2e7ba3ee --- /dev/null +++ b/tests/periph_gpio_ext/Makefile @@ -0,0 +1,16 @@ +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_gpio +FEATURES_REQUIRED = periph_gpio_ext +FEATURES_OPTIONAL = periph_gpio_irq + +USEMODULE += extend_gpio +USEMODULE += shell +USEMODULE += benchmark + +INCLUDES += -I$(APPDIR) + +include $(RIOTBASE)/Makefile.include + +bench: + tests/02-bench.py diff --git a/tests/periph_gpio_ext/Makefile.ci b/tests/periph_gpio_ext/Makefile.ci new file mode 100644 index 000000000000..a9ca96961596 --- /dev/null +++ b/tests/periph_gpio_ext/Makefile.ci @@ -0,0 +1,8 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-nano \ + arduino-uno \ + atmega328p \ + stm32f030f4-demo \ + # diff --git a/tests/periph_gpio_ext/bar_gpio_ext.c b/tests/periph_gpio_ext/bar_gpio_ext.c new file mode 100644 index 000000000000..d0fb5c5a5457 --- /dev/null +++ b/tests/periph_gpio_ext/bar_gpio_ext.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests_periph_gpio_ext + * @{ + * + * @file + * @brief Example GPIO extender driver + * + * @author Gunar Schorcht + */ + +#ifdef MODULE_EXTEND_GPIO + +#include "bar_gpio_ext.h" + +const gpio_driver_t bar_gpio_ext_driver = { + .init = (gpio_dev_init_t)bar_gpio_ext_init, +#ifdef MODULE_PERIPH_GPIO_IRQ + .init_int = (gpio_dev_init_int_t)bar_gpio_ext_init_int, + .irq_enable = (gpio_dev_irq_enable_t)bar_gpio_ext_irq_enable, + .irq_disable = (gpio_dev_irq_disable_t)bar_gpio_ext_irq_disable, +#endif + .read = (gpio_dev_read_t)bar_gpio_ext_read, + .set = (gpio_dev_set_t)bar_gpio_ext_set, + .clear = (gpio_dev_clear_t)bar_gpio_ext_clear, + .toggle = (gpio_dev_toggle_t)bar_gpio_ext_toggle, + .write = (gpio_dev_write_t)bar_gpio_ext_write, +}; + +int bar_gpio_ext_init(bar_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode) +{ + (void)mode; + printf("init dev %p (%s) pin %u\n", dev, dev->name, pin); + return 0; +} + +#ifdef MODULE_PERIPH_GPIO_IRQ +int bar_gpio_ext_init_int(bar_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg) +{ + (void)mode; + (void)flank; + (void)cb; + (void)arg; + printf("init_int dev %p (%s) pin %u\n", dev, dev->name, pin); + return 0; +} + +void bar_gpio_ext_irq_enable(bar_gpio_ext_t *dev, uint8_t pin) +{ + printf("irq_enable dev %p (%s) pin %u\n", dev, dev->name, pin); +} + +void bar_gpio_ext_irq_disable(bar_gpio_ext_t *dev, uint8_t pin) +{ + printf("irq_disable dev %p (%s) pin %u\n", dev, dev->name, pin); +} +#endif + +gpio_mask_t bar_gpio_ext_read(bar_gpio_ext_t *dev) +{ + printf("read dev %p (%s) state 0x%02x\n", dev, dev->name, dev->state); + return dev->state; +} + +void bar_gpio_ext_set(bar_gpio_ext_t *dev, gpio_mask_t pins) +{ + dev->state |= pins; + printf("set dev %p (%s) pins 0x%02x, state 0x%02x\n", + dev, dev->name, pins, dev->state); +} + +void bar_gpio_ext_clear(bar_gpio_ext_t *dev, gpio_mask_t pins) +{ + dev->state &= ~pins; + printf("clear dev %p (%s) pins 0x%02x, state 0x%02x\n", + dev, dev->name, pins, dev->state); +} + +void bar_gpio_ext_toggle(bar_gpio_ext_t *dev, gpio_mask_t pins) +{ + dev->state ^= pins; + printf("toggle dev %p (%s) pins 0x%02x, state 0x%02x\n", + dev, dev->name, pins, dev->state);} + +void bar_gpio_ext_write(bar_gpio_ext_t *dev, gpio_mask_t values) +{ + dev->state = values; + printf("write dev %p (%s) values 0x%02x, state 0x%02x\n", + dev, dev->name, values, dev->state); +} + +#endif /* MODULE_EXTEND_GPIO */ diff --git a/tests/periph_gpio_ext/bar_gpio_ext.h b/tests/periph_gpio_ext/bar_gpio_ext.h new file mode 100644 index 000000000000..05acfc1942a0 --- /dev/null +++ b/tests/periph_gpio_ext/bar_gpio_ext.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests_periph_gpio_ext + * @{ + * + * @file + * @brief Example GPIO extender driver + * + * @author Gunar Schorcht + */ + +#ifndef BAR_GPIO_EXT_H +#define BAR_GPIO_EXT_H + +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Example GPIO extender device structure type + */ +typedef struct { + const char *name; + gpio_mask_t state; +} bar_gpio_ext_t; + +/** + * @brief Example GPIO extender driver structure + */ +extern const gpio_driver_t bar_gpio_ext_driver; + +/** + * @name API of the example GPIO extender driver that implements the + * low-level GPIO API. + * @{ + */ +int bar_gpio_ext_init(bar_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode); +#ifdef MODULE_PERIPH_GPIO_IRQ +int bar_gpio_ext_init_int(bar_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg); +void bar_gpio_ext_irq_enable(bar_gpio_ext_t *dev, uint8_t pin); +void bar_gpio_ext_irq_disable(bar_gpio_ext_t *dev, uint8_t pin); +#endif +gpio_mask_t bar_gpio_ext_read(bar_gpio_ext_t *dev); +void bar_gpio_ext_set(bar_gpio_ext_t *dev, gpio_mask_t pins); +void bar_gpio_ext_clear(bar_gpio_ext_t *dev, gpio_mask_t pins); +void bar_gpio_ext_toggle(bar_gpio_ext_t *dev, gpio_mask_t pins); +void bar_gpio_ext_write(bar_gpio_ext_t *dev, gpio_mask_t values); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* BAR_GPIO_EXT_H */ +/** @} */ diff --git a/tests/periph_gpio_ext/foo_gpio_ext.c b/tests/periph_gpio_ext/foo_gpio_ext.c new file mode 100644 index 000000000000..cd41fe0f905f --- /dev/null +++ b/tests/periph_gpio_ext/foo_gpio_ext.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests_periph_gpio_ext + * @{ + * + * @file + * @brief Example GPIO extender driver + * + * @author Gunar Schorcht + */ + +#ifdef MODULE_EXTEND_GPIO + +#include "foo_gpio_ext.h" + +const gpio_driver_t foo_gpio_ext_driver = { + .init = (gpio_dev_init_t)foo_gpio_ext_init, +#ifdef MODULE_PERIPH_GPIO_IRQ + .init_int = (gpio_dev_init_int_t)foo_gpio_ext_init_int, + .irq_enable = (gpio_dev_irq_enable_t)foo_gpio_ext_irq_enable, + .irq_disable = (gpio_dev_irq_disable_t)foo_gpio_ext_irq_disable, +#endif + .read = (gpio_dev_read_t)foo_gpio_ext_read, + .set = (gpio_dev_set_t)foo_gpio_ext_set, + .clear = (gpio_dev_clear_t)foo_gpio_ext_clear, + .toggle = (gpio_dev_toggle_t)foo_gpio_ext_toggle, + .write = (gpio_dev_write_t)foo_gpio_ext_write, +}; + +int foo_gpio_ext_init(foo_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode) +{ + (void)mode; + printf("init dev %p (%s) pin %u\n", dev, dev->name, pin); + return 0; +} + +#ifdef MODULE_PERIPH_GPIO_IRQ +int foo_gpio_ext_init_int(foo_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg) +{ + (void)mode; + (void)flank; + (void)cb; + (void)arg; + printf("init_int dev %p (%s) pin %u\n", dev, dev->name, pin); + return 0; +} + +void foo_gpio_ext_irq_enable(foo_gpio_ext_t *dev, uint8_t pin) +{ + printf("irq_enable dev %p (%s) pin %u\n", dev, dev->name, pin); +} + +void foo_gpio_ext_irq_disable(foo_gpio_ext_t *dev, uint8_t pin) +{ + printf("irq_disable dev %p (%s) pin %u\n", dev, dev->name, pin); +} +#endif + +gpio_mask_t foo_gpio_ext_read(foo_gpio_ext_t *dev) +{ + printf("read dev %p (%s) state 0x%02x\n", dev, dev->name, dev->state); + return dev->state; +} + +void foo_gpio_ext_set(foo_gpio_ext_t *dev, gpio_mask_t pins) +{ + dev->state |= pins; + printf("set dev %p (%s) pins 0x%02x, state 0x%02x\n", + dev, dev->name, pins, dev->state); +} + +void foo_gpio_ext_clear(foo_gpio_ext_t *dev, gpio_mask_t pins) +{ + dev->state &= ~pins; + printf("clear dev %p (%s) pins 0x%02x, state 0x%02x\n", + dev, dev->name, pins, dev->state); +} + +void foo_gpio_ext_toggle(foo_gpio_ext_t *dev, gpio_mask_t pins) +{ + dev->state ^= pins; + printf("toggle dev %p (%s) pins 0x%02x, state 0x%02x\n", + dev, dev->name, pins, dev->state);} + +void foo_gpio_ext_write(foo_gpio_ext_t *dev, gpio_mask_t values) +{ + dev->state = values; + printf("write dev %p (%s) values 0x%02x, state 0x%02x\n", + dev, dev->name, values, dev->state); +} + +#endif /* MODULE_EXTEND_GPIO */ diff --git a/tests/periph_gpio_ext/foo_gpio_ext.h b/tests/periph_gpio_ext/foo_gpio_ext.h new file mode 100644 index 000000000000..6c37bff690b1 --- /dev/null +++ b/tests/periph_gpio_ext/foo_gpio_ext.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests_periph_gpio_ext + * @{ + * + * @file + * @brief Example GPIO extender driver + * + * @author Gunar Schorcht + */ + +#ifndef FOO_GPIO_EXT_H +#define FOO_GPIO_EXT_H + +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Example GPIO extender device structure type + */ +typedef struct { + const char *name; + gpio_mask_t state; +} foo_gpio_ext_t; + +/** + * @brief Example GPIO extender driver structure + */ +extern const gpio_driver_t foo_gpio_ext_driver; + +/** + * @name API of the example GPIO extender driver that implements the + * low-level GPIO API. + * @{ + */ +int foo_gpio_ext_init(foo_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode); +#ifdef MODULE_PERIPH_GPIO_IRQ +int foo_gpio_ext_init_int(foo_gpio_ext_t *dev, uint8_t pin, gpio_mode_t mode, + gpio_flank_t flank, gpio_cb_t cb, void *arg); +void foo_gpio_ext_irq_enable(foo_gpio_ext_t *dev, uint8_t pin); +void foo_gpio_ext_irq_disable(foo_gpio_ext_t *dev, uint8_t pin); +#endif +gpio_mask_t foo_gpio_ext_read(foo_gpio_ext_t *dev); +void foo_gpio_ext_set(foo_gpio_ext_t *dev, gpio_mask_t pins); +void foo_gpio_ext_clear(foo_gpio_ext_t *dev, gpio_mask_t pins); +void foo_gpio_ext_toggle(foo_gpio_ext_t *dev, gpio_mask_t pins); +void foo_gpio_ext_write(foo_gpio_ext_t *dev, gpio_mask_t values); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* FOO_GPIO_EXT_H */ +/** @} */ diff --git a/tests/periph_gpio_ext/gpio_ext_conf.c b/tests/periph_gpio_ext/gpio_ext_conf.c new file mode 100644 index 000000000000..8d2f8ff9b8bd --- /dev/null +++ b/tests/periph_gpio_ext/gpio_ext_conf.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests_periph_gpio_ext + * @{ + * + * @file + * @brief Example GPIO extender configuration + * + * The configuration of GPIO extenders is either part of the board definition + * or of the application. In the latter case, the application's `Makefile` must + * add the according include PATH for the configuration before it includes the + * default `$(RIOTBASE)/Makefile.include`. + * ``` + * INCLUDES += -I$(APPDIR) + * ``` + * + * @author Gunar Schorcht + */ + +#ifdef MODULE_EXTEND_GPIO + +#include "gpio_ext_conf.h" + +/** + * @brief Definition of example GPIO extender devices + */ +foo_gpio_ext_t foo_gpio_ext_1 = { .name = "foo1" }; +foo_gpio_ext_t foo_gpio_ext_2 = { .name = "foo2" }; +bar_gpio_ext_t bar_gpio_ext = { .name = "bar" }; + +#endif /* MODULE_EXTEND_GPIO */ diff --git a/tests/periph_gpio_ext/gpio_ext_conf.h b/tests/periph_gpio_ext/gpio_ext_conf.h new file mode 100644 index 000000000000..5277c6d9e3dd --- /dev/null +++ b/tests/periph_gpio_ext/gpio_ext_conf.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests_periph_gpio_ext + * @{ + * + * @file + * @brief Example GPIO extender configuration + * + * The configuration of GPIO extenders is either part of the board definition + * or of the application. In the latter case, the application's `Makefile` must + * add the according include PATH for the configuration before it includes the + * default `$(RIOTBASE)/Makefile.include`. + * ``` + * INCLUDES += -I$(APPDIR) + * ``` + * + * @author Gunar Schorcht + */ + +#ifndef GPIO_EXT_CONF_H +#define GPIO_EXT_CONF_H + +#include "periph/gpio.h" + +#include "foo_gpio_ext.h" /* include header of `foo` GPIO extender driver */ +#include "bar_gpio_ext.h" /* include header of `bar` GPIO extender driver */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Declaration of example GPIO extender devices + */ +extern foo_gpio_ext_t foo_gpio_ext_1; +extern foo_gpio_ext_t foo_gpio_ext_2; +extern bar_gpio_ext_t bar_gpio_ext; + +/** + * @brief Example GPIO extender configuration + */ +#define GPIO_EXT_PORTS \ + { .port.dev = &foo_gpio_ext_1, .driver = &foo_gpio_ext_driver }, \ + { .port.dev = &foo_gpio_ext_2, .driver = &foo_gpio_ext_driver }, \ + { .port.dev = &bar_gpio_ext , .driver = &bar_gpio_ext_driver }, + +#ifdef __cplusplus +} +#endif + +#endif /* GPIO_EXT_CONF_H */ +/** @} */ diff --git a/tests/periph_gpio_ext/main.c b/tests/periph_gpio_ext/main.c new file mode 100644 index 000000000000..e230cc572536 --- /dev/null +++ b/tests/periph_gpio_ext/main.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2014,2017 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup tests + * @defgroup tests_periph_gpio_ext + * @{ + * + * @file + * @brief Test application for GPIO peripheral drivers + * + * @author Hauke Petersen + * + * @} + */ + +#include +#include +#include + +#include "irq.h" +#include "shell.h" +#include "benchmark.h" +#include "periph/gpio.h" + +#define BENCH_RUNS_DEFAULT (1000UL * 1000) + +#ifdef MODULE_PERIPH_GPIO_IRQ +static void cb(void *arg) +{ + printf("INT: external interrupt from GPIO_PIN(%i, %i)\n", + (int)arg >> 8, (int)arg & 0xff); +} +#endif + +static int str2port(char *port) +{ + if (strncmp(port, "ext", 3) == 0) { + return GPIO_EXT_PORT + atoi(&port[3]); + } + else { + return atoi(port); + } +} + +static int init_pin(int argc, char **argv, gpio_mode_t mode) +{ + int po, pi; + + if (argc < 3) { + printf("usage: %s \n", argv[0]); + return 1; + } + + po = str2port(argv[1]); + pi = atoi(argv[2]); + + if (gpio_init(GPIO_PIN(po, pi), mode) < 0) { + printf("Error to initialize GPIO_PIN(%i, %i)\n", po, pi); + return 1; + } + + return 0; +} + +static int init_out(int argc, char **argv) +{ + return init_pin(argc, argv, GPIO_OUT); +} + +static int init_in(int argc, char **argv) +{ + return init_pin(argc, argv, GPIO_IN); +} + +static int init_in_pu(int argc, char **argv) +{ + return init_pin(argc, argv, GPIO_IN_PU); +} + +static int init_in_pd(int argc, char **argv) +{ + return init_pin(argc, argv, GPIO_IN_PD); +} + +static int init_od(int argc, char **argv) +{ + return init_pin(argc, argv, GPIO_OD); +} + +static int init_od_pu(int argc, char **argv) +{ + return init_pin(argc, argv, GPIO_OD_PU); +} + +#ifdef MODULE_PERIPH_GPIO_IRQ +static int init_int(int argc, char **argv) +{ + int po, pi; + gpio_mode_t mode = GPIO_IN; + gpio_flank_t flank; + int fl; + + if (argc < 4) { + printf("usage: %s [pull_config]\n", argv[0]); + puts("\tflank:\n" + "\t0: falling\n" + "\t1: rising\n" + "\t2: both\n" + "\tpull_config:\n" + "\t0: no pull resistor (default)\n" + "\t1: pull up\n" + "\t2: pull down"); + return 1; + } + + po = str2port(argv[1]); + pi = atoi(argv[2]); + + fl = atoi(argv[3]); + switch (fl) { + case 0: + flank = GPIO_FALLING; + break; + case 1: + flank = GPIO_RISING; + break; + case 2: + flank = GPIO_BOTH; + break; + default: + puts("error: invalid value for active flank"); + return 1; + } + + if (argc >= 5) { + int pr = atoi(argv[4]); + switch (pr) { + case 0: + mode = GPIO_IN; + break; + case 1: + mode = GPIO_IN_PU; + break; + case 2: + mode = GPIO_IN_PD; + break; + default: + puts("error: invalid pull resistor option"); + return 1; + } + } + + if (gpio_init_int(GPIO_PIN(po, pi), mode, flank, cb, (void *)((po << 8) + pi)) < 0) { + printf("error: init_int of GPIO_PIN(%i, %i) failed\n", po, pi); + return 1; + } + printf("GPIO_PIN(%i, %i) successfully initialized as ext int\n", po, pi); + + return 0; +} + +static int enable_int(int argc, char **argv) +{ + int po, pi; + int status; + + if (argc < 4) { + printf("usage: %s \n", argv[0]); + puts("\tstatus:\n" + "\t0: disable\n" + "\t1: enable\n"); + return 1; + } + + po = str2port(argv[1]); + pi = atoi(argv[2]); + + status = atoi(argv[3]); + + switch (status) { + case 0: + puts("disabling GPIO interrupt"); + gpio_irq_disable(GPIO_PIN(po, pi)); + break; + case 1: + puts("enabling GPIO interrupt"); + gpio_irq_enable(GPIO_PIN(po, pi)); + break; + default: + puts("error: invalid status"); + return 1; + } + + return 0; +} +#endif + +static int read(int argc, char **argv) +{ + int port, pin; + + if (argc < 3) { + printf("usage: %s \n", argv[0]); + return 1; + } + + port = str2port(argv[1]); + pin = atoi(argv[2]); + + if (gpio_read(GPIO_PIN(port, pin))) { + printf("GPIO_PIN(%i, %i) is HIGH\n", port, pin); + } + else { + printf("GPIO_PIN(%i, %i) is LOW\n", port, pin); + } + + return 0; +} + +static int set(int argc, char **argv) +{ + if (argc < 3) { + printf("usage: %s \n", argv[0]); + return 1; + } + + gpio_set(GPIO_PIN(str2port(argv[1]), atoi(argv[2]))); + + return 0; +} + +static int clear(int argc, char **argv) +{ + if (argc < 3) { + printf("usage: %s \n", argv[0]); + return 1; + } + + gpio_clear(GPIO_PIN(str2port(argv[1]), atoi(argv[2]))); + + return 0; +} + +static int toggle(int argc, char **argv) +{ + if (argc < 3) { + printf("usage: %s \n", argv[0]); + return 1; + } + + gpio_toggle(GPIO_PIN(str2port(argv[1]), atoi(argv[2]))); + + return 0; +} + +static int writep(int argc, char **argv) +{ + if (argc < 4) { + printf("usage: %s \n", argv[0]); + return 1; + } + + gpio_write(GPIO_PIN(str2port(argv[1]), atoi(argv[2])), atoi(argv[3])); + + return 0; +} + +/* BENCHMARK_FUNC disables the interrupts and do not work on some platforms */ +#define MY_BENCHMARK_FUNC(name, runs, func) \ + { \ + uint32_t _benchmark_time = xtimer_now_usec(); \ + for (unsigned long i = 0; i < runs; i++) { \ + func; \ + } \ + _benchmark_time = (xtimer_now_usec() - _benchmark_time);\ + benchmark_print_time(_benchmark_time, runs, name); \ + } + +static int bench(int argc, char **argv) +{ + if (argc < 3) { + printf("usage: %s [# of runs]\n", argv[0]); + return 1; + } + + gpio_t pin = GPIO_PIN(str2port(argv[1]), atoi(argv[2])); + unsigned long runs = BENCH_RUNS_DEFAULT; + if (argc > 3) { + runs = (unsigned long)atol(argv[3]); + } + + puts("\nGPIO driver run-time performance benchmark\n"); + MY_BENCHMARK_FUNC("nop loop", runs, __asm__ volatile("nop")); + MY_BENCHMARK_FUNC("gpio_set", runs, gpio_set(pin)); + MY_BENCHMARK_FUNC("gpio_clear", runs, gpio_clear(pin)); + MY_BENCHMARK_FUNC("gpio_toggle", runs, gpio_toggle(pin)); + MY_BENCHMARK_FUNC("gpio_read", runs, (void)gpio_read(pin)); + MY_BENCHMARK_FUNC("gpio_write", runs, gpio_write(pin, 1)); + puts("\n --- DONE ---"); + return 0; +} + +static const shell_command_t shell_commands[] = { + { "init_out", "init as output (push-pull mode)", init_out }, + { "init_in", "init as input w/o pull resistor", init_in }, + { "init_in_pu", "init as input with pull-up", init_in_pu }, + { "init_in_pd", "init as input with pull-down", init_in_pd }, + { "init_od", "init as output (open-drain without pull resistor)", init_od }, + { "init_od_pu", "init as output (open-drain with pull-up)", init_od_pu }, +#ifdef MODULE_PERIPH_GPIO_IRQ + { "init_int", "init as external INT w/o pull resistor", init_int }, + { "enable_int", "enable or disable gpio interrupt", enable_int }, +#endif + { "read", "read pin status", read }, + { "set", "set pin to HIGH", set }, + { "clear", "set pin to LOW", clear }, + { "toggle", "toggle pin", toggle }, + { "write", "write pin", writep }, + { "bench", "run a set of predefined benchmarks", bench }, + { NULL, NULL, NULL } +}; + +int main(void) +{ + puts("GPIO peripheral driver test\n"); + puts("In this test, pins are specified by integer port and pin numbers.\n" + "So if your platform has a pin PA01, it will be port=0 and pin=1,\n" + "PC14 would be port=2 and pin=14 etc.\n\n" + "NOTE: make sure the values you use exist on your platform! The\n" + " behavior for not existing ports/pins is not defined!"); + + /* start the shell */ + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +} diff --git a/tests/periph_gpio_ext/tests/01-run.py b/tests/periph_gpio_ext/tests/01-run.py new file mode 100755 index 000000000000..2cacd69e2cfb --- /dev/null +++ b/tests/periph_gpio_ext/tests/01-run.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2017 Freie Universität Berlin +# 2020 Gunar Schorcht +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +# On slow platforms, like AVR, this test can take some time to complete. +TIMEOUT = 30 + + +def testfunc(child): + child.expect_exact("GPIO peripheral driver test") + child.expect_exact(">") + + # execute bench for a MCU port to verify that MCU ports still work when + # GPIO extension is enabled + child.sendline("bench 0 0") + child.expect(r" *nop loop: +(\d+)us --- +(\d+\.\d+)us per call --- +(\d+) calls per sec") + child.expect(r" *gpio_set: +(\d+)us --- +(\d+\.\d+)us per call --- +(\d+) calls per sec") + child.expect(r" *gpio_clear: +(\d+)us --- +(\d+\.\d+)us per call --- +(\d+) calls per sec") + child.expect(r" *gpio_toggle: +(\d+)us --- +(\d+\.\d+)us per call --- +(\d+) calls per sec") + child.expect(r" *gpio_read: +(\d+)us --- +(\d+\.\d+)us per call --- +(\d+) calls per sec") + child.expect(r" *gpio_write: +(\d+)us --- +(\d+\.\d+)us per call --- +(\d+) calls per sec") + child.expect_exact(" --- DONE ---") + child.expect_exact(">") + + # test all functions with first example GPIO extender + child.sendline("init_out ext0 3") + child.expect(r"init dev (0[xX])?[\dA-Fa-f]+ \(foo1\) pin 3") + child.expect_exact(">") + child.sendline("init_out ext0 5") + child.expect(r"init dev (0[xX])?[\dA-Fa-f]+ \(foo1\) pin 5") + child.expect_exact(">") + child.sendline("set ext0 3") + child.expect(r"set dev (0[xX])?[\dA-Fa-f]+ \(foo1\) pins 0x08, state 0x08") + child.expect_exact(">") + child.sendline("read ext0 3") + child.expect(r"read dev (0[xX])?[\dA-Fa-f]+ \(foo1\) state 0x08") + child.expect(r"GPIO_PIN\(\d+, 3\) is HIGH") + child.expect_exact(">") + child.sendline("read ext0 5") + child.expect(r"read dev (0[xX])?[\dA-Fa-f]+ \(foo1\) state 0x08") + child.expect(r"GPIO_PIN\(\d+, 5\) is LOW") + child.expect_exact(">") + child.sendline("toggle ext0 5") + child.expect(r"toggle dev (0[xX])?[\dA-Fa-f]+ \(foo1\) pins 0x20, state 0x28") + child.expect_exact(">") + child.sendline("read ext0 5") + child.expect(r"read dev (0[xX])?[\dA-Fa-f]+ \(foo1\) state 0x28") + child.expect(r"GPIO_PIN\(\d+, 5\) is HIGH") + child.expect_exact(">") + child.sendline("write ext0 5 0") + child.expect(r"clear dev (0[xX])?[\dA-Fa-f]+ \(foo1\) pins 0x20, state 0x08") + child.expect_exact(">") + child.sendline("write ext0 5 1") + child.expect(r"set dev (0[xX])?[\dA-Fa-f]+ \(foo1\) pins 0x20, state 0x28") + child.expect_exact(">") + + # test the correct redirection to the other example GPIO extenders + child.sendline("init_out ext1 1") + child.expect(r"init dev (0[xX])?[\dA-Fa-f]+ \(foo2\) pin 1") + child.expect_exact(">") + child.sendline("init_out ext2 2") + child.expect(r"init dev (0[xX])?[\dA-Fa-f]+ \(bar\) pin 2") + child.expect_exact(">") + + print("SUCCESS") + + +if __name__ == "__main__": + sys.exit(run(testfunc, timeout=TIMEOUT))