This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to use both I2C pins on nRF52840 ?

Problem : 

I have two I2C devices and would like to connect them both to nRF52840 DK on different I2C pins. According to datasheet nRF52840 has two I2C pins (P1.00, P0.22) and (P0.27, 0.26). I want to connect one device on (P1.00, P0.22) and other on (P0.27, 0.26).

I am using SDK 15.3.0.

Current Code :

I have created two TWI Instance.

static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(0);
static const nrf_drv_twi_t m_twi2 = NRF_DRV_TWI_INSTANCE(1);

I have also initialized both of them.

/**
 * @brief TWI initialization.
 */
void twi_init (void)
{
    ret_code_t err_code;

    const nrf_drv_twi_config_t twi_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);

    const nrf_drv_twi_config_t twi_config2 = {
       .scl                = NRF_GPIO_PIN_MAP(0,22),
       .sda                = NRF_GPIO_PIN_MAP(1,0),
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };

    err_code = nrf_drv_twi_init(&m_twi2, &twi_config2, NULL, NULL);
    NRF_LOG_INFO("%d", err_code);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi2);
}

Further I try to scan for I2C devices on both TWI instances and fail to read on (P1.00, P0.22).

Things I have tried :

  1. Scan only one TWI instance.
    Scanning on (P0.27, P0.26) works but (P1.00, P0.22) doesn't work.
  2. Try using same NRF_DRV_TWI_INSTANCE
    static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(0);
    static const nrf_drv_twi_t m_twi2 = NRF_DRV_TWI_INSTANCE(0);

Some other questions I have :

  1. What is the use NRF_DRV_TWI_INSTANCE() ? What is TWI instance exactly ?
  2. What is the difference between the TWI hardware driver and TWI transaction Manager ?

Link to Source Code

  • Hi,

    According to datasheet nRF52840 has two I2C pins (P1.00, P0.22) and (P0.27, 0.26).

    Where do you see this? There are no dedicated TWI pins in the nRF5 devices. Any GPIO pin can be used for any function with any digital peripheral. You just need to configure the peripheral to use the correct pins, typically via the driver configuration as you do.

    I try to scan for I2C devices on both TWI instances and fail to read on (P1.00, P0.22).

    In what way does it fail? Also, does your project build without any warnings or errors? Have you remembered to set at least TWI_ENABLED, TWI0_ENABLED and TWI1_ENABLED to 1 in your projects sdk_config.h (You should have gotten a linker error if not)?

    What is the use NRF_DRV_TWI_INSTANCE() ? What is TWI instance exactly ?

    You can think of the TWI master driver instance crated by NRF_DRV_TWI_INSTANCE() as a TWI object. This represents a TWI peripheral, connected to a specific TWI bus (set of TWI/I2C pins). Since each of the two instances represents independent HW, they can be used independently.

    What is the difference between the TWI hardware driver and TWI transaction Manager ?

    The TWI hardware driver is a low-level driver that handles the TWI peripheral for you, so you don't need to think about or know how to use the TWIM peripheral in the nRF52 device in detail. The TWI transaction manager, on the other hand, is a higher-level library that helps you with more "complex" transactions. It uses the driver under the hood. Which of those make more sense depending on your use case. There is also an even high-level library nrf_twi_sensor that use the TWI transaction manager that may or may not be suited for your needs.

  • In what way does it fail?

    It fails to detect device connected to the corresponding pins.

    Also, does your project build without any warnings or errors?

    Yes, It builds without any error.

    Have you remembered to set at least TWI_ENABLED, TWI0_ENABLED and TWI1_ENABLED to 1 in your projects sdk_config.h

    I have set all the three macros (TWI_ENABLED, TWI0_ENABLED and TWI1_ENABLED) to 1. Download sdk_config.h

    What is the purpose of TWI_ENABLED, TWI0_ENABLED and TWI1_ENABLED ?

    You can think of the TWI master driver instance crated by NRF_DRV_TWI_INSTANCE() as a TWI object.

    What is the purpose of 0 or 1 given to NRF_DRV_TWI_INSTANCE() as an input ?

  • Hi,

    shockline said:
    It fails to detect device connected to the corresponding pins.

    I see. Do you mind sharing the code where you try to talk to the I2C device? Have you measured with a logic analyzer on the I2C lines (SCL and SDA) to see what is happening? Could there be a problem with the device you are trying to communicate with? For instance, what happens if you move the slave device that you were able to communicate with to the other bus which did not work?

    shockline said:
    What is the purpose of TWI_ENABLED, TWI0_ENABLED and TWI1_ENABLED ?

    These configuration macros are used to enable or disable parts of the driver. This approach is used across most of the SDK to have the preprocessor strip out unused code. So if you need some functionality, you need to enable it in sdk_config.h. This is not as tricky as it might sound since you would get a linker error if you tried to use something that was not included by the preprocessor due to it not being enabled in sdk_config.h.

    Specifically, TWI_ENABLED enabled the TWI_DRIVER. If this is set to 0, all other TWI configurations will be ignored. TWI0_ENABLED enables the driver for the TWI0 peripheral. TWI1_ENABLED enables the driver for the TWI1 peripheral. There is also the TWI0_USE_EASY_DMA and TWI1_USE_EASY_DMA, which is used to select if you want to use DMA (TWIM peripheral) or not (legacy TWI peripheral). Setting it to 1 is most sensible in most cases.

    shockline said:
    What is the purpose of 0 or 1 given to NRF_DRV_TWI_INSTANCE() as an input ?

    The only parameter for NRF_DRV_TWI_INSTANCE is the instance ID, which can be either 0 or 1. 0 represents the TWIM0 peripheral and 1 represents TWIM1 peripheral.

  • Do you mind sharing the code where you try to talk to the I2C device?

    Link to Source Code

    what happens if you move the slave device that you were able to communicate with to the other bus which did not work?

    Both the slave devices work on (P0.27, P0.26) but none of them work on the other pins.

    TWI0_ENABLED enables the driver for the TWI0 peripheral

    What do you mean by TWI0 & TWI1 peripherial ?

    The only parameter for NRF_DRV_TWI_INSTANCE is the instance ID, which can be either 0 or 1. 0 represents the TWIM0 peripheral and 1 represents TWIM1 peripheral.

    If TWI1_ENABLED is set to 0 in sdk_config.h and create a TWI instance with NRF_DRV_TWI_INSTANCE giving it an input of 1. Will I get a linker error ?

  • Hi,

    The code looks good.

    shockline said:
    Both the slave devices work on (P0.27, P0.26) but none of them work on the other pins.

    I see. There is one important point I forgot to ask about earlier. P0.22 is connected to the onboard external flash on the DK by default, and not to the pin header. So you need to short solder bridge SB25 and cut SB15. Have you done that? If not, there is no electrical connection between the pin on the chip and the corresponding pin header.

    shockline said:
    What do you mean by TWI0 & TWI1 peripherial ?

    That was a typo on my part. I meant to write TWIM0 and TWIM1, which are the two instances of the TWIM peripheral. TWI0 and TWI1 are the two instances of the corresponding non-DMA peripheral. Note that the driver often uses TWI for both (without the M), since it separates between the TWI and TWIM peripheral by the TWI0_USE_EASY_DMA and TWI1_USE_EASY_DMA configuration parameters in sdk_config.h.

    shockline said:
    If TWI1_ENABLED is set to 0 in sdk_config.h and create a TWI instance with NRF_DRV_TWI_INSTANCE giving it an input of 1. Will I get a linker error ?

    Yes, you will get a build error. But it will probably fail earlier than linking, during compilation.

Related