Skip to content

Nordic RF52 does not correctly support simultaneous use of I2C and SPI #4357

@NeilMacMullen

Description

@NeilMacMullen

Mbed OS 5
Target UBLOX_EVK_NINA_B1
Toolchain GCC_ARM

The Nordic RF52 SoC uses digital 'TWI' control blocks to control both I2C and SPI. When declaring an I2C object, the Nordic platform code in targets/TARGET_NORDIC/TARGET_NRF5/i2c_api.c uses the method "i2c_init" to allocate the first available TWI by examining previously-allocated I2C instances. Similar code is used in the SPI drivers (spi_api.c) where previously-allocated SPI instances are checked.

This approach fails when allocating a mixture of I2C and SPI instances since both _init methods then consider TWI0 to be available and allocate it to both the I2C and SPI interfaces. This leads to unpredictable results when the interfaces are used.

If you only have a single I2C and SPI instance, it's possible to work around this by forcing one of the allocators to allocate TWI1 (example code below) but the correct fix would be to implement a central allocator which would be used for both types of interface.

diff --git a/targets/TARGET_NORDIC/TARGET_NRF5/i2c_api.c b/targets/TARGET_NORDIC/TARGET_NRF5/i2c_api.c
index 66063b4..ca551d4 100644
--- a/targets/TARGET_NORDIC/TARGET_NRF5/i2c_api.c
+++ b/targets/TARGET_NORDIC/TARGET_NRF5/i2c_api.c
@@ -283,6 +283,7 @@ static void twi_clear_bus(twi_info_t *twi_info)
     }
}
+#define I2C_TWI 1
void i2c_init(i2c_t *obj, PinName sda, PinName scl)
{
     int i;
@@ -290,7 +291,7 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
         if (m_twi_info[i].initialized &&
             m_twi_info[i].pselsda == (uint32_t)sda &&
             m_twi_info[i].pselscl == (uint32_t)scl) {
-            TWI_IDX(obj) = i;
+            TWI_IDX(obj) = I2C_TWI;
             TWI_INFO(obj)->frequency = NRF_TWI_FREQ_100K;
             i2c_reset(obj);
             return;
@@ -299,7 +300,7 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
 
     for (i = 0; i < TWI_COUNT; ++i) {
         if (!m_twi_info[i].initialized) {
-            TWI_IDX(obj) = i;
+            TWI_IDX(obj) = I2C_TWI;
 
             twi_info_t *twi_info = TWI_INFO(obj);
             twi_info->initialized = true;
 

Copying @MarceloSalazar by request

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions