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

TWIM XFER Hangs Unless NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER used as a flag

Hello! 

I have this interesting bug with the twim driver.

It works perfectly with the NRFX_TWIM_XFER_TXRX transfer type: I see the transaction go out on the bus lines and the interrupt calls my handler when the transfer is complete. 

When I switch the xfer type to NRFX_TWIM_XFER_TX, however, I get the following: 

1) The transaction occurs successfully: I see the start and stop bits and all the bits in between are as expected. 

2) My handler is never called. 

3) If I poll wait using 'nrfx_twim_is_busy', it never leaves the while loop. 

4) If I use the NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER flag, the data goes out on the pins, the handler is never called (as expected) BUT 'nrfx_twim_is_busy' eventually 

    returns 'false'. 

What am I missing? I see that I have to enable EasyDMA on the active Twim instance for the project to compile but I don't have any easy DMA code setup. 

Parents
  • Here is the initialization: 

    //Initialization
    const nrfx_twim_t drv = {
       .p_twim			 = NRF_TWIM0,
       .drv_inst_idx     = NRFX_TWIM0_INST_IDX
    };
    
    const nrfx_twim_config_t cfg = {
       .scl                = I2C_SCL,
       .sda                = I2C_SDA,
       .frequency          = NRF_TWIM_FREQ_400K,
       .interrupt_priority = NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY,
       .hold_bus_uninit     = true
    };
    	
    void i2c_init(void)
    {
    	ret_code_t errCode = 0;
    
    	//	Init variables
    	memset( (void *) &xferStruct, 0, sizeof(nrfx_twim_xfer_desc_t));
    	memset( (void *) addrBuff, 0, (sizeof(uint8_t) * ADDR_LEN) );
    	blockCall = 0;
    	usrCallBack = NULL;
    
    	//	Set-up SDA and SCL as outputs first
    	nrf_gpio_pin_set(I2C_SCL);
    	nrf_gpio_pin_set(I2C_SDA);
    	nrf_gpio_cfg(I2C_SCL, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL,
    			NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);
    
    	nrf_gpio_cfg(I2C_SDA, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL,
    			NRF_GPIO_PIN_S0S1, NRF_GPIO_PIN_NOSENSE);
    
    
    	//Initialize inputs
    	if(!nrfx_gpiote_is_init())
    	{
    		nrfx_gpiote_init();
    	}
    
    	//	Initialize driver and enable
    	errCode = nrfx_twim_init(&drv, &cfg, handler, (void *)&context);
        NRF_LOG_INFO("Twi init: %d", errCode);
        NRF_LOG_FLUSH();
    
    	nrfx_twim_enable(&drv);
    	return;
    }

    and here is the write function. I do not use PPI. I just use the call to twim_xfer: 

    //here is the tx function 
    
    uint8_t setRegBuff[RAM_REG_LEN + 1];
    nrfx_twim_evt_t tmpEvt;
    ret_code_t write_i2c_reg(uint8_t regAddr, uint8_t *regBuff, done_call_back_t cb)
    {
    	ret_code_t errCode = NRF_SUCCESS;
    
    	if(nrfx_twim_is_busy(&drv))
    	{
    		errCode = NRF_ERROR_BUSY;
    	}
    	else
    	{
    
    		setRegBuff[0] = regAddr;
    		setRegBuff[1] = regBuff[0];
    		setRegBuff[2] = regBuff[1];
    
    		xferStruct.address = BUS_I2C_REG_ADDR;
    		xferStruct.p_primary_buf = setRegBuff;
    		xferStruct.primary_length = RAM_REG_LEN + 1;
    		xferStruct.p_secondary_buf = NULL;
    		xferStruct.secondary_length = 0;
    		xferStruct.type = NRFX_TWIM_XFER_TX;
    
    		usrCallBack = NULL;
    		blockCall = 1;
    
    		//Should NOT be called with the NO_XFER_EVT flag but otherwise it hangs up ...
    		//My work-around is to block wait until the transfer is done, and then call
    		//the handler directy
    		errCode = nrfx_twim_xfer(&drv, &xferStruct, NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER);
    
    
    		//wait till done if no call back defined
    		// For some reason _TX transfers do not call an interrupt when finished
    		while(nrfx_twim_is_busy(&drv))
    		{
    			nrf_delay_us(MAX17330_BLOCK_DELAY);
    		}
    
    		//Force a delay... bytes are still being shifted out at this point
    		//so subsequent writes might override 
    		nrf_delay_us(BLOCK_DELAY * 3);
    
            //simulate the interrupt by calling the handler directly 
    		tmpEvt.type = NRFX_TWIM_EVT_DONE;
    		memcpy( &tmpEvt.xfer_desc, &xferStruct, sizeof(nrfx_twim_xfer_desc_t) );
    		handler(&tmpEvt, NULL);
    
    	}
    	return errCode;
    }

    As much as I hate editing SDK files, I also commented out the "apply_old_configs.h" file in the include tree. This was 

    over-riding my sdk_config. BTW, that is super confusing. Why set the SDK up this way? the sdk_config should be the source of truth for the project but I guess thats another ticket haha 

  • Hello again! 

    1) I removed the NRFX_TWIM_INSTANCE macro as a result of troubleshooting why the "old_config.h" file was rewriting my sdk_config. I've added it back without any problem. 

    2) I've been in debug mode and have verified that all of my return codes are "NRF_SUCCESS". 

    By 'logger' do you mean the J-Link application that captures NRF_LOG_INFO messages? I've heard that its possible 

    to have your firmware store these messages in flash and that they can be retrieved later.  I'm new to this chip/IDE. Is this possible? As a side-note, is there a page with describing how to use this functionality? 

    Thank you so much for your help! 

  • Julio said:
    Thank you so much for your help!

    It is no problem at all Julio, I am happy to help!

    Julio said:
    1) I removed the NRFX_TWIM_INSTANCE macro as a result of troubleshooting why the "old_config.h" file was rewriting my sdk_config. I've added it back without any problem. 

    Oh, I see. It seems I forgot to answer that part of your previous comment. The apply_old_config file is included for backwards compatibility - but it has been reported several times as perhaps less-than-ideal..
    Please see this ticket for a more detailed discussion of the issue. In essence, it will override your sdk_config define if you leave something defined, regardless of if it is defined to 0 ( which then intuitively should mean that it is excluded for the build, of course ). I am sorry that you too encountered issues with this configuration.

    Julio said:
    2) I've been in debug mode and have verified that all of my return codes are "NRF_SUCCESS". 

    Ok, at least that is good - but I would strongly recommend that you always from here on out check your returned error codes in your application. You might still encounter != NRF_SUCCESS error codes when the firmware is out of development and deployed, and these error code checks are you only way of knowing if this has occurred(for whatever reason) and that your program may not proceed as usual.

    Julio said:

    By 'logger' do you mean the J-Link application that captures NRF_LOG_INFO messages? I've heard that its possible 

    to have your firmware store these messages in flash and that they can be retrieved later.  I'm new to this chip/IDE. Is this possible? As a side-note, is there a page with describing how to use this functionality? 

    I am here referring to the Logger module of the SDK - your configuration of the logger module will determine which backends it uses, and thus also where it outputs its logs (such as either RTT, UART, CLI, or FLASH). Which backend are you currently using - RTT?
    You may configure the logger to store logs in flash, yes. Or are you here asking about the deferred logging option?
    Deferred logging lets you postpone logging processing till the CPU is idle, so that it minimally impacts your application performance. You can see how this is done in most - if not all - of the SDK examples, where NRF_LOG_PROCESS is called as part of the idle_state_handler function, right before the device goes to low power mode.
    Deferred logging then also means that the logs are not written out until this call to NRF_LOG_PROCESS is made, so they may appear later than expected when compared to in-place logging(non-deferred).
    You may read more about the logger module in the logger module documentation.

    If this was not what you were asking about, or if anything still should be unclear about the logger module, please do not hesitate to ask! :) 

    Best regards,
    Karl 

  • 1) Noted: I will use the APP_ERROR_CHECK (or other suitable logging method) moving forward. Thank you for pointing me to the logger page. I am currently using the RTT debug option through my J-Link but I would definitely like to store debug messages in flash and retrieve them later after running for a long time. 

    2) We went on a side mission haha but I'm still having trouble with the original ticket. The interrupt after calling nrfx_twim_xfer with the NRFX_TWIM_XFER_TX type works but never calls the handler when the transfer 

    is complete. Are you able to duplicate this with the SDK 16? 

  • Thank you for your patience.

    Julio said:
    Noted: I will use the APP_ERROR_CHECK (or other suitable logging method) moving forward.

    Great, I am glad to hear that!

    Julio said:
    Thank you for pointing me to the logger page.

    No problem at all, I am happy to help. 

    Julio said:
    We went on a side mission haha but I'm still having trouble with the original ticket. The interrupt after calling nrfx_twim_xfer with the NRFX_TWIM_XFER_TX type works but never calls the handler when the transfer 

    Hehe yes, suddenly we had diverged from the original issue.
    So, back to the initial issue: would it be possible for you to share the entire main.c file with me? It would be a lot easier to look through the initialization when I also could see what the different parameters used actually point to. Especially so if you have already made changes to the code since you shared it last.

    If there is an issue of sharing the code publicly here please let me know so I can make the ticket private - only viewable by yourself and the support staff here at Nordic.
    Please let me know if you would like me to do so before you share the code.

    Looking forward to resolving this issue together,

    Best regards,
    Karl

  • Hi Karl, 

    I cannot share that code publicly. I made sure to scrub the code I did share to remove sensitive information. Such a task would be too much for the entire main.c (and additional source code). 

    Are you unable to duplicate this? It's a pretty straightforward phenomenon. If you have good, known working code that does what I am attempting to do, please post it.  This is a minor problem thats been more my curiosity than a real problem. 

  • Hello Julio,

    Julio said:
    I cannot share that code publicly. I made sure to scrub the code I did share to remove sensitive information. Such a task would be too much for the entire main.c (and additional source code).

    As I said, I can make the ticket here private - so that it is only viewable for you yourself, and the support staff here at Nordic.
    Would this allow you to share the code?

    Julio said:
    If you have good, known working code that does what I am attempting to do, please post it.  This is a minor problem thats been more my curiosity than a real problem. 

    I have never heard about this specific issue before - so I have not created an example for this - but the twi_sensor example is a minimal implementation that does this with an _RX transaction without problem. If you have defined and set NRF_DRV_TWI_USE_TWIM in your sdk_config, the example will use the TWIM driver.
    Could you run this example - replacing the default pins and addresses in the example with those relevant for your device - and see if you are seeing the same behavior?

    Seeing the code would undoubtedly be helpful in order to efficiently debug this - but if this is not possible I'm sure we will be able to make due.

    Best regards,
    Karl

Reply
  • Hello Julio,

    Julio said:
    I cannot share that code publicly. I made sure to scrub the code I did share to remove sensitive information. Such a task would be too much for the entire main.c (and additional source code).

    As I said, I can make the ticket here private - so that it is only viewable for you yourself, and the support staff here at Nordic.
    Would this allow you to share the code?

    Julio said:
    If you have good, known working code that does what I am attempting to do, please post it.  This is a minor problem thats been more my curiosity than a real problem. 

    I have never heard about this specific issue before - so I have not created an example for this - but the twi_sensor example is a minimal implementation that does this with an _RX transaction without problem. If you have defined and set NRF_DRV_TWI_USE_TWIM in your sdk_config, the example will use the TWIM driver.
    Could you run this example - replacing the default pins and addresses in the example with those relevant for your device - and see if you are seeing the same behavior?

    Seeing the code would undoubtedly be helpful in order to efficiently debug this - but if this is not possible I'm sure we will be able to make due.

    Best regards,
    Karl

Children
No Data
Related