How to use the same i2c peripheral in two different pins?

Hi, I have a project using the chip nRF52832 and sdk nRF5 14.2, I'm updating the firmware to use the nRF Connect SDK 2.2(NCS).

In my project, i use spi0 and spi2, so a can just use i2c1 to talk with the i2c sensors, but 2 sensors have the same address, so I need to communicate with than using different pin.

In sdk 14.2 for every communication, I switch the instance:

nrf_drv_twi_disable(&m_twi);
nrf_drv_twi_uninit(&m_twi);

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

How can I do this in NCS or other kind of workaround?
Parents Reply Children
  • Hi Priyanka,
    This ticket shows an example of using i2c in two different addresses, but I need to communicate with sensors that have different pinouts.
    In my project I have a total of 5 sensors, where two of them have the same address so I have to programmatically change between the i2c communication pins:
    4 sensors are on pins-> SDA pin 7 SCL pin 5;
    1 sensor is on pins ->    SDA pin 8 SCL pin 6;
    I need to alternate the i2c communication pins to be able to read all the sensors.

  • Hi Rodrigo,

    I believe you can get a solution by using Dynamic pincontrol. You can have same addresses for sensors, but you need to use two different pins for the connections.

    Please do take a look at this and do let me know how it goes.

    -Priyanka

  • Hi, I tried to use the Dynamic pincontrol example, but I had some doubts.


    1 - In the example, it says that you have to make the change before booting the system, in my case I want to change it while the device is working, is this possible?


    2 - How do I return the pins to default again? Would you use the pinctrl_update_states command again? If so, what would this macro look like? PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), i2c1); ?


    3 - I tried following that example to change the control pins and make an i2c communication using the following code:

    dts file:

    &pinctrl{
    	i2c1_battery_default:i2c1_battery_default {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA,0,8)>,
    					<NRF_PSEL(TWIM_SCL,0,6)>;
    		};
    	};
    	i2c1_battery_sleep:i2c1_battery_sleep {
    		group1 {
    			psels = <NRF_PSEL(TWIM_SDA,0,8)>,
    					<NRF_PSEL(TWIM_SCL,0,6)>;
    			low-power-enable;
    		};
    	};
    };
    
    /{
    	zephyr,user{
    		i2c1_battery_default = <&i2c1_battery_default>;
    		i2c1_battery_sleep = <&i2c1_battery_sleep>;
    	};
    };

    conf file:

    CONFIG_DYNAMIC_INTERRUPTS=y
    
    CONFIG_PINCTRL=y
    CONFIG_PINCTRL_DYNAMIC=y
    CONFIG_CONSOLE_INIT_PRIORITY=70
    CONFIG_I2C_INIT_PRIORITY=60
    CONFIG_PM_DEVICE=y

    code to initialize i2c and communicate:

    BUILD_ASSERT((CONFIG_GPIO_INIT_PRIORITY < CONFIG_REMAP_INIT_PRIORITY) &&
    	           (CONFIG_REMAP_INIT_PRIORITY < CONFIG_I2C_INIT_PRIORITY),
           	     "Device driver priorities are not set correctly");
    
    PINCTRL_DT_DEV_CONFIG_DECLARE(DT_NODELABEL(i2c1));
    PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), i2c1_battery_default);
    PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), i2c1_battery_sleep);
    
    static const struct pinctrl_state i2c1_alt[] = {
    	PINCTRL_DT_STATE_INIT(i2c1_battery_default, PINCTRL_STATE_DEFAULT),
    	PINCTRL_DT_STATE_INIT(i2c1_battery_sleep, PINCTRL_STATE_SLEEP),
    };
    
    static const struct i2c_dt_spec eeprom_i2c   = I2C_DT_SPEC_GET(DT_NODELABEL(eeprom_i2c));
    
    (void) main (void){
        struct pinctrl_dev_config *i2c1_config =
        		PINCTRL_DT_DEV_CONFIG_GET(DT_NODELABEL(i2c1));
        
        pinctrl_update_states(i2c1_config, i2c1_alt, ARRAY_SIZE(i2c1_alt));
        
        fnBMP280_Init(); //initiate this driver in i2c1 default pinout and works fine
        
        if (!device_is_ready(eeprom_i2c.bus)) // initiate the device to read in i2c1 alternative pinout
            LOG_INF("I2C bus %s is not ready!\n\r",eeprom_i2c.bus->name);
        
        struct pinctrl_dev_config *i2c1_config =
    			PINCTRL_DT_DEV_CONFIG_GET(DT_NODELABEL(i2c1));
    
    	pinctrl_update_states(i2c1_config, i2c1_alt, ARRAY_SIZE(i2c1_alt));
    	
        int ret;
        uint8_t u8_reg = 0
        uint8_t pu8_reg_data[6];
        
        ret = i2c_burst_read_dt(&eeprom_i2c,0,&pu8_reg_data[0],6);
        if(ret != 0){
            printk("Failed to read from I2C device address %x at Reg. %x n", eeprom_i2c.addr,u8_reg);
        }
    }

    Using this code, when I try to communicate with the eeprom_i2c device I get the error "i2c_nrf_twim: Error 0x0BAE0001 occurred for message 0.

     , can you help me with these problems?

  • Hi Rodrigo,

    I see that you have another ticket for the same issue with my colleague and are getting support there. Please continue the conversation there. Slight smile

    -Priyanka

Related