Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

TWI reading and writing basics

Hello all, 

I have pinged the sensor on the "twi bus" successfully, now I am following the post on the read/write function that is needed to actually read the data off the sensor. This is what I am reading at the moment:  https://medium.com/vicara-hardware-university/setting-up-twi-on-nrf52xx-dcaf83a50baa

Indeed, I have the sensor's library , however, I am not really sure how to apply the following example and use the library.


/*
 * dev_addr -> Device address
 * reg_adddr -> Register address
 * data -> Buffer which holds data to be written
 * length -> Length of data to be written
 */
int8_t twi_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t length)
{
    uint32_t err_code;

    uint8_t buffer[255] = {0};
    buffer[0] = reg_addr;
    memcpy(&buffer[1], data, length);
    m_xfer_done = false;
    err_code = nrf_drv_twi_tx(&m_twi, dev_addr, buffer, sizeof(length), false);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);

   return err_code;
}

/*
 * dev_addr -> Device address
 * reg_adddr -> Register address
 * data -> Buffer where data read from TWI will be stored
 * length -> Length of data to be read
 */
int8_t twi_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t length)
{
    uint32_t err_code;
    m_xfer_done = false;
    err_code = nrf_drv_twi_tx(&m_twi, dev_addr, &reg_addr, sizeof(reg_addr), true);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);

    m_xfer_done = false;
    err_code = nrf_drv_twi_rx(&m_twi, dev_addr, data, length);
    APP_ERROR_CHECK(err_code);
    while (m_xfer_done == false);

    return err_code;

}

and obtain the data from the sensors registers.

BTW the library uses the i2c for the STM32 like this:

//STM32F specific I2C API call
#ifdef STM32F
	//All of the I2C API functions (For Example: HAL_I2C_Master_Transmit()) are being called from stm32f4xx_hal.h

	//hi2c1 - The variable to the I2C handler which is needed later in the Write and Read I2C function.
	//hi2c1 is defined in the stm32f4xx_hal.h and being called here via extern I2C_HandleTypeDef hi2c1;.
	extern I2C_HandleTypeDef hi2c1;

	//Master sends I2C write command via pointer *Data from the Sensor API.
	//The function returns HAL_OK (=0) when there is no error and -1 when there is an error.
	int WriteI2C_Bus(struct TransferData *Data)
	{
		//Initialization of intial Error = 0
		int Error = 0;

		//Define an array of 3 Bytes to be sent as I2C Write Command as shown in Fig. 10 in the Datasheet Page 7
		uint8_t WData[3]={Data->RegisterAddress, Data->WData[0], Data->WData[1]};

		//Send I2C Write Command as shown in Fig. 10 in the Datasheet Page 7 with Error checking.
		/*Format defined by STM:
		*HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout).
		*HAL_I2C_Master_Transmit() is used for transmitting data to the I2C device. It takes following arguments:
		*
		*I2C_HandleTypeDef *hi2c - is the pointer to the i2c handler. hi2c1 is defined in the stm32f4xx_hal.h and being called here via extern I2C_HandleTypeDef *hi2c1;.
		*uint16_t DevAddress - is the Address of the I2C device (Need to be shifted by 1 to left since the input of function expects 8 bits).
		*uint8_t *pData  - is the pointer to the data to be transmitted.
		*uint16_t Size  - is the size of the transmitted data in bytes.
		*uint32_t Timeout - timeout in millisecond in case of any error.
		*Return Error.
		*/
		Error = HAL_I2C_Master_Transmit(&hi2c1, (Data->Slave_Address)<<1, WData, 3, 100);

		//Return -1 when there is error and return HAL_OK (= 0) when no error
		if (Error != HAL_OK)
		{
			return -1;
		}
		else
		{
			return HAL_OK;
		}
	}

	//Master sends I2C Read command and save the read data via pointer *Data.
	//The function returns HAL_OK (=0) when no error and -1 when there is error.
	int ReadI2C_Bus (struct TransferData *Data)
	{
		//Initialization of intial Error = 0
		int Error = 0;

		//Send I2C Read Command as shown in Fig. 10 in the Datasheet Page 7 with Error checking.
		/*Format defined by STM:
		*HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c1, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout).
		*HAL_I2C_Mem_Read () is used for reading data from the I2C device. It has been used instead of HAL_I2C_Master_Receive() because it sends restart condition
		*while the latter which sends stop condition and thus not working. It takes following arguments:
		*
		*I2C_HandleTypeDef *hi2c - is the pointer to the i2c handler.
		*uint16_t DevAddress - is the Address of the I2C device (Need to be shifted by 1 to left since the input of function expects 8 bits).
		*uint16_t MemAddress - is the Internal memory address in the slave which is the register address.
		*uint16_t MemAddSize - the size of memory address (in Byte) which is the size of register address (In the case of Vishay's Sensor always 1 Byte).
		*uint8_t *pData  - is the pointer to the data to be received.
		*uint16_t Size  - is the size of the received data in bytes.
		*uint32_t Timeout - timeout in millisecond in case of any error.
		*Return Error.
		*
		*/
		Error = HAL_I2C_Mem_Read(&hi2c1, (Data->Slave_Address)<<1, Data->RegisterAddress, 1,Data->RData,2,100);

		//Return -1 when there is error and return HAL_OK (= 0) when no error
		if (Error !=HAL_OK)
		{
			return -1;
		}
		else
		{
			return HAL_OK;
		}
	}

	//Master sends I2C Gesture Read command and save the read data via pointer *Data.
	//The function returns HAL_OK (=0) when no error and -1 when there is error.
    int ReadI2C_Bus_Gesture_Mode(struct GestureTransferData *Data)
	{
		//Initialization of intial Error = 0
		int Error = 0;

		//Send I2C Gesture Read Command as shown in the Application Note Page 19 with Error checking.
		/*Format defined by STM:
		*HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout).
		*HAL_I2C_Master_Receive () is used for reading data from the I2C device. It has been used instead of HAL_I2C_Mem_Read() because no restart condition is *needed.
		*It takes following arguments:
		*
		*I2C_HandleTypeDef *hi2c - is the pointer to the i2c handler. hi2c1 is defined in the stm32f4xx_hal.h and being called here via extern I2C_HandleTypeDef *hi2c1;.
		*uint16_t DevAddress - is the Address of the I2C device (Need to be shifted by 1 to left since the input of function expects 8 bits).
		*uint8_t *pData  - is the pointer to the data to be received.
		*uint16_t Size  - is the size of the received data in bytes (For Gesture Stream 6 Bytes are needed).
		*uint32_t Timeout - timeout in millisecond in case of any error.
		*Return Error.
		*
		*/
		Error = HAL_I2C_Master_Receive(&hi2c1,(Data->Slave_Address)<<1,Data->RData,6,100);

		//Return -1 when there is error and return HAL_OK (= 0) when no error
		if (Error != HAL_OK)
		{
			return -1;
		}
		else
		{
			return HAL_OK;
		}
	}
#endif

So, I need to port the nrf twi and its sdk, right ? to eventually use the library with the nrf52dk?

In addition, I would like to use the pooling rather than interrupt. I guess as well this is done in the main() but within the while(true) loop?

Any ideas, example how to do, approach this?

Best.

PS yeah , I am new to this, just realized that I should write the code to read off the sensor in the while (true) loop :) where I am now printing text , juhej! 

  • Hi

    Our experts on this are out of office due to the Easter Holiday.

    We will have a closer look at this case during next week.

    Regards,
    Sigurd Hellesvik

  • Thank you and I am looking forward to the reply.

    Indeed, happy Easter holidays!

  • MuRa said:
    For the Read I2C protocol, it is important that the restart condition is being sent before the second slave address and please ensure that no Stop condition being sent before the restart condition because some I2C library sends stop condition before restart condition ???

    This is typically handled by the no_stop parameter, e.g.:

    /**
     * @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);

  • Hello Kenneth!

    Thank you for your reply, information, 

    would you please be so kind and let me know,

    do I have to implement the function you are referring or it can be found in the existing drivers?

    In that case where, where it has to be implemented or where it can be found?

    Thank you in advance for your answer.

    best. 

  • If you are referring to my answer here:
    https://devzone.nordicsemi.com/f/nordic-q-a/84978/twi-reading-and-writing-basics/363652#363652 

    Then that is already available in the twi driver, it's just calling the twi api with the no_stop bit set or cleared according to your expecations. I suggest to have a logic analyzer at hand so you can see the transacations on byte level, with the start, stop and re-start conditions.

    Kenneth

Related