diff --git a/Firmware/RTK_Surveyor/Begin.ino b/Firmware/RTK_Surveyor/Begin.ino index 6fe9c1fc0..80366949b 100644 --- a/Firmware/RTK_Surveyor/Begin.ino +++ b/Firmware/RTK_Surveyor/Begin.ino @@ -787,3 +787,22 @@ void beginLBand() online.lband = true; } + +void beginIdleTasks() +{ + char taskName[32]; + + for (int index = 0; index < MAX_CPU_CORES; index++) + { + sprintf(taskName, "IdleTask%d", index); + if (idleTaskHandle[index] == NULL) + xTaskCreatePinnedToCore( + idleTask, + taskName, //Just for humans + 2000, //Stack Size + NULL, //Task input parameter + 0, // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest + &idleTaskHandle[index], //Task handle + index); //Core where task should run, 0=core, 1=Arduino + } +} diff --git a/Firmware/RTK_Surveyor/RTK_Surveyor.ino b/Firmware/RTK_Surveyor/RTK_Surveyor.ino index 5073a2c6b..34583a3eb 100644 --- a/Firmware/RTK_Surveyor/RTK_Surveyor.ino +++ b/Firmware/RTK_Surveyor/RTK_Surveyor.ino @@ -41,6 +41,11 @@ const int FIRMWARE_VERSION_MINOR = 3; #include "settings.h" +#define MAX_CPU_CORES 2 +#define IDLE_COUNT_PER_SECOND 196289 +#define IDLE_TIME_DISPLAY_SECONDS 5 +#define MAX_IDLE_TIME_COUNT (IDLE_TIME_DISPLAY_SECONDS * IDLE_COUNT_PER_SECOND) + //Hardware connections //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //These pins are set in beginBoard() @@ -417,6 +422,10 @@ unsigned long systemTestDisplayTime = 0; //Timestamp for swapping the graphic du uint8_t systemTestDisplayNumber = 0; //Tracks which test screen we're looking at unsigned long rtcWaitTime = 0; //At poweron, we give the RTC a few seconds to update during PointPerfect Key checking +uint32_t cpuIdleCount[MAX_CPU_CORES]; +TaskHandle_t idleTaskHandle[MAX_CPU_CORES]; +uint32_t cpuLastIdleDisplayTime; + //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- void setup() @@ -426,6 +435,11 @@ void setup() Wire.begin(); //Start I2C on core 1 //Wire.setClock(400000); + //Initialize the CPU idle time counts + for (int index = 0; index < MAX_CPU_CORES; index++) + cpuIdleCount[index] = 0; + cpuLastIdleDisplayTime = millis(); + beginDisplay(); //Start display first to be able to display any errors beginGNSS(); //Connect to GNSS to get module type @@ -463,10 +477,15 @@ void setup() log_d("Boot time: %d", millis()); danceLEDs(); //Turn on LEDs like a car dashboard + + beginIdleTasks(); } void loop() { + uint32_t delayTime; + + if (online.gnss == true) { i2cGNSS.checkUblox(); //Regularly poll to get latest data and any RTCM @@ -501,7 +520,40 @@ void loop() //Convert current system time to minutes. This is used in F9PSerialReadTask()/updateLogs() to see if we are within max log window. systemTime_minutes = millis() / 1000L / 60; - delay(10); //A small delay prevents panic if no other I2C or functions are called + //Display the CPU idle time + if (settings.enablePrintIdleTime) + printIdleTimes(); + + //A small delay prevents panic if no other I2C or functions are called + delay(10); +} + +//Print the CPU idle times +void printIdleTimes() +{ + uint32_t idleCount[MAX_CPU_CORES]; + int index; + + //Determine if it is time to print the CPU idle times + if ((millis() - cpuLastIdleDisplayTime) >= (IDLE_TIME_DISPLAY_SECONDS * 1000)) + { + //Get the idle times + cpuLastIdleDisplayTime = millis(); + for (index = 0; index < MAX_CPU_CORES; index++) + { + idleCount[index] = cpuIdleCount[index]; + cpuIdleCount[index] = 0; + } + + //Display the idle times + for (int index = 0; index < MAX_CPU_CORES; index++) + Serial.printf("CPU %d idle time: %d%% (%d/%d)\r\n", index, + idleCount[index] * 100 / MAX_IDLE_TIME_COUNT, + idleCount[index], MAX_IDLE_TIME_COUNT); + + //Print the task count + Serial.printf("%d Tasks\r\n", uxTaskGetNumberOfTasks()); + } } //Create or close files as needed (startup or as user changes settings) diff --git a/Firmware/RTK_Surveyor/Tasks.ino b/Firmware/RTK_Surveyor/Tasks.ino index b0cb2ea0d..b5f0e5901 100644 --- a/Firmware/RTK_Surveyor/Tasks.ino +++ b/Firmware/RTK_Surveyor/Tasks.ino @@ -438,3 +438,30 @@ void ButtonCheckTask(void *e) taskYIELD(); } } + +void idleTask(void *e) +{ + uint32_t lastStackPrintTime; + + while (1) + { + if (settings.enablePrintIdleTime) + { + //Increment a count during the idle time + cpuIdleCount[xPortGetCoreID()]++; + + //Let other same priority tasks run + yield(); + } + else + delay(1000); + + //Display the high water mark if requested + if ((settings.enableTaskReports == true) && ((millis() - lastStackPrintTime) >= 1000)) + { + lastStackPrintTime = millis(); + Serial.printf("idleTask %d High watermark: %d\n\r", + xPortGetCoreID(), uxTaskGetStackHighWaterMark(NULL)); + } + } +} diff --git a/Firmware/RTK_Surveyor/menuSystem.ino b/Firmware/RTK_Surveyor/menuSystem.ino index ecb636527..db4d684c2 100644 --- a/Firmware/RTK_Surveyor/menuSystem.ino +++ b/Firmware/RTK_Surveyor/menuSystem.ino @@ -301,6 +301,9 @@ void menuDebug() Serial.print(F("16) Periodically print position: ")); Serial.printf("%s\r\n", settings.enablePrintPosition ? "Enabled" : "Disabled"); + Serial.print(F("17) Periodically print CPU idle time: ")); + Serial.printf("%s\r\n", settings.enablePrintIdleTime ? "Enabled" : "Disabled"); + Serial.println(F("t) Enter Test Screen")); Serial.println(F("e) Erase LittleFS")); @@ -429,6 +432,10 @@ void menuDebug() { settings.enablePrintPosition ^= 1; } + else if (incoming == 17) + { + settings.enablePrintIdleTime ^= 1; + } else printUnknown(incoming); } diff --git a/Firmware/RTK_Surveyor/settings.h b/Firmware/RTK_Surveyor/settings.h index 1b43b540e..b97bf7a62 100644 --- a/Firmware/RTK_Surveyor/settings.h +++ b/Firmware/RTK_Surveyor/settings.h @@ -431,6 +431,7 @@ typedef struct { bool enablePrintNtripServerState = false; bool enablePrintNtripServerRtcm = false; bool enablePrintPosition = false; + bool enablePrintIdleTime = false; } Settings; Settings settings;