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

How to process a queue in the background?

nRF52832
SDK 14.2


Hi.

I would like to know how I can run a function in the background? In my case, I want to process a queue in the background. Here is the scneario:

Let's say I have two functions fooA(..) and fooB(...). If I call fooA(..), item A gets added to the queue and the function returns with QUEUED. If I call fooB(..), item B gets added to the queue and then function returns with QUEUED. (They are not executed yet.)

The queue needs to be processed to execute the items that are on the queue. My question is when and where should the processQueue function be called?
I am writing a library component and the users only have access to fooA(..) and fooB(..). The user will call these functions and they will return with QUEUED i.e item is on the queue.
But I am not sure when and how my library should be processing the queue? Should the processing be done in the background? What should trigger the processQueue(..) function to run?

Here is a rough pseudocode that I wrote to make things a bit clearer:

fooA(...){

//add item A to the queue
//return QUEUED;
}

fooB(...){

//add item B to the queue
//return QUEUED;
}


processQueue(..){

	item = getQueueItem(..)
	
	switch(item){
	
		case A:
					execute_A(..)
					break;
					
	  case B:
	  			execute_B(..)
	  			break;			
	}

}

execute_A(..){

//actual execution of A
}


execute_B(..){

//actual execution of B
}

Parents
  • Hi,

    This is commonly done using some sort of scheduler, to reduce the processing time in interrupts and change priority level from interrupt context to thread (also called main) context.

    We have the library app_scheduler than can do this, where you add the call to app_sched_execute() to the main loop.

    To add an item to the queue, you can call app_sched_event_put(NULL, 0, my_function); and it will get processed when you enter the main for-loop.

    Many BLE-examples (ble_app_hids_*) has the scheduler initialized and uses this for BLE events and app_timer handlers, and the nfc\writeable_ndef_msg uses it as well.

    Most RTOSes have the same concept available.

    You can also go the other way around. Everytime fooA or fooB is called, you set a interrupt pending, and have a software interrupt in your module, here shown with some crude code:

    ret_t fooA(...)
    {
      ...
      ret = add_to_queue(fooA);
      if ( ret != success)
        NVIC_SetPending(SWIx_IRQn);
      return ret;
    }
    
    ret_t fooB(...)
    {
      ...
      ret = add_to_queue(fooB);
      if ( ret != success)
        NVIC_SetPending(SWIx_IRQn);
      return ret;
    }
    
    void SWIx_IRQHandler(void)
    {
      process_queue();
    }
    
    static ret_t fooA_process(...)
    {
      ...
    }
    
    static ret_t fooB_process(...)
    {
      ...
    }

    It all depends on how this module is hooked into the rest of your system.

    Cheers,

    Håkon

Reply
  • Hi,

    This is commonly done using some sort of scheduler, to reduce the processing time in interrupts and change priority level from interrupt context to thread (also called main) context.

    We have the library app_scheduler than can do this, where you add the call to app_sched_execute() to the main loop.

    To add an item to the queue, you can call app_sched_event_put(NULL, 0, my_function); and it will get processed when you enter the main for-loop.

    Many BLE-examples (ble_app_hids_*) has the scheduler initialized and uses this for BLE events and app_timer handlers, and the nfc\writeable_ndef_msg uses it as well.

    Most RTOSes have the same concept available.

    You can also go the other way around. Everytime fooA or fooB is called, you set a interrupt pending, and have a software interrupt in your module, here shown with some crude code:

    ret_t fooA(...)
    {
      ...
      ret = add_to_queue(fooA);
      if ( ret != success)
        NVIC_SetPending(SWIx_IRQn);
      return ret;
    }
    
    ret_t fooB(...)
    {
      ...
      ret = add_to_queue(fooB);
      if ( ret != success)
        NVIC_SetPending(SWIx_IRQn);
      return ret;
    }
    
    void SWIx_IRQHandler(void)
    {
      process_queue();
    }
    
    static ret_t fooA_process(...)
    {
      ...
    }
    
    static ret_t fooB_process(...)
    {
      ...
    }

    It all depends on how this module is hooked into the rest of your system.

    Cheers,

    Håkon

Children
No Data
Related