From 7b7eb9d17bc7d88fcacc8c8890f6818d3156cb04 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 19 Aug 2022 15:32:09 +0200 Subject: [PATCH] cpu/nrf5x: allow multiple I2C and SPI buses on a shared periph --- cpu/nrf52/include/periph_cpu.h | 12 +++++--- cpu/nrf52/spi_twi_irq.c | 11 +++++-- cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c | 30 +++++++++++++++---- cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c | 32 +++++++++++++++++---- cpu/nrf9160/include/periph_cpu.h | 12 +++++--- cpu/nrf9160/spi_twi_irq.c | 10 +++++-- 6 files changed, 84 insertions(+), 23 deletions(-) diff --git a/cpu/nrf52/include/periph_cpu.h b/cpu/nrf52/include/periph_cpu.h index d888c0a55c..ae3ca87a8f 100644 --- a/cpu/nrf52/include/periph_cpu.h +++ b/cpu/nrf52/include/periph_cpu.h @@ -268,8 +268,10 @@ void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, * @brief Acquire the shared I2C/SPI peripheral in I2C mode * * @param bus bus to acquire exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument */ -void nrf5x_i2c_acquire(NRF_TWIM_Type *bus); +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); /** * @brief Release the shared I2C/SPI peripheral in I2C mode @@ -281,16 +283,18 @@ void nrf5x_i2c_release(NRF_TWIM_Type *bus); /** * @brief Acquire the shared I2C/SPI peripheral in SPI mode * - * @param bus bus to acquire exclusive access on + * @param bus bus to release exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument */ -void nrf5x_spi_release(NRF_SPIM_Type *bus); +void nrf5x_spi_acquire(NRF_SPIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); /** * @brief Acquire the shared I2C/SPI peripheral in SPI mode * * @param bus bus to release exclusive access on */ -void nrf5x_spi_acquire(NRF_SPIM_Type *bus); +void nrf5x_spi_release(NRF_SPIM_Type *bus); /** * @brief USBDEV buffers must be word aligned because of DMA restrictions diff --git a/cpu/nrf52/spi_twi_irq.c b/cpu/nrf52/spi_twi_irq.c index 6db7b0065f..30083c16a9 100644 --- a/cpu/nrf52/spi_twi_irq.c +++ b/cpu/nrf52/spi_twi_irq.c @@ -140,19 +140,26 @@ void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, _irq[num] = cb; _irq_arg[num] = arg; + NVIC_EnableIRQ(_isr[num]); } -void nrf5x_i2c_acquire(NRF_TWIM_Type *bus) +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, + spi_twi_irq_cb_t cb, void *arg) { size_t num = _i2c_dev2num(bus); mutex_lock(&_locks[num]); + _irq[num] = cb; + _irq_arg[num] = arg; } -void nrf5x_spi_acquire(NRF_SPIM_Type *bus) +void nrf5x_spi_acquire(NRF_SPIM_Type *bus, + spi_twi_irq_cb_t cb, void *arg) { size_t num = _spi_dev2num(bus); mutex_lock(&_locks[num]); + _irq[num] = cb; + _irq_arg[num] = arg; } void nrf5x_i2c_release(NRF_TWIM_Type *bus) diff --git a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c index 8069051535..0c9070ad16 100644 --- a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c +++ b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c @@ -102,8 +102,18 @@ static void _init_pins(i2c_t dev) { gpio_init(i2c_config[dev].scl, GPIO_IN_OD_PU); gpio_init(i2c_config[dev].sda, GPIO_IN_OD_PU); +} + +/* Beware: This needs to be kept in sync with the SPI version of this. + * Specifically, when registers are configured that are valid to the peripheral + * in both SPI and I2C mode, the register needs to be configured in both the I2C + * and the SPI variant of _setup_shared_peripheral() to avoid from parameters + * leaking from one bus into the other */ +static void _setup_shared_peripheral(i2c_t dev) +{ bus(dev)->PSEL.SCL = i2c_config[dev].scl; bus(dev)->PSEL.SDA = i2c_config[dev].sda; + bus(dev)->FREQUENCY = i2c_config[dev].speed; } void i2c_init(i2c_t dev) @@ -111,7 +121,6 @@ void i2c_init(i2c_t dev) assert(dev < I2C_NUMOF); /* Initialize mutex */ - mutex_init(&locks[dev]); mutex_init(&busy[dev]); mutex_lock(&busy[dev]); @@ -122,8 +131,8 @@ void i2c_init(i2c_t dev) /* configure pins */ _init_pins(dev); - /* configure dev clock speed */ - bus(dev)->FREQUENCY = i2c_config[dev].speed; + /* configure shared periphal speed */ + _setup_shared_peripheral(dev); spi_twi_irq_register_i2c(bus(dev), i2c_isr_handler, (void *)(uintptr_t)dev); @@ -158,7 +167,13 @@ void i2c_acquire(i2c_t dev) { assert(dev < I2C_NUMOF); - mutex_lock(&locks[dev]); + if (IS_USED(MODULE_PERIPH_I2C_RECONFIGURE)) { + mutex_lock(&locks[dev]); + } + + nrf5x_i2c_acquire(bus(dev), i2c_isr_handler, (void *)(uintptr_t)dev); + _setup_shared_peripheral(dev); + bus(dev)->ENABLE = TWIM_ENABLE_ENABLE_Enabled; DEBUG("[i2c] acquired dev %i\n", (int)dev); @@ -169,7 +184,12 @@ void i2c_release(i2c_t dev) assert(dev < I2C_NUMOF); bus(dev)->ENABLE = TWIM_ENABLE_ENABLE_Disabled; - mutex_unlock(&locks[dev]); + + if (IS_USED(MODULE_PERIPH_I2C_RECONFIGURE)) { + mutex_unlock(&locks[dev]); + } + + nrf5x_i2c_release(bus(dev)); DEBUG("[i2c] released dev %i\n", (int)dev); } diff --git a/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c b/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c index 6161a2fb1f..e14e8d7062 100644 --- a/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c +++ b/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c @@ -123,16 +123,28 @@ static void _clear_workaround(spi_t bus) #endif } +/* Beware: This needs to be kept in sync with the I2C version of this. + * Specifically, when registers are configured that are valid to the peripheral + * in both SPI and I2C mode, the register needs to be configured in both the I2C + * and the SPI variant of _setup_shared_peripheral() to avoid from parameters + * leaking from one bus into the other */ +static void _setup_shared_peripheral(spi_t bus) +{ + SPI_SCKSEL = spi_config[bus].sclk; + SPI_MOSISEL = spi_config[bus].mosi; + SPI_MISOSEL = spi_config[bus].miso; +} + void spi_init(spi_t bus) { assert(bus < SPI_NUMOF); /* initialize mutex */ - mutex_init(&locks[bus]); mutex_init(&busy[bus]); mutex_lock(&busy[bus]); /* initialize pins */ spi_init_pins(bus); + _setup_shared_peripheral(bus); } int spi_init_with_gpio_mode(spi_t bus, const spi_gpio_mode_t* mode) @@ -165,9 +177,6 @@ void spi_init_pins(spi_t bus) spi_init_with_gpio_mode(bus, &gpio_modes); /* select pins for the SPI device */ - SPI_SCKSEL = spi_config[bus].sclk; - SPI_MOSISEL = spi_config[bus].mosi; - SPI_MISOSEL = spi_config[bus].miso; _setup_workaround_for_ftpan_58(bus); spi_twi_irq_register_spi(dev(bus), spi_isr_handler, (void *)(uintptr_t)bus); } @@ -177,7 +186,13 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) (void)cs; assert((unsigned)bus < SPI_NUMOF); - mutex_lock(&locks[bus]); + if (IS_USED(MODULE_PERIPH_SPI_RECONFIGURE)) { + mutex_lock(&locks[bus]); + } + + nrf5x_spi_acquire(dev(bus), spi_isr_handler, (void *)(uintptr_t)bus); + _setup_shared_peripheral(bus); + /* configure bus */ dev(bus)->CONFIG = mode; dev(bus)->FREQUENCY = clk; @@ -189,7 +204,12 @@ void spi_release(spi_t bus) { /* power off everything */ dev(bus)->ENABLE = 0; - mutex_unlock(&locks[bus]); + + if (IS_USED(MODULE_PERIPH_SPI_RECONFIGURE)) { + mutex_unlock(&locks[bus]); + } + + nrf5x_spi_release(dev(bus)); } static size_t _transfer(spi_t bus, const uint8_t *out_buf, uint8_t *in_buf, diff --git a/cpu/nrf9160/include/periph_cpu.h b/cpu/nrf9160/include/periph_cpu.h index f140e34a21..7e162da886 100644 --- a/cpu/nrf9160/include/periph_cpu.h +++ b/cpu/nrf9160/include/periph_cpu.h @@ -212,8 +212,10 @@ void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, * @brief Acquire the shared I2C/SPI peripheral in I2C mode * * @param bus bus to acquire exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument */ -void nrf5x_i2c_acquire(NRF_TWIM_Type *bus); +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); /** * @brief Release the shared I2C/SPI peripheral in I2C mode @@ -225,16 +227,18 @@ void nrf5x_i2c_release(NRF_TWIM_Type *bus); /** * @brief Acquire the shared I2C/SPI peripheral in SPI mode * - * @param bus bus to acquire exclusive access on + * @param bus bus to release exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument */ -void nrf5x_spi_release(NRF_SPIM_Type *bus); +void nrf5x_spi_acquire(NRF_SPIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); /** * @brief Acquire the shared I2C/SPI peripheral in SPI mode * * @param bus bus to release exclusive access on */ -void nrf5x_spi_acquire(NRF_SPIM_Type *bus); +void nrf5x_spi_release(NRF_SPIM_Type *bus); #ifdef __cplusplus } diff --git a/cpu/nrf9160/spi_twi_irq.c b/cpu/nrf9160/spi_twi_irq.c index 60fe1e03ef..ee98dfea06 100644 --- a/cpu/nrf9160/spi_twi_irq.c +++ b/cpu/nrf9160/spi_twi_irq.c @@ -91,16 +91,22 @@ void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, NVIC_EnableIRQ(_isr[num]); } -void nrf5x_i2c_acquire(NRF_TWIM_Type *bus) +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, + spi_twi_irq_cb_t cb, void *arg) { size_t num = _i2c_dev2num(bus); mutex_lock(&_locks[num]); + _irq[num] = cb; + _irq_arg[num] = arg; } -void nrf5x_spi_acquire(NRF_SPIM_Type *bus) +void nrf5x_spi_acquire(NRF_SPIM_Type *bus, + spi_twi_irq_cb_t cb, void *arg) { size_t num = _spi_dev2num(bus); mutex_lock(&_locks[num]); + _irq[num] = cb; + _irq_arg[num] = arg; } void nrf5x_i2c_release(NRF_TWIM_Type *bus)