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

nRF52840 - SDK16 - Understanding TWI driver

Hi everyone,

I am looking the TWI examples and I am confused regarding the nrf_drv_twi_tx and nrf_drv_twi_rx. What I've understand so far is that the nrf_drv_twi_tx function is used either to write on a register or before reading a register right?

1. What I have seen so far is that, in order to read a specific register you have to first write on it, to instruct the slave which register it wishes to read from. After that you can read the register by using  nrf_drv_twi_rx. So, fisrt send a write command using the  nrf_drv_twi_tx. What is the length parameter that we send in this case?

For example looking this I2C Read wrapping function, the lengh parameter of nrf_drv_twi_tx is 1. In that case it writes 1 to reg_addr right? What is the purpose? This is always the case before reading a register?

int8_t Acc_i2c_Read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) {
                     
  int8_t rslt = 0;

  rslt = nrf_drv_twi_tx(&m_twi, dev_id, &reg_addr, 1, false); 
  APP_ERROR_CHECK(rslt);

  if (rslt == 0) {
    rslt = nrf_drv_twi_rx(&m_twi, dev_id, reg_data, len);
  }
  return rslt;
}

2. Then I was looking an I2C Write wrapping  function. This is also confusing for me. Looking the function the data parameter holds both the reg_address and reg_data. Then it passes data to nrf_drv_twi_tx. This is always the case? The the first index of data parameter holds the register address and the rest of the indexes the data we wish to write?

int8_t Acc_i2c_Write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) {

  
  int8_t rslt = 0;
  uint8_t data[len + 1];
  data[0] = reg_addr;
  for (uint16_t i = 0; i < len; i++) {
    data[i + 1] = reg_data[i]; 
  }

  rslt = nrf_drv_twi_tx(&m_twi, dev_id, data, len + 1, false); 
  APP_ERROR_CHECK(rslt);
  NRF_LOG_INFO("Print Here");

  return rslt;
}

Sorry to be so naive, but I trying to understand the basics Slight smile

Thanks in advance

Nick

  • Hi,

    To answer your questions:

    1. Before the I2C master can read from a slave it would have to send the specific register that it wants the slave to output the data from i.e the register that it wants to read. This is the reason a transmission (tx) is done before a read (rx). The length of the register is usually 1 byte. 
    2. The reason that the address is put at the start of the array is because it allows the driver to a continues write of the whole array without restarting the process. So what happens is that the I2C master will start with the first byte which contains the register address that it wants to write to and then follow up with 1 byte at a time until it has written the whole array. 

    I think this site is good resource for understanding the I2C protocol.

    Hope it helps :) 

    regards

    Jared 

  • Thank you for your great responce Jared!!

    The length of the register is usually 1 byte.

    So the len parameter is the length of the buffer right?

    So what happens is that the I2C master will start with the first byte which contains the register address that it wants to write to and then follow up with 1 byte at a time until it has written the whole array. 

    But in order to write the whole the len parameter must be equal to the array size right? For example looking the funtion definition below. If the size of the p_data is 4byte and length = 3, then it will transmit the first three byte of the buffer, right?

    /**
     * @brief Function for sending data to a TWI slave.
     *
     * The transmission will be stopped when an error occurs. If a transfer is ongoing,
     * the function returns the error code @ref NRF_ERROR_BUSY.
     *
     * @param[in] p_instance Pointer to the driver instance structure.
     * @param[in] address    Address of a specific slave device (only 7 LSB).
     * @param[in] p_data     Pointer to a transmit buffer.
     * @param[in] length     Number of bytes to send.
     * @param[in] no_stop    If set, the stop condition is not generated on the bus
     *                       after the transfer has completed successfully (allowing
     *                       for a repeated start in the next transfer).
     *
     * @retval NRF_SUCCESS                  If the procedure was successful.
     * @retval NRF_ERROR_BUSY               If the driver is not ready for a new transfer.
     * @retval NRF_ERROR_INTERNAL           If an error was detected by hardware.
     * @retval NRF_ERROR_INVALID_ADDR       If the EasyDMA is used and memory adress in not in RAM.
     * @retval NRF_ERROR_DRV_TWI_ERR_ANACK  If NACK received after sending the address in polling mode.
     * @retval NRF_ERROR_DRV_TWI_ERR_DNACK  If NACK received after sending a data byte in polling mode.
     */
    __STATIC_INLINE
    ret_code_t nrf_drv_twi_tx(nrf_drv_twi_t const * p_instance,
                              uint8_t               address,
                              uint8_t const *       p_data,
                              uint8_t               length,
                              bool                  no_stop);

  • Nikosant03 said:

    So the len parameter is the length of the buffer right?

     The len parameter of the nrf_drv_twi_tx() function is the number of bytes are being sent so yes it's effectively the length of the transmit buffer. 

     

    Nikosant03 said:
    But in order to write the whole the len parameter must be equal to the array size right? For example looking the funtion definition below. If the size of the p_data is 4byte and length = 3, then it will transmit the first three byte of the buffer, right?

     Yes? I'm not sure where this would contradict with my previous comment? Slight smile

    regards

    Jared 

Related