FreeRTOS Scheduling Issue (rtl8720dn)

Hey everyone,

Currently I’m working on the FreeRTOS / Scheduling part of the system. The problem is related to the scheduling in FreeRTOS in combination with the tasks which get scheduled by the SDK itself. The code below is an example of how the issue can be faced. The code is built on top of the Arduino SDK.

#include "FreeRTOS.h"
#include "task.h"

void Task1( void *pvParameters );
void Task2( void *pvParameters );

void setup() {
  Serial.begin(115200);
  while(!Serial){};

  // Now set up two tasks to run independently.
  xTaskCreate(
    Task1
    ,  "First Task"
    ,  4096  // Stack size
    ,  NULL
    ,  1000  // priority
    ,  NULL );

  xTaskCreate(
    Task2
    ,  "Second Task"
    ,  4096
    ,  NULL
    ,  1000
    ,  NULL );

}

void loop()
{
  // Empty. Things are done in Tasks.
}


void Task1(void *pvParameters)
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
   printf("\nThead 1");
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

void Task2(void *pvParameters)
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    printf("\nThead 2");
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

As shown above I’m starting adding two tasks which will run continuously. However, the SDK also makes use of tasks and I’m curious if this could have any problems related to the priority. For example, the ‘wifi_set_promisc()’ function (sdk/component/common/api/wifi/wifi_conf.h) makes use of a callback function which will be triggered whenever a management frame is detected. To be making sure that this function is getting called, the main tasks have to be delayed. So for example:

wifi_set_mode(RTW_MODE_PROMISC);
wifi_enter_promisc_mode();
wifi_set_channel(5)
wifi_set_promisc(3, callbackFunc, 1);

while(1)
{
    printf("Delaying task...");
    delay(5000);
}

The assumption I make is that the set_promisc function operates from other tasks (osPriorityRealtime), which gets scheduled whenever the main task gets delayed. That’s where the delay loop is for. Is this assumption correct? And if so, how could we combine a task from the SDK such as the example, with a task of your own software. Currently both tasks (own tasks) are getting scheduled, as the example has shown. I think since both of these tasks are high in priority, there isn’t a chance for the callback tasks to run since both tasks (task1 & task2) are higher in priority, and gets rescheduled every time.

Have any of you guys faced an issue while running your own tasks in combination with tasks from tasks which are used in the SDK? Would love hearing your experiences, and how to fix this.

1 Like

For the RTL8710DN, it looks like the Arduino SDK is written with the average user not using freeRTOS threads in mind, hence the main task running the setup() and loop() functions is given the highest priority, since that is where most users will write their code.

However, if you wish to define new tasks and leave the loop() function empty, it might make sense to go into cores/arduino/main.cpp and reduce the task priority of the main task, this might help the scheduler work out a better way of running the tasks.

1 Like

Hey,

thanks for your quick response! I have tried the solution direction you suggest for the rtl8720dn. Here I notice that the tasks that I start both switch fine (by means of a delay / time slicing). However, when i delay one of the tasks itself inside their loop, the scheduler won’t reschedule them.
So for example:

void Task1(void *pvParameters)
{
  (void) pvParameters;

  for (;;) // A Task shall never return or exit.
  {
    printf("\nThead 1");
    executeTaskWithDelayInside();
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

void  executeTaskWithDelayInside()
{
    while(1){
        printf("\n Will print this once, and then I'm stuck in another tasks. Probably the SDK's one. But which one?");
        delay(5000);
    }
}

Then it stops switching and stays in a task. In the case of the example above, he then gets stuck in promiscious task, taking in some frames, but then hangs. He no longer comes out of the loop as indicated above. I’ve checked on all priorities and this couldn’t be the case. The only thing I’m not sure how FreeRTOS reacts is when I’m starting / creating tasks upon a task. So how this is build, the SDK starts FreeRTOS and the main task executes the setup() (arduino func) and loop(). However, the tasks I’m creating are created in the setup() function. It feels like the tasks are stopping and going back to this part, which only keeps the loop() function alive with it’s serial monitor. However, the tasks which I created aren’t getting re-scheduled as desired.

Hopefully this gave some more context in the issue I’m facing.

Thanks!

I tried to replicate your issue using the following code, with the maintask at lowest priority

osThreadDef(main_task, osPriorityIdle, 1, MAIN_THREAD_STACK_SIZE);
#include "WiFi.h"
// global variables
TaskHandle_t Handle_aTask;
TaskHandle_t Handle_bTask;

void executeTaskWithDelayInside()
{
  while (1) {
    Serial.println("Will print this once");
    delay(5000);
  }
}

void threadA(void* pvParameters) {
  Serial.println("Thread A: Started");
  for (;;) {
    Serial.println("A");
    executeTaskWithDelayInside();
    delay(1000);
  }
}

void threadB(void* pvParameters) {
  Serial.println("Thread B: Started");
  for (;;) {
    Serial.println("B");
    delay(2000);
  }
}

char ssid[] = "ssid";     //  your network SSID (name)
char pass[] = "pw";  // your network password
int status = WL_IDLE_STATUS; 

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial) ;  // Wait for Serial terminal to open port before starting program
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }

  xTaskCreate(threadA, "Task A", 1024, NULL, tskIDLE_PRIORITY + 3, &Handle_aTask);
  xTaskCreate(threadB, "Task B", 1024, NULL, tskIDLE_PRIORITY + 2, &Handle_bTask);
}

void loop() {
  taskYIELD();
}

This code seems to work normally for me, with the log showing both tasks printing after connecting to wifi.

16:43:06.961 -> 

RTL8721D[Driver]: auth success, start assoc
16:43:06.961 -> 
16:43:07.542 -> 

RTL8721D[Driver]: association success(res=2)
16:43:07.542 -> 
16:43:07.624 -> 

RTL8721D[Driver]: set pairwise key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4)
16:43:07.624 -> 
16:43:07.624 -> 

RTL8721D[Driver]: set group key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4) keyid:2
16:43:07.624 -> 
16:43:16.301 -> 

Interface 0 IP address : 172.25.24.89Thread A: Started
16:43:26.298 -> A
16:43:26.298 -> Will print this once
16:43:26.298 -> Thread B: Started
16:43:26.298 -> B
16:43:28.297 -> B
16:43:30.339 -> B
16:43:31.289 -> Will print this once
16:43:32.291 -> B
16:43:34.297 -> B
16:43:36.303 -> Will print this once
16:43:36.303 -> B
16:43:38.307 -> B
16:43:40.313 -> B
16:43:41.316 -> Will print this once
1 Like

Hi @wyy ,

Thanks for your time and example! I uploaded your code and made the adjustment in the arduino core (main.cpp). However I’m getting a different result:

13:30:33.271 -> 
13:30:33.305 -> 

RTL8721D[Driver]: auth success, start assoc
13:30:33.305 -> 
13:30:33.305 -> 

RTL8721D[Driver]: association success(res=2)
13:30:33.305 -> 
13:30:34.083 -> 

Interface 0 IP address : 192.168.2.7

I’m on SDK version 3.0.8. and I’m uploading to the rtl8720dn_bw16. On what version are you building?

Thanks in advance!

Hi @TBeeren

Just tried the code on my BW16, I noticed that I got the WiFi connection messages through the LOG_UART serial port, but the RTOS Serial.println() messages is sent out over the onboard USB-UART serial port.
have you checked both serial ports?

Hi @wyy

Thanks for all your time and effort on this post! I’ve been messing around and got it working. Not sure how and why this is the fix, but it works for now. When I’ve got more time i’ll check why this could be a problem.

Right now I’ve been able to fix this ‘frozen task’ with adding some empty printlines (printf("")). This is pretty weird behaviour, but through debugging I faced this scenario where the UART Serial keeps active. I feel like the serial log task which is running on the main task isn’t getting called anymore for some reason without this. On the other hand, lowering the prio of the main task is also needed! Thanks for mentioning this.

Have a good day, and If I’m able to check why this behaviour is occuring, I’ll let you know.

1 Like

Hi TBerrren
I had the same result as you when I used the example provided by wyy. When I analyze the code. I found that it is probably caused by TaskYIELD()

TaskYILED is used to do Content Switch, if it is too busy, it may not work properly.
So I changed TaskYIELD() to vTaskDelay( 1000 / portTICK_PERIOD_MS );

But I don’t know why the mission starts only after 10 seconds of obtaining the IP(maybe handle other Task)

Also for viewing convenience. Change all Serial to Serial1 (can be viewed through the onboard USB to Serial chip)

Arduino : 1.8.13
Arduino SDK: 3.0.9 build20210520
BW16 FW Version: version:v2.4.1,amebaD v6.0a(Aug 14 2019)

2 Likes