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

TWI transaction failed

Hi, i am using:

-nRF 52 DK

-nRF 52832

-Sensor of Maxim Integrated

-SDK 17.0.2

I have some problems in handling the I2C through the nrfx module.

My I2C communication with the sensor is defined as a TX/RX.

I am using slightly different Read/Write function than the one used in the NRFX examples because i need some non-void function.

Here is my initialization,handler and read byte function:



 static const nrfx_twim_t twim_instance = NRFX_TWIM_INSTANCE(0);
 volatile bool twim_tx_done = false;
 volatile bool twim_rx_done = false;


void twim_handler(nrfx_twim_evt_t const * p_event, void * p_context)
{

    size_t primaryBufferSize = p_event->xfer_desc.primary_length;
    uint8_t *bytesTransferred = p_event->xfer_desc.p_primary_buf;
    size_t secondaryBufferSize = p_event->xfer_desc.secondary_length;
    uint8_t *bytesRead = p_event->xfer_desc.p_secondary_buf;

    switch (p_event->type)
    {
        case NRFX_TWIM_EVT_DONE:
    
            NRF_LOG_INFO("STATE OF BUFFERS IN EVENT HANDLER:");
            NRF_LOG_INFO("\t Size of primary buffer: %d", primaryBufferSize);
            NRF_LOG_INFO("\t Size of secondary buffer: %d", secondaryBufferSize);
          
					if (p_event->xfer_desc.type == NRFX_TWIM_XFER_TX)
            {
                twim_tx_done = true;
            }
          
						if (p_event->xfer_desc.type == NRFX_TWIM_XFER_RX)
            {
                twim_rx_done = true;
            }
            break;
        
				case NRFX_TWIM_EVT_ADDRESS_NACK:
            NRF_LOG_INFO("Received NACK after sending address!");
            break;
        
				case NRFX_TWIM_EVT_DATA_NACK:
            NRF_LOG_INFO("Received NACK after sending data.");
            break;
        default:
            break;
    }

	
uint32_t nrf_drv_oxi_init(void)
{
    uint32_t err_code;
    
    const nrfx_twim_config_t twi_oxi_config = {
       .scl                = OXI_TWI_SCL_PIN,
       .sda                = OXI_TWI_SDA_PIN,
       .frequency          = NRF_TWIM_FREQ_400K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGHEST,
       .hold_bus_uninit     = true
    };
    
		err_code = nrfx_twim_init(&twim_instance, &twi_oxi_config, twim_handler, NULL);
    APP_ERROR_CHECK(err_code);
    
    
	  nrfx_twim_enable(&twim_instance);
	
	  return NRF_SUCCESS;
}
//        ------------------------------------------------------------------------------------------------



uint8_t readByte( uint8_t familyByte, uint8_t indexByte)
{

		nrfx_err_t err_code;

		uint8_t StatusByte;    
        uint8_t ReturnByte;
   
        uint8_t rx_buffer[2];
		size_t rx_lenght =2;

		uint8_t tx_buffer[] = {familyByte, indexByte};    
		size_t tx_lenght = sizeof(familyByte) + sizeof(indexByte);

		nrfx_twim_xfer_desc_t tx_xfer = NRFX_TWIM_XFER_DESC_TX(OXI_ADDRESS_W, tx_buffer, tx_lenght);
		err_code = nrfx_twim_xfer(&twim_instance, &tx_xfer, 0);
		APP_ERROR_CHECK(err_code);
		
       while (!twim_tx_done)
        {
            __WFE();
        } 
        twim_tx_done  = false;

		
		nrfx_twim_xfer_desc_t rx_xfer = NRFX_TWIM_XFER_DESC_RX(OXI_ADDRESS_R, rx_buffer, rx_lenght);
		err_code = nrfx_twim_xfer(&twim_instance, &rx_xfer, 0);
		APP_ERROR_CHECK(err_code);
	
         while (!twim_rx_done )
        {
            __WFE();
        } 
        twim_rx_done  = false;
  
	
	
		StatusByte = rx_buffer[0];
        NRF_LOG_INFO("Status Byte: %lu \n",StatusByte);
    
		ReturnByte = rx_buffer[1];  
		return ReturnByte;
}

 

I don't receive any error (err_code always 0 (NRF_SUCCESS)) but it seems that after the first transaction (TX) nothing happen as i can see from the TWIM0 window:

No task is started and no byte is transferred.

I am a newbie in embedded system, probably my functions are correct (thanks to the help of Nordic Support Team) but probably i am missing some basics of I2C configuratiion.

Do you have any idea why this could happen? 

thanks,

polimarte

Parents
  • Hello Polimarte!

    From your included screenshot you seem to be encountering some errors. Is this correct? Which errors are these, and where do they come from?

    Are you ever entering your twim_handler?

    No task is started and no byte is transferred.

    Do you have access to a logic analyzer, so you may see what is happening on the pins themselves? 

    I don't receive any error (err_code always 0 (NRF_SUCCESS)) but it seems that after the first transaction (TX) nothing happen as i can see from the TWIM0 window:
    No task is started and no byte is transferred.

    Please elaborate where you are reading this. From what I can see in your screenshot, both ERROR and TXSTARTED is true - leading me to believe that a TX in fact is started, and an error is returned somewhere.
    Let us start by finding the source of this error, so we may get to the bottom of why this is not working as expected.

    Looking forward to resolving this issue together!

    Best regards,
    Karl

  • Hi Karl, it is a pleasure to hear you again!

    I have to admit that i found some problems in enabling the log uart in the last SDK so i am using the RTT viewer but nothing happen on my RTT terminal if i am stack in a loop as in my case.

    My code is stack at the loop for twim_tx_done, so NRFX_TWIM_EVT_DONE is never set.

    If i comment these loop on both the Read/Write Bytes functions on my window, my code run without block and i can see this on the RTT viewer:

    Are you ever entering your twim_handler?

    Yes i can enter on the twim_handler and as i can see from the RTT viewer i get : NRFX_TWIM_EVT_ADDRESS_NACK.

    Do you have access to a logic analyzer, so you may see what is happening on the pins themselves? 

    Yes, i do. I am using KEIL. Unfortunately i m still studying how to setup the logic analyzer because i am not able to let it work properly (i am getting always "Unknown Signal").

    Mange Takk Karl!

    polimarte

  • Hi Karl! 

    While this implementation might function, you have no way to know how long this loop will take to complete - the time will vary for each call to your function.

    Yes you are right, i forgot the possibility of faulty interaction of the interrupts with timer variables.

    Yes, and then have something else ( such as a retransmit ) happen if the NACK flag is set.

    I have modified my code in order to retransmit at the arrival of the twim_tx_failed (NACK event) or at the timeout of the timer.

    void twim_handler(nrfx_twim_evt_t const * p_event, void * p_context)
    {
    
        size_t primaryBufferSize = p_event->xfer_desc.primary_length;
        uint8_t *bytesTransferred = p_event->xfer_desc.p_primary_buf;
        size_t secondaryBufferSize = p_event->xfer_desc.secondary_length;
        uint8_t *bytesRead = p_event->xfer_desc.p_secondary_buf;
    
        switch (p_event->type)
        {
            case NRFX_TWIM_EVT_DONE:
        
                NRF_LOG_INFO("STATE OF BUFFERS IN EVENT HANDLER:");
                NRF_LOG_INFO("\t Size of primary buffer: %d", primaryBufferSize);
                NRF_LOG_INFO("\t Size of secondary buffer: %d", secondaryBufferSize);
              
    					if (p_event->xfer_desc.type == NRFX_TWIM_XFER_TX)
                {
                    twim_tx_done = true;
                }
              
    					if (p_event->xfer_desc.type == NRFX_TWIM_XFER_RX)
                {
                    twim_rx_done = true;
                }
                break;
            
    		case NRFX_TWIM_EVT_ADDRESS_NACK:
    						if (p_event->xfer_desc.type == NRFX_TWIM_XFER_TX)
                {
                    twim_tx_failed = true;
                }
              
    						if (p_event->xfer_desc.type == NRFX_TWIM_XFER_RX)
                {
                     twim_rx_failed = true;
                }
                NRF_LOG_INFO("Received NACK after sending address!");
                break;
            
    		case NRFX_TWIM_EVT_DATA_NACK:
                NRF_LOG_INFO("Received NACK after sending data.");
                break;
            default:
                break;
        }
    
    	}
    	
    uint8_t readByte( uint8_t familyByte, uint8_t indexByte)
    {
        
    	
    		uint8_t flag_retry=1;
    	
    		nrfx_err_t err_code;
    
    		uint8_t StatusByte;    
            uint8_t ReturnByte;
       
            uint8_t rx_buffer[2];
    		size_t rx_lenght =2;
    
    		uint8_t tx_buffer[] = {familyByte, indexByte};    
    		size_t tx_lenght = sizeof(familyByte) + sizeof(indexByte);
    
    		while(flag_retry==1){
    		uint32_t timeout = OXI_TWI_TIMEOUT;
    		nrfx_twim_xfer_desc_t tx_xfer = NRFX_TWIM_XFER_DESC_TX(OXI_ADDRESS_W, tx_buffer, tx_lenght);
    		err_code = nrfx_twim_xfer(&twim_instance, &tx_xfer, 0);
    		nrf_delay_ms(6);
    		APP_ERROR_CHECK(err_code);
    		
    		while((!twim_tx_done) && --timeout && 	twim_tx_failed == false);
    		if(!timeout) err_code=NRF_ERROR_TIMEOUT;
    		APP_ERROR_CHECK(err_code);
    		if(twim_tx_done) flag_retry=0;
    		if(twim_tx_failed) flag_retry=1;
    		}
    		
    
    		flag_retry=1;
    		
    		
    		while(flag_retry==1){
    		uint32_t timeout = OXI_TWI_TIMEOUT;
    			
    		nrfx_twim_xfer_desc_t rx_xfer = NRFX_TWIM_XFER_DESC_TX(OXI_ADDRESS_W, rx_buffer, rx_lenght);
    		err_code = nrfx_twim_xfer(&twim_instance, &rx_xfer, 0);
    		APP_ERROR_CHECK(err_code);
    		
    		while((!twim_rx_done) && --timeout && 	twim_rx_failed == false);
    		if(!timeout) err_code=NRF_ERROR_TIMEOUT;
    		APP_ERROR_CHECK(err_code);
    		if(twim_rx_done) flag_retry=0;
    		if(twim_tx_failed) flag_retry=1;
    		}
    		
    		StatusByte = rx_buffer[0];
            NRF_LOG_INFO("Status Byte: %lu \n",StatusByte);
        
    		ReturnByte = rx_buffer[1];  
    		return ReturnByte;
    }

    In this way till flag_retry is set the transaction starts again or abort in case of timeout with APP_ERROR_CHECK. I add also a delay after the transaction but still i am stack with NACK.

    This is correct, and with the current implementation this is as expected - since the nrfx_xfer function is non-blocking, it will return before the slave device has had the chance to NACK ( or otherwise misbehave ).

    Maybe i am missing something but i have set no flags on NRFX_TWIM_XFER_TX, allowing so the STOP condition. nrfx_twim_xfer without NRFX_TWIM_FLAG_TX_NO_STOP is blocking, suitable with the waiting for the twim_tx_done to be set, correct? 

    Apart from the screenshot you should see a debug output if anything else than NRF_SUCCESS was returned. 

    I have the RTT viewer which display the NACK and the TWIM viewer where the TX starts and the AMOUNT of bytes transferred is always 0. Where i can catch and show you other useful debug outputs? 

    I did a quick search for the part number MAX32664 and found this datasheet. Is this the part you are working with?

    Yes, i am working on it!

    Among other things, it describes that the device needs a given CMD_DELAY to ready data for transfer - this could for example lead the device to NACK a request, since it is not yet ready to proceed with a transfer. 

    I have read this, i have considered the CMD_DELAY between TX and RX solved by the possibility to have a check on the transaction state, having twim_tx_done set and the STOP condition.

    it describes that the device needs a given CMD_DELAY to ready data for transfer - this could for example lead the device to NACK a request, since it is not yet ready to proceed with a transfer. 

    I tryied also to insert some delay after any twim_xfer, to give time to the transaction to be done.

     Thanks,

    polimarte

  • Hello Polimarte,

    polimarte said:
    Yes you are right, i forgot the possibility of faulty interaction of the interrupts with timer variables.

    I would not call it a faulty interaction, but yes, this is definitely something to consider. If accuracy is needed, a timer should be used instead.

    polimarte said:
    I have modified my code in order to retransmit at the arrival of the twim_tx_failed (NACK event) or at the timeout of the timer.

     Great! Now it accounts for the possibility of a NACK atleast. I will note that APP_ERROR_CHECK() following your waiting while loop will be called regardless of the while loop ending due to a timeout or success. This means that it will be called twice with the error_code returned by twim_xfer. This might seem insignificant now, but it could induce some trouble if you later change your error handling.

    polimarte said:
    In this way till flag_retry is set the transaction starts again or abort in case of timeout with APP_ERROR_CHECK. I add also a delay after the transaction but still i am stack with NACK.

    So, we will still need to resolve why the NACK is sent. Why the slave device is not responding to the second call.
    Most likely ( if it is not a timing issue ), retransmission will not solve the issue in this case. You will for example get a NACK on the address if the address is not exposed on the device. Retrying the same address will then always generate NACK, since it will never be acknowledged.

    It seems you are only getting this NACK on the READ command, following the first Write, is this correct? If so, what is your OXI_ADDRESS_R - where did you find it, and what does the documentation say about this address?

    polimarte said:
    Maybe i am missing something but i have set no flags on NRFX_TWIM_XFER_TX, allowing so the STOP condition. nrfx_twim_xfer without NRFX_TWIM_FLAG_TX_NO_STOP is blocking, suitable with the waiting for the twim_tx_done to be set, correct? 

    No, this is incorrect. nrfx_twim_xfer is non blocking, even with the NO_STOP flag - this flag only means that no stop condition is generated between successive transfers. In your case, you will need a STOP condition when you switch between a read and a write command, and visa versa.

    polimarte said:
    I have read this, i have considered the CMD_DELAY between TX and RX solved by the possibility to have a check on the transaction state, having twim_tx_done set and the STOP condition.

    Sorry, I do not understand what you mean by this. You will indeed need the twim_tx_done set, after a STOP condition is sent. As I understand it from your provided documentation screenshot, you need the CMD_DELAY to happen AFTER the stop condition is sent, and the twim_tx_done is set. The CMD_DELAY is meant to give the slave time to prepare data / process the command, before the master may send a new command.
    So, can you tell me, how long does the datasheet specify that the CMD_DELAY needs to be, and how long is your actual wait between the completion of the TX and the start of the RX, with your current code?

    polimarte said:
    I tryied also to insert some delay after any twim_xfer, to give time to the transaction to be done.

    I see that you have put a 6 ms delay here. What is the required CMD_DELAY as specified in the datasheet?

    Looking forward to getting to the bottom of this!

    Best regards,
    Karl

  • Hi Karl i really appreciate your help!  

    This means that it will be called twice with the error_code returned by twim_xfer.

    Thanks for the note i will call the APP_ERROR_CHECK only ones in this case. II had inserted the second one as a break in case of timeout only, but you are right is not useful implemented like that.

    It seems you are only getting this NACK on the READ command, following the first Write, is this correct?

    No, unfortunately i have problem since the first read. To work with my sensor hub i have to enter in Application Mode first, through a sequence of set/clear of two pins, the Reset and the Mfio pin. This is working, even if i could not check with a logic analyzer i have seen the behave of the pins with the help of two leds. I know it is very naive. As well the sda and scl are set high, but nothing happen than. After this sequence i have the first read to apply in order to check the device mode. 

    If so, what is your OXI_ADDRESS_R - where did you find it, and what does the documentation say about this address?
    "The MAX32664 uses 0xAA as the I2C 8-bit slave write address and 0xAB is used as the I2C 8-bit slave read address"

    Initially i wrongly used two different slave adresses for the TX and RX transactions (OXI_ADDRESS_W=0xAA and OXI_ADRESS_R=0xAB) only than i noticed that the the nrfx_twim_*x nedeed the 7-bit address (LSB). So now i am using as address field 0x55 for both the transactions. 

    You will indeed need the twim_tx_done set, after a STOP condition is sent. As I understand it from your provided documentation screenshot, you need the CMD_DELAY to happen AFTER the stop condition is sent, and the twim_tx_done is set.

    Thanks for this important specification about stop condition and non-blocking mode, i was a bit confused about that.

    As I understand it from your provided documentation screenshot, you need the CMD_DELAY to happen AFTER the stop condition is sent, and the twim_tx_done is set.

    I had already tryed to insert some delay between the transactions in my previous modification of the code but still i had the NACK error. I will reintroduce this dalay between TX and the RX, in the code that i have shared i have  inserted a delay after the first xfer, i will change position of that.

    So, can you tell me, how long does the datasheet specify that the CMD_DELAY needs to be, and how long is your actual wait between the completion of the TX and the start of the RX, with your current code?

    The datasheet states that "The master waits for a period of CMD_DELAY (2ms) for the device to have its data ready". I have put a longer delay (6ms) as it is in my version of the code for ARDUINO (that is working correctly). i don't think it is an issue. 

    I checked with the twi_scanner example the address. When i directly connect the sensor to the DK it finds the right address at 0x55. I tryed than to use my read/write byte functions and they complete the transactions (the twi_*x_done is set correctly). While connecting the sensor to nRF52832 i am able to check the correct address but i am still stack at our NACK error. I am using general digital pins 16 and 17 on the nrf52832 as SDA and SCL and i am sure to have defined correctly these pins in the twi_init function as well to have connected in the right way the DK to my nrf52832.

    Looking forward to getting to the bottom of this!

    Thanks again Karl!

    polimarte

  • Hi, i finally i make it work! i had some problems with SDA/SCL pins, now the first read is done correctly.

    Thanks karl for the support! 

    polimarte

  • Hello Polimarte!

    Sorry for my late reply - I have been out of office for some days.

    polimarte said:
    i finally i make it work!

    Great, that is fantastic news! I am glad to hear that you figured it out and were able to resolve your issues!
    I hope my comments and suggestions have been helpful to you in this endeavor.

    polimarte said:
    Thanks karl for the support! 

    No problem at all, Polimarte, I am happy to help! :)

    Please do not hesitate to open a new ticket if you should encounter any issues or questions in the future.

    Good luck with your development!

    Best regards,
    Karl

Reply
  • Hello Polimarte!

    Sorry for my late reply - I have been out of office for some days.

    polimarte said:
    i finally i make it work!

    Great, that is fantastic news! I am glad to hear that you figured it out and were able to resolve your issues!
    I hope my comments and suggestions have been helpful to you in this endeavor.

    polimarte said:
    Thanks karl for the support! 

    No problem at all, Polimarte, I am happy to help! :)

    Please do not hesitate to open a new ticket if you should encounter any issues or questions in the future.

    Good luck with your development!

    Best regards,
    Karl

Children
No Data
Related