I appreciate your input. I thought since I had nothing in the loop that it took no resources. What should be put in Loop so that it doesn't bog the two tasks down? Will a delay command be all that is necessary?
Loop is constantly running, granted there is nothing for it to do when its empty. But in essence you have have 3 tasks. The two you created and then Loop. I'd just put a delay of a second in there.
I don't use ESP-ADF so my example with be in ESP-IDF. The concept is the same. You may look at this code example and think it would work just fine. Yet it doen't work at all. You may be saying I have a a higher priority for task1, and its pinned to its own core. What could be the issue. Well. you need to learn about what is called the scheduler in a RTOS environment. If your task never releases itself to the scheduler your going to run into trouble. The scheduler is like the overlord who tells what to run next and for how long.
Code: Select all
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
xTaskHandle TaskHandle_Task1;
xTaskHandle TaskHandle_Task2;
/* Can run 'make menuconfig' to choose the GPIO to blink,
or you can edit the following line and set a number here.
*/
#define BLINK_GPIO CONFIG_BLINK_GPIO
void task1(void *pvParameter)
{
gpio_pad_select_gpio(BLINK_GPIO);
/* Set the GPIO as a push/pull output */
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
while(1)
{
/* Blink off (output low) */
gpio_set_level(BLINK_GPIO, 0);
//vTaskDelay(1 / portTICK_PERIOD_MS);
/* Blink on (output high) */
gpio_set_level(BLINK_GPIO, 1);
//vTaskDelay(1 / portTICK_PERIOD_MS);
}
}
void task2(void *pvParameter)
{
uint16_t x = 0;
while (1)
{
printf("Hello World:%u\r\n", x++);
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
void app_main()
{
xTaskCreatePinnedToCore(&task1, "task1", 2048, NULL, 10, &TaskHandle_Task1, 0);
xTaskCreatePinnedToCore(&task2, "task2", 2048, NULL, 5, &TaskHandle_Task2, 1);
}
Here is what the output is doing when you run this.
E (370292) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (370292) task_wdt: - IDLE0 (CPU 0)
E (370292) task_wdt: Tasks currently running:
E (370292) task_wdt: CPU 0: task1
E (370292) task_wdt: CPU 1: IDLE1
Now if you un-comment the delays in task 1 you may now think "Hey I have a delay in there now things are good to go" but still no. a delay of 1 is not enough time to release this Task to perform any other tasks you created and all the background stuff (things you dont see that keep the processor going). So you still stave the other tasks for CPU time and you will get this in the output even with those delays in there.
E (30292) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (30292) task_wdt: - IDLE0 (CPU 0)
E (30292) task_wdt: Tasks currently running:
E (30292) task_wdt: CPU 0: task1
E (30292) task_wdt: CPU 1: IDLE1
Now if you change the delays to say 10, then it will run and you will now get this in the output.
Hello World:0
Hello World:1
Hello World:2
Hello World:3
Hello World:4
Hello World:5
and so on...
Now, your not out of the woods just yet. Just because its working now does not mean its working right. with a delay of 10 it works but with a delay of 5 it doesn't. So whats happening here is that with a delay of 10 your on the border line. Though it works, your not giving enough time for other tasks to run. With a delay of 200 (I.E. 200 ms) you should get a Hello World output 4 times a second, and in this example you do. But if you change that to say 25, Task1 is not going to give Task2 enough time to do spit those out fast enough anymore.
Basically is a balance game of what your trying to do per task and priority, delays, and other options so you can ensure each task is getting enough time to do what it needs to do and not hinder another task from getting CPU time to run.
Like another poster mentioned there are even yet other ways to skin this cat like using semaphores.
You can even do something like this as well. So that this task will do nothing until its signaled to do so. Thus you dont need to be concerned about delays here.
Code: Select all
const int ALARM_NORMAL_TIMER_START_BIT = BIT0;
EventGroupHandle_t timer_event_group;
void alarmTaskNormal(void * parameter)
{
timer_event_group = xEventGroupCreate();
// Clear the bit
xEventGroupClearBits(timer_event_group, TIMER_START_BIT);
for (;;)
{
// Wait here until we are signaled to start
xEventGroupWaitBits(timer_event_group, TIMER_START_BIT, true, false, portMAX_DELAY);
printf("Timer Triggered\r\n");
}
}
What happens here in this task, is it will sit and wait on xEventGroupWaitBits(). Only until another task issues this command will it then fall out from waiting and do the next line of code.
xEventGroupSetBits(timer_event_group, TIMER_START_BIT);
I cannot emphasize enough how important it is to learn how things work in a RTOS environment. Its a whole different mindset than line by line code which is what people are used to in Arduino. But I would bet anything that once a person invests the time to learn it they will never look back and only prefer a RTOS way.