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

Feeding an application timer?

Hi,

My use case is I have an RGB LED that I want to be green for normal operation, but blink red for 0.5s when a serial driver error occurs.

R, G, and B are each attached to a separate GPIO pin.

How I am planning to do this is: 

void serial_event_handler(struct nrf_serial_s const * p_serial, nrf_serial_event_t event)
{

	switch (event)
	{
	...
	    case NRF_SERIAL_EVENT_DRV_ERR:
        	nrf_gpio_pin_set(LED_RED);
        	err_code = app_timer_start(m_led_blink_timer_id, APP_TIMER_TICKS(500), NULL);
        	APP_ERROR_CHECK(err_code);
        	break;
    ...
    }
}

And the timeout_handler() clears LED_RED and sets LED_GREEN. 

But I am trying to support one edge case, which is: if a second error occurs within 0.5s of the first error, I would like to simply feed the timer, so it turns LED_RED off 0.5s after the most recent error, whenever it is. 

(For example, say an error occurs at time t = 0 and again at time t = 0.25s. This means LED_RED should be on from time t=0 to t=0.75s.)

My question: is there a way to feed an application timer?

I was thinking I could call app_timer_stop() before every call to app_timer_start(), but in the case of multiple errors occurring in rapid succession, I was concerned if too many start/stops get queued at once, I might hit this "no_mem" condition (screenshot):

1. how much memory does this queue have, and how much memory does one app_timer_start() or app_timer_stop() operation take?

2. is there a way to modify the timer register to feed the timer directly?

Thanks!

  • Hi,

    1. how much memory does this queue have, and how much memory does one app_timer_start() or app_timer_stop() operation take?

    You can configure the size of the operation queue in your sdk_config.h file by setting APP_TIMER_CONFIG_OP_QUEUE_SIZE. This will create an atomic FIFO holding elements of type timer_req_t which holds a pointer to the timer instance and the request type:

    /**
     * @brief Timer requests types.
     */
    typedef enum
    {
        TIMER_REQ_START,
        TIMER_REQ_STOP,
        TIMER_REQ_STOP_ALL
    } app_timer_req_type_t;
    
    /**
     * @brief Operation request structure.
     */
    typedef struct
    {
        app_timer_req_type_t type;    /**< Request type. */
        app_timer_t *        p_timer; /**< Timer instance. */
    } timer_req_t;
    
    /* Request FIFO instance. */
    NRF_ATFIFO_DEF(m_req_fifo, timer_req_t, APP_TIMER_CONFIG_OP_QUEUE_SIZE);

    2. is there a way to modify the timer register to feed the timer directly?

    As far as I can see, there is currently no such functionality in the app_timer implementation.

    Best regards,
    Jørgen

  • Thank you so much for the helpful answer, Jorgen.

    I see the default queue size is 10, does that mean up to 10 start/stop timer operations can be queued at once, for all timers in the application? Or is this per timer instance? 

    Is there a practical upper bound or recommended max for how big this queue can be? 

    Thanks!

  • A single FIFO is shared by all timers created in the app_timer library. The main limitation is the available RAM in your application/chip. Larger FIFO size will require more static memory. 

    I would recommend that you profile the FIFO usage in your application during stress-testing to determine the max utilization of the FIFO, and then add some margin on top of that .

  • Thanks for the recommendation Jorgen.

    I would recommend that you profile the FIFO usage in your application during stress-testing to determine the max utilization of the FIFO

    How do I do this? If you also have links to other resources that explain how to do stress-testing, that would be very helpful.

  • There is no standardized way to do this, as all applications will have different requirements and resources. You need to define some test-cases that will be is expected to put the larges amount of pressure on your application, in terms of high activity, interrupt handling delays, etc.

    You can check the utilization of the atomic FIFO using the head and tail parameters of the nrf_atfifo_t instance, which is created inside the NRF_ATFIFO_DEF() macro. You can also just make sure that you do not get the NO_MEM during the stress-testing. You should anyway implement some way of handling this error, in case it should happen anyway in a corner-case you have not thought about.

Related