Tasks apparently running at the same time in Single Core operation
Posted: Thu Jun 20, 2024 1:44 am
So I'm doing this automatic irrigation project and I've switched from arduino IDE to espressif IDE so I could be completely sure FreeRTOS is running on one core only. My objective is to acquire task starting and ending ticks so I can import this data to a python algorithm that plots a GANTT graph for better visualization of interruptions and whatnot.
For this, I've created a 2 column array for each task, the first column being the starting tick, and the second the ending tick; I've also used xTaskGetTickCount() both at the start of each task's function (the starting one right afther the while, and the ending one right before the vTaskDelay).
The thing is, when I look at the data it says 2 of the tasks always start and end at the same time. I've tried everything I could (I'm new to FreeRTOS and even newer to espressif IDE lol), and no matter what this won't change. I'd appreciate any help at all .
Thanks in advance!
For this, I've created a 2 column array for each task, the first column being the starting tick, and the second the ending tick; I've also used xTaskGetTickCount() both at the start of each task's function (the starting one right afther the while, and the ending one right before the vTaskDelay).
The thing is, when I look at the data it says 2 of the tasks always start and end at the same time. I've tried everything I could (I'm new to FreeRTOS and even newer to espressif IDE lol), and no matter what this won't change. I'd appreciate any help at all .
Code: Select all
// #include <LiquidCrystal_I2C.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include <driver/adc.h>
#include <driver/i2c.h>
#include <esp_log.h>
#include <string>
#include "sdkconfig.h"
#include "HD44780.h"
// Single core config -> ESP32's second core (app_cpu)
#if CONFIG_FREERTOS_UNICORE
static const BaseType_t app_cpu = 0;
#else
static const BaseType_t app_cpu = 1;
#endif
// Queue config
static const int queue_len = 5; // Size
static QueueHandle_t queue_handle; // Handle
// Mutex config
static SemaphoreHandle_t mutex_handle;
// Timer config
static const TickType_t timer_delay = 200 / portTICK_PERIOD_MS;
static TimerHandle_t software_timer_handle = NULL;
// LCD config
#define rs 19
#define en 23
#define d4 18
#define d5 17
#define d6 16
#define d7 15
// Resistive moisture sensor config
#define umiAnalog ADC1_CHANNEL_0
volatile int umiR; // stores the moisture
// Solenoid valve
#define solenoid_pin GPIO_NUM_26
// ESP32 In-built led -> Testing
static const int led_pin = 2;
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
const int l_size = 100; // Max tick data stored for each task
// First column of each array is for start ticks, second for end ticks
unsigned long l_umi[l_size][2]; // Moisture
int c_umi = 0; // index
unsigned long l_sol[l_size][2]; // Solenoid valve
int c_sol = 0;
unsigned long l_timer[l_size][2]; // Display timer
int c_timer = 0;
int aux_1 = 0; // Auxiliary variable for limiting array write
long converte(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void tempo(uint32_t ms)
{
// Convert milliseconds to ticks
TickType_t delay_ticks = pdMS_TO_TICKS(ms);
// Get the current tick count
TickType_t current_ticks = xTaskGetTickCount();
// Delay the task until the current tick count plus the delay
vTaskDelayUntil(¤t_ticks, delay_ticks);
}
void mostra_tempo(void *parameter){ // A function for printing one array on the serial monitor when it reaches l_size items (max size)
while (true){
if (aux_1 == 0 and c_umi == l_size){
printf("\nSensor, %d\n", c_umi);
for(int i = 0; i < l_size; i++){
printf("%lu %lu\n", l_umi[i][0], l_umi[i][1]);
}
aux_1 = 1;
}
if (aux_1 == 1 and c_sol == l_size){
printf("\nSolenoid, %d\n", c_sol);
for(int i = 0; i < l_size; i++){
printf("%lu %lu\n", l_sol[i][0], l_sol[i][1]);
}
aux_1 = 2;
}
if (aux_1 == 2 and c_timer == l_size){
printf("\nTimer display, %d\n", c_timer);
for(int i = 0; i < l_size; i++){
printf("%lu %lu\n", l_timer[i][0], l_timer[i][1]);
}
aux_1 = 3;
}
vTaskDelay(60000 / portTICK_PERIOD_MS); // Delay for preventing this task from overwriting the others ever so often
}
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Moisture sensor task
void leitura_sensorResistivo(void *parameter) {
while(1) {
///////////////////////////////////////////////////////////////////////////
if (c_umi < l_size){ // Stores the starting tick
l_umi[c_umi][0] = xTaskGetTickCount();
}
///////////////////////////////////////////////////////////////////////////
if (xSemaphoreTake(mutex_handle, portMAX_DELAY) == pdTRUE) {
umiR = adc1_get_raw(umiAnalog); // Reads moisture
if (xQueueSend(queue_handle, (void *)&umiR, 10) != pdTRUE) {
printf("ERROR: Sending of data to Queue incomplete\n");
}
xSemaphoreGive(mutex_handle);
} else {
printf("ERROR: MUTEX acquisition incomplete at the sensor\n");
}
tempo(50); // So that the task takes more than a few ticks
///////////////////////////////////////////////////////////////////////////
if (c_umi < l_size){ // Stores the ending tick
l_umi[c_umi][1] = xTaskGetTickCount();
c_umi++;
}
///////////////////////////////////////////////////////////////////////////
// Sensor delay
vTaskDelay(150 / portTICK_PERIOD_MS);
}
}
// Função para controle da válvula solenóide
void valv_control(void *parameter) {
while(1) {
///////////////////////////////////////////////////////////////////////////
if (c_sol < l_size){ // Stores the starting tick
l_sol[c_sol][0] = xTaskGetTickCount();
}
///////////////////////////////////////////////////////////////////////////
int rcv_data;
// Limite de umidade
const int limite_umidade_superior = 50; // "Moist" (Upper) moisture limit
const int limite_umidade_inferior = 35; // "Dry" (Lower) moisture limit // Caso tenha algo novo na fila considere para fazer o controle da válvula
if (xQueueReceive(queue_handle, (void *)&rcv_data, 10) == pdTRUE) {
int umidade_medida = converte(umiR, 4095, 2100, 0, 100);
if (umidade_medida < limite_umidade_inferior && gpio_get_level(solenoid_pin) == 0) {
printf("Starting solenoid\n");
gpio_set_level(solenoid_pin, 1);
} else if (umidade_medida >= limite_umidade_superior && gpio_get_level(solenoid_pin) == 1) {
printf("Shutting solenoid off\n");
gpio_set_level(solenoid_pin, 0);
}
}
tempo(50);
///////////////////////////////////////////////////////////////////////////
if (c_sol < l_size){ // Stores the ending tick
l_sol[c_sol][1] = xTaskGetTickCount();
c_sol++;
}
///////////////////////////////////////////////////////////////////////////
// Task delay
vTaskDelay(150 / portTICK_PERIOD_MS);
}
}
// Timer callback
void softwareTimer_callback(TimerHandle_t xTimer) {
///////////////////////////////////////////////////////////////////////////
if (c_timer < l_size){ // Stores the starting tick
l_timer[c_timer][0] = xTaskGetTickCount();
}
///////////////////////////////////////////////////////////////////////////
if (xSemaphoreTake(mutex_handle, portMAX_DELAY) == pdTRUE) {
// Moisture value at the display
int umidade = converte(umiR, 4095, 2000, 0, 100); // Converts the digital value to moisture percentage
//LCD_setCursor(0,1);
//LCD_clearScreen();
//LCD_writeStr("Moisture: ");
char str_umi = static_cast<char>(umidade);
//LCD_writeStr(str_umi);
xSemaphoreGive(mutex_handle);
} else {
printf("ERROR: MUTEX acquisition incomplete at the Display\n");
}
tempo(50);
///////////////////////////////////////////////////////////////////////////
if (c_timer < l_size){ // Stores the ending tick
l_timer[c_timer][1] = xTaskGetTickCount();
c_timer++;
}
///////////////////////////////////////////////////////////////////////////
}
extern "C" void app_main() {
// Delay
vTaskDelay(500 / portTICK_PERIOD_MS);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0);
printf("-- Starting irrigation system --\n");
// LCD configs
//LCD_init(0x27, 19, 18, 16, 2);
// Solenoid valve pin configuration
// pinMode(solenoid_pin, OUTPUT);
gpio_set_direction(solenoid_pin, GPIO_MODE_OUTPUT);
gpio_set_level(solenoid_pin, 0); // Valve starts closed
// Creating the queue
queue_handle = xQueueCreate(queue_len, sizeof(int));
if (queue_handle == NULL) {
printf("ERROR: Failed queue creation\n");
while (1);
}
// Creating the mutex
mutex_handle = xSemaphoreCreateMutex();
if (mutex_handle == NULL) {
printf("ERROR: Failed mutex creation\n");
while (1);
}
// Creating the software timer
software_timer_handle = xTimerCreate("software_timer_handle", timer_delay, pdTRUE, (void *)0, softwareTimer_callback); // Parâmetros: Name of timer, Period of timer (in ticks), Auto-reload, Timer ID, Callback function
if (software_timer_handle == NULL) {
printf("ERROR: Failed software timer creation\n");
while (1);
}
// Starting the timer
xTimerStart(software_timer_handle, portMAX_DELAY); // Blocks the task until a command is successfully given to the timer queue
// Task creation
xTaskCreatePinnedToCore(
leitura_sensorResistivo, // Function
"leitura_sensorResistivo", // Name
1024, // Stack size (bytes in ESP32, words in FreeRTOS)
NULL, // Parameters
1, // Task priority (0 to configMAX_PRIORITIES - 1)
NULL, // Handle
app_cpu); // Single core
xTaskCreatePinnedToCore(
valv_control, // // Function
"valv_control", // // Name
1024, // // Stack size (bytes in ESP32, words in FreeRTOS
NULL, // // Parameters
1, // // Task priority (0 to configMAX_PRIORITIES - 1)
NULL, // // Handle
app_cpu); // // Single core
xTaskCreatePinnedToCore(
mostra_tempo,
"mostra_tempo",
4096,
NULL,
2,
NULL,
app_cpu
);
// Delete "setup and loop" task
vTaskDelete(NULL);
}