Task Understanding
Task Understanding
I have been reading about the ESP32 (on Arduino IDE) and it's FreeRTOS implementation and something isnt quite clicking with me. The Task examples that I have seen are very simple with Task1 and Task2 being called (or some variation of that).
is there a more complicated example out there? I am trying to figure out how I want to start coding my project where there are 9 "tasks" and I want to utilize both cores efficiently. In the examples, each task is in an infinite loop. Im not sure that applies to me. I "could" code my tasks to stay in an infinite loop, but not sure that is good practice. here is a breakdown of what I need
Task1 - runs every hour or so (not crazy time restrictive)
Task2 - runs every second (but can be pushed back if another task with a higher priority needs to run then
Task3 - runs every time the display is touched (touchscreen) and trumps all other tasks
Task4 - runs only when needed by task 3.
Task5 - runs non-stop at lowest priority
Task6 - runs every few seconds
Task7 - runs when invoked and until Task3 tells it to stop
Task8 - same as Task7
Task9 - not sure (this task deals with incoming MQTT requests)
Each task would have a different priority except for Task7 and 8. they are very similar and would never run at the same time.
ultimately, Im trying to understand when to use a task, and when not to (utilizing the millis() to control timing) and if there are any considerations to be had.
is there a more complicated example out there? I am trying to figure out how I want to start coding my project where there are 9 "tasks" and I want to utilize both cores efficiently. In the examples, each task is in an infinite loop. Im not sure that applies to me. I "could" code my tasks to stay in an infinite loop, but not sure that is good practice. here is a breakdown of what I need
Task1 - runs every hour or so (not crazy time restrictive)
Task2 - runs every second (but can be pushed back if another task with a higher priority needs to run then
Task3 - runs every time the display is touched (touchscreen) and trumps all other tasks
Task4 - runs only when needed by task 3.
Task5 - runs non-stop at lowest priority
Task6 - runs every few seconds
Task7 - runs when invoked and until Task3 tells it to stop
Task8 - same as Task7
Task9 - not sure (this task deals with incoming MQTT requests)
Each task would have a different priority except for Task7 and 8. they are very similar and would never run at the same time.
ultimately, Im trying to understand when to use a task, and when not to (utilizing the millis() to control timing) and if there are any considerations to be had.
-
- Posts: 9727
- Joined: Thu Nov 26, 2015 4:08 am
Re: Task Understanding
No, tasks usually run in an infinite loop - they wait (well, they actually block, meaning the scheduler doesn't give them any CPU time) until something happens that they're interested in - touch screen gets touched, a delay passes, some other task wants them to do something, whatever. Things like 'runs only when taskx needs them' are done using message passing using queues or semaphores.
The alternative is to create and destroy tasks on demand, which certainly is possible - but as it's pretty expensive to do so (costs quite a few CPU cycles), the common method is to spin them all up at startup and have them block.
The alternative is to create and destroy tasks on demand, which certainly is possible - but as it's pretty expensive to do so (costs quite a few CPU cycles), the common method is to spin them all up at startup and have them block.
-
- Posts: 166
- Joined: Wed Aug 01, 2018 12:06 pm
Re: Task Understanding
Yes and no to the tasks running in infinite loops.
This task run in an infinite loop infinaltly:
This task runs in an infinite loop but the task items are only ran when triggered:
This line holds the task until the task is triggered by an event.
You can run your taks by time or by round robin. You can create tasks groups that will trigger several tasks at the same time or just one task at a time.
Bookmark this site https://www.freertos.org/ and refer to it often.
To pin a task to a core use:
Use: to find out your tasks stack use. Starting with 10K is typical.
This task run in an infinite loop infinaltly:
Code: Select all
void fBlinkBuiltIn( void* pvParameters )
{
// toggle built in LED off/on
for (;;)
{
vTaskDelay( pdMS_TO_TICKS( 10 ) );
REG_WRITE( GPIO_OUT_W1TC_REG, BIT2 ); // GPIO2 LOW (clear)
vTaskDelay( pdMS_TO_TICKS( OneK ) );
REG_WRITE( GPIO_OUT_W1TS_REG, BIT2 ); //GPIO2 HIGH (set)
}
vTaskDelete( NULL );
}
Code: Select all
void fDoLIDAR( void * pvParameters )
{
int iLIDAR_Distance = 0;
int iLIDAR_Strength = 0;
while (1)
{
xEventGroupWaitBits (eg, evtDoLIDAR, pdTRUE, pdTRUE, portMAX_DELAY) ;
tfmini.externalTrigger();
iLIDAR_Distance = tfmini.getDistance();
if ( iLIDAR_Distance > LIDAR_Max_Distance )
{
Serial.print ( " TFMini distance issue " );
Serial.println ( iLIDAR_Distance );
}
iLIDAR_Strength = tfmini.getRecentSignalStrength();
xSemaphoreTake( sema_LIDAR_INFO, xSemaphoreTicksToWait );
xSemaphoreTake( sema_LIDAR_FOR_ALARM, xSemaphoreTicksToWait );
x_LIDAR_INFO.Range[x_LIDAR_INFO.CurrentCell] = iLIDAR_Distance;
xSemaphoreGive( sema_LIDAR_INFO );
xSemaphoreGive( sema_LIDAR_FOR_ALARM );
xEventGroupSetBits( eg, evtLIDAR_ServoAspectChange );
// Serial.print( "fDoLIDAR " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
}
vTaskDelete( NULL );
}
Code: Select all
xEventGroupWaitBits (eg, evtDoLIDAR, pdTRUE, pdTRUE, portMAX_DELAY) ;
You can run your taks by time or by round robin. You can create tasks groups that will trigger several tasks at the same time or just one task at a time.
Bookmark this site https://www.freertos.org/ and refer to it often.
To pin a task to a core use:
Code: Select all
xTaskCreatePinnedToCore( fDoLIDAR, "fDoLIDAR", TaskStack15K, NULL, Priority4, NULL, TaskCore1 ); //assigned to core 1
Code: Select all
Serial.print( "fDoLIDAR " );
Serial.print(uxTaskGetStackHighWaterMark( NULL ));
Serial.println();
Serial.flush();
-
- Posts: 166
- Joined: Wed Aug 01, 2018 12:06 pm
Re: Task Understanding
Here is an example of a GPS program using various task schemes as well as semaphores and queues:
Code: Select all
#include <driver/adc.h>
#include <Adafruit_BMP280.h>
#include <SPI.h>
#include "UTM.h"
#include <U8g2lib.h>
#include <stdio.h> //for function sprintf
#include <TinyGPS++.h>
#include <HardwareSerial.h>
//
/*
Flash mode QI0 is the fastest
Flash size = 4Mb
*/
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
/* define event bits */
#define CalDistance ( 1 << 0 ) //1
#define AnalogVoltReadTask ( 1 << 1 ) //10
#define DO_UTM_TASK_BIT ( 1 << 2 ) //100
#define UPDATE_DISPLAY_TASK_BIT ( 1 << 3 ) //1000
#define GPS_Parse ( 1 << 4 ) //10000
#define Not_Used ( 1 << 5 ) //100000
#define PressureEvent ( 1 << 6 ) //1000000
#define DoPressureDataCollectionEvent ( 1 << 7 ) //10000000
#define RunTimeEvent ( 1 << 8 ) //100000000
#define OneSecondGroupBits ( UPDATE_DISPLAY_TASK_BIT | RunTimeEvent )
////////////////////////////////////////////////////////////////////////////////////
/* create a hardware timer */
hw_timer_t * timer = NULL;
/* create event group */
EventGroupHandle_t eg;
//////////////////////////////////
SemaphoreHandle_t sema_CalDistance;
SemaphoreHandle_t sema_PressureDataCollection;
SemaphoreHandle_t sema_UTM;
SemaphoreHandle_t sema_RunTime;
SemaphoreHandle_t sema_AnalogVoltRead;
SemaphoreHandle_t sema_CheckPressure;
SemaphoreHandle_t sema_GPS_Gate;
SemaphoreHandle_t sema_Time;
SemaphoreHandle_t sema_Date;
SemaphoreHandle_t sema_Posit;
SemaphoreHandle_t sema_Sats;
SemaphoreHandle_t sema_Alti;
SemaphoreHandle_t sema_Hdg;
SemaphoreHandle_t sema_Speed;
//SemaphoreHandle_t sema_UTM_Posit;
////
U8G2_SSD1327_EA_W128128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
////
#define TimerDivider 80
#define TaskCore1 1
#define TaskCore0 0
// #define A0Pin 36 //analog pin
// #define A1Pin 39 //analog pin
#define BlinkLED 2
#define FiveHundred 500
#define EightHundred 800
#define OneK 1000
#define OneKfive 1500
#define TwoK 2000
#define ThreeThreeK 3300
#define TaskStack10K 10000
#define TaskStack10K1 10100
#define TaskStack10K2 10200
#define TaskStack15K 15000
#define TwentyK 20000
#define UpdateDisplayK 20500
#define Priority1 1
#define Priority2 2
#define Priority3 3
#define Priority4 4
#define Priority5 5
//#define DEGREE 600000
// #define uPvolts 3.3
// #define ADbits 4095
#define SerialDataBits 115200
#define GPS_DataBits 9600
#define TIMER_FOUR 3
#define PressureDataArrayCount 8
/////////////////////////////////
TickType_t xTicksToWait0 = 0;
TickType_t QueueReceiveDelayTime = 10;
TickType_t xTicksToWait20 = 20;
TickType_t xSemaphoreTicksToWait = 12;
////////////////////////////////
HardwareSerial GPSSerial(2);
// Connect to the GPS on the hardware port
// The TinyGPS++ object
TinyGPSPlus GPS;
// Adafruit_GPS GPS(&GPSSerial);
// UltimateGPS rx to ESP32 I017 - Serial2
// UltimateGPS tx to ESP32 IO16 - Serial2
// pin 16=RX, pin 17=TX
//?????????????????????????????????????????
volatile int iTicCount = 0; //counts milliseconds
bool bLED_On = false;
///////////////////////////////////////////
QueueHandle_t xQ_DistanceMessage;
struct stuDistance
{
unsigned long Distance = 0; //meters
} xDistanceMessage;
QueueHandle_t xQ_Speed;
struct stuSpeed
{
float MPH = 0.0; // m.p.h.
float KPH = 0.0;
} xSpeed;
////
QueueHandle_t xQ_PowerMessage;
struct stuPower
{
float Vbatt = 0.0;
float BattPercent = 0;
} xPowerMessage;
/////////////////////////////////////
// from lat long to UTM conversion, shared data between two functions
QueueHandle_t xQ_UTM_Message;
struct stuUTM
{
float UTM_North = 0.0; // holds northing info
float UTM_West = 0.0; // holds easting info
int iZone = 0; // holds zone info
} xUTM_Message;
////////////////////////////////////////////////////////////////
//temperature, pressure, altitude, sealevelpressure
#define DEVICE_PIN 5
// BME_SCK 18 // keep for reference info
// BME_MISO 19
// BME_MOSI 23
Adafruit_BMP280 bme(DEVICE_PIN); // hardware SPI
// Adafruit_BMP280 bme(DEVICE_PIN, BME_MOSI, BME_MISO, BME_SCK); // keep for reference
QueueHandle_t xQ_PressureMessage;
struct stuPressureMessage
{
float BMEpressure = 0.0;
float BMEtemperature = 0.0;
} xPressureMessage;
// float BMEpressure = 0.0;
// float BMEtemperature = 0.0;
////////////////////////////////////////////////////////////////
QueueHandle_t xQ_PressureDataMessage;
struct stuPressureData
{
int mmHg_Hourly[8] =
{
0, 0, 0, 0, 0, 0, 0, 0
};
int BMEpressure = 0;
} xPressureData;
//
QueueHandle_t xQ_RunTimeMessage;
struct stuRunTimeData
{
int iSeconds;
int iMinutes;
int iHours;
} xRunTimeData;
//
QueueHandle_t xQ_Time;
struct stuTime
{
int iSeconds;
int iMinutes;
int iHours;
} xTime;
////
struct stuDate
{
int iDay;
int iMonth;
int iYear;
} xDate;
////
QueueHandle_t xQ_Posit;
struct stuPosit
{
float Lat;
float Lon;
} xPosit;
////
QueueHandle_t xQ_Sats;
////
QueueHandle_t xQ_Alti;
////
QueueHandle_t xQ_UTM_Posit;
struct stuUTM_Posit
{
float Lat;
float Lon;
} xUTM_Posit;
////
QueueHandle_t xQ_Hdg;
////
////////////////////////////////////////////////////////////////
// timer ISR callback set at 1000X a second
void IRAM_ATTR onTimer()
{
BaseType_t xHigherPriorityTaskWoken;
iTicCount++;
//
if ( (xSemaphoreTakeFromISR(sema_GPS_Gate, &xHigherPriorityTaskWoken)) == pdTRUE ) // grab semaphore, no wait
{
xEventGroupSetBitsFromISR(eg, GPS_Parse, &xHigherPriorityTaskWoken); // trigger every 1mS, if not already processing
}
if ( iTicCount == OneK )
{
xEventGroupSetBitsFromISR(eg, OneSecondGroupBits, &xHigherPriorityTaskWoken); // trigger every 1X a second
// reset counter to start again
iTicCount = 0;
}
} // void IRAM_ATTR onTimer()
////
////
void setup()
{
////
// Wire.setClock( 100000 );
Wire.setClock( 2000000 ); // shoud use pullups
//Wire.setClock( 3400000 ); // shoud use pullups
Serial.begin( SerialDataBits );
// Serial.println(MOSI); // 23 Master Out Slave In, SDI, DIN
// Serial.println(MISO); // 19 Master In Slave Out, SDO
// Serial.println(SCK); // 18 Clock
// Serial.println(SS); // 5 Slave Select, Chip Seclect
pinMode( BlinkLED, OUTPUT ); // for blink LED
SPI.begin();
while (!bme.begin())
{
Serial.println("Could not find BME280 sensor!");
vTaskDelay( pdMS_TO_TICKS( OneK ) );
}
//
u8g2.begin();
////
eg = xEventGroupCreate();
//
GPSSerial.begin( GPS_DataBits ); // begin GPS hardwareware serial
//
vTaskDelay( pdMS_TO_TICKS( OneK ) ); // delay one second
// https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
// set up A:D channels
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_11db);
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_11db);
/*
When VDD_A is 3.3V: 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V
*/
////
/* Use 4th timer of 4.
1 tick 1/(80MHZ/80) = 1us set divider 80 and count up.
Attach onTimer function to timer
Set alarm to call timer ISR, every 10000uS and repeat / reset ISR (true) after each alarm
Start an timer alarm
*/
timer = timerBegin( TIMER_FOUR, TimerDivider, true );
timerAttachInterrupt( timer, &onTimer, true );
timerAlarmWrite(timer, OneK, true);
timerAlarmEnable(timer);
////
///////////// create queues
// queue length, queue item size
xQ_PressureMessage = xQueueCreate( 1, sizeof(struct stuPressureMessage*) ); // sends a queue pointer to the structure
xQ_PressureDataMessage = xQueueCreate( 1, sizeof(struct stuPressureData*) ); // sends a queue pointer to the structure
xQ_DistanceMessage = xQueueCreate( 5, sizeof(struct stuDistance) ); // sends a copy of the structure
xQ_Speed = xQueueCreate( 1, sizeof(struct stuSpeed) ); // sends a copy of the structure
xQ_PowerMessage = xQueueCreate( 1, sizeof(struct stuPower*) ); // sends a queue pointer to the structure
xQ_UTM_Message = xQueueCreate( 1, sizeof(struct stuUTM) ); //sends copy of the structure
xQ_RunTimeMessage = xQueueCreate( 1, sizeof(struct stuRunTimeData*) ); //sends a queue pointer to the structure
xQ_Time = xQueueCreate( 1, sizeof(struct stuTime*) );
xQ_Sats = xQueueCreate( 1, sizeof(int) );
xQ_Alti = xQueueCreate( 1, sizeof(float) );
xQ_UTM_Posit = xQueueCreate( 1, sizeof(stuUTM_Posit*) );
xQ_Hdg = xQueueCreate( 1, sizeof(float) );
xQ_Posit = xQueueCreate( 1, sizeof(struct stuUTM_Posit) ); //sends copy of the structure
////////////////////////////
// Task function, name of task, Stack size of task, parameter of the task, priority of the task, Task handle to keep track of created task, task core
/////////////////////////// TASK CORE 0
xTaskCreatePinnedToCore( fGPS_Parse, "fGPS_Parse", TaskStack10K2, NULL, Priority4, NULL, TaskCore0 ); // assigned to core 0
sema_Time = xSemaphoreCreateMutex();
xSemaphoreGive( sema_Time );
sema_Date = xSemaphoreCreateMutex();
xSemaphoreGive( sema_Date );
sema_Posit = xSemaphoreCreateMutex();
xSemaphoreGive( sema_Posit);
sema_Sats = xSemaphoreCreateMutex();
xSemaphoreGive( sema_Sats );
sema_Alti = xSemaphoreCreateMutex();
xSemaphoreGive( sema_Alti );
xQ_UTM_Posit = xSemaphoreCreateMutex();
xSemaphoreGive( xQ_UTM_Posit );
sema_CalDistance = xSemaphoreCreateMutex(); // create Semaphore
xSemaphoreGive( sema_CalDistance );
sema_Hdg = xSemaphoreCreateMutex();
xSemaphoreGive( sema_Hdg );
sema_GPS_Gate = xSemaphoreCreateMutex();
xSemaphoreGive( sema_GPS_Gate );
xTaskCreatePinnedToCore( fGetUTM, "fGetUTM", TaskStack15K, NULL, Priority4, NULL, TaskCore0 ); // assigned to core 0
sema_UTM = xSemaphoreCreateMutex();
xSemaphoreGive( sema_UTM );
xTaskCreatePinnedToCore( fRunTime, "fRunTime", TaskStack10K2, NULL, Priority4, NULL, TaskCore0 ); //assigned to core 0
sema_RunTime = xSemaphoreCreateMutex();
xSemaphoreGive( sema_RunTime );
xTaskCreatePinnedToCore( fDoPressureDataCollection, "fDoPressureDataCollection", TaskStack10K, NULL, Priority4, NULL, TaskCore0 ); // assigned to core 0
sema_PressureDataCollection = xSemaphoreCreateMutex();
xSemaphoreGive( sema_PressureDataCollection );
sema_Speed = xSemaphoreCreateMutex();
xSemaphoreGive( sema_Speed );
//////////////////////////////// TASK CORE 1 ///////////////////////////////////////////////////////////////////////////////////////////////////
xTaskCreatePinnedToCore( fUpdateDisplay, "fUpdateDisplay", TaskStack15K, NULL, Priority4, NULL, TaskCore1 ); // assigned to core 1
xTaskCreatePinnedToCore( fCheck_Pressure, "fCheck_Pressure", TaskStack10K1, NULL, Priority3, NULL, TaskCore1 ); //assigned to core 1
sema_CheckPressure = xSemaphoreCreateMutex(); // create Semaphore
xSemaphoreGive( sema_CheckPressure );
xTaskCreatePinnedToCore( fBlinkBuiltIn, "fBlinkBuiltIn", TaskStack10K1, NULL, Priority2, NULL, TaskCore1 ); //assigned to core 1
xTaskCreatePinnedToCore( TaskAnalogVoltRead, "fTaskAnalogVoltRead", TaskStack10K1, NULL, Priority3, NULL, TaskCore1 ); // assigned to core 1
sema_AnalogVoltRead = xSemaphoreCreateMutex();
xSemaphoreGive( sema_AnalogVoltRead );
//////
} //void setup() // runs on core 1
///////////////////////////
void loop() {} // runs on core 1
//////////////////////////
/////////////////////////
//
void fRunTime( void * parameter )
{
struct stuRunTimeData *pxMessage;
for (;;)
{
xEventGroupWaitBits (eg, RunTimeEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
if ( xSemaphoreTake( sema_RunTime, xSemaphoreTicksToWait ) == pdTRUE )
{
xRunTimeData.iSeconds++;
if ( xRunTimeData.iSeconds == 60 )
{
xRunTimeData.iMinutes++;
xRunTimeData.iSeconds = 0;
}
if ( xRunTimeData.iMinutes == 60 )
{
xRunTimeData.iHours++;
xRunTimeData.iMinutes = 0;
}
pxMessage = &xRunTimeData;
xQueueOverwrite( xQ_RunTimeMessage, (void *) &pxMessage );
xSemaphoreGive( sema_RunTime );
}
// Serial.println( "fRunTime" );
// Serial.print( "fRunTime " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
}
vTaskDelete( NULL );
} // void fRunTime( void * parameter )
//
void fDoPressureDataCollection( void * parameter )
{
struct stuPressureData *pxMessage;
int iArrayCell = 0;
bool bDidInitialArray = false;
int iPast = 0;
for (;;)
{
xEventGroupWaitBits (eg, DoPressureDataCollectionEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
//seed initial value and hour cell
if ( bDidInitialArray == false )
{
if ( xPressureData.BMEpressure != 0 )
{
if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore to get minute data
{
iPast = xTime.iMinutes; // store periodic
xSemaphoreGive( sema_Time ); // give up semaphore
xPressureData.mmHg_Hourly[iArrayCell] = xPressureData.BMEpressure;
iArrayCell++;
pxMessage = &xPressureData;
xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage );
bDidInitialArray = true;
}
}
} // if ( bDidInitialArray == fasle )
else
{
if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore to get minute data
{
int iCurrentMinute = xTime.iMinutes;
xSemaphoreGive( sema_Time ); // give up semaphore
if ( iPast != iCurrentMinute )
{
if ( ((iCurrentMinute % 15) == 0) )
{
if ( xSemaphoreTake( sema_PressureDataCollection, xSemaphoreTicksToWait ) == pdTRUE )
{
iPast = iCurrentMinute; // keep current minute
////
xPressureData.mmHg_Hourly[iArrayCell] = xPressureData.BMEpressure; //add new periodic reading to array
////
iArrayCell++; // go to the next cell
pxMessage = &xPressureData;
xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage );
xSemaphoreGive( sema_PressureDataCollection );
if ( iArrayCell == PressureDataArrayCount )
{
iArrayCell = 0; // start array count over
} // if ( iArrayCell == PressureDataArrayCount )
} // if( xSemaphoreTake( s_Pressure, xTicksToWait20 ) == pdTRUE )
} // if ( ((GPS.minute % 15) == 0) )
else // if ( iPast != GPS.minute )
{
if ( xSemaphoreTake( sema_PressureDataCollection, xTicksToWait0 ) == pdTRUE )
{
pxMessage = &xPressureData;
xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage ); // just send the collected data without adding any new data
xSemaphoreGive( sema_PressureDataCollection );
} // if( xSemaphoreTake( s_Pressure, ( TickType_t ) TicDe
} // if ( iPast != GPS.minute )
} // else if ( iPast != GPS.minute )
}
else // if ( iPast != GPS.minute )
{
if ( xSemaphoreTake( sema_PressureDataCollection, xTicksToWait0 ) == pdTRUE )
{
pxMessage = &xPressureData;
xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage ); // just send the collected data without adding any new data
xSemaphoreGive( sema_PressureDataCollection );
} // if( xSemaphoreTake( s_Pressure, ( TickType_t ) TicDe
}
}
// Serial.println( "fDoPressureDataGather " );
// Serial.print( "fDoPressureDataGather " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
}
vTaskDelete( NULL );
} // void fDoPressureDataCollection
////
////
/* The display routine will trigger the UTN update when needed.
The display runs once per second
the display will only call on the UTM update as needed
the UTM runs on the other core from the display
*/
void fGetUTM( void * parameter )
{
struct stuUTM pxMessage;
float tmpUTM_North = 0.0; // holds northing info
float tmpUTM_West = 0.0; // holds easting info
int tmpZone = 0; // holds zone info
for (;;)
{
EventBits_t xbit = xEventGroupWaitBits (eg, DO_UTM_TASK_BIT, pdTRUE, pdTRUE, portMAX_DELAY) ;
// int LatLonToUTMXY (FLOAT lat, FLOAT lon, int zone, FLOAT & x, FLOAT & y)
if ( xSemaphoreTake( sema_UTM, xSemaphoreTicksToWait ) == pdTRUE )
{
tmpZone = LatLonToUTMXY(xUTM_Posit.Lat, xUTM_Posit.Lon, 0, tmpUTM_North, tmpUTM_West );
pxMessage.UTM_North = tmpUTM_North;
pxMessage.UTM_West = tmpUTM_West;
pxMessage.iZone = tmpZone;
xQueueOverwrite( xQ_UTM_Message, (void *) &pxMessage );
xSemaphoreGive( sema_UTM );
}
}
vTaskDelete( NULL );
}
////
void fUpdateDisplay( void * parameter )
{
struct stuPressureMessage *pxRxedPressureMessage; // a pointer to a structure
struct stuDistance pxDistanceMessage; // a copy of the queue sent
struct stuPower *pxRxedPowerMessage; // a pointer to a structure
struct stuUTM UTM_MessageReceiced; // a copy of the queue sent
struct stuPressureData *pxPressureDataMessage; // a pointer to a structure
struct stuRunTimeData *RunTimeDataMessage; // a pointer to a structure
struct stuTime *pxTime;
struct stuSpeed pxSpeed; // a copy of the queue sent
// struct stuDate pxDate;
struct stuPosit pxPosit;
int iSats = 0;
static int iCount = 0;
float Alti = 0.0;
float Hdg = 0.0;
float f = 0.0;
static char buf[25];
int iHdgY = 72;
int iAltiY = 61;
int iYposition = 94;
int iLeftPosition = 0;
int iTotalCount = 30;
u8g2.setFont( u8g2_font_t0_11_mr );
for (;;)
{
/* wait forever until event bit of task 1 is set */
EventBits_t xbit = xEventGroupWaitBits (eg, UPDATE_DISPLAY_TASK_BIT, pdTRUE, pdTRUE, portMAX_DELAY) ;
u8g2.clearBuffer(); // clear the internal memory
//
if ( (xQ_Time != NULL) && (uxQueueMessagesWaiting(xQ_Time)) ) // if queue not null and something is waiting in queue
{
if (xQueueReceive ( xQ_Time, &(pxTime), QueueReceiveDelayTime ) ) // receive queue info
{
if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore and place data
{
sprintf(buf, "UTC: %02d:%02d:%02d", pxTime->iHours, pxTime->iMinutes, pxTime->iSeconds);
xSemaphoreGive( sema_Time ); // give up semaphore
u8g2.setCursor(1, 10); u8g2.print(buf); // place data in display buffer
} // if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE )
} // if (xQueueReceive ( xQ_RunTimeMessage, &(RunTimeDataMessage), QueueReceiveDelayTime ) )
} // if ( (xQ_Time not NULL) && (uxQueueMessagesWaiting(xQ_Time)) )
//
if ( uxQueueMessagesWaiting(xQ_Sats) )
{
xSemaphoreTake( sema_Sats, xSemaphoreTicksToWait );
xQueueReceive(xQ_Sats, &iSats, QueueReceiveDelayTime );
xSemaphoreGive( sema_Sats );
u8g2.drawStr(85, 10, "^");
u8g2.setCursor(95, 10); u8g2.print( iSats );
}
if ( (iCount >= 0) && (iCount <= 9) )
{
if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore and place data
{
sprintf( buf, "Date: %02d/%02d/%02d", xDate.iMonth, xDate.iDay, xDate.iYear );
xSemaphoreGive( sema_Date ); // give up semaphore
u8g2.setCursor(0, 21); u8g2.print(buf);
} // if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE )
} // if ( (iCount >= 0) && (iCount <= 9) )
else
{
// is the queue not NULL && is there a queue message waiting? 0 = no messages
if ( (xQ_RunTimeMessage != NULL) && (uxQueueMessagesWaiting(xQ_RunTimeMessage) > 0) )
{
if (xQueueReceive ( xQ_RunTimeMessage, &(RunTimeDataMessage), QueueReceiveDelayTime ) )
{
if ( xSemaphoreTake( sema_RunTime, xSemaphoreTicksToWait ) == pdTRUE )
{
sprintf(buf, "Run: %03d:%02d:%02d", RunTimeDataMessage->iHours, RunTimeDataMessage->iMinutes, RunTimeDataMessage->iSeconds);
xSemaphoreGive( sema_RunTime );
u8g2.setCursor(0, 23); u8g2.print(buf);
}
}
}
} // else if ( (iCount >= 0) && (iCount <= 9) )
u8g2.drawHLine(3, 27, 100);
u8g2.drawVLine(3, 27, 22);
u8g2.drawHLine(3, 49, 100);
u8g2.drawVLine(103, 27, 23);
// // Display Lat and long
if ( (iCount >= 0) && (iCount <= 9) )
{
if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore and place data
{
if (xQueueReceive ( xQ_Posit, &pxPosit, QueueReceiveDelayTime ) )
{
// Serial.println( pxPosit.Lat );
sprintf( buf, "%0.6f", pxPosit.Lat );
u8g2.setCursor(20, 37 ); u8g2.print( buf ) ;
sprintf( buf, "%0.6f", pxPosit.Lon );
u8g2.setCursor(20, 47); u8g2.print( buf );
}
xSemaphoreGive( sema_Posit ); // give up semaphore
} // if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
} // if ( (iCount >= 0) && (iCount <= 9) )
if ( (iCount >= 10) && (iCount <= 19) )
{
if ( (xQ_UTM_Message != NULL ) && (uxQueueMessagesWaiting(xQ_UTM_Message)) )
{
if (xQueueReceive ( xQ_UTM_Message, &(UTM_MessageReceiced), QueueReceiveDelayTime ) )
{
if ( xSemaphoreTake( sema_UTM, xSemaphoreTicksToWait ) == pdTRUE )
{
//display UTM northing, easting, and zone
u8g2.setCursor(12, 37); u8g2.print( UTM_MessageReceiced.UTM_North );
u8g2.setCursor(12, 47); u8g2.print( UTM_MessageReceiced.UTM_West);
u8g2.setCursor(75, 37); u8g2.print( UTM_MessageReceiced.iZone);
xSemaphoreGive( sema_UTM );
}
}
}
} // if ( (iCount >= 0) && (iCount <= 9) )
if ( (iCount >= 20) && (iCount <= iTotalCount) )
{
//// portMAX_DELAY will cause a wait forever for something to show up in the buffer. time of portMAX_DELAY is 47 days
//// wait for 10 clock tics for data to arrive in the queue buffer
if ( (xQ_PressureDataMessage != 0) && (uxQueueMessagesWaiting(xQ_PressureDataMessage)) )
{
if (xQueueReceive ( xQ_PressureDataMessage, &(pxPressureDataMessage), QueueReceiveDelayTime ) )
{
if ( pxPressureDataMessage != 0) // check if structure is null
{
if ( xSemaphoreTake( sema_PressureDataCollection, xSemaphoreTicksToWait ) == pdTRUE )
{
int x = 30; // set x position
int yBase = 38;
// int y1 = yBase;
int x2 = 5;
int pressureBase = 0;
int iBaseLineReading = pxPressureDataMessage->mmHg_Hourly[0];
u8g2.drawHLine( x, yBase, x2 );
for ( int i = 1; i <= (PressureDataArrayCount - 1); i++ )
{
if ( pxPressureDataMessage->mmHg_Hourly[i] != 0 )
{
x = x + 6; // position next x
u8g2.drawHLine( x, yBase + (iBaseLineReading - pxPressureDataMessage->mmHg_Hourly[i] ), x2 );
}
sprintf( buf, "%04d", iBaseLineReading ) ; // display basy line reading to the left
u8g2.setCursor( 9, 43 ); u8g2.print( buf );
} // for (int i = 1; i <= (PressureDataArrayCount - 1); i++)
xSemaphoreGive( sema_PressureDataCollection );
} // if ( xSemaphoreTake( s_Pressure, ( TickType_t ) 10 ) == pdTRUE )
}
else
{
Serial.println( "pxPressureDataMessage" );
}
} // if (xQueueReceive ( xQ_PressureDataMessage, &(pxPressureDataMessage), ( TickType_t ) QueueReceiveDelayTime ) )
} // if ( xQ_PressureDataMessage != 0 )
} // if ( (iCount >= 20) && (iCount <= 30) )
if ( uxQueueMessagesWaiting(xQ_Hdg) )
{
xSemaphoreTake( sema_Hdg, xSemaphoreTicksToWait );
xQueueReceive(xQ_Hdg, &Hdg, QueueReceiveDelayTime );
xSemaphoreGive( sema_Hdg );
u8g2.drawStr(iLeftPosition, iHdgY, "Hdg: ");
u8g2.setCursor(28, iHdgY); u8g2.print( Hdg );
}
if ( uxQueueMessagesWaiting(xQ_Alti) )
{
xSemaphoreTake( sema_Alti, xSemaphoreTicksToWait );
xQueueReceive(xQ_Alti, &Alti, QueueReceiveDelayTime );
xSemaphoreGive( sema_Alti );
u8g2.drawStr(iLeftPosition, iAltiY, "Alti: ");
u8g2.setCursor(30, iAltiY); u8g2.print( (Alti * 3.2808) );
}
if ( (iCount >= 1) && (iCount <= 15) )
{
if ( xSemaphoreTake( sema_Speed, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore to stop the queue from being over wrote
{
if (xQueueReceive ( xQ_Speed, &pxSpeed, QueueReceiveDelayTime ) )
{
sprintf( buf, "%.1fKPH %.1fMPH" , pxSpeed.KPH, pxSpeed.MPH );
u8g2.setCursor( iLeftPosition, 83 ); u8g2.print( buf );
}
xSemaphoreGive( sema_Speed ); // release semaphore
} // if ( xSemaphoreTake( sema_Speed, xSemaphoreTicksToWait ) == pdTRUE )
}
else
{
if ( xSemaphoreTake( sema_CalDistance, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore to stop the queue from being over wrote
{
if (xQueueReceive ( xQ_DistanceMessage, &pxDistanceMessage, QueueReceiveDelayTime ) )
{
sprintf( buf, "%d " , pxDistanceMessage.Distance );
u8g2.setCursor( iLeftPosition, 83 ); u8g2.print( buf );
}
xSemaphoreGive( sema_CalDistance );
} // if ( xSemaphoreTake( sema_CalDistance, xSemaphoreTicksToWait ) == pdTRUE )
}
if ( (iCount >= 1) && (iCount <= 10) )
{
if ( xQ_PowerMessage != 0 )
{
if ( xQueueReceive( xQ_PowerMessage, &( pxRxedPowerMessage ), QueueReceiveDelayTime ) )
{
if ( pxRxedPowerMessage != 0) // check if structure is null
{
if ( xSemaphoreTake( sema_AnalogVoltRead, xSemaphoreTicksToWait ) == pdTRUE )
{
sprintf( buf, "V: %.2f %.2f% ", pxRxedPowerMessage->Vbatt, pxRxedPowerMessage->BattPercent );
u8g2.setCursor( iLeftPosition, iYposition ); u8g2.print( buf );
xSemaphoreGive( sema_AnalogVoltRead );
}
}
else
{
Serial.println( "pxRxedPowerMessage" );
}
}
} // if ( xQ_PowerMessage != 0 )
} // if ( (iCount >= 1) && (iCount <= 10) )
if ( (iCount >= 11) && (iCount <= 20) )
{
// Receive a message on the created queue.
if ( xQ_PressureMessage != 0 )
{
if ( xQueueReceive( xQ_PressureMessage, &( pxRxedPressureMessage ), QueueReceiveDelayTime ) )
{
if ( pxRxedPressureMessage != 0) // check if structure is null
{
if ( xSemaphoreTake( sema_CheckPressure, xSemaphoreTicksToWait ) == pdTRUE )
{
sprintf( buf, "%.2fC %.2fF", pxRxedPressureMessage->BMEtemperature, ((pxRxedPressureMessage->BMEtemperature * 1.8) + 32) );
u8g2.setCursor( iLeftPosition, iYposition ); u8g2.print( buf );
xSemaphoreGive( sema_CheckPressure );
}
}
else
{
Serial.println( "pxRxedPressureMessage 1" );
}
}
}
} // if ( (iCount >= 11) && (iCount <= 20) )
if ( (iCount >= 21) && (iCount <= 30) )
{
if ( xQ_PressureMessage != 0 )
{
if ( xQueueReceive( xQ_PressureMessage, &( pxRxedPressureMessage ), QueueReceiveDelayTime ) )
{
if ( pxRxedPressureMessage != 0) // check if structure is null
{
if ( xSemaphoreTake( sema_CheckPressure, xSemaphoreTicksToWait ) == pdTRUE )
{
sprintf( buf, "%.2fmmHg", pxRxedPressureMessage->BMEpressure );
u8g2.setCursor( iLeftPosition, iYposition ); u8g2.print( buf );
xSemaphoreGive( sema_CheckPressure );
}
}
else
{
Serial.println( "pxRxedPressureMessage 2" );
}
}
}
} // if ( (iCount >= 21) && (iCount <= 30) )
u8g2.sendBuffer(); // transfer internal memory to the display
if ( (iCount >= 20) && (iCount <= 29) )
{
xEventGroupSetBits( eg, PressureEvent ); // trigger pressure readings
} // if ( (iCount >= 20 ) && (iCount <= 29) )
if ( (iCount >= 10) && (iCount <= 19) )
{
xEventGroupSetBits( eg, PressureEvent ); // trigger pressure readings
} // if ( (iCount >= 10) && (iCount <= 19) )
if ( (iCount >= 8) && (iCount <= 18) )
{
// trigger UTM update, update utm just before its used as a display value
xEventGroupSetBits( eg, DO_UTM_TASK_BIT ); // trigger UTM calculations
} // if ( (iCount >= 8) && (iCount <= 18) )
if ( (iCount >= 0) && (iCount <= 9) )
{
xEventGroupSetBits( eg, AnalogVoltReadTask ); // trigger analog voltage read and calculation
} // if ( (iCount >= 0) && (iCount <= 9) )
iCount++;
if ( iCount >= iTotalCount )
{
iCount = 0;
}
// Serial.print( "fUpdateDisplay " );
// Serial.print( " " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
// xSemaphoreGive( sema_GPS_Gate ); // see (xSemaphoreTakeFromISR(sema_GPS_Gate, &xHigherPriorityTaskWoken)) in void IRAM_ATTR onTimer()
}
vTaskDelete( NULL );
} // void fUpdateDisplay( void * parameter )
//////
void fGPS_Parse( void * parameter )
{
TickType_t xDoDistanceExpireTicks;
struct stuTime *pxTime;
// struct stuDate pxDate;
struct stuPosit pxPosit;
struct stuDistance pxDistance;
struct stuSpeed pxSpeed;
float Alti;
float Hdg;
int Sats;
float LatNow;
float LonNow;
float LatPast;
float LonPast;
int DoDistanceTicks = 5000;
////
xDoDistanceExpireTicks = xTaskGetTickCount() + pdMS_TO_TICKS( DoDistanceTicks ); // add DoDistanceTicks mS worth of ticks to current tick count
for (;;)
{
xEventGroupWaitBits (eg, GPS_Parse, pdTRUE, pdTRUE, portMAX_DELAY) ;
//query GPS: has a new complete chunk of data been received?
if ( GPSSerial.available() > 1 )
{
if ( GPS.encode(GPSSerial.read()) )
{
// if (totalGPGSVMessages.isUpdated()) ///????????????????
// {
if ( GPS.location.isValid())
{
//used for distance calculation
LatNow = GPS.location.lat();
LonNow = GPS.location.lng();
// //
if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
{
pxPosit.Lat = LatNow; // store data into structure
pxPosit.Lon = LonNow;
xQueueOverwrite( xQ_Posit, (void *) &pxPosit );
if ( xSemaphoreTake( sema_UTM, xSemaphoreTicksToWait ) == pdTRUE ) // place lat lon for utm calculation
{
xUTM_Posit.Lat = pxPosit.Lat;
xUTM_Posit.Lon = pxPosit.Lon;
xSemaphoreGive( sema_UTM );
}
xSemaphoreGive( sema_Posit );
}
} // if ( GPS.location.isValid())
// do distance calculations
if ( xTaskGetTickCount() >= xDoDistanceExpireTicks ) // do only once every xDoDistanceExpireTicks
{
if ( xSemaphoreTake( sema_CalDistance, xSemaphoreTicksToWait ) == pdTRUE ) // has tick count expired
{
if ( LatPast != 0.0 )
{
pxDistance.Distance = (unsigned long)TinyGPSPlus::distanceBetween( LatNow, LonNow, LatPast, LonPast) / 1000; // in Kilometers
xQueueSendToBack( xQ_DistanceMessage, (void *) &pxDistance, xTicksToWait0 );
// unsigned long distanceKmToLondon = (unsigned long)TinyGPSPlus::distanceBetween( gps.location.lat(), gps.location.lng(), LONDON_LAT, LONDON_LON) / 1000;
}
LatPast = LatNow; // update past lat n lon with now lat lon for next calculation
LonPast = LonNow;
xSemaphoreGive( sema_CalDistance );
}
xDoDistanceExpireTicks = xTaskGetTickCount() + pdMS_TO_TICKS( DoDistanceTicks ); // set new time peorid to do distance calculation
} // if ( xTaskGetTickCount() >= xDoDistanceExpireTicks )
if (GPS.speed.isValid())
{
if ( xSemaphoreTake( sema_Speed, xSemaphoreTicksToWait ) == pdTRUE ) // has tick count expired
{
pxSpeed.MPH = GPS.speed.mph();
pxSpeed.KPH = GPS.speed.kmph();
// xSpeed.MPH = GPS.speed.mph();
// xSpeed.KPH = GPS.speed.kmph();
xQueueOverwrite( xQ_Speed, (void *) &pxSpeed );
xSemaphoreGive( sema_Speed );
}
//}
} // if ( GPS.location.isValid())
if (GPS.time.isValid())
{
xTime.iSeconds = GPS.time.second();
xTime.iMinutes = GPS.time.minute();
xTime.iHours = GPS.time.hour();
if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE )
{
pxTime = &xTime;
xQueueOverwrite( xQ_Time, (void *) &pxTime );
xSemaphoreGive( sema_Time );
}
} // if (GPS.time.isValid())
if (GPS.date.isValid())
{
if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE )
{
xDate.iMonth = GPS.date. month();
xDate.iDay = GPS.date.day();
xDate.iYear = GPS.date.year();
xSemaphoreGive( sema_Date );
}
}
if ( GPS.satellites.isValid() )
{
if ( xSemaphoreTake( sema_Sats, xSemaphoreTicksToWait ) == pdTRUE )
{
Sats = GPS.satellites.value();
xQueueOverwrite( xQ_Sats, ( void * ) &Sats );
xSemaphoreGive( sema_Sats );
}
}
if ( GPS.altitude.isValid() )
{
if ( xSemaphoreTake( sema_Alti, xSemaphoreTicksToWait ) == pdTRUE )
{
Alti = GPS.altitude.meters();
xQueueOverwrite( xQ_Alti, ( void * ) &Alti );
xSemaphoreGive( sema_Alti );
}
} // if ( GPS.altitude.isValid() )
if ( GPS.course.isUpdated() )
{
if ( xSemaphoreTake( sema_Hdg, xSemaphoreTicksToWait ) == pdTRUE )
{
Hdg = GPS.course.deg();
xQueueOverwrite( xQ_Hdg, ( void * ) &Hdg );
xSemaphoreGive( sema_Hdg );
}
} // if ( GPS.course.isUpdated() )
// Serial.print( "fGPS_Parse " );
// Serial.print( " " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
} // if ( GPS.encode(GPSSerial.read()))
} // if ( GPSSerial.available() > 0 )
// else
// {
xSemaphoreGive( sema_GPS_Gate ); // see (xSemaphoreTakeFromISR(sema_GPS_Gate, &xHigherPriorityTaskWoken)) in void IRAM_ATTR onTimer()
// }
} // for (;;)
vTaskDelete( NULL );
} // void fGPS_Parse( void *pdata )
//////////////////////////////////////////////////
void fBlinkBuiltIn( void* pvParameters )
{
// toggle built in LED off/on
for (;;)
{
vTaskDelay( pdMS_TO_TICKS( 10 ) );
REG_WRITE( GPIO_OUT_W1TC_REG, BIT2 ); // GPIO2 LOW (clear)
vTaskDelay( pdMS_TO_TICKS( OneK ) );
REG_WRITE( GPIO_OUT_W1TS_REG, BIT2 ); //GPIO2 HIGH (set)
}
vTaskDelete( NULL );
}
////////////////////////////////////////////////
// example of a ticks to wait use
void TaskAnalogVoltRead( void *pvParameters )
{
struct stuPower *pxMessage;
float ADbits = 4095.0;
float uPvolts = 3.3;
float r1 = 27000.0; // R1 in ohm, 27k = 27000.0 //actual resistor size 27K
float r2 = 10000.0; // R2 in ohm, 10k = 10000.0 //actual 10K
// ADC1 channel 0 is GPIO36
// ADC1 channel 1 is GPIO37
// https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
for (;;)
{
// group handle, WaitForBits, ClearOnExitBit, WaitForAllBits, TicksToWait
xEventGroupWaitBits( eg, AnalogVoltReadTask, pdTRUE, pdTRUE, portMAX_DELAY );
// read the input
// ADC1 channel 1 input is ground, any ground noise readings get substracted from voltage reading
if ( xSemaphoreTake( sema_AnalogVoltRead, xSemaphoreTicksToWait ) == pdTRUE )
{
xPowerMessage.Vbatt = ( (( uPvolts * float(adc1_get_raw(ADC1_CHANNEL_0) - adc1_get_raw(ADC1_CHANNEL_1))) / ADbits) / r2 * ( r1 + r2) );
fBatteryPercentRemaingCharge();
pxMessage = &xPowerMessage;
xQueueOverwrite( xQ_PowerMessage, (void *) &pxMessage );
xSemaphoreGive( sema_AnalogVoltRead );
}
// Serial.print( "TaskAnalogVoltRead " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
}
vTaskDelete( NULL );
}
/////////////////////////////////////////////////////////
void fBatteryPercentRemaingCharge()
{
byte V_BattNominal = 8;
byte V_MinRange = 6; //volts is lowest recomemded operating voltage
////
if ( xPowerMessage.Vbatt >= V_BattNominal)
{
xPowerMessage.BattPercent = 100.00;
}
else
{
xPowerMessage.BattPercent = ( ((xPowerMessage.Vbatt - V_MinRange) * 100.0) / (V_BattNominal - V_MinRange) );
}
}// end fBatteryPercentRemaingCharge()
//*****************************************************************************************
///////////////////////////////////////////////////////////////////////////////////////////
void fCheck_Pressure( void * parameter )
{
struct stuPressureMessage *pxMessage;
while (1)
{
xEventGroupWaitBits (eg, PressureEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
if ( xSemaphoreTake( sema_CheckPressure, xSemaphoreTicksToWait ) == pdTRUE )
{
xPressureMessage.BMEtemperature = bme.readTemperature();
xPressureMessage.BMEpressure = bme.readPressure() / 133.3223684; // mmHg
if ( xSemaphoreTake(sema_PressureDataCollection, xSemaphoreTicksToWait ) == pdTRUE )
{
xPressureData.BMEpressure = int( xPressureMessage.BMEpressure ); // transfer pressure reading into xPressureData.BMEpressure
xSemaphoreGive( sema_PressureDataCollection );
}
//// BMEpressure = bme.readPressure() * 0.0002952998751 ; // inHg
pxMessage = &xPressureMessage;
xQueueOverwrite( xQ_PressureMessage, (void *) &pxMessage ); // sends a copy of the structure in the queue
xEventGroupSetBits( eg, DoPressureDataCollectionEvent ); // trigger fDoPressureDataCollection
xSemaphoreGive( sema_CheckPressure );
}
// Serial.print( "fCheck_Pressure " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
}
vTaskDelete( NULL );
} // void fCheck_Pressure( void * parameter )
//*****************************************************************************************
// templates and examples
//*****************************************************************************************
//void fTaskTemplateEventGroupUsingHardwareTimerTriggers( void * parameter )
//{
// for (;;) {
/* Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
the event group. Clear the bits before exiting. */
// uxBits = xEventGroupWaitBits(
// xEventGroup, /* The event group being tested. */
// BIT_0 | BIT_4, /* The bits within the event group to wait for. */
// pdTRUE, /* BIT_0 & BIT_4 should be cleared before returning. */
// pdFALSE, /* Don't wait for both bits, either bit will do. */
// xTicksToWait );/* Wait a maximum of 100ms for either bit to be set. */
// if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
// {
// /* xEventGroupWaitBits() returned because both bits were set. */
// }
// else if( ( uxBits & BIT_0 ) != 0 )
// {
// /* xEventGroupWaitBits() returned because just BIT_0 was set. */
// }
// else if( ( uxBits & BIT_4 ) != 0 )
// {
// /* xEventGroupWaitBits() returned because just BIT_4 was set. */
// }
// else
// {
// /* xEventGroupWaitBits() returned because xTicksToWait ticks passed
// without either BIT_0 or BIT_4 becoming set. */
// }
//}
// /* wait forever until event bit of task 1 is set */
// EventBits_t xbit = xEventGroupWaitBits (eg, TASK_BIT, pdTRUE, pdTRUE, portMAX_DELAY) ;
// do this things here
// }
// vTaskDelete( NULL );
//}
//////
//void fTaskTemplateWithInternalDelay( void * parameter )
//{
// for (;;)
// {
// do the ting here
// vTaskDelay( pdMS_TO_TICKS( lLIDAR_SequenceInterval ) );
// or
// vTaskDelay( 1 / portTICK_PERIOD_MS );
// }
// vTaskDelete( NULL );
//}
Re: Task Understanding
Thank you for that. Ill read through that example and try to fully understand it.
for the task block item, if i had a task that needed to run every second, and that task has a block in it's while loop. that block will not hold up the CPU like a delay will?
im coming from an ESP8266 with this same code. I upgraded my board to use an esp32 and now porting the code over. i used millis() for EVERYTHING as to not block code execution.
for the task block item, if i had a task that needed to run every second, and that task has a block in it's while loop. that block will not hold up the CPU like a delay will?
im coming from an ESP8266 with this same code. I upgraded my board to use an esp32 and now porting the code over. i used millis() for EVERYTHING as to not block code execution.
Re: Task Understanding
Here is what I am thinking for one of the tasks. there is a global variable of "TickType_t oneWireDelay = pdMS_TO_TICKS(750);"
The idea is that this task will run forever, and not block anything else from running. and vTaskDelete should never be hit. its there just as a precaution.
Am I understanding this correctly?
The idea is that this task will run forever, and not block anything else from running. and vTaskDelete should never be hit. its there just as a precaution.
Am I understanding this correctly?
Code: Select all
void OneWireTask(void * parameter) {
for (;;)
{
Serial2.println("Requesting Temperatures");
sensorC.requestTemperatures();
sensorB.requestTemperatures();
sensorA.requestTemperatures();
vTaskDelay(oneWireDelay);
Serial2.println("Updating Temperatures");
if ( sensorC.getTempFByIndex(0) > 0 && sensorC.getTempFByIndex(0) < 212) actualSensorCTemp = sensorC.getTempFByIndex(0);
if ( sensorA.getTempFByIndex(0) > 0 && sensorA.getTempFByIndex(0) < 212) actualSensorATemp = sensorA.getTempFByIndex(0);
if ( sensorB.getTempFByIndex(0) > 0 && sensorB.getTempFByIndex(0) < 212) actualSensorBTemp = sensorB.getTempFByIndex(0);
Serial2.print("SensorA: ");
Serial2.println(actualSensorATemp);
Serial2.print("SensorB: ");
Serial2.println(actualSensorBTemp);
Serial2.print("SensorC: ");
Serial2.println(actualSensorCTemp);
}
vTaskDelete(NULL);
}
-
- Posts: 166
- Joined: Wed Aug 01, 2018 12:06 pm
Re: Task Understanding
Event waits do not stop the CPU.theskaz wrote: ↑Fri Jan 25, 2019 3:54 pmThank you for that. Ill read through that example and try to fully understand it.
for the task block item, if i had a task that needed to run every second, and that task has a block in it's while loop. that block will not hold up the CPU like a delay will?
im coming from an ESP8266 with this same code. I upgraded my board to use an esp32 and now porting the code over. i used millis() for EVERYTHING as to not block code execution.
Semaphores do not stop the CPU.
vTaskDelay does not stop the CPU.
vTaskDelay( pdMS_TO_TICKS( 10 ) ) and vTaskDelay( 10 ) are way two different delays.
This is vTaskDelay( pdMS_TO_TICKS( 10 ) ) a delay of 10mSec, this vTaskDelay( 10 ) is a delay of 10 clock ticks. With the ESP32 running at 240Mhz it is 0.0000041666666666667 ms per clock tick. Multiply 0.0000041666666666667 ms by X to get your time delay or you can use pdMS_TO_TICKS( X ) which will do it for you.
Re: Task Understanding
the delay should be 750ms in this example.
Who is online
Users browsing this forum: No registered users and 65 guests