Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Running TWI from within app_timer callback.

I am trying to make TWI calls from an APP_TIMER event.  However the TWI calls are failing.  I can see that the twi message is sent on an oscilloscope, but the function never returns (handler function doesnt get called), and it holds the clock low after the last message.

I have tried increasing the TWI priority to highest (0) but no change.  I am not running a soft device or any other timers.

Is there something prohibiting use of TWI functions from a timer callback function?  Am I doing anything wrong, or is there a better way to go about this?

My main function is as follows, and does not work (twi as shown in image above):

int main(void)
{	
    lfclk_config();
 	utils_setup();
	twi_init_all();
	twi_read_init();
	while (true)
	{
		nrf_pwr_mgmt_run();
		NRF_LOG_FLUSH();
	}
}

If I modify it to call the twi_timer_handler function in the main loop, then it does work as expected.

int main(void)
{	
    lfclk_config();
 	utils_setup();
	twi_init_all();
	while (true)
	{
		nrf_pwr_mgmt_run();
		NRF_LOG_FLUSH();
		nrf_delay_ms(100);
		twi_timer_handler(NULL);
	}
}

Here is full code listing:

#include <stdio.h>
#include "nrf.h"
#include "bsp.h"
#include "hardfault.h"
#include "app_error.h"
#include "app_timer.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_drv_clock.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_drv_twi.h"

#include "nrf_delay.h"


APP_TIMER_DEF(twi_timer);

static void utils_setup(void)
{
		ret_code_t err_code = NRF_LOG_INIT(NULL);
		APP_ERROR_CHECK(err_code);
	
		err_code = app_timer_init();
		APP_ERROR_CHECK(err_code);

		err_code = nrf_pwr_mgmt_init();
		APP_ERROR_CHECK(err_code);

		NRF_LOG_DEFAULT_BACKENDS_INIT();
}

static void lfclk_config(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);
    nrf_drv_clock_lfclk_request(NULL);
}

typedef struct
{    
    const nrf_drv_twi_t     twi_inst;
    volatile bool           xfer_status;    ///< status for twi_instance
    uint8_t                 id_num;         ///< twi id
}  twi_struct;

static twi_struct twi_instance= {
        .twi_inst       =   NRF_DRV_TWI_INSTANCE(0),
        .xfer_status    =   false,
        .id_num         =   0
        };

static void twi_event_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
    switch (p_event->type)
    {
        case NRF_DRV_TWI_EVT_DONE:
            twi_instance.xfer_status = true;
            break;
        case NRF_DRV_TWI_EVT_ADDRESS_NACK:
            break;
        case NRF_DRV_TWI_EVT_DATA_NACK:
            break;
        default:
            break;
    }
}

void twi_init (nrf_drv_twi_config_t * p_twi_config)
{
    ret_code_t err_code;
    err_code = nrf_drv_twi_init(&twi_instance.twi_inst, p_twi_config, twi_event_handler, NULL);
    APP_ERROR_CHECK(err_code);
    nrf_drv_twi_enable(&twi_instance.twi_inst);
}

void twi_init_all()
{
	nrf_drv_twi_config_t twi_config = {
		 .scl								= 16,
		 .sda								= 12,
		 .frequency					= NRF_TWI_FREQ_100K,
		 .interrupt_priority = APP_IRQ_PRIORITY_LOWEST,
		 .clear_bus_init		 = false
		};
		twi_init(&twi_config);
}

void twi_write_register(uint8_t address, uint8_t * p_reg, uint8_t reg_size)
{
    //ret_code_t err_code = nrf_drv_twi_tx(&twi_i[id_num].twi_inst, address, reg, reg_size, false);
    twi_instance.xfer_status = false;
    ret_code_t err_code = nrf_drv_twi_tx(&twi_instance.twi_inst, address, p_reg, reg_size, false);
    APP_ERROR_CHECK(err_code);
    while (twi_instance.xfer_status == false);
    twi_instance.xfer_status = false;
}

void twi_read_register(uint8_t address, uint8_t * p_reg, uint8_t * p_data, uint8_t data_size)
{
    twi_write_register(address, p_reg, 1);
    ret_code_t err_code = nrf_drv_twi_rx(&twi_instance.twi_inst, address, p_data, data_size);
    APP_ERROR_CHECK(err_code);
    while (twi_instance.xfer_status == false);
    twi_instance.xfer_status = false;
}

void twi_timer_handler(void * p_context)
{
	uint8_t buffer_local[3];	
	uint8_t reg=0xA2;
	twi_read_register(0x76,&reg,&buffer_local[0],3);
}


 void twi_read_init()
{
    ret_code_t err_code;
	
    err_code = app_timer_create(&twi_timer, APP_TIMER_MODE_REPEATED, twi_timer_handler);
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_start(twi_timer, APP_TIMER_TICKS(10), NULL);
    APP_ERROR_CHECK(err_code);
}

int main(void)
{	
    lfclk_config();
 		utils_setup();
		twi_init_all();
		twi_read_init();
		while (true)
		{
			nrf_pwr_mgmt_run();
			NRF_LOG_FLUSH();
		}
}

Many thanks!

Parents
  • Hi,

     

    You are triggering a new interrupt from a interrupt handler, then busy-looping over this.

    That will not work if the app_timer handler and the TWIM handler runs in the same context (or TWIM runs in a lower priority).

    app_timer runs in sdk_config.h::APP_TIMER_CONFIG_IRQ_PRIORITY interrupt priority (normally '7'), so if your TWIM IRQ priority is '6' or higher, it should work.

     

    If you omit the twi_evt_handler in your init (set it to NULL), the driver shall do polling instead of event-driven. You shall then be able to call it from any context.

     

    Best regards,

    Håkon

  • Dear Hakon,

    My apologies, I had misunderstood a couple of things.

    Both of your suggestions work:

    • Setting event handler to "NULL" enables blocking mode, which is simplest solution.

    void twi_init (nrf_drv_twi_config_t * p_twi_config)
    {
        ret_code_t err_code;
        err_code = nrf_drv_twi_init(&twi_instance.twi_inst, p_twi_config, NULL, NULL);		// <-- set event handler to "NULL" to enable blocking mode.
        APP_ERROR_CHECK(err_code);
        nrf_drv_twi_enable(&twi_instance.twi_inst);
    }

    • Increasing TWI IRQ priority to 6 also works.  I had misunderstood where to do this - it is done in the twi_init function:

    void twi_init_all()
    {
    	nrf_drv_twi_config_t twi_config = {
    		 .scl								= 16,
    		 .sda								= 12,
    		 .frequency					= NRF_TWI_FREQ_100K,
    		 .interrupt_priority = 6,								// <----- this is where to set TWI IRQ priority!
    		 .clear_bus_init		 = false
    		};
    		twi_init(&twi_config);
    }

    Many thanks for such a quick solution!

    Barney

Reply
  • Dear Hakon,

    My apologies, I had misunderstood a couple of things.

    Both of your suggestions work:

    • Setting event handler to "NULL" enables blocking mode, which is simplest solution.

    void twi_init (nrf_drv_twi_config_t * p_twi_config)
    {
        ret_code_t err_code;
        err_code = nrf_drv_twi_init(&twi_instance.twi_inst, p_twi_config, NULL, NULL);		// <-- set event handler to "NULL" to enable blocking mode.
        APP_ERROR_CHECK(err_code);
        nrf_drv_twi_enable(&twi_instance.twi_inst);
    }

    • Increasing TWI IRQ priority to 6 also works.  I had misunderstood where to do this - it is done in the twi_init function:

    void twi_init_all()
    {
    	nrf_drv_twi_config_t twi_config = {
    		 .scl								= 16,
    		 .sda								= 12,
    		 .frequency					= NRF_TWI_FREQ_100K,
    		 .interrupt_priority = 6,								// <----- this is where to set TWI IRQ priority!
    		 .clear_bus_init		 = false
    		};
    		twi_init(&twi_config);
    }

    Many thanks for such a quick solution!

    Barney

Children
No Data
Related