From 83a6ad182dc02c59b3e43feb97b0783b6ba3485b Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Fri, 29 May 2020 09:37:42 +0200 Subject: [PATCH] nrf52/i2c: Use mutex and IRQ for blocking This commit enhances the I2C code of the nRF52 family to block on a mutex while the I2C transfer is busy. The mutex is unlocked in the ISR when it is trigger by either a stop condition or an error condition. --- cpu/nrf52/periph/i2c.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/cpu/nrf52/periph/i2c.c b/cpu/nrf52/periph/i2c.c index 32d04a4c759a..5c2162974a9b 100644 --- a/cpu/nrf52/periph/i2c.c +++ b/cpu/nrf52/periph/i2c.c @@ -45,6 +45,14 @@ */ static mutex_t locks[I2C_NUMOF]; +/** + * @brief array with a busy mutex for each I2C device, used to block the + * thread until the transfer is done + */ +static mutex_t busy[I2C_NUMOF]; + +void i2c_isr_handler(void *arg); + static inline NRF_TWIM_Type *bus(i2c_t dev) { return i2c_config[dev].dev; @@ -53,9 +61,9 @@ static inline NRF_TWIM_Type *bus(i2c_t dev) static int finish(i2c_t dev) { DEBUG("[i2c] waiting for STOPPED or ERROR event\n"); - while ((!(bus(dev)->EVENTS_STOPPED)) && (!(bus(dev)->EVENTS_ERROR))) { - nrf52_sleep(); - } + /* Unmask interrupts */ + bus(dev)->INTENSET = TWIM_INTEN_STOPPED_Msk | TWIM_INTEN_ERROR_Msk; + mutex_lock(&busy[dev]); if ((bus(dev)->EVENTS_STOPPED)) { bus(dev)->EVENTS_STOPPED = 0; @@ -85,6 +93,9 @@ void i2c_init(i2c_t dev) /* Initialize mutex */ mutex_init(&locks[dev]); + mutex_init(&busy[dev]); + mutex_lock(&busy[dev]); + /* disable device during initialization, will be enabled when acquire is * called */ bus(dev)->ENABLE = TWIM_ENABLE_ENABLE_Disabled; @@ -96,6 +107,8 @@ void i2c_init(i2c_t dev) /* configure dev clock speed */ bus(dev)->FREQUENCY = i2c_config[dev].speed; + spi_twi_irq_register_i2c(bus(dev), i2c_isr_handler, (void *)dev); + /* re-enable the device. We expect that the device was being acquired before * the i2c_init_master() function is called, so it should be enabled when * exiting this function. */ @@ -211,3 +224,13 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, return finish(dev); } + +void i2c_isr_handler(void *arg) +{ + i2c_t dev = (i2c_t)arg; + + /* Mask interrupts to ensure that they only trigger once */ + bus(dev)->INTENCLR = TWIM_INTEN_STOPPED_Msk | TWIM_INTEN_ERROR_Msk; + + mutex_unlock(&busy[dev]); +}