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

Procedure for using TWI for I2C between the NRF52DK BMX055

Hi Nordic,

I am a beginner in programming outside of the Arduino IDE. I'm familiar enough with C to understand much of the code in the examples, but using I2C with the above mentioned sensor has proven to be quite challenging for me.

I am using Segger Embedded Studio 3.5 with the NRF52 DK SDK 15.2.0 on a windwos 10 machine.

I am trying to read the gyroscope information on the BMX055 sensor through the TWI interface using the Bosch BMA2x2_drivers. 

To start, I opened the example "twi_master_with_twis_slave_pca10040”  and made the following changes to the config.h file as per my design.

#define TWI_SCL_M           26      //!< Master SCL pin.

#define TWI_SDA_M           27       //!< Master SDA pin.

The initialization of the service seems to be handled in main. I address of the gyroscope on the chip in question is 0x69, but that is as far as I have gotten. 

  • I should add that the TWI scanner example finds devices at 0x13, 0x19, and 0x69

  • This is useful information. These addresses correcsponds to the acellerometer, gyroscope, and magnetometer. It seems like the three sensors acts like three individual TWI/I2C slaves. You should read Chapter 11.2 of the BMX055 datasheet as it describes the TWI interface. 

    This is good news as it tells us that the TWI bus seems to be operational. 

    I suggest you skip the bosch driver for now and try to learn the basics of how to interface with an IC over TWI/I2C, as this will become very useful in your future. 
    The first thing you should do is to perform a read operation on one of the sensors registers, I suggest we start with the accellerometers 'Chip-ID' register. 


    You will need to initiate a read operation by sending the 7-bit address of the acellerometer + the R/W-bit followed by the address of the Chip-ID register. The slave will then send back the content of the chosen register if able. 

    The two bytes you send must then be 0x13 and 0x00, or 0b00100110 and 0b00000000. The first bytes lsb is the R/W bit and signals the slave that the current operation is a read operation (logic low). The slave will then prepare to transmit the content of the chosen register and wait for the master (you) to signal that it's time for the slave to write to the TWI bus. This is done by transmitting the slave address with the R/W bit set to logic high, then the slave will respond with the content of the previously chosen register.

    Our TWI master driver is designed to automate this operation with its usage of transfer descriptors, see Advanced usage. The transfer type called NRF_DRV_TWI_XFER_TXRX is used to easily read registers. With this functionality you can set up the entire TWI transaction beforehand and just hit "go". 

    See Chapter 11.2 read access on page 148 for details. A few youtube videos on I2C in general might also help. And you will need to read the API documentation for the TWIM driver and HAL. 

    Once you're able to read and write to the registers you can start to use Bosch's driver. It will require that you change its read/write implementations to fit our driver's. 

  • Thanks for your help,

    I've followed your advice and have actually seen some progress!

    My read commands look like this

    nrf_drv_twi_rx(nrf_drv_twi_t const * p_instance,
                              uint8_t               address,
                              uint8_t *             p_data,
                              uint8_t               length)

    My write commands look like this

    uint8_t buffer[] = {register, value};

        nrf_drv_twi_tx(nrf_drv_twi_t const * p_instance,
                              uint8_t               address,
                              uint8_t const *       buffer,
                              uint8_t               size of buffer,
                              bool                  no_stop);
                              

    Thanks for the guidance, one I knew where to look it was pretty straight-forward.

  • Hi, 

    I have followed your above guide, Thanx for that. 

    My read and write functions work well. I verified it by verifying with the verification of 'WHO I am ' register. 

    But now the issue is that when I try to get x,y,z values by using read function it does not show any thing. 

    Can you kindly guide where might be the issue .

    my reading function. 

    void readAccelData(int16_t * destination)
    {
      static uint8_t rawData[6];  // x/y/z accel register data stored here
      bmxme_register_read(BMA2x2_X_AXIS_LSB_ADDR, &rawData[0],6);       // Read the six raw data registers into data array
      if((rawData[0] & 0x01) && (rawData[2] & 0x01) && (rawData[4] & 0x01)) {  // Check that all 3 axes have new data
      destination[0] = (int16_t) (((int16_t)rawData[1] << 8) | rawData[0]) >> 4;  // Turn the MSB and LSB into a signed 12-bit value
      destination[1] = (int16_t) (((int16_t)rawData[3] << 8) | rawData[2]) >> 4;  
      destination[2] = (int16_t) (((int16_t)rawData[5] << 8) | rawData[4]) >> 4; 
      }
    }
    

    and in main i am using it like this : 

        float aRes = 2.0/2048.0;
        static int16_t AccValue[3];
        static int16_t accelCount[3];  // Stores the 16-bit signed accelerometer sensor output
        float ax, ay, az;
        
        while (NRF_LOG_PROCESS() == true)
        {
            /*if(bmxme_ReadAcc(&AccValue[0], &AccValue[1], &AccValue[2]) == true) // Read acc value from bmx055 internal registers and save them in the array
            {
              NRF_LOG_INFO("ACC Values:  x = %d  y = %d  z = %d", AccValue[0], AccValue[1], AccValue[2]); // display the read values
            }
            else
            {
              NRF_LOG_INFO("Reading ACC values Failed!!!"); // if reading was unsuccessful then let the user know about it
            }*/
            readAccelData(accelCount);
       
               // Now we'll calculate the accleration value into actual g's
               ax = (float)accelCount[0]*aRes; // + accelBias[0];  // get actual g value, this depends on scale being set
               ay = (float)accelCount[1]*aRes; // + accelBias[1];   
               az = (float)accelCount[2]*aRes; // + accelBias[2];
    
               NRF_LOG_INFO("ACC Values:  x = %d  y = %d  z = %d", ax,ay,az); // display the read values
    
           nrf_delay_ms(100); // give some delay 
    
    
        }
    }
    
    /** @} */

Related