0
votes

I started using FreeRTOS on ESP32 with AVR framework on top of it. I need a counter to be activated when a task/function is called, once this function is called, my display module needs to display the second counter. So far I cant seem to be able to count the seconds.

Initially I made it work with this logic:


   unsigned long timeShowedS = 1000;
   unsigned long timeNowS = 0;
   unsigned long timeStartMs= 0;
   while (stpC <= 3600){
       timeNowS = (millis() - timeStartMs) / 1000;
       if (timeNowS != timeShowedS) {
           timeShowedS = timeNowS;
           updateTime(timeShowedS);// function that updates the screen
           delay (20);
           stpC++;
           }

   }

The stpC is just for test purposes, I plan on making this run in a while loop. But the problem with this approach is I am able to count and display the seconds, but I am not able to reset the timer. millis() gets the time of the system since it was turned on, so resetting that is not the best idea. Then I tried making a software timer with the ticks in FreeRTOS

       unsigned long xStart, xEnd, xDifference;
       xDifference =0;
       while (1){
         xStart  = xTaskGetTickCount();
         vTaskDelay(pdMS_TO_TICKS(1000UL));
         xEnd  = xTaskGetTickCount();
         xDifference += (xEnd-xStart)/1000; 
         updateTime(xDifference);
        }

Without calling the updateTime() function the counter works. But once I call the function it not working as intended, I am getting way slower "seconds". I believe this is due to delaying the task for 1000 ticks.

So my question is, how am I able to create a timer to serve as counter in my screen? In the end I want to be able to display a counter once the updateTime() function is called, and when it is done the counter should be reset and wait for the next iteration.

---- EDIT ----

So I managed to make it to somehow work, but I do not think it is nowhere near to an optimal solution. I just created two different tasks, and both tasks share one global variable xDifference (which I read usually it is a bad idea).


uint32_t xDifference= 0; 

void taskCounter (void *parameter){

   TickType_t xStart, xEnd;//, xDifference;
   xDifference =0;

 while (1){
   xStart  = xTaskGetTickCount();
   vTaskDelay(pdMS_TO_TICKS(1000UL));
   xEnd  = xTaskGetTickCount();
   xDifference += (xEnd-xStart)/1000; 


 }
 vTaskDelete( NULL );
}

void taskOne( void * parameter )
{
   uint32_t ePapertime= 0;

   while (1){

     if (ePapertime != xDifference ){
     ePapertime = xDifference;
     updateTime(ePapertime);
     delay(20);
    }
   delay(20);
   }

   vTaskDelete( NULL );
  }

1

1 Answers

0
votes

First, I agree that a global variable is probably not the way for your tasks to communicate. You can review this page for the alternatives. I personally like queues; while they might be mild overkill for your application, but they work well and the overhead is minimal.

Regarding the timer, I'd put something in your event loop like this (just as an example):

while (true)
{
    stateTickStart = xTaskGetTickCount();
    while (xTaskGetTickCount() - stateTickStart ONE_SECOND)
    {
        // send a queue message.
        // do your other stuff.
        vTaskDelay(INTERVAL_TICKS); // like 20ms or so.
    }
}

You might have to massage the logic a bit, but this should work. In the event loop of the receiving task, you'll just look for a message in the queue without waiting too long for it.