Hi Kevin,
One pattern I have used for solving the problem would be to create one
extra task simply signaling the first task and looping on the required
timeout. That guarantees to some extent that the first task is always
waken up at a fixed rate. Something on the lines of (disclaimer:
non-tested code!):
static struct os_eventq timeout_evq;
static struct os_event timeout_evt;
static void
poller_handler(void *arg)
{
os_eventq_init(&timeout_evq);
while (1) {
/* will wait here for waking up signal from other task! */
os_eventq_get(&timeout_evq);
read_my_sensor();
}
}
static void
timeout_handler(void *arg)
{
/* Wait for eventq initialization */
while (!os_eventq_inited(&timeout_evq)) {
os_time_delay(OS_TICKS_PER_SEC / 100);
}
while (1) {
/* wake up the other thread regularly */
os_eventq_put(&timeout_evq, &timeout_evt);
os_time_delay(timeout);
}
}
This should probably work but having the functionality in the OS would
be cool!
Cheers,
Fabio Utzig
On Mon, Dec 26, 2016, at 09:01 AM, Kevin Townsend wrote:
> Is there a mechanism in the scheduler to fire a task at a specific
> interval, where the task execution time itself might be variable and
> 'os_time_delay' might not work.
>
> For example, assume we need to fire the task reliably at 50hz (within
> scheduler limits) then push data into a time sensitive algorithm, but
> the task workload has a variable execution time. This won't work:
>
> void my_task_func(void *arg) {
> /* The task is a forever loop that does not return */
> while (1) {
> /* Sample data at 50Hz */
> os_time_delay( OS_TICKS_PER_SEC/50);
>
> /* Variable time task to get data */
> do_something_with_variable_delay()
> }
> }
>
> If we knew the time for 'do_something' this would be easy, but if not we
> need to get the timestamp before execution, and then delay for the
> required timespan minus execution time, taking into account timer
> rollover, task overrun, etc. That doesn't seem very elegant.
>
> I was wondering if some mechanism to do something like this exists
> already in the system, perhaps in another form like indicating a fixed
> delay when the task is created:
>
> void my_50hz_func(void *arg) {
> static uint32_t a, b;
>
> while (1) {
> a = GET_CURRENT_TIMESTAMP; /* Imaginary macro for discussion
> purposes! */
>
> /* Variable time task to get data */
> do_something_with_variable_delay()
>
> /* Delay until the 20ms interval has passed */
> *os_time_delay_until(a + OS_TICKS_PER_SEC/50);**
> *** }
> }
>
> Alternatively if something like delay_until is a bad approach (?), can
> you initialize a task somehow with a fixed delay, saying fire this every
> 20ms for example, and then just put the task to sleep once the read is
> done and you've sent the data to the time sensitive algorithm?
>
> Sorry if I'm missed something obvious looking through the scheduler,
> task and time documentation.