How to generate a Delay in a tickless FreeRTOS

mehrad1983 wrote on Thursday, March 23, 2017:

Hi there,

I have been using SAMD21 and the Tickless FreeRTOS coming with ASF.
When I switched to tickless I have removed the Systick driver from ASF and substituted my cpu_delay_ms( ) with vTaskDelay( ) available through FreeRTOS, however, I require couple of delays inside some of the i2c callback methods in which are operating outside of the body of my tasks and (in the hard way) I realised, since I am not issuing the vTaskDelay( ) inside the body of the task, I don’t get a delay.

So now I am looking for a solution which could mimic a ms delay (in a rough ms ballpark) without enabling and initializing the Systick and using cpu_delay_ms( ), which I believe would cancel out the benefits of switching to a tickless edition.

Is there such a method you could suggest that I could use all over the code which would delay for the required amount of ms regardless of the place the delay is used?

Regards,

PS: please correct me if any of my assumptions where wrong.

richard_damon wrote on Thursday, March 23, 2017:

You will want some form of interrupt to get the time delay (since you want to be able to sto the processor during the delay to go low power mode). If you don’t want the SysTick running (so you can go very low power when you don’t need a timer), another option is to setup a hardware timer to run only when you need a controlled delay and interrupt at the end of the delay, which would send the wakeup notification to the task requesting it. Your call back functions MUST be either operating in the context of a Task (perhaps the Service task if being scheduled by an interrupt) or in the context of an interrupt (in which case they really don’t want to do a delay with in them),

mehrad1983 wrote on Wednesday, May 17, 2017:

Hi Richard,

First of all, thank you for your reply. I have been busy with another project in the meanwhile and now I am back on the same subject.

I have decided to use a TimerCounter to run my delay and now I am experiencing some sort of an odd issue which is highly likely related to the “MUST” you have pointed out in your answer.
My TC works perfectly fine if I instantly enable it in the init() for testing, however, if I only initialise it and wait for a delay request so I can enable it when I am trying to delay during the code, for some reason, my callback function never gets called.

So my code gets into a task, say task1, and inside task1 there is a delay, so it get’s into a delay function I have written in the helper functions and inside that I am trying to enable or start the TC that I have already initialized at the beginning with all the other inits. In this situation, TC is starting and according to the TC registers it hits the CC0 and get’s triggered, however, this won’t fire up my callback function.

Now I am wondering what you meant by this part of your answer

Your call back functions MUST be either operating in the context of a Task (perhaps the Service task if being scheduled by an interrupt) or in the context of an interrupt (in which case they really don’t want to do a delay with in them),

Could you please elaborate on that part since I am starting to run our of options. :slight_smile:

Cheers,

Mehrad

mehrad1983 wrote on Friday, May 19, 2017:

Hey Richard,

I have done some testing and this is the summery.
I have created my own delay using TC3 and initialize my delay_ms at the start of my program before the task scheduler start and only leave the enable_tc() behind so I can enable it when I need a delay for a required time. So whenever I need a delay I call my delay_ms() and it would do something like this.

`void delay_ms( uint16_t duration )
{

// Enable the timer
tc_enable(&tc_);

while (timeUp == false) 
{
	sleepmgr_enter_sleep();
}
// The moment the callback gets triggered I change the value of timeUp inside it so I would jump out of the blocking while above.
timeUp = false;
tc_disable(&tc_);

}
`

I can do:
When I enable my TC from within the body of one of the tasks, the relevant callback gets triggered.

I cannot do:
When I enable my TC from within a body of a i2c callback method, the relevant callback never gets called.

I have gone up and down and checked all the hardware values and put a watch on any var you can imagine but I cannot draw any conclusion that, why I cannot trigger a TC interrupt from within a body of a non task method ( in this example, i2c callback ). And to be honest, this is the only place I would need a delay which works using a hardware counter. I could have easily used the vTaskDelay() if I needed a delay inside the body of the task. :confused:

Please let me know if you have any idea about this.

rtel wrote on Friday, May 19, 2017:

You say this is being called from the I2C callback, which is not running
in a task. Does that mean delay_ms() is being called in an interrupt
service routine? If so, as a general design principal, that would not
seem to be a good thing as you will be stopping all the tasks in your
system from executing during the delay. I’m also not sure of the
implication of putting the CPU to sleep inside an interrupt if you are
relaying on interrupt entry to bring the CPU out of sleep. Try it
without the sleep, and ensure the priority of the tc interrupt is above
the priority of the interrupt calling delay_ms().