diff --git a/Binaries/OpenLog_Artemis-V10-v112_BETA.bin b/Binaries/OpenLog_Artemis-V10-v112_BETA.bin deleted file mode 100644 index 9b24db4..0000000 Binary files a/Binaries/OpenLog_Artemis-V10-v112_BETA.bin and /dev/null differ diff --git a/Binaries/OpenLog_Artemis-V10-v20.bin b/Binaries/OpenLog_Artemis-V10-v20.bin new file mode 100644 index 0000000..ffe18b6 Binary files /dev/null and b/Binaries/OpenLog_Artemis-V10-v20.bin differ diff --git a/Binaries/OpenLog_Artemis-X04-v20.bin b/Binaries/OpenLog_Artemis-X04-v20.bin new file mode 100644 index 0000000..3394b61 Binary files /dev/null and b/Binaries/OpenLog_Artemis-X04-v20.bin differ diff --git a/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino b/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino index 38605b0..0b3a566 100644 --- a/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino +++ b/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino @@ -11,10 +11,11 @@ This firmware runs the OpenLog Artemis. A large variety of system settings can be adjusted by connecting at 115200bps. - The Board should be set to SparkFun Apollo3 \ SparkFun RedBoard Artemis ATP. + The Board should be set to SparkFun Apollo3 \ RedBoard Artemis ATP. - Please note: this firmware currently only compiles on v1.2.1 of the Apollo3 boards. - It does not yet work with the new Mbed version (v2.0) of the core. + Please note: this version of the firmware compiles on v2.1.0 of the Apollo3 boards. + + (At the time of writing, data logging with the the u-blox ZED-F9P is problematic when using v2.1.1 of the core.) v1.0 Power Consumption: Sleep between reads, RTC fully charged, no Qwiic, SD, no USB, no Power LED: 260uA @@ -93,12 +94,23 @@ (done) Add support for exFAT. Requires v2.0.6 of Bill Greiman's SdFat library. https://github.com/sparkfun/OpenLog_Artemis/issues/34 (done) Add minimum awake time: https://github.com/sparkfun/OpenLog_Artemis/issues/83 (done) Add support for the Pulse Oximeter: https://github.com/sparkfun/OpenLog_Artemis/issues/81 - (won't do?) Add support for the Qwiic Button. The QB uses clock-stretching and the Artemis really doesn't enjoy that... + (done - but does not work) Add support for the Qwiic Button. The QB uses clock-stretching and the Artemis really doesn't enjoy that... (done) Increase DMP data resolution to five decimal places https://github.com/sparkfun/OpenLog_Artemis/issues/90 + + (in progress) Update to Apollo3 v2.1.0 - FIRMWARE_VERSION_MAJOR = 2. + (done) Implement printf float (OLA uses printf float in _so_ many places...): https://github.com/sparkfun/Arduino_Apollo3/issues/278 + (worked around) attachInterrupt(PIN_POWER_LOSS, powerDownOLA, FALLING); triggers an immediate interrupt - https://github.com/sparkfun/Arduino_Apollo3/issues/416 + (done) Add a setQwiicPullups function + (done) Check if we need ap3_set_pin_to_analog when coming out of sleep + (done) Investigate why code does not wake from deep sleep correctly + (worked around) Correct SerialLog RX: https://github.com/sparkfun/Arduino_Apollo3/issues/401 + The work-around is to use Serial1 in place of serialLog and then to manually force UART1 to use pins 12 and 13 + We need a work-around anyway because if pins 12 or 13 have been used as analog inputs, Serial1.begin does not re-configure them for UART TX and RX + (in progress) Reduce sleep current as much as possible. v1.2.1 achieved ~110uA. With v2.1.0 the draw is more like 260uA... */ -const int FIRMWARE_VERSION_MAJOR = 1; -const int FIRMWARE_VERSION_MINOR = 12; +const int FIRMWARE_VERSION_MAJOR = 2; +const int FIRMWARE_VERSION_MINOR = 0; //Define the OLA board identifier: // This is an int which is unique to this variant of the OLA and which allows us @@ -108,7 +120,7 @@ const int FIRMWARE_VERSION_MINOR = 12; // the variant * 0x100 (OLA = 1; GNSS_LOGGER = 2; GEOPHONE_LOGGER = 3) // the major firmware version * 0x10 // the minor firmware version -#define OLA_IDENTIFIER 0x11B // Stored as 283 decimal in OLA_settings.txt +#define OLA_IDENTIFIER 0x120 // Stored as 288 decimal in OLA_settings.txt #include "settings.h" @@ -146,6 +158,10 @@ const byte PIN_TRIGGER = 11; const byte PIN_QWIIC_SCL = 8; const byte PIN_QWIIC_SDA = 9; +const byte PIN_SPI_SCK = 5; +const byte PIN_SPI_CIPO = 6; +const byte PIN_SPI_COPI = 7; + // Include this many extra bytes when starting a mux - to try and avoid the slippery mux bug // This should be 0 but 3 or 7 seem to work better depending on which way the wind is blowing. const byte EXTRA_MUX_STARTUP_BYTES = 3; @@ -159,7 +175,7 @@ enum returnStatus { //Setup Qwiic Port //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #include -TwoWire qwiic(1); //Will use pads 8/9 +TwoWire qwiic(PIN_QWIIC_SDA,PIN_QWIIC_SCL); //Will use pads 8/9 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //EEPROM for storing settings @@ -171,7 +187,7 @@ TwoWire qwiic(1); //Will use pads 8/9 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #include -#include //SdFat v2.0.6 by Bill Greiman: http://librarymanager/All#SdFat_exFAT +#include //SdFat v2.0.7 by Bill Greiman: http://librarymanager/All#SdFat_exFAT #define SD_FAT_TYPE 3 // SD_FAT_TYPE = 0 for SdFat/File, 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT. #define SD_CONFIG SdSpiConfig(PIN_MICROSD_CHIP_SELECT, SHARED_SPI, SD_SCK_MHZ(24)) // 24MHz @@ -204,13 +220,16 @@ const int sdPowerDownDelay = 100; //Delay for this many ms before turning off th //Add RTC interface for Artemis //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #include "RTC.h" //Include RTC library included with the Aruino_Apollo3 core -APM3_RTC myRTC; //Create instance of RTC class +Apollo3RTC myRTC; //Create instance of RTC class //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //Create UART instance for OpenLog style serial logging //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -Uart SerialLog(1, 13, 12); // Declares a Uart object called Serial1 using instance 1 of Apollo3 UART peripherals with RX on pin 13 and TX on pin 12 (note, you specify *pins* not Apollo3 pads. This uses the variant's pin map to determine the Apollo3 pad) -unsigned long lastSeriaLogSyncTime = 0; + +//UART SerialLog(BREAKOUT_PIN_TX, BREAKOUT_PIN_RX); // Declares a Uart object called SerialLog with TX on pin 12 and RX on pin 13 + +uint64_t lastSeriaLogSyncTime = 0; +uint64_t lastAwakeTimeMillis; const int MAX_IDLE_TIME_MSEC = 500; bool newSerialData = false; char incomingBuffer[256 * 2]; //This size of this buffer is sensitive. Do not change without analysis using OpenLog_Serial. @@ -251,7 +270,7 @@ icm_20948_DMP_data_t dmpData; // Global storage for the DMP data - extracted fro #include "SparkFun_SGP40_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_SGP40 #include "SparkFun_SDP3x_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_SDP3x #include "MS5837.h" // Click here to download the library: https://github.com/sparkfunX/BlueRobotics_MS5837_Library -//#include "SparkFun_Qwiic_Button.h" // Click here to get the library: http://librarymanager/All#SparkFun_Qwiic_Button_Switch +#include "SparkFun_Qwiic_Button.h" // Click here to get the library: http://librarymanager/All#SparkFun_Qwiic_Button_Switch #include "SparkFun_Bio_Sensor_Hub_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_Bio_Sensor //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -271,12 +290,13 @@ bool sleepAfterRead = false; //Used to keep the code awake for at least minimumA const uint64_t maxUsBeforeSleep = 2000000ULL; //Number of us between readings before sleep is activated. const byte menuTimeout = 15; //Menus will exit/timeout after this number of seconds volatile static bool stopLoggingSeen = false; //Flag to indicate if we should stop logging -unsigned long qwiicPowerOnTime = 0; //Used to delay after Qwiic power on to allow sensors to power on, then answer autodetect +uint64_t qwiicPowerOnTime = 0; //Used to delay after Qwiic power on to allow sensors to power on, then answer autodetect unsigned long qwiicPowerOnDelayMillis; //Wait for this many milliseconds after turning on the Qwiic power before attempting to communicate with Qwiic devices int lowBatteryReadings = 0; // Count how many times the battery voltage has read low const int lowBatteryReadingsLimit = 10; // Don't declare the battery voltage low until we have had this many consecutive low readings (to reject sampling noise) volatile static bool triggerEdgeSeen = false; //Flag to indicate if a trigger interrupt has been seen char serialTimestamp[40]; //Buffer to store serial timestamp, if needed +volatile static bool powerLossSeen = false; //Flag to indicate if a power loss event has been seen //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- uint8_t getByteChoice(int numberOfSeconds, bool updateDZSERIAL = false); // Header @@ -288,14 +308,12 @@ void SerialPrintln(const char *); void SerialPrintln(const __FlashStringHelper *); void DoSerialPrint(char (*)(const char *), const char *, bool newLine = false); -//unsigned long startTime = 0; - -#define DUMP( varname ) {Serial.printf("%s: %llu\r\n", #varname, varname); if (settings.useTxRxPinsForTerminal == true) SerialLog.printf("%s: %llu\r\n", #varname, varname);} -#define SerialPrintf1( var ) {Serial.printf( var ); if (settings.useTxRxPinsForTerminal == true) SerialLog.printf( var );} -#define SerialPrintf2( var1, var2 ) {Serial.printf( var1, var2 ); if (settings.useTxRxPinsForTerminal == true) SerialLog.printf( var1, var2 );} -#define SerialPrintf3( var1, var2, var3 ) {Serial.printf( var1, var2, var3 ); if (settings.useTxRxPinsForTerminal == true) SerialLog.printf( var1, var2, var3 );} -#define SerialPrintf4( var1, var2, var3, var4 ) {Serial.printf( var1, var2, var3, var4 ); if (settings.useTxRxPinsForTerminal == true) SerialLog.printf( var1, var2, var3, var4 );} -#define SerialPrintf5( var1, var2, var3, var4, var5 ) {Serial.printf( var1, var2, var3, var4, var5 ); if (settings.useTxRxPinsForTerminal == true) SerialLog.printf( var1, var2, var3, var4, var5 );} +#define DUMP( varname ) {Serial.printf("%s: %d\r\n", #varname, varname); if (settings.useTxRxPinsForTerminal == true) Serial1.printf("%s: %d\r\n", #varname, varname);} +#define SerialPrintf1( var ) {Serial.printf( var ); if (settings.useTxRxPinsForTerminal == true) Serial1.printf( var );} +#define SerialPrintf2( var1, var2 ) {Serial.printf( var1, var2 ); if (settings.useTxRxPinsForTerminal == true) Serial1.printf( var1, var2 );} +#define SerialPrintf3( var1, var2, var3 ) {Serial.printf( var1, var2, var3 ); if (settings.useTxRxPinsForTerminal == true) Serial1.printf( var1, var2, var3 );} +#define SerialPrintf4( var1, var2, var3, var4 ) {Serial.printf( var1, var2, var3, var4 ); if (settings.useTxRxPinsForTerminal == true) Serial1.printf( var1, var2, var3, var4 );} +#define SerialPrintf5( var1, var2, var3, var4, var5 ) {Serial.printf( var1, var2, var3, var4, var5 ); if (settings.useTxRxPinsForTerminal == true) Serial1.printf( var1, var2, var3, var4, var5 );} // The Serial port for the Zmodem connection // must not be the same as DSERIAL unless all @@ -311,49 +329,60 @@ void setup() { delay(1); // Let PIN_POWER_LOSS stabilize - if (digitalRead(PIN_POWER_LOSS) == LOW) powerDown(); //Check PIN_POWER_LOSS just in case we missed the falling edge - attachInterrupt(digitalPinToInterrupt(PIN_POWER_LOSS), powerDown, FALLING); + if (digitalRead(PIN_POWER_LOSS) == LOW) powerDownOLA(); //Check PIN_POWER_LOSS just in case we missed the falling edge + //attachInterrupt(PIN_POWER_LOSS, powerDownOLA, FALLING); // We can't do this with v2.1.0 as attachInterrupt causes a spontaneous interrupt + attachInterrupt(PIN_POWER_LOSS, powerLossISR, FALLING); + powerLossSeen = false; // Make sure the flag is clear powerLEDOn(); // Turn the power LED on - if the hardware supports it pinMode(PIN_STAT_LED, OUTPUT); digitalWrite(PIN_STAT_LED, HIGH); // Turn the STAT LED on while we configure everything - Serial.begin(115200); //Default for initial debug messages if necessary - SerialLog.begin(115200); //Default for initial debug messages if necessary - SerialPrintln(F("")); - SPI.begin(); //Needed if SD is disabled + //Do not start Serial1 before productionTest() otherwise the pin configuration gets overwritten + //and subsequent Serial1.begin's don't restore the pins to UART mode... + productionTest(); //Check if we need to go into production test mode + //We need to manually restore the Serial1 TX and RX pins after they were changed by productionTest() + configureSerial1TxRx(); + + Serial.begin(115200); //Default for initial debug messages if necessary + Serial1.begin(115200); //Default for initial debug messages if necessary + //pinMode(PIN_LOGIC_DEBUG, OUTPUT); // Debug pin to assist tracking down slippery mux bugs //digitalWrite(PIN_LOGIC_DEBUG, HIGH); // Use the worst case power on delay for the Qwiic bus for now as we don't yet know what sensors are connected // (worstCaseQwiicPowerOnDelay is defined in settings.h) qwiicPowerOnDelayMillis = worstCaseQwiicPowerOnDelay; - + + EEPROM.init(); + beginQwiic(); // Turn the qwiic power on as early as possible beginSD(); //285 - 293ms - enableCIPOpullUp(); // Enable CIPO pull-up after beginSD + enableCIPOpullUp(); // Enable CIPO pull-up _after_ beginSD loadSettings(); //50 - 250ms if (settings.useTxRxPinsForTerminal == true) { - SerialLog.begin(settings.serialTerminalBaudRate); // Restart the serial port + Serial1.flush(); //Complete any previous prints at the previous baud rate + Serial1.begin(settings.serialTerminalBaudRate); // Restart the serial port } else { - SerialLog.end(); // Stop the SerialLog port + Serial1.flush(); //Complete any previous prints + Serial1.end(); // Stop the SerialLog port } Serial.flush(); //Complete any previous prints Serial.begin(settings.serialTerminalBaudRate); - + SerialPrintf3("Artemis OpenLog v%d.%d\r\n", FIRMWARE_VERSION_MAJOR, FIRMWARE_VERSION_MINOR); if (settings.useGPIO32ForStopLogging == true) @@ -361,7 +390,10 @@ void setup() { SerialPrintln(F("Stop Logging is enabled. Pull GPIO pin 32 to GND to stop logging.")); pinMode(PIN_STOP_LOGGING, INPUT_PULLUP); delay(1); // Let the pin stabilize - attachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING), stopLoggingISR, FALLING); // Enable the interrupt + attachInterrupt(PIN_STOP_LOGGING, stopLoggingISR, FALLING); // Enable the interrupt + am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + pin_config(PinName(PIN_STOP_LOGGING), intPinConfig); // Make sure the pull-up does actually stay enabled stopLoggingSeen = false; // Make sure the flag is clear } @@ -369,16 +401,20 @@ void setup() { { pinMode(PIN_TRIGGER, INPUT_PULLUP); delay(1); // Let the pin stabilize + am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; if (settings.fallingEdgeTrigger == true) { SerialPrintln(F("Falling-edge triggering is enabled. Sensor data will be logged on a falling edge on GPIO pin 11.")); - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, FALLING); // Enable the interrupt + attachInterrupt(PIN_TRIGGER, triggerPinISR, FALLING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; } else { SerialPrintln(F("Rising-edge triggering is enabled. Sensor data will be logged on a rising edge on GPIO pin 11.")); - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, RISING); // Enable the interrupt + attachInterrupt(PIN_TRIGGER, triggerPinISR, RISING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; } + pin_config(PinName(PIN_TRIGGER), intPinConfig); // Make sure the pull-up does actually stay enabled triggerEdgeSeen = false; // Make sure the flag is clear } @@ -419,10 +455,10 @@ void setup() { loadDeviceSettingsFromFile(); //Load config settings into node list configureQwiicDevices(); //Apply config settings to each device in the node list int deviceCount = printOnlineDevice(); // Pretty-print the online devices - + if ((deviceCount == 0) && (settings.resetOnZeroDeviceCount == true)) // Check for resetOnZeroDeviceCount { - if ((Serial.available()) || ((settings.useTxRxPinsForTerminal == true) && (SerialLog.available()))) + if ((Serial.available()) || ((settings.useTxRxPinsForTerminal == true) && (Serial1.available()))) menuMain(); //Present user menu - in case the user wants to disable resetOnZeroDeviceCount else { @@ -439,17 +475,12 @@ void setup() { //If we are sleeping between readings then we cannot rely on millis() as it is powered down //Use RTC instead - if (((settings.useGPIO11ForTrigger == false) && (settings.usBetweenReadings >= maxUsBeforeSleep)) - || (settings.useGPIO11ForFastSlowLogging == true) - || (settings.useRTCForFastSlowLogging == true)) - measurementStartTime = rtcMillis(); - else - measurementStartTime = millis(); - - //SerialPrintf2("Setup time: %.02f ms\r\n", (micros() - startTime) / 1000.0); + measurementStartTime = bestMillis(); digitalWrite(PIN_STAT_LED, LOW); // Turn the STAT LED off now that everything is configured + lastAwakeTimeMillis = rtcMillis(); + //If we are immediately going to go to sleep after the first reading then //first present the user with the config menu in case they need to change something if (checkIfItIsTimeToSleep()) @@ -457,10 +488,10 @@ void setup() { } void loop() { - + checkBattery(); // Check for low battery - if ((Serial.available()) || ((settings.useTxRxPinsForTerminal == true) && (SerialLog.available()))) + if ((Serial.available()) || ((settings.useTxRxPinsForTerminal == true) && (Serial1.available()))) menuMain(); //Present user menu if (settings.logSerial == true && online.serialLogging == true && settings.useTxRxPinsForTerminal == false) @@ -468,15 +499,15 @@ void loop() { size_t timestampCharsLeftToWrite = strlen(serialTimestamp); //SerialPrintf2("timestampCharsLeftToWrite is %d\r\n", timestampCharsLeftToWrite); //SerialFlush(); - - if (SerialLog.available() || (timestampCharsLeftToWrite > 0)) + + if (Serial1.available() || (timestampCharsLeftToWrite > 0)) { - while (SerialLog.available() || (timestampCharsLeftToWrite > 0)) + while (Serial1.available() || (timestampCharsLeftToWrite > 0)) { if (timestampCharsLeftToWrite > 0) // Based on code written by @DennisMelamed in PR #70 { incomingBuffer[incomingBufferSpot++] = serialTimestamp[0]; // Add a timestamp character to incomingBuffer - + for (size_t i = 0; i < timestampCharsLeftToWrite; i++) { serialTimestamp[i] = serialTimestamp[i+1]; // Shuffle the remaining chars along by one @@ -486,7 +517,7 @@ void loop() { } else { - incomingBuffer[incomingBufferSpot++] = SerialLog.read(); + incomingBuffer[incomingBufferSpot++] = Serial1.read(); //Get the RTC timestamp if we just received the timestamp token if (settings.timestampSerial && (incomingBuffer[incomingBufferSpot-1] == settings.timeStampToken)) @@ -497,7 +528,7 @@ void loop() { serialTimestamp[strlen(serialTimestamp) - 1] = 0x0A; // Change the final comma of the timestamp to a Line Feed } } - + if (incomingBufferSpot == sizeof(incomingBuffer)) { digitalWrite(PIN_STAT_LED, HIGH); //Toggle stat LED to indicating log recording @@ -509,12 +540,14 @@ void loop() { checkBattery(); } - lastSeriaLogSyncTime = millis(); //Reset the last sync time to now + //If we are sleeping between readings then we cannot rely on millis() as it is powered down + //Use RTC instead + lastSeriaLogSyncTime = bestMillis(); //Reset the last sync time to now newSerialData = true; } else if (newSerialData == true) { - if ((millis() - lastSeriaLogSyncTime) > MAX_IDLE_TIME_MSEC) //If we haven't received any characters recently then sync log file + if ((bestMillis() - lastSeriaLogSyncTime) > MAX_IDLE_TIME_MSEC) //If we haven't received any characters recently then sync log file { if (incomingBufferSpot > 0) { @@ -530,13 +563,13 @@ void loop() { } newSerialData = false; - lastSeriaLogSyncTime = millis(); //Reset the last sync time to now + lastSeriaLogSyncTime = bestMillis(); //Reset the last sync time to now printDebug("Total chars received: " + (String)charsReceived + "\r\n"); } } } - //micros() resets to 0 during sleep so only test if we are not sleeping + //In v2.1 of the core micros() becomes corrupted during deep sleep so only test if we are not sleeping if (settings.usBetweenReadings < maxUsBeforeSleep) { if ((micros() - lastReadTime) >= settings.usBetweenReadings) @@ -606,7 +639,7 @@ void loop() { //Output to TX pin if ((settings.outputSerial == true) && (online.serialOutput == true)) - SerialLog.print(outputData); //Print to TX pin + Serial1.print(outputData); //Print to TX pin //Record to SD if (settings.logData == true) @@ -624,9 +657,9 @@ void loop() { } //Force sync every 500ms - if (millis() - lastDataLogSyncTime > 500) + if (bestMillis() - lastDataLogSyncTime > 500) { - lastDataLogSyncTime = millis(); + lastDataLogSyncTime = bestMillis(); sensorDataFile.sync(); if (settings.frequentFileAccessTimestamps == true) updateDataFileAccess(&sensorDataFile); // Update the file access time & date @@ -684,7 +717,7 @@ void loop() { { // Check if we have been awake long enough (millis is reset to zero when waking from sleep) // goToSleep will automatically compensate for how long we have been awake - if (millis() < settings.minimumAwakeTimeMillis) + if ((bestMillis() - lastAwakeTimeMillis) < settings.minimumAwakeTimeMillis) return; // Too early to sleep - leave sleepAfterRead set true } @@ -701,7 +734,7 @@ uint32_t howLongToSleepFor(void) //We need to be careful with the multiply as we will overflow uint32_t if msToSleep is > 131072 //goToSleep will automatically compensate for how long we have been awake - + uint32_t msToSleep; if (checkSleepOnFastSlowPin()) @@ -731,7 +764,7 @@ uint32_t howLongToSleepFor(void) { msToSleep = (uint32_t)(settings.usBetweenReadings / 1000ULL); // Sleep for usBetweenReadings } - + uint32_t sysTicksToSleep; if (msToSleep < 131000) { @@ -787,7 +820,7 @@ bool checkSleepOnRTCTime(void) { myRTC.getTime(); // Get the RTC time int minutesOfDay = (myRTC.hour * 60) + myRTC.minute; - + if (settings.slowLoggingStartMOD > settings.slowLoggingStopMOD) // If slow logging starts later than the stop time (i.e. slow over midnight) { if ((minutesOfDay >= settings.slowLoggingStartMOD) || (minutesOfDay < settings.slowLoggingStopMOD)) @@ -806,15 +839,54 @@ bool checkSleepOnRTCTime(void) void beginQwiic() { pinMode(PIN_QWIIC_POWER, OUTPUT); + pin_config(PinName(PIN_QWIIC_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured qwiicPowerOn(); qwiic.begin(); - qwiic.setPullups(settings.qwiicBusPullUps); //Just to make it really clear what pull-ups are being used, set pullups here. + setQwiicPullups(settings.qwiicBusPullUps); //Just to make it really clear what pull-ups are being used, set pullups here. +} + +void setQwiicPullups(uint32_t qwiicBusPullUps) +{ + //Change SCL and SDA pull-ups manually using pin_config + am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM1_SCL; + am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM1_SDA; + + if (qwiicBusPullUps == 0) + { + sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // No pull-ups + sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; + } + else if (qwiicBusPullUps == 1) + { + sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; // Use 1K5 pull-ups + sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; + } + else if (qwiicBusPullUps == 6) + { + sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; // Use 6K pull-ups + sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_6K; + } + else if (qwiicBusPullUps == 12) + { + sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; // Use 12K pull-ups + sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_12K; + } + else + { + sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; // Use 24K pull-ups + sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_24K; + } + + pin_config(PinName(PIN_QWIIC_SCL), sclPinCfg); + pin_config(PinName(PIN_QWIIC_SDA), sdaPinCfg); } void beginSD() { pinMode(PIN_MICROSD_POWER, OUTPUT); + pin_config(PinName(PIN_MICROSD_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured pinMode(PIN_MICROSD_CHIP_SELECT, OUTPUT); + pin_config(PinName(PIN_MICROSD_CHIP_SELECT), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_MICROSD_CHIP_SELECT, HIGH); //Be sure SD is deselected if (settings.enableSD == true) @@ -822,7 +894,7 @@ void beginSD() // For reasons I don't understand, we seem to have to wait for at least 1ms after SPI.begin before we call microSDPowerOn. // If you comment the next line, the Artemis resets at microSDPowerOn when beginSD is called from wakeFromSleep... // But only on one of my V10 red boards. The second one I have doesn't seem to need the delay!? - delay(1); + delay(5); microSDPowerOn(); @@ -869,25 +941,37 @@ void beginSD() } } -void enableCIPOpullUp() +void enableCIPOpullUp() // updated for v2.1.0 of the Apollo3 core { - //Add CIPO pull-up - ap3_err_t retval = AP3_OK; - am_hal_gpio_pincfg_t cipoPinCfg = AP3_GPIO_DEFAULT_PINCFG; - cipoPinCfg.uFuncSel = AM_HAL_PIN_6_M0MISO; - cipoPinCfg.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA; - cipoPinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL; - cipoPinCfg.uIOMnum = AP3_SPI_IOM; + //Add 1K5 pull-up on CIPO + am_hal_gpio_pincfg_t cipoPinCfg = g_AM_BSP_GPIO_IOM0_MISO; cipoPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; - padMode(MISO, cipoPinCfg, &retval); - if (retval != AP3_OK) - printDebug(F("Setting CIPO padMode failed!")); + pin_config(PinName(PIN_SPI_CIPO), cipoPinCfg); +} + +void disableCIPOpullUp() // updated for v2.1.0 of the Apollo3 core +{ + am_hal_gpio_pincfg_t cipoPinCfg = g_AM_BSP_GPIO_IOM0_MISO; + pin_config(PinName(PIN_SPI_CIPO), cipoPinCfg); +} + +void configureSerial1TxRx(void) // Configure pins 12 and 13 for UART1 TX and RX +{ + am_hal_gpio_pincfg_t pinConfigTx = g_AM_BSP_GPIO_COM_UART_TX; + pinConfigTx.uFuncSel = AM_HAL_PIN_12_UART1TX; + pin_config(PinName(BREAKOUT_PIN_TX), pinConfigTx); + am_hal_gpio_pincfg_t pinConfigRx = g_AM_BSP_GPIO_COM_UART_RX; + pinConfigRx.uFuncSel = AM_HAL_PIN_13_UART1RX; + pinConfigRx.ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK; // Put a weak pull-up on the Rx pin + pin_config(PinName(BREAKOUT_PIN_RX), pinConfigRx); } void beginIMU() { pinMode(PIN_IMU_POWER, OUTPUT); + pin_config(PinName(PIN_IMU_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured pinMode(PIN_IMU_CHIP_SELECT, OUTPUT); + pin_config(PinName(PIN_IMU_CHIP_SELECT), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_IMU_CHIP_SELECT, HIGH); //Be sure IMU is deselected if (settings.enableIMU == true && settings.logMaxRate == false) @@ -948,7 +1032,7 @@ void beginIMU() } bool success = true; - + //Check if we are using the DMP if (settings.imuUseDMP == false) { @@ -958,7 +1042,7 @@ void beginIMU() { SerialPrintln(F("Error: Could not startup the IMU in non-DMP mode!")); success = false; - } + } //Update the full scale and DLPF settings retval = myICM.enableDLPF(ICM_20948_Internal_Acc, settings.imuAccDLPF); if (retval != ICM_20948_Stat_Ok) @@ -1177,7 +1261,10 @@ void beginSerialLogging() updateDataFileCreate(&serialDataFile); // Update the file create time & date - SerialLog.begin(settings.serialLogBaudRate); + //We need to manually restore the Serial1 TX and RX pins + configureSerial1TxRx(); + + Serial1.begin(settings.serialLogBaudRate); online.serialLogging = true; } @@ -1189,7 +1276,10 @@ void beginSerialOutput() { if (settings.outputSerial == true) { - SerialLog.begin(settings.serialLogBaudRate); // (Re)start the serial port + //We need to manually restore the Serial1 TX and RX pins + configureSerial1TxRx(); + + Serial1.begin(settings.serialLogBaudRate); // (Re)start the serial port online.serialOutput = true; } else @@ -1238,6 +1328,12 @@ extern "C" void am_stimer_cmpr6_isr(void) } } +//Power Loss ISR +void powerLossISR(void) +{ + powerLossSeen = true; +} + //Stop Logging ISR void stopLoggingISR(void) { @@ -1255,7 +1351,7 @@ void SerialFlush(void) Serial.flush(); if (settings.useTxRxPinsForTerminal == true) { - SerialLog.flush(); + Serial1.flush(); } } @@ -1268,8 +1364,7 @@ void SerialPrint(const char *line) void SerialPrint(const __FlashStringHelper *line) { - DoSerialPrint([](const char *ptr) {return (char) pgm_read_byte_near(ptr);}, - (const char*) line); + DoSerialPrint([](const char *ptr) {return (char) pgm_read_byte_near(ptr);}, (const char*) line); } void SerialPrintln(const char *line) @@ -1279,8 +1374,7 @@ void SerialPrintln(const char *line) void SerialPrintln(const __FlashStringHelper *line) { - DoSerialPrint([](const char *ptr) {return (char) pgm_read_byte_near(ptr);}, - (const char*) line, true); + DoSerialPrint([](const char *ptr) {return (char) pgm_read_byte_near(ptr);}, (const char*) line, true); } void DoSerialPrint(char (*funct)(const char *), const char *string, bool newLine) @@ -1291,13 +1385,13 @@ void DoSerialPrint(char (*funct)(const char *), const char *string, bool newLine { Serial.print(ch); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print(ch); + Serial1.print(ch); } if (newLine) { Serial.println(); if (settings.useTxRxPinsForTerminal == true) - SerialLog.println(); + Serial1.println(); } } diff --git a/Firmware/OpenLog_Artemis/Sensors.ino b/Firmware/OpenLog_Artemis/Sensors.ino index db337ee..c5eb695 100644 --- a/Firmware/OpenLog_Artemis/Sensors.ino +++ b/Firmware/OpenLog_Artemis/Sensors.ino @@ -5,6 +5,9 @@ void getData() measurementTotal++; char tempData[50]; + char tempData1[16]; + char tempData2[16]; + char tempData3[16]; outputData[0] = '\0'; //Clear string contents if (settings.logRTC) @@ -22,7 +25,8 @@ void getData() if (settings.logAnalogVoltages == true) { float voltage = analog11 * 2 / 16384.0; - sprintf(tempData, "%.2f,", voltage); + olaftoa(voltage, tempData1, 2, sizeof(tempData1) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); } else sprintf(tempData, "%d,", analog11); @@ -37,7 +41,8 @@ void getData() if (settings.logAnalogVoltages == true) { float voltage = analog12 * 2 / 16384.0; - sprintf(tempData, "%.2f,", voltage); + olaftoa(voltage, tempData1, 2, sizeof(tempData1) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); } else sprintf(tempData, "%d,", analog12); @@ -52,7 +57,8 @@ void getData() if (settings.logAnalogVoltages == true) { float voltage = analog13 * 2 / 16384.0; - sprintf(tempData, "%.2f,", voltage); + olaftoa(voltage, tempData1, 2, sizeof(tempData1) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); } else sprintf(tempData, "%d,", analog13); @@ -67,7 +73,8 @@ void getData() if (settings.logAnalogVoltages == true) { float voltage = analog32 * 2 / 16384.0; - sprintf(tempData, "%.2f,", voltage); + olaftoa(voltage, tempData1, 2, sizeof(tempData1) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); } else sprintf(tempData, "%d,", analog32); @@ -78,7 +85,8 @@ void getData() if (settings.logVIN) { float voltage = readVIN(); - sprintf(tempData, "%.2f,", voltage); + olaftoa(voltage, tempData1, 2, sizeof(tempData1) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } @@ -91,27 +99,37 @@ void getData() if (myICM.dataReady()) { //printDebug("getData: myICM.dataReady = " + (String)myICM.dataReady() + "\r\n"); - + myICM.getAGMT(); //Update values - + if (settings.logIMUAccel) { - sprintf(tempData, "%.2f,%.2f,%.2f,", myICM.accX(), myICM.accY(), myICM.accZ()); + olaftoa(myICM.accX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); + olaftoa(myICM.accY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); + olaftoa(myICM.accZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); + sprintf(tempData, "%s,%s,%s,", tempData1, tempData2, tempData3); strcat(outputData, tempData); } if (settings.logIMUGyro) { - sprintf(tempData, "%.2f,%.2f,%.2f,", myICM.gyrX(), myICM.gyrY(), myICM.gyrZ()); + olaftoa(myICM.gyrX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); + olaftoa(myICM.gyrY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); + olaftoa(myICM.gyrZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); + sprintf(tempData, "%s,%s,%s,", tempData1, tempData2, tempData3); strcat(outputData, tempData); } if (settings.logIMUMag) { - sprintf(tempData, "%.2f,%.2f,%.2f,", myICM.magX(), myICM.magY(), myICM.magZ()); + olaftoa(myICM.magX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); + olaftoa(myICM.magY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); + olaftoa(myICM.magZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); + sprintf(tempData, "%s,%s,%s,", tempData1, tempData2, tempData3); strcat(outputData, tempData); } if (settings.logIMUTemp) { - sprintf(tempData, "%.2f,", myICM.temp()); + olaftoa(myICM.temp(), tempData1, 2, sizeof(tempData1) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -129,14 +147,18 @@ void getData() } if (settings.imuLogDMPQuat6) { - sprintf(tempData, "%.5f,%.5f,%.5f,", ((double)dmpData.Quat6.Data.Q1) / 1073741824.0, - ((double)dmpData.Quat6.Data.Q2) / 1073741824.0, ((double)dmpData.Quat6.Data.Q3) / 1073741824.0); + olaftoa(((double)dmpData.Quat6.Data.Q1) / 1073741824.0, tempData1, 5, sizeof(tempData1) / sizeof(char)); + olaftoa(((double)dmpData.Quat6.Data.Q2) / 1073741824.0, tempData2, 5, sizeof(tempData2) / sizeof(char)); + olaftoa(((double)dmpData.Quat6.Data.Q3) / 1073741824.0, tempData3, 5, sizeof(tempData3) / sizeof(char)); + sprintf(tempData, "%s,%s,%s,", tempData1, tempData2, tempData3); strcat(outputData, tempData); } if (settings.imuLogDMPQuat9) { - sprintf(tempData, "%.5f,%.5f,%.5f,%d,", ((double)dmpData.Quat9.Data.Q1) / 1073741824.0, - ((double)dmpData.Quat9.Data.Q2) / 1073741824.0, ((double)dmpData.Quat9.Data.Q3) / 1073741824.0, dmpData.Quat9.Data.Accuracy); + olaftoa(((double)dmpData.Quat9.Data.Q1) / 1073741824.0, tempData1, 5, sizeof(tempData1) / sizeof(char)); + olaftoa(((double)dmpData.Quat9.Data.Q2) / 1073741824.0, tempData2, 5, sizeof(tempData2) / sizeof(char)); + olaftoa(((double)dmpData.Quat9.Data.Q3) / 1073741824.0, tempData3, 5, sizeof(tempData3) / sizeof(char)); + sprintf(tempData, "%s,%s,%s,%d,", tempData1, tempData2, tempData3, dmpData.Quat9.Data.Accuracy); strcat(outputData, tempData); } if (settings.imuLogDMPAccel) @@ -166,21 +188,14 @@ void getData() //If we are sleeping between readings then we cannot rely on millis() as it is powered down //Use RTC instead - if (((settings.useGPIO11ForTrigger == false) && (settings.usBetweenReadings >= maxUsBeforeSleep)) - || (settings.useGPIO11ForFastSlowLogging == true) - || (settings.useRTCForFastSlowLogging == true)) - { - currentMillis = rtcMillis(); - } + currentMillis = bestMillis(); + float actualRate; + if ((currentMillis - measurementStartTime) < 1) // Avoid divide by zero + actualRate = 0.0; else - { - //Calculate the actual update rate based on the sketch start time and the - //number of updates we've completed. - currentMillis = millis(); - } - - float actualRate = measurementCount * 1000.0 / (currentMillis - measurementStartTime); - sprintf(tempData, "%.02f,", actualRate); //Hz + actualRate = measurementCount * 1000.0 / (currentMillis - measurementStartTime); + olaftoa(actualRate, tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } @@ -200,6 +215,7 @@ void getData() void gatherDeviceValues() { char tempData[100]; + char tempData1[20]; //Step through list, printing values as we go node *temp = head; @@ -226,7 +242,8 @@ void gatherDeviceValues() if (nodeSetting->log == true) { float currentWeight = nodeDevice->getWeight(false, nodeSetting->averageAmount); //Do not allow negative weights, take average of X readings - sprintf(tempData, "%.*f,", nodeSetting->decimalPlaces, currentWeight); + olaftoa(currentWeight, tempData1, nodeSetting->decimalPlaces, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -258,7 +275,7 @@ void gatherDeviceValues() break; case DEVICE_GPS_UBLOX: { - qwiic.setPullups(0); //Disable pullups to minimize CRC issues + setQwiicPullups(0); //Disable pullups to minimize CRC issues SFE_UBLOX_GNSS *nodeDevice = (SFE_UBLOX_GNSS *)temp->classPtr; struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; @@ -267,10 +284,27 @@ void gatherDeviceValues() { if (nodeSetting->logDate) { + char gnssDayStr[3]; + char gnssMonthStr[3]; + char gnssYearStr[5]; + int gnssDay = nodeDevice->getDay(); + int gnssMonth = nodeDevice->getMonth(); + int gnssYear = nodeDevice->getYear(); + if (gnssDay < 10) + sprintf(gnssDayStr, "0%d", gnssDay); + else + sprintf(gnssDayStr, "%d", gnssDay); + if (gnssMonth < 10) + sprintf(gnssMonthStr, "0%d", gnssMonth); + else + sprintf(gnssMonthStr, "%d", gnssMonth); + sprintf(gnssYearStr, "%d", gnssYear); if (settings.americanDateStyle == true) - sprintf(tempData, "%02d/%02d/%d,", nodeDevice->getMonth(), nodeDevice->getDay(), nodeDevice->getYear()); + { + sprintf(tempData, "%s/%s/%s,", gnssMonthStr, gnssDayStr, gnssYearStr); + } else - sprintf(tempData, "%02d/%02d/%d,", nodeDevice->getDay(), nodeDevice->getMonth(), nodeDevice->getYear()); + sprintf(tempData, "%s/%s/%s,", gnssDayStr, gnssMonthStr, gnssYearStr); strcat(outputData, tempData); } if (nodeSetting->logTime) @@ -278,7 +312,35 @@ void gatherDeviceValues() int adjustedHour = nodeDevice->getHour(); if (settings.hour24Style == false) if (adjustedHour > 12) adjustedHour -= 12; - sprintf(tempData, "%02d:%02d:%02d.%03d,", adjustedHour, nodeDevice->getMinute(), nodeDevice->getSecond(), nodeDevice->getMillisecond()); + + char gnssHourStr[3]; + char gnssMinStr[3]; + char gnssSecStr[3]; + char gnssMillisStr[4]; + int gnssMin = nodeDevice->getMinute(); + int gnssSec = nodeDevice->getSecond(); + int gnssMillis = nodeDevice->getMillisecond(); + + if (adjustedHour < 10) + sprintf(gnssHourStr, "0%d", adjustedHour); + else + sprintf(gnssHourStr, "%d", adjustedHour); + if (gnssMin < 10) + sprintf(gnssMinStr, "0%d", gnssMin); + else + sprintf(gnssMinStr, "%d", gnssMin); + if (gnssSec < 10) + sprintf(gnssSecStr, "0%d", gnssSec); + else + sprintf(gnssSecStr, "%d", gnssSec); + if (gnssMillis < 10) + sprintf(gnssMillisStr, "00%d", gnssMillis); + else if (gnssMillis < 100) + sprintf(gnssMillisStr, "0%d", gnssMillis); + else + sprintf(gnssMillisStr, "%d", gnssMillis); + + sprintf(tempData, "%s:%s:%s.%s,", gnssHourStr, gnssMinStr, gnssSecStr, gnssMillisStr); strcat(outputData, tempData); } if (nodeSetting->logPosition) @@ -333,7 +395,7 @@ void gatherDeviceValues() } } - qwiic.setPullups(settings.qwiicBusPullUps); //Re-enable pullups + setQwiicPullups(settings.qwiicBusPullUps); //Re-enable pullups } break; case DEVICE_PROXIMITY_VCNL4040: @@ -366,7 +428,8 @@ void gatherDeviceValues() { if (nodeSetting->logTemperature) { - sprintf(tempData, "%.04f,", nodeDevice->readTempC()); //Resolution to 0.0078°C, accuracy of 0.1°C + olaftoa(nodeDevice->readTempC(), tempData1, 4, sizeof(tempData) / sizeof(char)); //Resolution to 0.0078°C, accuracy of 0.1°C + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -381,12 +444,14 @@ void gatherDeviceValues() { if (nodeSetting->logPressure) { - sprintf(tempData, "%.02f,", nodeDevice->getPressure()); + olaftoa(nodeDevice->getPressure(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->getTemperature()); + olaftoa(nodeDevice->getTemperature(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -400,12 +465,14 @@ void gatherDeviceValues() { if (nodeSetting->logPressure) { - sprintf(tempData, "%.02f,", nodeDevice->getPressure_hPa()); + olaftoa(nodeDevice->getPressure_hPa(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->getTemperature_degC()); + olaftoa(nodeDevice->getTemperature_degC(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -419,22 +486,26 @@ void gatherDeviceValues() { if (nodeSetting->logPressure) { - sprintf(tempData, "%.02f,", nodeDevice->readFloatPressure()); + olaftoa(nodeDevice->readFloatPressure(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logHumidity) { - sprintf(tempData, "%.02f,", nodeDevice->readFloatHumidity()); + olaftoa(nodeDevice->readFloatHumidity(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logAltitude) { - sprintf(tempData, "%.02f,", nodeDevice->readFloatAltitudeMeters()); + olaftoa(nodeDevice->readFloatAltitudeMeters(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->readTempC()); + olaftoa(nodeDevice->readTempC(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -448,17 +519,20 @@ void gatherDeviceValues() { if (nodeSetting->logUVA) { - sprintf(tempData, "%.02f,", nodeDevice->uva()); + olaftoa(nodeDevice->uva(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logUVB) { - sprintf(tempData, "%.02f,", nodeDevice->uvb()); + olaftoa(nodeDevice->uvb(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logUVIndex) { - sprintf(tempData, "%.02f,", nodeDevice->index()); + olaftoa(nodeDevice->index(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -530,12 +604,14 @@ void gatherDeviceValues() } if (nodeSetting->logHumidity) { - sprintf(tempData, "%.02f,", nodeDevice->getHumidity()); + olaftoa(nodeDevice->getHumidity(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->getTemperature()); + olaftoa(nodeDevice->getTemperature(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -549,17 +625,20 @@ void gatherDeviceValues() { if (nodeSetting->logHumidity) { - sprintf(tempData, "%.02f,", nodeDevice->getHumidity()); + olaftoa(nodeDevice->getHumidity(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logPressure) { - sprintf(tempData, "%.02f,", nodeDevice->getPressure()); + olaftoa(nodeDevice->getPressure(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->getTemperature()); + olaftoa(nodeDevice->getTemperature(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -573,12 +652,14 @@ void gatherDeviceValues() { if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->getThermocoupleTemp()); + olaftoa(nodeDevice->getThermocoupleTemp(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logAmbientTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->getAmbientTemp()); + olaftoa(nodeDevice->getAmbientTemp(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -592,12 +673,14 @@ void gatherDeviceValues() { if (nodeSetting->logHumidity) { - sprintf(tempData, "%.02f,", nodeDevice->getHumidity()); + olaftoa(nodeDevice->getHumidity(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->getTemperature()); + olaftoa(nodeDevice->getTemperature(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -612,12 +695,14 @@ void gatherDeviceValues() nodeDevice->update(); if (nodeSetting->logHumidity) { - sprintf(tempData, "%.02f,", nodeDevice->toPercent()); + olaftoa(nodeDevice->toPercent(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->toDegC()); + olaftoa(nodeDevice->toDegC(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -667,20 +752,23 @@ void gatherDeviceValues() } else nodeDevice->setDataRate(ADS122C04_DATA_RATE_20SPS); // Default to 20Hz - + if (nodeSetting->logCentigrade) { - sprintf(tempData, "%.03f,", nodeDevice->readPT100Centigrade()); + olaftoa(nodeDevice->readPT100Centigrade(), tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logFahrenheit) { - sprintf(tempData, "%.03f,", nodeDevice->readPT100Fahrenheit()); + olaftoa(nodeDevice->readPT100Fahrenheit(), tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logInternalTemperature) { - sprintf(tempData, "%.03f,", nodeDevice->readInternalTemperature()); + olaftoa(nodeDevice->readInternalTemperature(), tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logRawVoltage) @@ -699,37 +787,44 @@ void gatherDeviceValues() { if (nodeSetting->usePSI) { - sprintf(tempData, "%.04f,", nodeDevice->readPressure()); + olaftoa(nodeDevice->readPressure(), tempData1, 4, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->usePA) { - sprintf(tempData, "%.01f,", nodeDevice->readPressure(PA)); + olaftoa(nodeDevice->readPressure(PA), tempData1, 1, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->useKPA) { - sprintf(tempData, "%.04f,", nodeDevice->readPressure(KPA)); + olaftoa(nodeDevice->readPressure(KPA), tempData1, 4, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->useTORR) { - sprintf(tempData, "%.03f,", nodeDevice->readPressure(TORR)); + olaftoa(nodeDevice->readPressure(TORR), tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->useINHG) { - sprintf(tempData, "%.04f,", nodeDevice->readPressure(INHG)); + olaftoa(nodeDevice->readPressure(INHG), tempData1, 4, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->useATM) { - sprintf(tempData, "%.06f,", nodeDevice->readPressure(ATM)); + olaftoa(nodeDevice->readPressure(ATM), tempData1, 6, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->useBAR) { - sprintf(tempData, "%.06f,", nodeDevice->readPressure(BAR)); + olaftoa(nodeDevice->readPressure(BAR), tempData1, 6, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -743,17 +838,20 @@ void gatherDeviceValues() { if (nodeSetting->logPM1) { - sprintf(tempData, "%.02f,", nodeDevice->getPM1_0()); + olaftoa(nodeDevice->getPM1_0(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logPM25) { - sprintf(tempData, "%.02f,", nodeDevice->getPM2_5()); + olaftoa(nodeDevice->getPM2_5(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logPM10) { - sprintf(tempData, "%.02f,", nodeDevice->getPM10()); + olaftoa(nodeDevice->getPM10(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logPC05) @@ -838,12 +936,14 @@ void gatherDeviceValues() } if (nodeSetting->logPressure) { - sprintf(tempData, "%.02f,", pressure); + olaftoa(pressure, tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", temperature); + olaftoa(temperature, tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -861,68 +961,74 @@ void gatherDeviceValues() } if (nodeSetting->logPressure) { - sprintf(tempData, "%.02f,", nodeDevice->pressure(nodeSetting->conversion)); + olaftoa(nodeDevice->pressure(nodeSetting->conversion), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logTemperature) { - sprintf(tempData, "%.02f,", nodeDevice->temperature()); + olaftoa(nodeDevice->temperature(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logDepth) { - sprintf(tempData, "%.03f,", nodeDevice->depth()); + olaftoa(nodeDevice->depth(), tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } if (nodeSetting->logAltitude) { - sprintf(tempData, "%.02f,", nodeDevice->altitude()); + olaftoa(nodeDevice->altitude(), tempData1, 2, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); + strcat(outputData, tempData); + } + } + } + break; + case DEVICE_QWIIC_BUTTON: + { + QwiicButton *nodeDevice = (QwiicButton *)temp->classPtr; + struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; + if (nodeSetting->log == true) + { + long pressedPopped = 0; + while (nodeDevice->isPressedQueueEmpty() == false) + { + pressedPopped = nodeDevice->popPressedQueue(); + } + if (nodeSetting->logPressed) + { + olaftoa(((float)pressedPopped) / 1000.0, tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); + strcat(outputData, tempData); + } + + long clickedPopped = 0; + while (nodeDevice->isClickedQueueEmpty() == false) + { + clickedPopped = nodeDevice->popClickedQueue(); + nodeSetting->ledState ^= 1; // Toggle nodeSetting->ledState on _every_ click (not just the most recent) + } + if (nodeSetting->logClicked) + { + olaftoa(((float)clickedPopped) / 1000.0, tempData1, 3, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); + strcat(outputData, tempData); + } + + if (nodeSetting->toggleLEDOnClick) + { + if (nodeSetting->ledState) + nodeDevice->LEDon(nodeSetting->ledBrightness); + else + nodeDevice->LEDoff(); + sprintf(tempData, "%d,", nodeSetting->ledState); strcat(outputData, tempData); } } } break; -// case DEVICE_QWIIC_BUTTON: -// { -// QwiicButton *nodeDevice = (QwiicButton *)temp->classPtr; -// struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; -// if (nodeSetting->log == true) -// { -// long pressedPopped = 0; -// while (nodeDevice->isPressedQueueEmpty() == false) -// { -// pressedPopped = nodeDevice->popPressedQueue(); -// } -// if (nodeSetting->logPressed) -// { -// sprintf(tempData, "%.03f,", ((float)pressedPopped) / 1000.0); // Record only the most recent press - that's the best we can do -// strcat(outputData, tempData); -// } -// -// long clickedPopped = 0; -// while (nodeDevice->isClickedQueueEmpty() == false) -// { -// clickedPopped = nodeDevice->popClickedQueue(); -// nodeSetting->ledState ^= 1; // Toggle nodeSetting->ledState on _every_ click (not just the most recent) -// } -// if (nodeSetting->logClicked) -// { -// sprintf(tempData, "%.03f,", ((float)clickedPopped) / 1000.0); // Record only the most recent click - that's the best we can do -// strcat(outputData, tempData); -// } -// -// if (nodeSetting->toggleLEDOnClick) -// { -// if (nodeSetting->ledState) -// nodeDevice->LEDon(nodeSetting->ledBrightness); -// else -// nodeDevice->LEDoff(); -// sprintf(tempData, "%d,", nodeSetting->ledState); -// strcat(outputData, tempData); -// } -// } -// } -// break; case DEVICE_BIO_SENSOR_HUB: { SparkFun_Bio_Sensor_Hub *nodeDevice = (SparkFun_Bio_Sensor_Hub *)temp->classPtr; @@ -961,7 +1067,8 @@ void gatherDeviceValues() } if (nodeSetting->logRValue) { - sprintf(tempData, "%.01f,", body.rValue); + olaftoa(body.rValue, tempData1, 1, sizeof(tempData) / sizeof(char)); + sprintf(tempData, "%s,", tempData1); strcat(outputData, tempData); } } @@ -1383,20 +1490,20 @@ void printHelperText(bool terminalOnly) } } break; -// case DEVICE_QWIIC_BUTTON: -// { -// struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; -// if (nodeSetting->log) -// { -// if (nodeSetting->logPressed) -// strcat(helperText, "pressS,"); -// if (nodeSetting->logClicked) -// strcat(helperText, "clickS,"); -// if (nodeSetting->toggleLEDOnClick) -// strcat(helperText, "LED,"); -// } -// } -// break; + case DEVICE_QWIIC_BUTTON: + { + struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; + if (nodeSetting->log) + { + if (nodeSetting->logPressed) + strcat(helperText, "pressS,"); + if (nodeSetting->logClicked) + strcat(helperText, "clickS,"); + if (nodeSetting->toggleLEDOnClick) + strcat(helperText, "LED,"); + } + } + break; case DEVICE_BIO_SENSOR_HUB: { struct_BIO_SENSOR_HUB *nodeSetting = (struct_BIO_SENSOR_HUB *)temp->configPtr; @@ -1461,7 +1568,10 @@ void setMaxI2CSpeed() //Check if i2cSpeed is lowered struct_uBlox *sensor = (struct_uBlox*)temp->configPtr; if (sensor->i2cSpeed == 100000) + { + //printDebug("setMaxI2CSpeed: sensor->i2cSpeed is 100000. Reducing maxSpeed to 100kHz\r\n"); maxSpeed = 100000; + } } temp = temp->next; @@ -1469,14 +1579,26 @@ void setMaxI2CSpeed() //If user wants to limit the I2C bus speed, do it here if (maxSpeed > settings.qwiicBusMaxSpeed) + { + //printDebug("setMaxI2CSpeed: maxSpeed is > settings.qwiicBusMaxSpeed. Reducing maxSpeed to " + (String)settings.qwiicBusMaxSpeed + "Hz\r\n"); maxSpeed = settings.qwiicBusMaxSpeed; + } - qwiic.setClock(maxSpeed); + if (maxSpeed > 200000) + { + printDebug("setMaxI2CSpeed: setting qwiic clock speed to " + (String)AM_HAL_IOM_400KHZ + "Hz\r\n"); + qwiic.setClock(AM_HAL_IOM_400KHZ); + } + else + { + printDebug("setMaxI2CSpeed: setting qwiic clock speed to " + (String)AM_HAL_IOM_100KHZ + "Hz\r\n"); + qwiic.setClock(AM_HAL_IOM_100KHZ); + } for (int i = 0; i < 100; i++) //Allow time for the speed to change { checkBattery(); delay(1); - } + } } //Read the VIN voltage diff --git a/Firmware/OpenLog_Artemis/autoDetect.ino b/Firmware/OpenLog_Artemis/autoDetect.ino index 9dd451b..47b7b06 100644 --- a/Firmware/OpenLog_Artemis/autoDetect.ino +++ b/Firmware/OpenLog_Artemis/autoDetect.ino @@ -255,12 +255,12 @@ bool addDevice(deviceType_e deviceType, uint8_t address, uint8_t muxAddress, uin temp->configPtr = new struct_MS5837; } break; -// case DEVICE_QWIIC_BUTTON: -// { -// temp->classPtr = new QwiicButton; -// temp->configPtr = new struct_QWIIC_BUTTON; -// } -// break; + case DEVICE_QWIIC_BUTTON: + { + temp->classPtr = new QwiicButton; + temp->configPtr = new struct_QWIIC_BUTTON; + } + break; case DEVICE_BIO_SENSOR_HUB: { temp->classPtr = new SparkFun_Bio_Sensor_Hub(32, 11, address); // Reset pin is 32, MFIO pin is 11 @@ -295,7 +295,7 @@ bool beginQwiicDevices() bool everythingStarted = true; waitForQwiicBusPowerDelay(); // Wait while the qwiic devices power up - if required - + qwiicPowerOnDelayMillis = settings.qwiicBusPowerUpDelayMs; // Set qwiicPowerOnDelayMillis to the _minimum_ defined by settings.qwiicBusPowerUpDelayMs. It will be increased if required. int numberOfSCD30s = 0; // Keep track of how many SCD30s we begin so we can delay before starting the second and subsequent ones @@ -312,13 +312,13 @@ bool beginQwiicDevices() while (temp != NULL) { openConnection(temp->muxAddress, temp->portNumber); //Connect to this device through muxes as needed - + if (settings.printDebugMessages == true) { SerialPrintf2("beginQwiicDevices: attempting to begin deviceType %s", getDeviceName(temp->deviceType)); SerialPrintf4(" at address 0x%02X using mux address 0x%02X and port number %d\r\n", temp->address, temp->muxAddress, temp->portNumber); } - + //Attempt to begin the device switch (temp->deviceType) { @@ -349,12 +349,13 @@ bool beginQwiicDevices() break; case DEVICE_GPS_UBLOX: { - qwiic.setPullups(0); //Disable pullups for u-blox comms. + setQwiicPullups(0); //Disable pullups for u-blox comms. SFE_UBLOX_GNSS *tempDevice = (SFE_UBLOX_GNSS *)temp->classPtr; struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; //Create a local pointer that points to same spot as node does if (nodeSetting->powerOnDelayMillis > qwiicPowerOnDelayMillis) qwiicPowerOnDelayMillis = nodeSetting->powerOnDelayMillis; // Increase qwiicPowerOnDelayMillis if required + if(settings.printGNSSDebugMessages == true) tempDevice->enableDebugging(); // Enable debug messages if required temp->online = tempDevice->begin(qwiic, temp->address); //Wire port, Address - qwiic.setPullups(settings.qwiicBusPullUps); //Re-enable pullups. + setQwiicPullups(settings.qwiicBusPullUps); //Re-enable pullups. } break; case DEVICE_PROXIMITY_VCNL4040: @@ -527,15 +528,15 @@ bool beginQwiicDevices() temp->online = true; } break; -// case DEVICE_QWIIC_BUTTON: -// { -// QwiicButton *tempDevice = (QwiicButton *)temp->classPtr; -// struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; //Create a local pointer that points to same spot as node does -// if (nodeSetting->powerOnDelayMillis > qwiicPowerOnDelayMillis) qwiicPowerOnDelayMillis = nodeSetting->powerOnDelayMillis; // Increase qwiicPowerOnDelayMillis if required -// if (tempDevice->begin(temp->address, qwiic) == true) //Address, Wire port. Returns true on success. -// temp->online = true; -// } -// break; + case DEVICE_QWIIC_BUTTON: + { + QwiicButton *tempDevice = (QwiicButton *)temp->classPtr; + struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; //Create a local pointer that points to same spot as node does + if (nodeSetting->powerOnDelayMillis > qwiicPowerOnDelayMillis) qwiicPowerOnDelayMillis = nodeSetting->powerOnDelayMillis; // Increase qwiicPowerOnDelayMillis if required + if (tempDevice->begin(temp->address, qwiic) == true) //Address, Wire port. Returns true on success. + temp->online = true; + } + break; case DEVICE_BIO_SENSOR_HUB: { SparkFun_Bio_Sensor_Hub *tempDevice = (SparkFun_Bio_Sensor_Hub *)temp->classPtr; @@ -657,7 +658,7 @@ void configureDevice(node * temp) break; case DEVICE_GPS_UBLOX: { - qwiic.setPullups(0); //Disable pullups for u-blox comms. + setQwiicPullups(0); //Disable pullups for u-blox comms. SFE_UBLOX_GNSS *sensor = (SFE_UBLOX_GNSS *)temp->classPtr; struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; @@ -667,7 +668,7 @@ void configureDevice(node * temp) sensor->saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the current ioPortsettings to flash and BBR sensor->setAutoPVT(nodeSetting->useAutoPVT); // Use autoPVT as required - + if (1000000ULL / settings.usBetweenReadings <= 1) //If we are slower than 1Hz logging rate // setNavigationFrequency expects a uint8_t to define the number of updates per second // So the slowest rate we can set with setNavigationFrequency is 1Hz @@ -678,7 +679,7 @@ void configureDevice(node * temp) else sensor->setNavigationFrequency(10); //Set nav freq to 10Hz. Max output depends on the module used. - qwiic.setPullups(settings.qwiicBusPullUps); //Re-enable pullups. + setQwiicPullups(settings.qwiicBusPullUps); //Re-enable pullups. } break; case DEVICE_PROXIMITY_VCNL4040: @@ -818,17 +819,17 @@ void configureDevice(node * temp) sensor->setFluidDensity(sensorSetting->fluidDensity); } break; -// case DEVICE_QWIIC_BUTTON: -// { -// QwiicButton *sensor = (QwiicButton *)temp->classPtr; -// struct_QWIIC_BUTTON *sensorSetting = (struct_QWIIC_BUTTON *)temp->configPtr; -// -// if (sensorSetting->ledState) -// sensor->LEDon(sensorSetting->ledBrightness); -// else -// sensor->LEDoff(); -// } -// break + case DEVICE_QWIIC_BUTTON: + { + QwiicButton *sensor = (QwiicButton *)temp->classPtr; + struct_QWIIC_BUTTON *sensorSetting = (struct_QWIIC_BUTTON *)temp->configPtr; + + if (sensorSetting->ledState) + sensor->LEDon(sensorSetting->ledBrightness); + else + sensor->LEDoff(); + } + break; case DEVICE_BIO_SENSOR_HUB: { SparkFun_Bio_Sensor_Hub *sensor = (SparkFun_Bio_Sensor_Hub *)temp->classPtr; @@ -854,6 +855,10 @@ void configureQwiicDevices() configureDevice(temp); temp = temp->next; } + + //Now that the settings are loaded and the devices are configured, + //try for 400kHz but reduce to 100kHz if certain devices are attached + setMaxI2CSpeed(); } //Returns a pointer to the menu function that configures this particular device type @@ -936,9 +941,9 @@ FunctionPointer getConfigFunctionPtr(uint8_t nodeNumber) case DEVICE_PRESSURE_MS5837: ptr = (FunctionPointer)menuConfigure_MS5837; break; -// case DEVICE_QWIIC_BUTTON: -// ptr = (FunctionPointer)menuConfigure_QWIIC_BUTTON; -// break; + case DEVICE_QWIIC_BUTTON: + ptr = (FunctionPointer)menuConfigure_QWIIC_BUTTON; + break; case DEVICE_BIO_SENSOR_HUB: ptr = (FunctionPointer)menuConfigure_BIO_SENSOR_HUB; break; @@ -1088,7 +1093,7 @@ void swap(struct node * a, struct node * b) #define ADR_VCNL4040 0x60 #define ADR_SCD30 0x61 #define ADR_MCP9600 0x60 //0x60 to 0x67 -//#define ADR_QWIIC_BUTTON 0x6F //But can be any address... Limit the range to 0x68-0x6F +#define ADR_QWIIC_BUTTON 0x6F //But can be any address... Limit the range to 0x68-0x6F #define ADR_MULTIPLEXER 0x70 //0x70 to 0x77 #define ADR_SHTC3 0x70 #define ADR_MS5637 0x76 @@ -1204,15 +1209,15 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb case 0x42: { //Confidence: High - Sends/receives CRC checked data response - qwiic.setPullups(0); //Disable pullups to minimize CRC issues + setQwiicPullups(0); //Disable pullups to minimize CRC issues SFE_UBLOX_GNSS sensor; - if(settings.printDebugMessages == true) sensor.enableDebugging(); // Enable debug messages if required + if(settings.printGNSSDebugMessages == true) sensor.enableDebugging(); // Enable debug messages if required if (sensor.begin(qwiic, i2cAddress) == true) //Wire port, address { - qwiic.setPullups(settings.qwiicBusPullUps); //Re-enable pullups to prevent ghosts at 0x43 onwards + setQwiicPullups(settings.qwiicBusPullUps); //Re-enable pullups to prevent ghosts at 0x43 onwards return (DEVICE_GPS_UBLOX); } - qwiic.setPullups(settings.qwiicBusPullUps); //Re-enable pullups for normal discovery + setQwiicPullups(settings.qwiicBusPullUps); //Re-enable pullups for normal discovery } break; case 0x44: @@ -1380,20 +1385,20 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb return (DEVICE_TEMPERATURE_MCP9600); } break; -// case 0x68: -// case 0x69: -// case 0x6A: -// case 0x6B: -// case 0x6C: -// case 0x6D: -// case 0x6E: -// case 0x6F: -// { -// QwiicButton sensor; -// if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port -// return (DEVICE_QWIIC_BUTTON); -// } -// break; + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + { + QwiicButton sensor; + if (sensor.begin(i2cAddress, qwiic) == true) //Address, Wire port + return (DEVICE_QWIIC_BUTTON); + } + break; case 0x70: { //Ignore devices we've already recorded. This was causing the mux to get tested, a begin() would happen, and the mux would be reset. @@ -1445,7 +1450,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb if (sensor2.begin(qwiic) == true) //Wire port { if (sensor2.getModel() <= 1) // Check that getModel returns 0 or 1. It will (hopefully) return 255 if an MS5637 is attached. - return (DEVICE_PRESSURE_MS5837); + return (DEVICE_PRESSURE_MS5837); } //Confidence: High - does CRC on internal EEPROM read - but do this second as a MS5837 will appear as a MS5637 @@ -1469,7 +1474,7 @@ deviceType_e testDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portNumb { //Ignore devices we've already recorded. This was causing the mux to get tested, a begin() would happen, and the mux would be reset. if (deviceExists(DEVICE_MULTIPLEXER, i2cAddress, muxAddress, portNumber) == true) return (DEVICE_MULTIPLEXER); - + BME280 sensor; sensor.setI2CAddress(i2cAddress); if (sensor.beginI2C(qwiic) == true) //Wire port @@ -1510,7 +1515,7 @@ deviceType_e testMuxDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portN { //Ignore devices we've already recorded. This was causing the mux to get tested, a begin() would happen, and the mux would be reset. if (deviceExists(DEVICE_MULTIPLEXER, i2cAddress, muxAddress, portNumber) == true) return (DEVICE_MULTIPLEXER); - + //Confidence: Medium - Write/Read/Clear to 0x00 if (multiplexerBegin(i2cAddress, qwiic) == true) //Address, Wire port return (DEVICE_MULTIPLEXER); @@ -1521,7 +1526,7 @@ deviceType_e testMuxDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portN //Ignore devices we've already recorded. This was causing the mux to get tested, a begin() would happen, and the mux would be reset. if (deviceExists(DEVICE_MULTIPLEXER, i2cAddress, muxAddress, portNumber) == true) return (DEVICE_MULTIPLEXER); - // If an MS8607 is connected, multiplexerBegin causes the MS8607 to 'crash' and lock up the I2C bus... So we need to check if an MS8607 is connected first. + // If an MS8607 is connected, multiplexerBegin causes the MS8607 to 'crash' and lock up the I2C bus... So we need to check if an MS8607 is connected first. // We will use the MS5637 as this will test for itself, the MS5837 and the pressure sensor of the MS8607 // Just to make life even more complicated, a mux with address 0x76 will also appear as an MS5637 due to the way the MS5637 eeprom crc check is calculated. // So, we can't use .begin as the test for a MS5637 / MS5837 / MS8607. We need to be more creative! @@ -1530,7 +1535,7 @@ deviceType_e testMuxDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portN // An MS5637 / MS5837 / MS8607 will return the value stored in its eeprom which _hopefully_ is not 0xA0A0! // Let's hope this doesn't cause problems for the BME280...! We should be OK as the default address for the BME280 is 0x77. - + qwiic.beginTransmission((uint8_t)i2cAddress); qwiic.write((uint8_t)0xA0); uint8_t i2c_status = qwiic.endTransmission(); @@ -1558,7 +1563,7 @@ deviceType_e testMuxDevice(uint8_t i2cAddress, uint8_t muxAddress, uint8_t portN { //Ignore devices we've already recorded. This was causing the mux to get tested, a begin() would happen, and the mux would be reset. if (deviceExists(DEVICE_MULTIPLEXER, i2cAddress, muxAddress, portNumber) == true) return (DEVICE_MULTIPLEXER); - + //Confidence: Medium - Write/Read/Clear to 0x00 if (multiplexerBegin(i2cAddress, qwiic) == true) //Address, Wire port return (DEVICE_MULTIPLEXER); @@ -1614,7 +1619,7 @@ bool setMuxPortState(uint8_t portBits, uint8_t deviceAddress, TwoWire &wirePort, wirePort.beginTransmission(deviceAddress); for (int i = 0; i < extraBytes; i++) { - wirePort.write(0x00); // Writing these extra bytes seems key to avoiding the slippery mux problem + wirePort.write((uint8_t)0x00); // Writing these extra bytes seems key to avoiding the slippery mux problem } wirePort.write(portBits); if (wirePort.endTransmission() != 0) @@ -1706,9 +1711,9 @@ const char* getDeviceName(deviceType_e deviceNumber) case DEVICE_PRESSURE_MS5837: return "Pressure-MS5837"; break; -// case DEVICE_QWIIC_BUTTON: -// return "Qwiic_Button"; -// break; + case DEVICE_QWIIC_BUTTON: + return "Qwiic_Button"; + break; case DEVICE_BIO_SENSOR_HUB: return "Bio-Sensor-Oximeter"; break; diff --git a/Firmware/OpenLog_Artemis/logging.ino b/Firmware/OpenLog_Artemis/logging.ino index 1135815..e7c1f06 100644 --- a/Firmware/OpenLog_Artemis/logging.ino +++ b/Firmware/OpenLog_Artemis/logging.ino @@ -26,7 +26,18 @@ char* findNextAvailableLog(int &newFileNumber, const char *fileLeader) static char newFileName[40]; while (1) { - sprintf(newFileName, "%s%05u.TXT", fileLeader, newFileNumber); //Splice the new file number into this file name. Max no. is 99999. + char newFileNumberStr[6]; + if (newFileNumber < 10) + sprintf(newFileNumberStr, "0000%d", newFileNumber); + else if (newFileNumber < 100) + sprintf(newFileNumberStr, "000%d", newFileNumber); + else if (newFileNumber < 1000) + sprintf(newFileNumberStr, "00%d", newFileNumber); + else if (newFileNumber < 10000) + sprintf(newFileNumberStr, "0%d", newFileNumber); + else + sprintf(newFileNumberStr, "%d", newFileNumber); + sprintf(newFileName, "%s%s.TXT", fileLeader, newFileNumberStr); //Splice the new file number into this file name. Max no. is 99999. if (sd.exists(newFileName) == false) break; //File name not found so we will use it. diff --git a/Firmware/OpenLog_Artemis/lowerPower.ino b/Firmware/OpenLog_Artemis/lowerPower.ino index 292e664..199ec6d 100644 --- a/Firmware/OpenLog_Artemis/lowerPower.ino +++ b/Firmware/OpenLog_Artemis/lowerPower.ino @@ -1,6 +1,6 @@ // Read the battery voltage // If it is low, increment lowBatteryReadings -// If lowBatteryReadings exceeds lowBatteryReadingsLimit then powerDown +// If lowBatteryReadings exceeds lowBatteryReadingsLimit then powerDownOLA void checkBattery(void) { #if(HARDWARE_VERSION_MAJOR >= 1) @@ -12,9 +12,9 @@ void checkBattery(void) lowBatteryReadings++; // Increment the low battery count if (lowBatteryReadings > lowBatteryReadingsLimit) // Have we exceeded the low battery count limit? { - // Gracefully powerDown + // Gracefully powerDownOLA - //Save files before powerDown + //Save files before powerDownOLA if (online.dataLogging == true) { sensorDataFile.sync(); @@ -35,7 +35,7 @@ void checkBattery(void) SerialFlush(); //Finish any prints - powerDown(); // power down and wait for reset + powerDownOLA(); // power down and wait for reset } } else @@ -44,28 +44,31 @@ void checkBattery(void) } } #endif + + if (powerLossSeen) + powerDownOLA(); // power down and wait for reset } //Power down the entire system but maintain running of RTC //This function takes 100us to run including GPIO setting //This puts the Apollo3 into 2.36uA to 2.6uA consumption mode //With leakage across the 3.3V protection diode, it's approx 3.00uA. -void powerDown() +void powerDownOLA(void) { //Prevent voltage supervisor from waking us from sleep - detachInterrupt(digitalPinToInterrupt(PIN_POWER_LOSS)); + detachInterrupt(PIN_POWER_LOSS); //Prevent stop logging button from waking us from sleep if (settings.useGPIO32ForStopLogging == true) { - detachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING)); // Disable the interrupt + detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt pinMode(PIN_STOP_LOGGING, INPUT); // Remove the pull-up } //Prevent trigger from waking us from sleep if (settings.useGPIO11ForTrigger == true) { - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up } @@ -89,12 +92,13 @@ void powerDown() SPI.end(); //Power down SPI - power_adc_disable(); //Power down ADC. It it started by default before setup(). + powerControlADC(false); // power_adc_disable(); //Power down ADC. It it started by default before setup(). Serial.end(); //Power down UART - SerialLog.end(); + Serial1.end(); //Force the peripherals off + //This will cause badness with v2.1 of the core but we don't care as we are waiting for a reset am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); @@ -105,21 +109,19 @@ void powerDown() am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); - //Disable pads + //Disable pads (this disables the LEDs too) for (int x = 0; x < 50; x++) { - if ((x != ap3_gpio_pin2pad(PIN_POWER_LOSS)) && - //(x != ap3_gpio_pin2pad(PIN_LOGIC_DEBUG)) && - (x != ap3_gpio_pin2pad(PIN_MICROSD_POWER)) && - (x != ap3_gpio_pin2pad(PIN_QWIIC_POWER)) && - (x != ap3_gpio_pin2pad(PIN_IMU_POWER))) + if ((x != PIN_POWER_LOSS) && + //(x != PIN_LOGIC_DEBUG) && + (x != PIN_MICROSD_POWER) && + (x != PIN_QWIIC_POWER) && + (x != PIN_IMU_POWER)) { am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE); } } - //powerLEDOff(); - //Make sure PIN_POWER_LOSS is configured as an input for the WDT pinMode(PIN_POWER_LOSS, INPUT); // BD49K30G-TL has CMOS output and does not need a pull-up @@ -177,12 +179,13 @@ void resetArtemis(void) SPI.end(); //Power down SPI - power_adc_disable(); //Power down ADC. It it started by default before setup(). + powerControlADC(false); // power_adc_disable(); //Power down ADC. It it started by default before setup(). Serial.end(); //Power down UART - SerialLog.end(); + Serial1.end(); //Force the peripherals off + //This will cause badness with v2.1 of the core but we don't care as we are going to force a WDT reset am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); @@ -196,11 +199,11 @@ void resetArtemis(void) //Disable pads for (int x = 0; x < 50; x++) { - if ((x != ap3_gpio_pin2pad(PIN_POWER_LOSS)) && - //(x != ap3_gpio_pin2pad(PIN_LOGIC_DEBUG)) && - (x != ap3_gpio_pin2pad(PIN_MICROSD_POWER)) && - (x != ap3_gpio_pin2pad(PIN_QWIIC_POWER)) && - (x != ap3_gpio_pin2pad(PIN_IMU_POWER))) + if ((x != PIN_POWER_LOSS) && + //(x != PIN_LOGIC_DEBUG) && + (x != PIN_MICROSD_POWER) && + (x != PIN_QWIIC_POWER) && + (x != PIN_IMU_POWER)) { am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE); } @@ -225,17 +228,15 @@ void resetArtemis(void) //Power everything down and wait for interrupt wakeup void goToSleep(uint32_t sysTicksToSleep) { - //printDebug("goToSleep: sysTicksToSleep = " + (String)sysTicksToSleep + "\r\n"); - - //printDebug("goToSleep: online.IMU = " + (String)online.IMU + "\r\n"); - + printDebug("goToSleep: sysTicksToSleep = " + (String)sysTicksToSleep + "\r\n"); + //Prevent voltage supervisor from waking us from sleep - detachInterrupt(digitalPinToInterrupt(PIN_POWER_LOSS)); + detachInterrupt(PIN_POWER_LOSS); //Prevent stop logging button from waking us from sleep if (settings.useGPIO32ForStopLogging == true) { - detachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING)); // Disable the interrupt + detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt pinMode(PIN_STOP_LOGGING, INPUT); // Remove the pull-up } @@ -243,7 +244,7 @@ void goToSleep(uint32_t sysTicksToSleep) //(This should be redundant. We should not be going to sleep if triggering is enabled?) if (settings.useGPIO11ForTrigger == true) { - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up } @@ -263,40 +264,64 @@ void goToSleep(uint32_t sysTicksToSleep) delay(sdPowerDownDelay); // Give the SD card time to finish writing ***** THIS IS CRITICAL ***** - SerialFlush(); //Finish any prints - - // Wire.end(); //Power down I2C - qwiic.end(); //Power down I2C + //qwiic.end(); //DO NOT Power down I2C - causes badness with v2.1 of the core: https://github.com/sparkfun/Arduino_Apollo3/issues/412 SPI.end(); //Power down SPI - power_adc_disable(); //Power down ADC. It it started by default before setup(). + powerControlADC(false); //Power down ADC - Serial.end(); //Power down UART - SerialLog.end(); + //Adjust sysTicks down by the amount we've be at 48MHz + //Read millis _before_ we switch to the lower power clock! + uint64_t msBeenAwake = rtcMillis() - lastAwakeTimeMillis; + uint64_t sysTicksAwake = msBeenAwake * 32768L / 1000L; //Convert to 32kHz systicks + if (sysTicksAwake < sysTicksToSleep) + sysTicksToSleep -= sysTicksAwake; + else + sysTicksToSleep = 0; + printDebug("goToSleep: sysTicksToSleep (adjusted) = " + (String)sysTicksToSleep + "\r\n\r\n"); + + SerialFlush(); //Finish any prints + Serial.end(); + Serial1.end(); //Force the peripherals off - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); - //Disable pads - for (int x = 0; x < 50; x++) + //With v2.1 of the core, very bad things happen if the IOMs are disabled. + //We must leave them enabled: https://github.com/sparkfun/Arduino_Apollo3/issues/412 + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); // SPI + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); // qwiic I2C + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); + //if (settings.useTxRxPinsForTerminal == true) + // am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); + + //Disable as many pins as we can + const int pinsToDisable[] = {0,1,2,10,14,17,12,24,25,28,36,38,39,40,41,42,43,45,21,22,16,31,35,-1}; + for (int x = 0; pinsToDisable[x] >= 0; x++) { - if ((x != ap3_gpio_pin2pad(PIN_POWER_LOSS)) && - //(x != ap3_gpio_pin2pad(PIN_LOGIC_DEBUG)) && - (x != ap3_gpio_pin2pad(PIN_MICROSD_POWER)) && - (x != ap3_gpio_pin2pad(PIN_QWIIC_POWER)) && - (x != ap3_gpio_pin2pad(PIN_IMU_POWER))) - { - am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE); - } + am_hal_gpio_pinconfig(pinsToDisable[x], g_AM_HAL_GPIO_DISABLE); + } + + //Do disable CIPO, COPI, SCLK and chip selects to minimise the current draw during deep sleep + am_hal_gpio_pinconfig(PIN_SPI_CIPO , g_AM_HAL_GPIO_DISABLE); //ICM / microSD CIPO + am_hal_gpio_pinconfig(PIN_SPI_COPI , g_AM_HAL_GPIO_DISABLE); //ICM / microSD COPI + am_hal_gpio_pinconfig(PIN_SPI_SCK , g_AM_HAL_GPIO_DISABLE); //ICM / microSD SCK + am_hal_gpio_pinconfig(PIN_IMU_CHIP_SELECT , g_AM_HAL_GPIO_DISABLE); //ICM CS + am_hal_gpio_pinconfig(PIN_IMU_INT , g_AM_HAL_GPIO_DISABLE); //ICM INT + am_hal_gpio_pinconfig(PIN_MICROSD_CHIP_SELECT , g_AM_HAL_GPIO_DISABLE); //microSD CS + + //Do disable qwiic SDA and SCL to minimise the current draw during deep sleep + am_hal_gpio_pinconfig(PIN_QWIIC_SDA , g_AM_HAL_GPIO_DISABLE); + am_hal_gpio_pinconfig(PIN_QWIIC_SCL , g_AM_HAL_GPIO_DISABLE); + + //If requested, disable pins 48 and 49 (UART0) to stop them back-feeding the CH340 + if (settings.serialTxRxDuringSleep == false) + { + am_hal_gpio_pinconfig(48 , g_AM_HAL_GPIO_DISABLE); //TX0 + am_hal_gpio_pinconfig(49 , g_AM_HAL_GPIO_DISABLE); //RX0 } //Make sure PIN_POWER_LOSS is configured as an input for the WDT @@ -315,13 +340,8 @@ void goToSleep(uint32_t sysTicksToSleep) //Leave the power LED on if the user desires it if (settings.enablePwrLedDuringSleep == true) powerLEDOn(); - //else - // powerLEDOff(); - - //Adjust sysTicks down by the amount we've be at 48MHz - //Read millis _before_ we switch to the lower power clock! - uint32_t msBeenAwake = millis(); - uint32_t sysTicksAwake = msBeenAwake * 32768L / 1000L; //Convert to 32kHz systicks + else + powerLEDOff(); //Power down cache, flash, SRAM am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Power down all flash and cache @@ -332,10 +352,8 @@ void goToSleep(uint32_t sysTicksToSleep) am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ | AM_HAL_STIMER_CFG_COMPARE_G_ENABLE); //Check that sysTicksToSleep is >> sysTicksAwake - if (sysTicksToSleep > (sysTicksAwake + 3277)) // Abort if we are trying to sleep for < 100ms + if (sysTicksToSleep > 3277) // Abort if we are trying to sleep for < 100ms { - sysTicksToSleep -= sysTicksAwake; - //Setup interrupt to trigger when the number of ms have elapsed am_hal_stimer_compare_delta_set(6, sysTicksToSleep); @@ -368,76 +386,121 @@ void wakeFromSleep() am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE); am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ); + // Power up SRAM, turn on entire Flash + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX); + + // Update lastAwakeTimeMillis + lastAwakeTimeMillis = rtcMillis(); + //Turn on ADC - uint32_t adcError = (uint32_t)ap3_adc_setup(); - if (settings.logA11 == true) adcError += (uint32_t)ap3_set_pin_to_analog(11); // Set _pad_ 11 to analog if enabled for logging - if (settings.logA12 == true) adcError += (uint32_t)ap3_set_pin_to_analog(12); // Set _pad_ 12 to analog if enabled for logging - if (settings.logA13 == true) adcError += (uint32_t)ap3_set_pin_to_analog(13); // Set _pad_ 13 to analog if enabled for logging - if (settings.logA32 == true) adcError += (uint32_t)ap3_set_pin_to_analog(32); // Set _pad_ 32 to analog if enabled for logging + powerControlADC(true); + + //Re-enable analog inputs + //if (settings.logA11 == true) adcError += (uint32_t)ap3_set_pin_to_analog(11); // Set _pad_ 11 to analog if enabled for logging + //if (settings.logA12 == true) adcError += (uint32_t)ap3_set_pin_to_analog(12); // Set _pad_ 12 to analog if enabled for logging + //if (settings.logA13 == true) adcError += (uint32_t)ap3_set_pin_to_analog(13); // Set _pad_ 13 to analog if enabled for logging + //if (settings.logA32 == true) adcError += (uint32_t)ap3_set_pin_to_analog(32); // Set _pad_ 32 to analog if enabled for logging #if(HARDWARE_VERSION_MAJOR >= 1) - adcError += (uint32_t)ap3_set_pin_to_analog(PIN_VIN_MONITOR); // Set _pad_ PIN_VIN_MONITOR to analog + //adcError += (uint32_t)ap3_set_pin_to_analog(PIN_VIN_MONITOR); // Set _pad_ PIN_VIN_MONITOR to analog #endif //Run setup again //If 3.3V rail drops below 3V, system will enter low power mode and maintain RTC pinMode(PIN_POWER_LOSS, INPUT); // BD49K30G-TL has CMOS output and does not need a pull-up + pin_config(PinName(PIN_POWER_LOSS), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured delay(1); // Let PIN_POWER_LOSS stabilize - attachInterrupt(digitalPinToInterrupt(PIN_POWER_LOSS), powerDown, FALLING); - - if (digitalRead(PIN_POWER_LOSS) == LOW) powerDown(); //Check PIN_POWER_LOSS just in case we missed the falling edge + if (digitalRead(PIN_POWER_LOSS) == LOW) powerDownOLA(); //Check PIN_POWER_LOSS just in case we missed the falling edge + //attachInterrupt(PIN_POWER_LOSS, powerDownOLA, FALLING); // We can't do this with v2.1.0 as attachInterrupt causes a spontaneous interrupt + attachInterrupt(PIN_POWER_LOSS, powerLossISR, FALLING); + powerLossSeen = false; // Make sure the flag is clear + if (settings.useGPIO32ForStopLogging == true) { pinMode(PIN_STOP_LOGGING, INPUT_PULLUP); + pin_config(PinName(PIN_STOP_LOGGING), g_AM_HAL_GPIO_INPUT_PULLUP); // Make sure the pin does actually get re-configured delay(1); // Let the pin stabilize - attachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING), stopLoggingISR, FALLING); // Enable the interrupt + attachInterrupt(PIN_STOP_LOGGING, stopLoggingISR, FALLING); // Enable the interrupt + am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + pin_config(PinName(PIN_STOP_LOGGING), intPinConfig); // Make sure the pull-up does actually stay enabled stopLoggingSeen = false; // Make sure the flag is clear } if (settings.useGPIO11ForTrigger == true) //(This should be redundant. We should not be going to sleep if triggering is enabled?) { pinMode(PIN_TRIGGER, INPUT_PULLUP); + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT_PULLUP); // Make sure the pin does actually get re-configured delay(1); // Let the pin stabilize + am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; if (settings.fallingEdgeTrigger == true) - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, FALLING); // Enable the interrupt + { + SerialPrintln(F("Falling-edge triggering is enabled. Sensor data will be logged on a falling edge on GPIO pin 11.")); + attachInterrupt(PIN_TRIGGER, triggerPinISR, FALLING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + } else - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, RISING); // Enable the interrupt + { + SerialPrintln(F("Rising-edge triggering is enabled. Sensor data will be logged on a rising edge on GPIO pin 11.")); + attachInterrupt(PIN_TRIGGER, triggerPinISR, RISING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; + } + pin_config(PinName(PIN_TRIGGER), intPinConfig); // Make sure the pull-up does actually stay enabled triggerEdgeSeen = false; // Make sure the flag is clear } if (settings.useGPIO11ForFastSlowLogging == true) { pinMode(PIN_TRIGGER, INPUT_PULLUP); + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT_PULLUP); // Make sure the pin does actually get re-configured } pinMode(PIN_STAT_LED, OUTPUT); + pin_config(PinName(PIN_STAT_LED), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_STAT_LED, LOW); powerLEDOn(); + //Re-enable pins 48 and 49 (UART0) if requested + if (settings.serialTxRxDuringSleep == false) + { + pin_config(PinName(48), g_AM_BSP_GPIO_COM_UART_TX); + pin_config(PinName(49), g_AM_BSP_GPIO_COM_UART_RX); + } + + //Re-enable CIPO, COPI, SCK and the chip selects but may as well leave ICM_INT disabled + pin_config(PinName(PIN_SPI_CIPO), g_AM_BSP_GPIO_IOM0_MISO); + pin_config(PinName(PIN_SPI_COPI), g_AM_BSP_GPIO_IOM0_MOSI); + pin_config(PinName(PIN_SPI_SCK), g_AM_BSP_GPIO_IOM0_SCK); + pin_config(PinName(PIN_IMU_CHIP_SELECT), g_AM_HAL_GPIO_OUTPUT); + pin_config(PinName(PIN_MICROSD_CHIP_SELECT) , g_AM_HAL_GPIO_OUTPUT); + + //Re-enable the SDA and SCL pins + pin_config(PinName(PIN_QWIIC_SCL), g_AM_BSP_GPIO_IOM1_SCL); + pin_config(PinName(PIN_QWIIC_SDA), g_AM_BSP_GPIO_IOM1_SDA); + Serial.begin(settings.serialTerminalBaudRate); if (settings.useTxRxPinsForTerminal == true) { - SerialLog.begin(settings.serialTerminalBaudRate); // Start the serial port - } + //We may need to manually restore the Serial1 TX and RX pins? + configureSerial1TxRx(); - printDebug(F("wakeFromSleep: I'm awake!\r\n")); - printDebug("wakeFromSleep: adcError is " + (String)adcError + "."); - if (adcError > 0) - printDebug(F(" This indicates an error was returned by ap3_adc_setup or one of the calls to ap3_set_pin_to_analog.")); - printDebug(F("\r\n")); + Serial1.begin(settings.serialTerminalBaudRate); // Start the serial port + } + printDebug(F("wakeFromSleep: I'm awake!\r\n")); SerialFlush(); + beginQwiic(); //Power up Qwiic bus as early as possible SPI.begin(); //Needed if SD is disabled beginSD(); //285 - 293ms - enableCIPOpullUp(); // Enable CIPO pull-up after beginSD + enableCIPOpullUp(); // Enable CIPO pull-up _after_ beginSD beginDataLogging(); //180ms @@ -448,7 +511,7 @@ void wakeFromSleep() } beginIMU(); //61ms - //printDebug("wakeFromSleep: online.IMU = " + (String)online.IMU + "\r\n"); + printDebug("wakeFromSleep: online.IMU = " + (String)online.IMU + "\r\n"); //If we powered down the Qwiic bus, then re-begin and re-configure everything if (settings.powerDownQwiicBusBetweenReads == true) @@ -458,15 +521,13 @@ void wakeFromSleep() configureQwiicDevices(); //Apply config settings to each device in the node list } - //SerialPrintf2("Wake up time: %.02f ms\r\n", (micros() - startTime) / 1000.0); - //When we wake up micros has been reset to zero so we need to let the main loop know to take a reading takeReading = true; } void stopLogging(void) { - detachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING)); // Disable the interrupt + detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt //Save files before going to sleep if (online.dataLogging == true) @@ -485,10 +546,10 @@ void stopLogging(void) SerialPrint(F("Logging is stopped. Please reset OpenLog Artemis and open a terminal at ")); Serial.print((String)settings.serialTerminalBaudRate); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print((String)settings.serialTerminalBaudRate); + Serial1.print((String)settings.serialTerminalBaudRate); SerialPrintln(F("bps...")); delay(sdPowerDownDelay); // Give the SD card time to shut down - powerDown(); + powerDownOLA(); } void waitForQwiicBusPowerDelay() // Wait while the qwiic devices power up @@ -496,7 +557,7 @@ void waitForQwiicBusPowerDelay() // Wait while the qwiic devices power up //Depending on what hardware is configured, the Qwiic bus may have only been turned on a few ms ago //Give sensors, specifically those with a low I2C address, time to turn on // If we're not using the SD card, everything will have happened much quicker than usual. - unsigned long qwiicPowerHasBeenOnFor = millis() - qwiicPowerOnTime; + uint64_t qwiicPowerHasBeenOnFor = bestMillis() - qwiicPowerOnTime; if (qwiicPowerHasBeenOnFor < qwiicPowerOnDelayMillis) { unsigned long delayFor = qwiicPowerOnDelayMillis - qwiicPowerHasBeenOnFor; @@ -511,17 +572,19 @@ void waitForQwiicBusPowerDelay() // Wait while the qwiic devices power up void qwiicPowerOn() { pinMode(PIN_QWIIC_POWER, OUTPUT); + pin_config(PinName(PIN_QWIIC_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured #if(HARDWARE_VERSION_MAJOR == 0) digitalWrite(PIN_QWIIC_POWER, LOW); #else digitalWrite(PIN_QWIIC_POWER, HIGH); #endif - qwiicPowerOnTime = millis(); //Record this time so we wait enough time before detecting certain sensors + qwiicPowerOnTime = bestMillis(); //Record this time so we wait enough time before detecting certain sensors } void qwiicPowerOff() { pinMode(PIN_QWIIC_POWER, OUTPUT); + pin_config(PinName(PIN_QWIIC_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured #if(HARDWARE_VERSION_MAJOR == 0) digitalWrite(PIN_QWIIC_POWER, HIGH); #else @@ -532,22 +595,26 @@ void qwiicPowerOff() void microSDPowerOn() { pinMode(PIN_MICROSD_POWER, OUTPUT); + pin_config(PinName(PIN_MICROSD_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_MICROSD_POWER, LOW); } void microSDPowerOff() { pinMode(PIN_MICROSD_POWER, OUTPUT); + pin_config(PinName(PIN_MICROSD_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_MICROSD_POWER, HIGH); } void imuPowerOn() { pinMode(PIN_IMU_POWER, OUTPUT); + pin_config(PinName(PIN_IMU_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_IMU_POWER, HIGH); } void imuPowerOff() { pinMode(PIN_IMU_POWER, OUTPUT); + pin_config(PinName(PIN_IMU_POWER), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_IMU_POWER, LOW); } @@ -555,6 +622,7 @@ void powerLEDOn() { #if(HARDWARE_VERSION_MAJOR >= 1) pinMode(PIN_PWR_LED, OUTPUT); + pin_config(PinName(PIN_PWR_LED), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_PWR_LED, HIGH); // Turn the Power LED on #endif } @@ -562,6 +630,7 @@ void powerLEDOff() { #if(HARDWARE_VERSION_MAJOR >= 1) pinMode(PIN_PWR_LED, OUTPUT); + pin_config(PinName(PIN_PWR_LED), g_AM_HAL_GPIO_OUTPUT); // Make sure the pin does actually get re-configured digitalWrite(PIN_PWR_LED, LOW); // Turn the Power LED off #endif } diff --git a/Firmware/OpenLog_Artemis/menuAnalogLogging.ino b/Firmware/OpenLog_Artemis/menuAnalogLogging.ino index 17326f3..68c3533 100644 --- a/Firmware/OpenLog_Artemis/menuAnalogLogging.ino +++ b/Firmware/OpenLog_Artemis/menuAnalogLogging.ino @@ -54,8 +54,9 @@ void menuAnalogLogging() settings.logA11 = true; // Disable triggering settings.useGPIO11ForTrigger = false; - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured triggerEdgeSeen = false; // Make sure the flag is clear } else @@ -117,8 +118,9 @@ void menuAnalogLogging() settings.logA32 = true; // Disable stop logging settings.useGPIO32ForStopLogging = false; - detachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING)); // Disable the interrupt + detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt pinMode(PIN_STOP_LOGGING, INPUT); // Remove the pull-up + pin_config(PinName(PIN_STOP_LOGGING), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured } else settings.logA32 = false; diff --git a/Firmware/OpenLog_Artemis/menuAttachedDevices.ino b/Firmware/OpenLog_Artemis/menuAttachedDevices.ino index e82cf10..99b9625 100644 --- a/Firmware/OpenLog_Artemis/menuAttachedDevices.ino +++ b/Firmware/OpenLog_Artemis/menuAttachedDevices.ino @@ -33,12 +33,12 @@ bool detectQwiicDevices() printDebug(F("detectQwiicDevices started\r\n")); bool somethingDetected = false; - qwiic.setClock(100000); //During detection, go slow + qwiic.setClock(AM_HAL_IOM_100KHZ); //During detection, go slow - qwiic.setPullups(settings.qwiicBusPullUps); //Set pullups. (Redundant. beginQwiic has done this too.) If we don't have pullups, detectQwiicDevices() takes ~900ms to complete. We'll disable pullups if something is detected. + setQwiicPullups(settings.qwiicBusPullUps); //Set pullups. (Redundant. beginQwiic has done this too.) If we don't have pullups, detectQwiicDevices() takes ~900ms to complete. We'll disable pullups if something is detected. //24k causes a bunch of unknown devices to be falsely detected. - //qwiic.setPullups(24); //Set pullups to 24k. If we don't have pullups, detectQwiicDevices() takes ~900ms to complete. We'll disable pullups if something is detected. + //setQwiicPullups(24); //Set pullups to 24k. If we don't have pullups, detectQwiicDevices() takes ~900ms to complete. We'll disable pullups if something is detected. waitForQwiicBusPowerDelay(); // Wait while the qwiic devices power up @@ -227,9 +227,10 @@ bool detectQwiicDevices() bubbleSortDevices(head); //This may destroy mux alignment to node 0. //*** Let's leave pull-ups set to 1k and only disable them when taking to a u-blox device *** - //qwiic.setPullups(0); //We've detected something on the bus so disable pullups. + //setQwiicPullups(0); //We've detected something on the bus so disable pullups. - setMaxI2CSpeed(); //Try for 400kHz but reduce to 100kHz or low if certain devices are attached + //We need to call setMaxI2CSpeed in configureQwiicDevices + //We cannot do it here as the device settings have not been loaded SerialPrintln(F("Autodetect complete")); @@ -336,9 +337,9 @@ void menuAttachedDevices() case DEVICE_PRESSURE_MS5837: SerialPrintf3("%s MS5837 (BAR30 / BAR02) Pressure Sensor %s\r\n", strDeviceMenu, strAddress); break; -// case DEVICE_QWIIC_BUTTON: -// SerialPrintf3("%s Qwiic Button %s\r\n", strDeviceMenu, strAddress); -// break; + case DEVICE_QWIIC_BUTTON: + SerialPrintf3("%s Qwiic Button %s\r\n", strDeviceMenu, strAddress); + break; case DEVICE_BIO_SENSOR_HUB: SerialPrintf3("%s Bio Sensor Pulse Oximeter %s\r\n", strDeviceMenu, strAddress); break; @@ -406,7 +407,7 @@ void menuAttachedDevices() settings.logA32 = false; if (settings.useGPIO11ForTrigger == true) // If interrupts are enabled, we need to disable and then re-enable { - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt settings.useGPIO11ForTrigger = false; } settings.useGPIO11ForFastSlowLogging = false; @@ -414,7 +415,16 @@ void menuAttachedDevices() { // Disable stop logging settings.useGPIO32ForStopLogging = false; - detachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING)); // Disable the interrupt + detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt + } + + recordSystemSettings(); //Record the new settings to EEPROM and config file now in case the user resets before exiting the menus + + if (detectQwiicDevices() == true) //Detect the oximeter + { + beginQwiicDevices(); //Begin() each device in the node list + configureQwiicDevices(); //Apply config settings to each device in the node list + recordDeviceSettingsToFile(); //Record the current devices settings to device config file now in case the user resets before exiting the menus } recordSystemSettings(); //Record the new settings to EEPROM and config file now in case the user resets before exiting the menus @@ -474,12 +484,10 @@ void menuConfigure_QwiicBus() settings.powerDownQwiicBusBetweenReads ^= 1; else if (incoming == '2') { - SerialPrint(F("Enter max frequency to run Qwiic bus: (100000 or 400000): ")); - uint32_t amt = getNumber(menuTimeout); - if ((amt == 100000) || (amt == 400000)) - settings.qwiicBusMaxSpeed = amt; + if (settings.qwiicBusMaxSpeed == 100000) + settings.qwiicBusMaxSpeed = 400000; else - SerialPrintln(F("Error: Out of range")); + settings.qwiicBusMaxSpeed = 100000; } else if (incoming == '3') { @@ -846,9 +854,12 @@ void menuConfigure_NAU7802(void *configPtr) if (sensorConfig->log == true) { SerialPrintln(F("2) Calibrate Scale")); - SerialPrintf2("\tScale calibration factor: %f\r\n", sensorConfig->calibrationFactor); + char tempStr[16]; + olaftoa(sensorConfig->calibrationFactor, tempStr, 6, sizeof(tempStr) / sizeof(char)); + SerialPrintf2("\tScale calibration factor: %s\r\n", tempStr); SerialPrintf2("\tScale zero offset: %d\r\n", sensorConfig->zeroOffset); - SerialPrintf2("\tWeight currently on scale: %f\r\n", sensor->getWeight()); + olaftoa(sensor->getWeight(), tempStr, sensorConfig->decimalPlaces, sizeof(tempStr) / sizeof(char)); + SerialPrintf2("\tWeight currently on scale: %s\r\n", tempStr); SerialPrintf2("3) Number of decimal places: %d\r\n", sensorConfig->decimalPlaces); SerialPrintf2("4) Average number of readings to take per weight read: %d\r\n", sensorConfig->averageAmount); @@ -877,7 +888,7 @@ void menuConfigure_NAU7802(void *configPtr) SerialPrint(F("New zero offset: ")); Serial.println(sensor->getZeroOffset()); if (settings.useTxRxPinsForTerminal == true) - SerialLog.println(sensor->getZeroOffset()); + Serial1.println(sensor->getZeroOffset()); SerialPrintln(F("Place known weight on scale. Press a key when weight is in place and stable.")); waitForInput(); @@ -1005,6 +1016,8 @@ void menuConfigure_uBlox(void *configPtr) if (sensorSetting->useAutoPVT == true) SerialPrintln(F("Yes")); else SerialPrintln(F("No")); + SerialPrintln(F("16) Reset GNSS to factory defaults")); + SerialFlush(); } SerialPrintln(F("x) Exit")); @@ -1050,6 +1063,18 @@ void menuConfigure_uBlox(void *configPtr) } else if (incoming == 15) sensorSetting->useAutoPVT ^= 1; + else if (incoming == 16) + { + SerialPrintln(F("Reset GNSS module to factory defaults. This will take 5 seconds to complete.")); + SerialPrintln(F("Are you sure? Press 'y' to confirm: ")); + byte bContinue = getByteChoice(menuTimeout); + if (bContinue == 'y') + { + gnssFactoryDefault(); + } + else + SerialPrintln(F("Reset GNSS aborted")); + } else if (incoming == STATUS_PRESSED_X) break; else if (incoming == STATUS_GETNUMBER_TIMEOUT) @@ -1064,7 +1089,6 @@ void menuConfigure_uBlox(void *configPtr) else printUnknown(incoming); } - } bool isUbloxAttached() @@ -1096,11 +1120,14 @@ void getUbloxDateTime(int &year, int &month, int &day, int &hour, int &minute, i { case DEVICE_GPS_UBLOX: { - qwiic.setPullups(0); //Disable pullups to minimize CRC issues + setQwiicPullups(0); //Disable pullups to minimize CRC issues SFE_UBLOX_GNSS *nodeDevice = (SFE_UBLOX_GNSS *)temp->classPtr; struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + //If autoPVT is enabled, flush the data to make sure we get fresh date and time + if (nodeSetting->useAutoPVT) nodeDevice->flushPVT(); + //Get latested date/time from GPS //These will be extracted from a single PVT packet year = nodeDevice->getYear(); @@ -1113,7 +1140,38 @@ void getUbloxDateTime(int &year, int &month, int &day, int &hour, int &minute, i timeValid = nodeDevice->getTimeValid(); millisecond = nodeDevice->getMillisecond(); - qwiic.setPullups(settings.qwiicBusPullUps); //Re-enable pullups + setQwiicPullups(settings.qwiicBusPullUps); //Re-enable pullups + } + } + temp = temp->next; + } +} + +void gnssFactoryDefault(void) +{ + //Step through node list + node *temp = head; + + while (temp != NULL) + { + switch (temp->deviceType) + { + case DEVICE_GPS_UBLOX: + { + setQwiicPullups(0); //Disable pullups to minimize CRC issues + + SFE_UBLOX_GNSS *nodeDevice = (SFE_UBLOX_GNSS *)temp->classPtr; + struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + + //Reset the module to the factory defaults + nodeDevice->factoryDefault(); + + delay(5000); //Blocking delay to allow module to reset + + nodeDevice->setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + nodeDevice->saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the current ioPortsettings to flash and BBR + + setQwiicPullups(settings.qwiicBusPullUps); //Re-enable pullups } } temp = temp->next; @@ -1573,7 +1631,7 @@ void menuConfigure_SCD30(void *configPtr) SerialPrint(F("The current temperature offset read from the sensor is: ")); Serial.print(sensor->getTemperatureOffset(), 2); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print(sensor->getTemperatureOffset(), 2); + Serial1.print(sensor->getTemperatureOffset(), 2); SerialPrintln(F("C")); SerialPrint(F("Enter new temperature offset in C (-50 to 50): ")); int amt = getNumber(menuTimeout); //x second timeout @@ -2455,73 +2513,73 @@ void menuConfigure_MS5837(void *configPtr) } } -//void menuConfigure_QWIIC_BUTTON(void *configPtr) -//{ -// struct_QWIIC_BUTTON *sensorSetting = (struct_QWIIC_BUTTON*)configPtr; -// -// while (1) -// { -// SerialPrintln(F("")); -// SerialPrintln(F("Menu: Configure Qwiic Button")); -// -// SerialPrint(F("1) Sensor Logging: ")); -// if (sensorSetting->log == true) SerialPrintln(F("Enabled")); -// else SerialPrintln(F("Disabled")); -// -// if (sensorSetting->log == true) -// { -// SerialPrint(F("2) Log Button Presses: ")); -// if (sensorSetting->logPressed == true) SerialPrintln(F("Enabled")); -// else SerialPrintln(F("Disabled")); -// -// SerialPrint(F("3) Log Button Clicks: ")); -// if (sensorSetting->logClicked == true) SerialPrintln(F("Enabled")); -// else SerialPrintln(F("Disabled")); -// -// SerialPrint(F("4) Toggle LED on each click (and log the LED state): ")); -// if (sensorSetting->toggleLEDOnClick == true) SerialPrintln(F("Enabled")); -// else SerialPrintln(F("Disabled")); -// -// SerialPrintf2("5) LED Brightness: %d\r\n", sensorSetting->ledBrightness); -// } -// SerialPrintln(F("x) Exit")); -// -// int incoming = getNumber(menuTimeout); //Timeout after x seconds -// -// if (incoming == 1) -// sensorSetting->log ^= 1; -// else if (sensorSetting->log == true) -// { -// if (incoming == 2) -// sensorSetting->logPressed ^= 1; -// else if (incoming == 3) -// sensorSetting->logClicked ^= 1; -// else if (incoming == 4) -// sensorSetting->toggleLEDOnClick ^= 1; -// else if (incoming == 5) -// { -// SerialPrint(F("Enter the LED brightness (0 to 255): ")); -// int bright = getNumber(menuTimeout); //x second timeout -// if (bright < 0 || bright > 255) -// SerialPrintln(F("Error: Out of range")); -// else -// sensorSetting->ledBrightness = bright; -// } -// else if (incoming == STATUS_PRESSED_X) -// break; -// else if (incoming == STATUS_GETNUMBER_TIMEOUT) -// break; -// else -// printUnknown(incoming); -// } -// else if (incoming == STATUS_PRESSED_X) -// break; -// else if (incoming == STATUS_GETNUMBER_TIMEOUT) -// break; -// else -// printUnknown(incoming); -// } -//} +void menuConfigure_QWIIC_BUTTON(void *configPtr) +{ + struct_QWIIC_BUTTON *sensorSetting = (struct_QWIIC_BUTTON*)configPtr; + + while (1) + { + SerialPrintln(F("")); + SerialPrintln(F("Menu: Configure Qwiic Button")); + + SerialPrint(F("1) Sensor Logging: ")); + if (sensorSetting->log == true) SerialPrintln(F("Enabled")); + else SerialPrintln(F("Disabled")); + + if (sensorSetting->log == true) + { + SerialPrint(F("2) Log Button Presses: ")); + if (sensorSetting->logPressed == true) SerialPrintln(F("Enabled")); + else SerialPrintln(F("Disabled")); + + SerialPrint(F("3) Log Button Clicks: ")); + if (sensorSetting->logClicked == true) SerialPrintln(F("Enabled")); + else SerialPrintln(F("Disabled")); + + SerialPrint(F("4) Toggle LED on each click (and log the LED state): ")); + if (sensorSetting->toggleLEDOnClick == true) SerialPrintln(F("Enabled")); + else SerialPrintln(F("Disabled")); + + SerialPrintf2("5) LED Brightness: %d\r\n", sensorSetting->ledBrightness); + } + SerialPrintln(F("x) Exit")); + + int incoming = getNumber(menuTimeout); //Timeout after x seconds + + if (incoming == 1) + sensorSetting->log ^= 1; + else if (sensorSetting->log == true) + { + if (incoming == 2) + sensorSetting->logPressed ^= 1; + else if (incoming == 3) + sensorSetting->logClicked ^= 1; + else if (incoming == 4) + sensorSetting->toggleLEDOnClick ^= 1; + else if (incoming == 5) + { + SerialPrint(F("Enter the LED brightness (0 to 255): ")); + int bright = getNumber(menuTimeout); //x second timeout + if (bright < 0 || bright > 255) + SerialPrintln(F("Error: Out of range")); + else + sensorSetting->ledBrightness = bright; + } + else if (incoming == STATUS_PRESSED_X) + break; + else if (incoming == STATUS_GETNUMBER_TIMEOUT) + break; + else + printUnknown(incoming); + } + else if (incoming == STATUS_PRESSED_X) + break; + else if (incoming == STATUS_GETNUMBER_TIMEOUT) + break; + else + printUnknown(incoming); + } +} void menuConfigure_BIO_SENSOR_HUB(void *configPtr) { diff --git a/Firmware/OpenLog_Artemis/menuDebug.ino b/Firmware/OpenLog_Artemis/menuDebug.ino index 1a63549..20a0976 100644 --- a/Firmware/OpenLog_Artemis/menuDebug.ino +++ b/Firmware/OpenLog_Artemis/menuDebug.ino @@ -13,6 +13,10 @@ void menuDebug() if (settings.resetOnZeroDeviceCount == true) SerialPrintln(F("Enabled")); else SerialPrintln(F("Disabled")); + SerialPrint(F("3) GNSS Debug Messages: ")); + if (settings.printGNSSDebugMessages == true) SerialPrintln(F("Enabled")); + else SerialPrintln(F("Disabled")); + SerialPrintln(F("x) Exit")); byte incoming = getByteChoice(menuTimeout); //Timeout after x seconds @@ -42,6 +46,10 @@ void menuDebug() settings.resetOnZeroDeviceCount ^= 1; } } + else if (incoming == '3') + { + settings.printGNSSDebugMessages ^= 1; + } else if (incoming == 'x') break; else if (incoming == STATUS_GETBYTE_TIMEOUT) diff --git a/Firmware/OpenLog_Artemis/menuMain.ino b/Firmware/OpenLog_Artemis/menuMain.ino index 5809998..c65d62d 100644 --- a/Firmware/OpenLog_Artemis/menuMain.ino +++ b/Firmware/OpenLog_Artemis/menuMain.ino @@ -111,7 +111,7 @@ void menuMain() SerialPrint(F("Settings erased. Please reset OpenLog Artemis and open a terminal at ")); Serial.print((String)settings.serialTerminalBaudRate); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print((String)settings.serialTerminalBaudRate); + Serial1.print((String)settings.serialTerminalBaudRate); SerialPrintln(F("bps...")); while (1); } @@ -140,10 +140,10 @@ void menuMain() SerialPrint(F("Log files are closed. Please reset OpenLog Artemis and open a terminal at ")); Serial.print((String)settings.serialTerminalBaudRate); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print((String)settings.serialTerminalBaudRate); + Serial1.print((String)settings.serialTerminalBaudRate); SerialPrintln(F("bps...")); delay(sdPowerDownDelay); // Give the SD card time to shut down - powerDown(); + powerDownOLA(); } else SerialPrintln(F("Quit aborted")); @@ -168,19 +168,14 @@ void menuMain() while (Serial.available()) Serial.read(); //Empty buffer of any newline chars if (settings.useTxRxPinsForTerminal == true) - while (SerialLog.available()) SerialLog.read(); //Empty buffer of any newline chars + while (Serial1.available()) Serial1.read(); //Empty buffer of any newline chars //Reset measurements measurementCount = 0; totalCharactersPrinted = 0; //If we are sleeping between readings then we cannot rely on millis() as it is powered down //Use RTC instead - if (((settings.useGPIO11ForTrigger == false) && (settings.usBetweenReadings >= maxUsBeforeSleep)) - || (settings.useGPIO11ForFastSlowLogging == true) - || (settings.useRTCForFastSlowLogging == true)) - measurementStartTime = rtcMillis(); - else - measurementStartTime = millis(); + measurementStartTime = bestMillis(); //Edge case: after 10Hz reading, user sets the log rate above 2s mark. We never go to sleep because //takeReading is not true. And since we don't wake up, takeReading never gets set to true. diff --git a/Firmware/OpenLog_Artemis/menuPower.ino b/Firmware/OpenLog_Artemis/menuPower.ino index 3f5c8d3..7abbf0c 100644 --- a/Firmware/OpenLog_Artemis/menuPower.ino +++ b/Firmware/OpenLog_Artemis/menuPower.ino @@ -23,12 +23,19 @@ void menuPower() else SerialPrintln(F("Disabled")); SerialPrint(F("5) Low Battery Threshold (V): ")); - SerialPrintf2("%.2f\r\n", settings.lowBatteryThreshold); + char tempStr[16]; + olaftoa(settings.lowBatteryThreshold, tempStr, 2, sizeof(tempStr) / sizeof(char)); + SerialPrintf2("%s\r\n", tempStr); SerialPrint(F("6) VIN measurement correction factor: ")); - SerialPrintf2("%.3f\r\n", settings.vinCorrectionFactor); + olaftoa(settings.vinCorrectionFactor, tempStr, 3, sizeof(tempStr) / sizeof(char)); + SerialPrintf2("%s\r\n", tempStr); #endif + SerialPrint(F("7) Serial Tx and Rx pins during sleep are: ")); + if (settings.serialTxRxDuringSleep == true) SerialPrintln(F("Enabled")); + else SerialPrintln(F("Disabled")); + SerialPrintln(F("x) Exit")); byte incoming = getByteChoice(menuTimeout); //Timeout after x seconds @@ -45,8 +52,9 @@ void menuPower() { // Disable stop logging settings.useGPIO32ForStopLogging = false; - detachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING)); // Disable the interrupt + detachInterrupt(PIN_STOP_LOGGING); // Disable the interrupt pinMode(PIN_STOP_LOGGING, INPUT); // Remove the pull-up + pin_config(PinName(PIN_STOP_LOGGING), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured stopLoggingSeen = false; // Make sure the flag is clear } else @@ -54,8 +62,12 @@ void menuPower() // Enable stop logging settings.useGPIO32ForStopLogging = true; pinMode(PIN_STOP_LOGGING, INPUT_PULLUP); + pin_config(PinName(PIN_STOP_LOGGING), g_AM_HAL_GPIO_INPUT_PULLUP); // Make sure the pin does actually get re-configured delay(1); // Let the pin stabilize - attachInterrupt(digitalPinToInterrupt(PIN_STOP_LOGGING), stopLoggingISR, FALLING); // Enable the interrupt + attachInterrupt(PIN_STOP_LOGGING, stopLoggingISR, FALLING); // Enable the interrupt + am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + pin_config(PinName(PIN_STOP_LOGGING), intPinConfig); // Make sure the pull-up does actually stay enabled stopLoggingSeen = false; // Make sure the flag is clear settings.logA32 = false; // Disable analog logging on pin 32 } @@ -98,6 +110,10 @@ void menuPower() settings.vinCorrectionFactor = tempCF; } #endif + else if (incoming == '7') + { + settings.serialTxRxDuringSleep ^= 1; + } else if (incoming == 'x') break; else if (incoming == STATUS_GETBYTE_TIMEOUT) diff --git a/Firmware/OpenLog_Artemis/menuSerialLogging.ino b/Firmware/OpenLog_Artemis/menuSerialLogging.ino index 350bcea..65cc64d 100644 --- a/Firmware/OpenLog_Artemis/menuSerialLogging.ino +++ b/Firmware/OpenLog_Artemis/menuSerialLogging.ino @@ -18,7 +18,7 @@ void menuSerialLogging() SerialPrint(F("3) zmodem start delay: ")); Serial.print(settings.zmodemStartDelay); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print(settings.zmodemStartDelay); + Serial1.print(settings.zmodemStartDelay); SerialPrintln(F(" seconds")); if ((settings.logSerial == true) || (settings.outputSerial == true)) @@ -26,7 +26,7 @@ void menuSerialLogging() SerialPrint(F("4) Set serial baud rate: ")); Serial.print(settings.serialLogBaudRate); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print(settings.zmodemStartDelay); + Serial1.print(settings.zmodemStartDelay); SerialPrintln(F(" bps")); } @@ -39,7 +39,7 @@ void menuSerialLogging() SerialPrint(F("6) Timestamp token: ")); Serial.print(settings.timeStampToken); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print(settings.timeStampToken); + Serial1.print(settings.timeStampToken); SerialPrint(F(" (Decimal)")); switch (settings.timeStampToken) { @@ -130,8 +130,9 @@ void menuSerialLogging() } else { + configureSerial1TxRx(); settings.serialLogBaudRate = newBaud; - SerialLog.begin(settings.serialLogBaudRate); + Serial1.begin(settings.serialLogBaudRate); } } else if (incoming == '5') diff --git a/Firmware/OpenLog_Artemis/menuTerminal.ino b/Firmware/OpenLog_Artemis/menuTerminal.ino index d8fe4d6..901d5de 100644 --- a/Firmware/OpenLog_Artemis/menuTerminal.ino +++ b/Firmware/OpenLog_Artemis/menuTerminal.ino @@ -16,7 +16,7 @@ void menuLogRate() SerialPrint(F("3) Set Serial Terminal Baud Rate: ")); Serial.print(settings.serialTerminalBaudRate); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print(settings.serialTerminalBaudRate); + Serial1.print(settings.serialTerminalBaudRate); SerialPrintln(F(" bps")); if (settings.useGPIO11ForTrigger == false) @@ -35,7 +35,9 @@ void menuLogRate() { //Display fractional Hertz uint32_t logRateSeconds = (uint32_t)(settings.usBetweenReadings / 1000000ULL); - SerialPrintf2("%.06lf\r\n", 1.0 / logRateSeconds); + char tempStr[16]; + olaftoa(1.0 / logRateSeconds, tempStr, 6, sizeof(tempStr) / sizeof(char)); + SerialPrintf2("%s\r\n", tempStr); } } @@ -51,7 +53,9 @@ void menuLogRate() else { float rate = (float)(settings.usBetweenReadings / 1000000.0); - SerialPrintf2("%.06f\r\n", rate); + char tempStr[16]; + olaftoa(rate, tempStr, 6, sizeof(tempStr) / sizeof(char)); + SerialPrintf2("%s\r\n", tempStr); } } @@ -124,12 +128,30 @@ void menuLogRate() SerialPrint(F("19) Slow logging starts at: ")); int slowHour = settings.slowLoggingStartMOD / 60; int slowMin = settings.slowLoggingStartMOD % 60; - SerialPrintf3("%02d:%02d\r\n", slowHour, slowMin); + char hourStr[3]; + char minStr[3]; + if (slowHour < 10) + sprintf(hourStr, "0%d", slowHour); + else + sprintf(hourStr, "%d", slowHour); + if (slowMin < 10) + sprintf(minStr, "0%d", slowMin); + else + sprintf(minStr, "%d", slowMin); + SerialPrintf3("%s:%s\r\n", hourStr, minStr); SerialPrint(F("20) Slow logging ends at: ")); slowHour = settings.slowLoggingStopMOD / 60; slowMin = settings.slowLoggingStopMOD % 60; - SerialPrintf3("%02d:%02d\r\n", slowHour, slowMin); + if (slowHour < 10) + sprintf(hourStr, "0%d", slowHour); + else + sprintf(hourStr, "%d", slowHour); + if (slowMin < 10) + sprintf(minStr, "0%d", slowMin); + else + sprintf(minStr, "%d", slowMin); + SerialPrintf3("%s:%s\r\n", hourStr, minStr); } if ((settings.useGPIO11ForTrigger == false) && (settings.usBetweenReadings >= maxUsBeforeSleep)) @@ -264,8 +286,9 @@ void menuLogRate() { // Disable triggering settings.useGPIO11ForTrigger = false; - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured triggerEdgeSeen = false; // Make sure the flag is clear } else @@ -273,11 +296,20 @@ void menuLogRate() // Enable triggering settings.useGPIO11ForTrigger = true; pinMode(PIN_TRIGGER, INPUT_PULLUP); + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT_PULLUP); // Make sure the pin does actually get re-configured delay(1); // Let the pin stabilize + am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; if (settings.fallingEdgeTrigger == true) - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, FALLING); // Enable the interrupt + { + attachInterrupt(PIN_TRIGGER, triggerPinISR, FALLING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + } else - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, RISING); // Enable the interrupt + { + attachInterrupt(PIN_TRIGGER, triggerPinISR, RISING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; + } + pin_config(PinName(PIN_TRIGGER), intPinConfig); // Make sure the pull-up does actually stay enabled triggerEdgeSeen = false; // Make sure the flag is clear settings.logA11 = false; // Disable analog logging on pin 11 settings.logMaxRate = false; // Disable max rate logging @@ -298,12 +330,20 @@ void menuLogRate() { if (settings.useGPIO11ForTrigger == true) // If interrupts are enabled, we need to disable and then re-enable { - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt settings.fallingEdgeTrigger ^= 1; // Invert the flag + am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; if (settings.fallingEdgeTrigger == true) - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, FALLING); // Enable the interrupt + { + attachInterrupt(PIN_TRIGGER, triggerPinISR, FALLING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + } else - attachInterrupt(digitalPinToInterrupt(PIN_TRIGGER), triggerPinISR, RISING); // Enable the interrupt + { + attachInterrupt(PIN_TRIGGER, triggerPinISR, RISING); // Enable the interrupt + intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; + } + pin_config(PinName(PIN_TRIGGER), intPinConfig); // Make sure the pull-up does actually stay enabled triggerEdgeSeen = false; // Make sure the flag is clear } else @@ -341,7 +381,11 @@ void menuLogRate() online.serialOutput = false; settings.logA12 = false; settings.logA13 = false; - SerialLog.begin(settings.serialTerminalBaudRate); // (Re)Start the serial port + + //We need to manually restore the Serial1 TX and RX pins before we can use Serial1 + configureSerial1TxRx(); + + Serial1.begin(settings.serialTerminalBaudRate); // (Re)Start the serial port using the terminal baud rate } else SerialPrintln(F("\"Use TX and RX pins for terminal\" aborted")); @@ -364,11 +408,12 @@ void menuLogRate() settings.useRTCForFastSlowLogging = false; settings.logA11 = false; // Disable analog logging on pin 11 pinMode(PIN_TRIGGER, INPUT_PULLUP); + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT_PULLUP); // Make sure the pin does actually get re-configured delay(1); // Let the pin stabilize // Disable triggering if (settings.useGPIO11ForTrigger == true) { - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt triggerEdgeSeen = false; // Make sure the flag is clear } settings.useGPIO11ForTrigger = false; @@ -377,6 +422,7 @@ void menuLogRate() { settings.useGPIO11ForFastSlowLogging = false; pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured } } else @@ -399,6 +445,7 @@ void menuLogRate() { settings.useGPIO11ForFastSlowLogging = false; pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured } } else if (incoming == 17) @@ -408,15 +455,17 @@ void menuLogRate() settings.useRTCForFastSlowLogging = true; if (settings.useGPIO11ForFastSlowLogging == true) { - pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up + pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured } settings.useGPIO11ForFastSlowLogging = false; settings.logA11 = false; // Disable analog logging on pin 11 // Disable triggering if (settings.useGPIO11ForTrigger == true) { - detachInterrupt(digitalPinToInterrupt(PIN_TRIGGER)); // Disable the interrupt + detachInterrupt(PIN_TRIGGER); // Disable the interrupt pinMode(PIN_TRIGGER, INPUT); // Remove the pull-up + pin_config(PinName(PIN_TRIGGER), g_AM_HAL_GPIO_INPUT); // Make sure the pin does actually get re-configured triggerEdgeSeen = false; // Make sure the flag is clear } settings.useGPIO11ForTrigger = false; diff --git a/Firmware/OpenLog_Artemis/menuTimeStamp.ino b/Firmware/OpenLog_Artemis/menuTimeStamp.ino index 6082b69..1b10775 100644 --- a/Firmware/OpenLog_Artemis/menuTimeStamp.ino +++ b/Firmware/OpenLog_Artemis/menuTimeStamp.ino @@ -7,22 +7,58 @@ void menuTimeStamp() SerialPrint(F("Current date/time: ")); myRTC.getTime(); - char rtcDate[11]; //10/12/2019 + char rtcDate[11]; // 10/12/2019 + char rtcDay[3]; + char rtcMonth[3]; + char rtcYear[5]; + if (myRTC.dayOfMonth < 10) + sprintf(rtcDay, "0%d", myRTC.dayOfMonth); + else + sprintf(rtcDay, "%d", myRTC.dayOfMonth); + if (myRTC.month < 10) + sprintf(rtcMonth, "0%d", myRTC.month); + else + sprintf(rtcMonth, "%d", myRTC.month); + if (myRTC.year < 10) + sprintf(rtcYear, "200%d", myRTC.year); + else + sprintf(rtcYear, "20%d", myRTC.year); if (settings.americanDateStyle == true) - sprintf(rtcDate, "%02d/%02d/20%02d", myRTC.month, myRTC.dayOfMonth, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); else - sprintf(rtcDate, "%02d/%02d/20%02d", myRTC.dayOfMonth, myRTC.month, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); SerialPrint(rtcDate); SerialPrint(F(" ")); - char rtcTime[12]; //09:14:37.41 + char rtcTime[13]; //09:14:37.41, int adjustedHour = myRTC.hour; if (settings.hour24Style == false) { if (adjustedHour > 12) adjustedHour -= 12; } - sprintf(rtcTime, "%02d:%02d:%02d.%02d", adjustedHour, myRTC.minute, myRTC.seconds, myRTC.hundredths); + char rtcHour[3]; + char rtcMin[3]; + char rtcSec[3]; + char rtcHundredths[3]; + if (adjustedHour < 10) + sprintf(rtcHour, "0%d", adjustedHour); + else + sprintf(rtcHour, "%d", adjustedHour); + if (myRTC.minute < 10) + sprintf(rtcMin, "0%d", myRTC.minute); + else + sprintf(rtcMin, "%d", myRTC.minute); + if (myRTC.seconds < 10) + sprintf(rtcSec, "0%d", myRTC.seconds); + else + sprintf(rtcSec, "%d", myRTC.seconds); + if (myRTC.hundredths < 10) + sprintf(rtcHundredths, "0%d", myRTC.hundredths); + else + sprintf(rtcHundredths, "%d", myRTC.hundredths); + sprintf(rtcTime, "%s:%s:%s.%s", rtcHour, rtcMin, rtcSec, rtcHundredths); + SerialPrintln(rtcTime); SerialPrint(F("1) Log Date: ")); @@ -65,7 +101,7 @@ void menuTimeStamp() SerialPrint(F("9) Local offset from UTC: ")); Serial.println(settings.localUTCOffset); if (settings.useTxRxPinsForTerminal == true) - SerialLog.println(settings.localUTCOffset); + Serial1.println(settings.localUTCOffset); } SerialPrint(F("10) Log Microseconds: ")); @@ -101,7 +137,7 @@ void menuTimeStamp() int dd = myRTC.dayOfMonth, mm = myRTC.month, yy = myRTC.year, h = myRTC.hour, m = myRTC.minute, s = myRTC.seconds, ms = (myRTC.hundredths * 10); bool dateValid, timeValid; getGPSDateTime(yy, mm, dd, h, m, s, ms, dateValid, timeValid); // Get the GPS date and time, corrected for localUTCOffset - myRTC.setTime(h, m, s, (ms / 10), dd, mm, (yy - 2000)); //Manually set RTC + myRTC.setTime((ms / 10), s, m, h, dd, mm, (yy - 2000)); //Manually set RTC lastSDFileNameChangeTime = rtcMillis(); // Record the time of the file name change SerialPrintln(F("RTC set to GPS (UTC) time")); if ((dateValid == false) || (timeValid == false)) @@ -138,7 +174,9 @@ void menuTimeStamp() SerialPrint(F("Enter current day (1 to 31): ")); dd = getNumber(menuTimeout); //Timeout after x seconds - myRTC.setTime(h, m, s, 0, dd, mm, yy); //Manually set RTC + myRTC.getTime(); + h = myRTC.hour; m = myRTC.minute; s = myRTC.seconds; + myRTC.setTime(0, s, m, h, dd, mm, yy); //Manually set RTC lastSDFileNameChangeTime = rtcMillis(); // Record the time of the file name change } else if (incoming == 5) @@ -164,7 +202,7 @@ void menuTimeStamp() SerialPrint(F("Enter current second (0 to 59): ")); s = getNumber(menuTimeout); //Timeout after x seconds - myRTC.setTime(h, m, s, 0, dd, mm, yy); //Manually set RTC + myRTC.setTime(0, s, m, h, dd, mm, yy); //Manually set RTC lastSDFileNameChangeTime = rtcMillis(); // Record the time of the file name change } else if (incoming == 7) diff --git a/Firmware/OpenLog_Artemis/nvm.ino b/Firmware/OpenLog_Artemis/nvm.ino index 09c7c0a..a46d0ab 100644 --- a/Firmware/OpenLog_Artemis/nvm.ino +++ b/Firmware/OpenLog_Artemis/nvm.ino @@ -145,13 +145,13 @@ void recordSystemSettingsToFile() settingsFile.println("enablePwrLedDuringSleep=" + (String)settings.enablePwrLedDuringSleep); settingsFile.println("logVIN=" + (String)settings.logVIN); settingsFile.println("openNewLogFilesAfter=" + (String)settings.openNewLogFilesAfter); - settingsFile.println("vinCorrectionFactor=" + (String)settings.vinCorrectionFactor); + settingsFile.print("vinCorrectionFactor="); settingsFile.println(settings.vinCorrectionFactor); settingsFile.println("useGPIO32ForStopLogging=" + (String)settings.useGPIO32ForStopLogging); settingsFile.println("qwiicBusPullUps=" + (String)settings.qwiicBusPullUps); settingsFile.println("outputSerial=" + (String)settings.outputSerial); settingsFile.println("zmodemStartDelay=" + (String)settings.zmodemStartDelay); settingsFile.println("enableLowBatteryDetection=" + (String)settings.enableLowBatteryDetection); - settingsFile.println("lowBatteryThreshold=" + (String)settings.lowBatteryThreshold); + settingsFile.print("lowBatteryThreshold="); settingsFile.println(settings.lowBatteryThreshold); settingsFile.println("frequentFileAccessTimestamps=" + (String)settings.frequentFileAccessTimestamps); settingsFile.println("useGPIO11ForTrigger=" + (String)settings.useGPIO11ForTrigger); settingsFile.println("fallingEdgeTrigger=" + (String)settings.fallingEdgeTrigger); @@ -180,6 +180,8 @@ void recordSystemSettingsToFile() settingsFile.println("imuLogDMPCpass=" + (String)settings.imuLogDMPCpass); settingsFile.println("minimumAwakeTimeMillis=" + (String)settings.minimumAwakeTimeMillis); settingsFile.println("identifyBioSensorHubs=" + (String)settings.identifyBioSensorHubs); + settingsFile.println("serialTxRxDuringSleep=" + (String)settings.serialTxRxDuringSleep); + settingsFile.println("printGNSSDebugMessages=" + (String)settings.printGNSSDebugMessages); updateDataFileAccess(&settingsFile); // Update the file access time & date settingsFile.close(); } @@ -280,11 +282,12 @@ bool parseLine(char* str) { // Convert string to double. double d = strtod(str, &ptr); - if (str == ptr || *skipSpace(ptr)) return false; //SerialPrintf2("d = %lf\r\n", d); //SerialFlush(); + if (str == ptr || *skipSpace(ptr)) return false; + // Get setting name if (strcmp(settingName, "sizeOfSettings") == 0) { @@ -456,6 +459,10 @@ bool parseLine(char* str) { settings.minimumAwakeTimeMillis = d; else if (strcmp(settingName, "identifyBioSensorHubs") == 0) settings.identifyBioSensorHubs = d; + else if (strcmp(settingName, "serialTxRxDuringSleep") == 0) + settings.serialTxRxDuringSleep = d; + else if (strcmp(settingName, "printGNSSDebugMessages") == 0) + settings.printGNSSDebugMessages = d; else { SerialPrintf2("Unknown setting %s. Ignoring...\r\n", settingName); @@ -508,7 +515,7 @@ void recordDeviceSettingsToFile() { struct_NAU7802 *nodeSetting = (struct_NAU7802 *)temp->configPtr; settingsFile.println((String)base + "log=" + nodeSetting->log); - settingsFile.println((String)base + "calibrationFactor=" + nodeSetting->calibrationFactor); + settingsFile.print((String)base + "calibrationFactor="); settingsFile.println(nodeSetting->calibrationFactor); settingsFile.println((String)base + "zeroOffset=" + nodeSetting->zeroOffset); settingsFile.println((String)base + "decimalPlaces=" + nodeSetting->decimalPlaces); settingsFile.println((String)base + "averageAmount=" + nodeSetting->averageAmount); @@ -724,8 +731,8 @@ void recordDeviceSettingsToFile() struct_SGP40 *nodeSetting = (struct_SGP40 *)temp->configPtr; settingsFile.println((String)base + "log=" + nodeSetting->log); settingsFile.println((String)base + "logVOC=" + nodeSetting->logVOC); - settingsFile.println((String)base + "RH=" + nodeSetting->RH); - settingsFile.println((String)base + "T=" + nodeSetting->T); + settingsFile.print((String)base + "RH="); settingsFile.println(nodeSetting->RH); + settingsFile.print((String)base + "T="); settingsFile.println(nodeSetting->T); } break; case DEVICE_PRESSURE_SDP3X: @@ -747,20 +754,20 @@ void recordDeviceSettingsToFile() settingsFile.println((String)base + "logDepth=" + nodeSetting->logDepth); settingsFile.println((String)base + "logAltitude=" + nodeSetting->logAltitude); settingsFile.println((String)base + "model=" + nodeSetting->model); - settingsFile.println((String)base + "fluidDensity=" + nodeSetting->fluidDensity); - settingsFile.println((String)base + "conversion=" + nodeSetting->conversion); + settingsFile.print((String)base + "fluidDensity="); settingsFile.println(nodeSetting->fluidDensity); + settingsFile.print((String)base + "conversion="); settingsFile.println(nodeSetting->conversion); + } + break; + case DEVICE_QWIIC_BUTTON: + { + struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; + settingsFile.println((String)base + "log=" + nodeSetting->log); + settingsFile.println((String)base + "logPressed=" + nodeSetting->logPressed); + settingsFile.println((String)base + "logClicked=" + nodeSetting->logClicked); + settingsFile.println((String)base + "toggleLEDOnClick=" + nodeSetting->toggleLEDOnClick); + settingsFile.println((String)base + "ledBrightness=" + nodeSetting->ledBrightness); } break; -// case DEVICE_QWIIC_BUTTON: -// { -// struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)temp->configPtr; -// settingsFile.println((String)base + "log=" + nodeSetting->log); -// settingsFile.println((String)base + "logPressed=" + nodeSetting->logPressed); -// settingsFile.println((String)base + "logClicked=" + nodeSetting->logClicked); -// settingsFile.println((String)base + "toggleLEDOnClick=" + nodeSetting->toggleLEDOnClick); -// settingsFile.println((String)base + "ledBrightness=" + nodeSetting->ledBrightness); -// } -// break; case DEVICE_BIO_SENSOR_HUB: { struct_BIO_SENSOR_HUB *nodeSetting = (struct_BIO_SENSOR_HUB *)temp->configPtr; @@ -1360,23 +1367,23 @@ bool parseDeviceLine(char* str) { SerialPrintf2("Unknown device setting: %s\r\n", deviceSettingName); } break; -// case DEVICE_QWIIC_BUTTON: -// { -// struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)deviceConfigPtr; //Create a local pointer that points to same spot as node does -// if (strcmp(deviceSettingName, "log") == 0) -// nodeSetting->log = d; -// else if (strcmp(deviceSettingName, "logPressed") == 0) -// nodeSetting->logPressed = d; -// else if (strcmp(deviceSettingName, "logClicked") == 0) -// nodeSetting->logClicked = d; -// else if (strcmp(deviceSettingName, "toggleLEDOnClick") == 0) -// nodeSetting->toggleLEDOnClick = d; -// else if (strcmp(deviceSettingName, "ledBrightness") == 0) -// nodeSetting->ledBrightness = d; -// else -// SerialPrintf2("Unknown device setting: %s\r\n", deviceSettingName); -// } -// break; + case DEVICE_QWIIC_BUTTON: + { + struct_QWIIC_BUTTON *nodeSetting = (struct_QWIIC_BUTTON *)deviceConfigPtr; //Create a local pointer that points to same spot as node does + if (strcmp(deviceSettingName, "log") == 0) + nodeSetting->log = d; + else if (strcmp(deviceSettingName, "logPressed") == 0) + nodeSetting->logPressed = d; + else if (strcmp(deviceSettingName, "logClicked") == 0) + nodeSetting->logClicked = d; + else if (strcmp(deviceSettingName, "toggleLEDOnClick") == 0) + nodeSetting->toggleLEDOnClick = d; + else if (strcmp(deviceSettingName, "ledBrightness") == 0) + nodeSetting->ledBrightness = d; + else + SerialPrintf2("Unknown device setting: %s\r\n", deviceSettingName); + } + break; case DEVICE_BIO_SENSOR_HUB: { struct_BIO_SENSOR_HUB *nodeSetting = (struct_BIO_SENSOR_HUB *)deviceConfigPtr; //Create a local pointer that points to same spot as node does diff --git a/Firmware/OpenLog_Artemis/productionTest.ino b/Firmware/OpenLog_Artemis/productionTest.ino index c9f404f..6beea0d 100644 --- a/Firmware/OpenLog_Artemis/productionTest.ino +++ b/Firmware/OpenLog_Artemis/productionTest.ino @@ -90,7 +90,12 @@ void productionTest() // OK. The breakout pins were held low and then released (pulled-up) within five seconds so let's go into production test mode! - //detachInterrupt(digitalPinToInterrupt(PIN_POWER_LOSS)); // Disable power loss interrupt + //We need to manually restore the Serial1 TX and RX pins before we can use Serial1 + configureSerial1TxRx(); + + Serial.begin(115200); //Default for initial debug messages if necessary + + //detachInterrupt(PIN_POWER_LOSS); // Disable power loss interrupt digitalWrite(PIN_STAT_LED, LOW); // Turn the STAT LED off powerLEDOff(); // Turn the power LED on - if the hardware supports it @@ -98,7 +103,7 @@ void productionTest() readVIN(); // Read VIN now to initialise the analog pin - SerialLog.begin(115200); // Begin the serial port using the TX and RX breakout pins + Serial1.begin(115200); // Begin the serial port using the TX and RX breakout pins #ifdef verboseProdTest Serial.println(F("OLA Production Test initiated!")); @@ -109,9 +114,13 @@ void productionTest() unsigned long lastHelloSent = 0; // Use this to record the last time a Hello was sent bool echoUSB = false; // Flag to indicate if we should be echoing on USB (command 0x16/0x17) + char tempData1[16]; + char tempData2[16]; + char tempData3[16]; + while (1) // Do this loop forever! { - while (!SerialLog.available()) // Wait until we receive a command byte + while (!Serial1.available()) // Wait until we receive a command byte { if ((sendHellos == true) && (millis() > lastHelloSent)) // Is it time to send a Hello? (5 x 10 / 115200 = 0.434ms) { @@ -128,7 +137,7 @@ void productionTest() } // Command byte received! Let's process it. - uint8_t commandByte = SerialLog.read(); + uint8_t commandByte = Serial1.read(); #ifdef verboseProdTest Serial.printf("Processing command byte: 0x%02X\r\n", commandByte); #endif @@ -139,15 +148,16 @@ void productionTest() { float vin = readVIN(); // Read VIN #ifdef verboseProdTest - Serial.printf("VIN is %fV\r\n", vin); + olaftoa(vin, tempData1, 2, sizeof(tempData1) / sizeof(char)); + Serial.printf("VIN is %sV\r\n", tempData1); #endif if ((vin >= 4.75) && (vin <= 5.25)) // Success { - SerialLog.write(0x01); + Serial1.write(0x01); } else { - SerialLog.write(0x81); + Serial1.write(0x81); } } // / 0x01: VIN/3 break; @@ -162,20 +172,21 @@ void productionTest() { myICM.getAGMT(); //Update values #ifdef verboseProdTest - Serial.printf("IMU Temp is: %.2fC\r\n", myICM.temp()); + olaftoa(myICM.temp(), tempData1, 2, sizeof(tempData1) / sizeof(char)); + Serial.printf("IMU Temp is: %sC\r\n", tempData1); #endif if ((myICM.temp() >= 10.0) && (myICM.temp() <= 40.0)) { - SerialLog.write(0x02); // Test passed + Serial1.write(0x02); // Test passed } else { - SerialLog.write(0x82); // Test failed - readings are out of range + Serial1.write(0x82); // Test failed - readings are out of range } } else { - SerialLog.write(0x82); // Test failed - IMU data is not ready + Serial1.write(0x82); // Test failed - IMU data is not ready #ifdef verboseProdTest Serial.println(F("IMU data not ready!")); #endif @@ -183,7 +194,7 @@ void productionTest() } else { - SerialLog.write(0x82); // Test failed - IMU is not online + Serial1.write(0x82); // Test failed - IMU is not online #ifdef verboseProdTest Serial.println(F("IMU is not online!")); #endif @@ -202,22 +213,25 @@ void productionTest() { myICM.getAGMT(); //Update values #ifdef verboseProdTest - Serial.printf("IMU Accel readings are: %.2f %.2f %.2f mg\r\n", myICM.accX(), myICM.accY(), myICM.accZ()); + olaftoa(myICM.accX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); + olaftoa(myICM.accY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); + olaftoa(myICM.accZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); + Serial.printf("IMU Accel readings are: %s %s %s mg\r\n", tempData1, tempData2, tempData3); #endif if (((myICM.accX() > -100) && (myICM.accX() < 100)) && // Check the readings are in range ((myICM.accY() > -100) && (myICM.accY() < 100)) && ((myICM.accZ() > -1100) && (myICM.accZ() < -900))) { - SerialLog.write(0x03); // Test passed + Serial1.write(0x03); // Test passed } else { - SerialLog.write(0x83); // Test failed - readings are out of range + Serial1.write(0x83); // Test failed - readings are out of range } } else { - SerialLog.write(0x83); // Test failed - IMU data is not ready + Serial1.write(0x83); // Test failed - IMU data is not ready #ifdef verboseProdTest Serial.println(F("IMU data not ready!")); #endif @@ -225,7 +239,7 @@ void productionTest() } else { - SerialLog.write(0x83); // Test failed - IMU is not online + Serial1.write(0x83); // Test failed - IMU is not online #ifdef verboseProdTest Serial.println(F("IMU is not online!")); #endif @@ -244,25 +258,29 @@ void productionTest() { myICM.getAGMT(); //Update values #ifdef verboseProdTest - Serial.printf("IMU Mag readings are: %.2f %.2f %.2f nT\r\n", myICM.magX(), myICM.magY(), myICM.magZ()); + olaftoa(myICM.magX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); + olaftoa(myICM.magY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); + olaftoa(myICM.magZ(), tempData3, 2, sizeof(tempData3) / sizeof(char)); + Serial.printf("IMU Mag readings are: %s %s %s nT\r\n", tempData1, tempData2, tempData3); #endif float magVectorProduct = sqrt((myICM.magX() * myICM.magX()) + (myICM.magY() * myICM.magY())); // Calculate the vector product of magX and magY #ifdef verboseProdTest - Serial.printf("IMU Mag XY vector product is: %.2f nT\r\n", magVectorProduct); + olaftoa(magVectorProduct, tempData1, 2, sizeof(tempData1) / sizeof(char)); + Serial.printf("IMU Mag XY vector product is: %s nT\r\n", tempData1); #endif if (((myICM.magZ() >= 20.0) && (myICM.magZ() <= 30.0)) && // Check the readings are in range ((magVectorProduct >= 20.0) && (magVectorProduct <= 30.0))) { - SerialLog.write(0x04); // Test passed + Serial1.write(0x04); // Test passed } else { - SerialLog.write(0x84); // Test failed - readings are out of range + Serial1.write(0x84); // Test failed - readings are out of range } } else { - SerialLog.write(0x84); // Test failed - IMU data is not ready + Serial1.write(0x84); // Test failed - IMU data is not ready #ifdef verboseProdTest Serial.println(F("IMU data not ready!")); #endif @@ -270,7 +288,7 @@ void productionTest() } else { - SerialLog.write(0x84); // Test failed - IMU is not online + Serial1.write(0x84); // Test failed - IMU is not online #ifdef verboseProdTest Serial.println(F("IMU is not online!")); #endif @@ -287,21 +305,21 @@ void productionTest() Serial.println(F("Going into deep sleep for 5 seconds...")); #endif Serial.flush(); //Finish any prints - qwiic.end(); //Power down I2C + //qwiic.end(); //Power down I2C SPI.end(); //Power down SPI - power_adc_disable(); //Power down ADC. It it started by default before setup(). + powerControlADC(false); //Power down ADC. It it started by default before setup(). Serial.end(); //Power down UART - SerialLog.end(); + Serial1.end(); //Force the peripherals off - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); //Use the lower power 32kHz clock. Use it to run CT6 as well. am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE); am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ | AM_HAL_STIMER_CFG_COMPARE_G_ENABLE); @@ -324,9 +342,9 @@ void productionTest() am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE); am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ); //Turn on ADC - ap3_adc_setup(); + powerControlADC(true); //ap3_adc_setup(); Serial.begin(115200); - SerialLog.begin(115200); + Serial1.begin(115200); SPI.begin(); myRTC.getTime(); // Read the RTC unsigned long hundredthsAfterSleep = (myRTC.hour * 360000) + (myRTC.minute * 6000) + (myRTC.seconds * 100) + myRTC.hundredths; @@ -338,100 +356,121 @@ void productionTest() #endif if ((elapsedHundredths > 490) && (elapsedHundredths < 510)) { - SerialLog.write(0x05); // Test passed + Serial1.write(0x05); // Test passed } else { - SerialLog.write(0x85); // Test failed + Serial1.write(0x85); // Test failed } } // /0x05: RTC Crystal break; case 0x06: qwiicPowerOn(); - SerialLog.write(0x06); + Serial1.write(0x06); break; case 0x07: qwiicPowerOff(); - SerialLog.write(0x07); + Serial1.write(0x07); break; case 0x08: powerLEDOn(); - SerialLog.write(0x08); + Serial1.write(0x08); break; case 0x09: powerLEDOff(); - SerialLog.write(0x09); + Serial1.write(0x09); break; case 0x0A: digitalWrite(PIN_STAT_LED, HIGH); - SerialLog.write(0x0A); + Serial1.write(0x0A); break; case 0x0B: digitalWrite(PIN_STAT_LED, LOW); - SerialLog.write(0x0B); + Serial1.write(0x0B); break; case 0x0C: pinMode(BREAKOUT_PIN_32, OUTPUT); digitalWrite(BREAKOUT_PIN_32, HIGH); - SerialLog.write(0x0C); + Serial1.write(0x0C); break; case 0x0D: pinMode(BREAKOUT_PIN_32, OUTPUT); digitalWrite(BREAKOUT_PIN_32, LOW); - SerialLog.write(0x0D); + Serial1.write(0x0D); break; case 0x0E: pinMode(PIN_QWIIC_SCL, OUTPUT); digitalWrite(PIN_QWIIC_SCL, HIGH); - SerialLog.write(0x0E); + Serial1.write(0x0E); break; case 0x0F: pinMode(PIN_QWIIC_SCL, OUTPUT); digitalWrite(PIN_QWIIC_SCL, LOW); - SerialLog.write(0x0F); + Serial1.write(0x0F); break; case 0x10: pinMode(PIN_QWIIC_SDA, OUTPUT); digitalWrite(PIN_QWIIC_SDA, HIGH); - SerialLog.write(0x10); + Serial1.write(0x10); break; case 0x11: pinMode(PIN_QWIIC_SDA, OUTPUT); digitalWrite(PIN_QWIIC_SDA, LOW); - SerialLog.write(0x11); + Serial1.write(0x11); break; case 0x12: pinMode(BREAKOUT_PIN_11, OUTPUT); digitalWrite(BREAKOUT_PIN_11, HIGH); - SerialLog.write(0x12); + Serial1.write(0x12); break; case 0x13: pinMode(BREAKOUT_PIN_11, OUTPUT); digitalWrite(BREAKOUT_PIN_11, LOW); - SerialLog.write(0x13); + Serial1.write(0x13); break; case 0x14: sendHellos = true; - SerialLog.write(0x14); + Serial1.write(0x14); break; case 0x15: sendHellos = false; - SerialLog.write(0x15); + Serial1.write(0x15); break; case 0x16: echoUSB = true; - SerialLog.write(0x16); + Serial1.write(0x16); break; case 0x17: echoUSB = false; - SerialLog.write(0x17); + Serial1.write(0x17); break; case 0x18: myRTC.getTime(); // Read the RTC - SerialLog.write(0x18); - SerialLog.printf("%02d:%02d:%02d.%02d", myRTC.hour, myRTC.minute, myRTC.seconds, myRTC.hundredths); + Serial1.write(0x18); + char rtcHour[3]; + char rtcMin[3]; + char rtcSec[3]; + char rtcHundredths[3]; + if (myRTC.hour < 10) + sprintf(rtcHour, "0%d", myRTC.hour); + else + sprintf(rtcHour, "%d", myRTC.hour); + if (myRTC.minute < 10) + sprintf(rtcMin, "0%d", myRTC.minute); + else + sprintf(rtcMin, "%d", myRTC.minute); + if (myRTC.seconds < 10) + sprintf(rtcSec, "0%d", myRTC.seconds); + else + sprintf(rtcSec, "%d", myRTC.seconds); + if (myRTC.hundredths < 10) + sprintf(rtcHundredths, "0%d", myRTC.hundredths); + else + sprintf(rtcHundredths, "%d", myRTC.hundredths); + + Serial1.printf("%s:%s:%s.%s", rtcHour, rtcMin, rtcSec, rtcHundredths); #ifdef verboseProdTest - Serial.printf("RTC time is %02d:%02d:%02d.%02d\r\n", myRTC.hour, myRTC.minute, myRTC.seconds, myRTC.hundredths); + Serial.printf("RTC time is %s:%s:%s.%s\r\n", rtcHour, rtcMin, rtcSec, rtcHundredths); #endif break; case 0x19: // SD Card Test @@ -463,7 +502,7 @@ void productionTest() if (strcmp(line, "112358132134\n") == 0) // Look for the correct sequence { testFile.close(); // Close the file - SerialLog.write(0x19); // Test passed + Serial1.write(0x19); // Test passed #ifdef verboseProdTest Serial.println(F("SD card test passed - file contents are correct")); #endif @@ -471,7 +510,7 @@ void productionTest() else { testFile.close(); // Close the file - SerialLog.write(0x99); // Test failed - data did not compare + Serial1.write(0x99); // Test failed - data did not compare #ifdef verboseProdTest Serial.println(F("Test file contents incorrect!")); for (int l = 0; l < 13; l++) @@ -483,7 +522,7 @@ void productionTest() else { testFile.close(); // Close the file - SerialLog.write(0x99); // Test failed - test file contents are not the correct length + Serial1.write(0x99); // Test failed - test file contents are not the correct length #ifdef verboseProdTest Serial.printf("Test file contents incorrect length (%d)!\r\n", n); #endif @@ -491,7 +530,7 @@ void productionTest() } else { - SerialLog.write(0x99); // Test failed - could not reopen the test file + Serial1.write(0x99); // Test failed - could not reopen the test file #ifdef verboseProdTest Serial.println(F("Failed to reopen test file")); #endif @@ -499,7 +538,7 @@ void productionTest() } else { - SerialLog.write(0x99); // Test failed - could not create the test file + Serial1.write(0x99); // Test failed - could not create the test file #ifdef verboseProdTest Serial.println(F("Failed to create test file")); #endif @@ -507,7 +546,7 @@ void productionTest() } else { - SerialLog.write(0x99); // Test failed - SD is not online + Serial1.write(0x99); // Test failed - SD is not online #ifdef verboseProdTest Serial.println(F("SD card is not online!")); #endif @@ -517,26 +556,26 @@ void productionTest() break; case 0x55: // Deep sleep { - detachInterrupt(digitalPinToInterrupt(PIN_POWER_LOSS)); // Disable power loss interrupt + detachInterrupt(PIN_POWER_LOSS); // Disable power loss interrupt Serial.end(); //Power down UART //Force the peripherals off - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); - am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); + //am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); //Disable pads for (int x = 0; x < 50; x++) { - if ((x != ap3_gpio_pin2pad(PIN_POWER_LOSS)) && - //(x != ap3_gpio_pin2pad(PIN_LOGIC_DEBUG)) && - (x != ap3_gpio_pin2pad(PIN_MICROSD_POWER)) && - (x != ap3_gpio_pin2pad(PIN_QWIIC_POWER)) && - (x != ap3_gpio_pin2pad(PIN_IMU_POWER))) + if ((x != PIN_POWER_LOSS) && + //(x != PIN_LOGIC_DEBUG) && + (x != PIN_MICROSD_POWER) && + (x != PIN_QWIIC_POWER) && + (x != PIN_IMU_POWER)) { am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE); } @@ -545,14 +584,15 @@ void productionTest() imuPowerOff(); microSDPowerOff(); qwiicPowerOff(); - //Power down Flash, SRAM, cache - am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_CACHE); //Turn off CACHE - am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); //Turn off everything but lower 512k - am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); //Turn off everything but lower 64k - //am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); //Turn off all memory (doesn't recover) - //Keep the 32kHz clock running for RTC + + //Power down cache, flash, SRAM + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); // Power down all flash and cache + am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_384K); // Retain all SRAM + + //Use the lower power 32kHz clock. Use it to run CT6 as well. am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE); - am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ); + am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ | AM_HAL_STIMER_CFG_COMPARE_G_ENABLE); + while (1) // Stay in deep sleep until we get reset { am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); //Sleep diff --git a/Firmware/OpenLog_Artemis/settings.h b/Firmware/OpenLog_Artemis/settings.h index b60b726..936cae1 100644 --- a/Firmware/OpenLog_Artemis/settings.h +++ b/Firmware/OpenLog_Artemis/settings.h @@ -26,7 +26,7 @@ typedef enum DEVICE_VOC_SGP40, DEVICE_PRESSURE_SDP3X, DEVICE_PRESSURE_MS5837, -// DEVICE_QWIIC_BUTTON, + DEVICE_QWIIC_BUTTON, DEVICE_BIO_SENSOR_HUB, DEVICE_TOTAL_DEVICES, //Marks the end, used to iterate loops @@ -315,15 +315,15 @@ struct struct_MS5837 { unsigned long powerOnDelayMillis = minimumQwiicPowerOnDelay; // Wait for at least this many millis before communicating with this device. Increase if required! }; -//struct struct_QWIIC_BUTTON { -// bool log = true; -// bool logPressed = true; -// bool logClicked = true; -// bool toggleLEDOnClick = true; -// bool ledState = false; // Do not store in NVM -// uint8_t ledBrightness = 255; -// unsigned long powerOnDelayMillis = 3000; // Wait for at least this many millis before communicating with this device. Increase if required! -//}; +struct struct_QWIIC_BUTTON { + bool log = true; + bool logPressed = true; + bool logClicked = true; + bool toggleLEDOnClick = true; + bool ledState = false; // Do not store in NVM + uint8_t ledBrightness = 255; + unsigned long powerOnDelayMillis = minimumQwiicPowerOnDelay; // Wait for at least this many millis before communicating with this device. Increase if required! +}; struct struct_BIO_SENSOR_HUB { bool log = true; @@ -403,7 +403,7 @@ struct struct_settings { int imuAccFSS = 0; // IMU accelerometer full scale - default to gpm2 (ICM_20948_ACCEL_CONFIG_FS_SEL_e) int imuAccDLPFBW = 7; // IMU accelerometer DLPF bandwidth - default to acc_d473bw_n499bw (ICM_20948_ACCEL_CONFIG_DLPCFG_e) int imuGyroFSS = 0; // IMU gyro full scale - default to 250 degrees per second (ICM_20948_GYRO_CONFIG_1_FS_SEL_e) - int imuGyroDLPFBW = 7; // IMU gyro DLPF bandwidth - default to gyr_d361bw4_n376bw5 (ICM_20948_GYRO_CONFIG_1_DLPCFG_e) + int imuGyroDLPFBW = 7; // IMU gyro DLPF bandwidth - default to gyr_d361bw4_n376bw5 (ICM_20948_GYRO_CONFIG_1_DLPCFG_e) bool logMicroseconds = false; // Log micros() bool useTxRxPinsForTerminal = false; // If true, the terminal is echo'd to the Tx and Rx pins. Note: setting this to true will _permanently_ disable serial logging and analog input on those pins! bool timestampSerial = false; // If true, the RTC time will be added to the serial log file when timeStampToken is received @@ -423,6 +423,8 @@ struct struct_settings { bool imuLogDMPCpass = false; // If true, log INV_ICM20948_SENSOR_MAGNETIC_FIELD_UNCALIBRATED unsigned long minimumAwakeTimeMillis = 0; // Set to greater than zero to keep the Artemis awake for this long between sleeps bool identifyBioSensorHubs = false; // If true, Bio Sensor Hubs (Pulse Oximeters) will be included in autoDetect (requires exclusive use of pins 32 and 11) + bool serialTxRxDuringSleep = false; // If true, the Serial Tx and Rx pins are left enabled during sleep - to prevent the COM port reinitializing + bool printGNSSDebugMessages = false; } settings; //These are the devices on board OpenLog that may be on or offline. diff --git a/Firmware/OpenLog_Artemis/support.ino b/Firmware/OpenLog_Artemis/support.ino index 70f7332..1acb047 100644 --- a/Firmware/OpenLog_Artemis/support.ino +++ b/Firmware/OpenLog_Artemis/support.ino @@ -1,21 +1,35 @@ +bool useRTCmillis(void) +{ + return (((settings.useGPIO11ForTrigger == false) && (settings.usBetweenReadings >= maxUsBeforeSleep)) + || (settings.useGPIO11ForFastSlowLogging == true) + || (settings.useRTCForFastSlowLogging == true)); +} + +uint64_t bestMillis(void) +{ + if (useRTCmillis()) + return(rtcMillis()); + else + return(millis()); +} + void printDebug(String thingToPrint) { if(settings.printDebugMessages == true) { Serial.print(thingToPrint); if (settings.useTxRxPinsForTerminal == true) - SerialLog.print(thingToPrint); + Serial1.print(thingToPrint); } } - //Option not known void printUnknown(uint8_t unknownChoice) { SerialPrint(F("Unknown choice: ")); Serial.write(unknownChoice); if (settings.useTxRxPinsForTerminal == true) - SerialLog.write(unknownChoice); + Serial1.write(unknownChoice); SerialPrintln(F("")); } void printUnknown(int unknownValue) @@ -23,7 +37,7 @@ void printUnknown(int unknownValue) SerialPrint(F("Unknown value: ")); Serial.write(unknownValue); if (settings.useTxRxPinsForTerminal == true) - SerialLog.write(unknownValue); + Serial1.write(unknownValue); SerialPrintln(F("")); } @@ -39,7 +53,7 @@ void waitForInput() while (Serial.available() > 0) Serial.read(); //Clear buffer if (settings.useTxRxPinsForTerminal == true) - while (SerialLog.available() > 0) SerialLog.read(); //Clear buffer + while (Serial1.available() > 0) Serial1.read(); //Clear buffer bool keepChecking = true; while (keepChecking) @@ -49,7 +63,7 @@ void waitForInput() if (settings.useTxRxPinsForTerminal == true) { - if (SerialLog.available()) + if (Serial1.available()) keepChecking = false; } @@ -74,7 +88,7 @@ uint8_t getByteChoice(int numberOfSeconds, bool updateDZSERIAL) while (Serial.available() > 0) Serial.read(); //Clear buffer if (settings.useTxRxPinsForTerminal == true) - while (SerialLog.available() > 0) SerialLog.read(); //Clear buffer + while (Serial1.available() > 0) Serial1.read(); //Clear buffer long startTime = millis(); byte incoming; @@ -91,24 +105,24 @@ uint8_t getByteChoice(int numberOfSeconds, bool updateDZSERIAL) // SerialPrint(F("byte: 0x")); // Serial.println(incoming, HEX); // if (settings.useTxRxPinsForTerminal == true) -// SerialLog.println(incoming, HEX); +// Serial1.println(incoming, HEX); if (incoming >= 'a' && incoming <= 'z') break; if (incoming >= 'A' && incoming <= 'Z') break; if (incoming >= '0' && incoming <= '9') break; } - if ((settings.useTxRxPinsForTerminal == true) && (SerialLog.available() > 0)) + if ((settings.useTxRxPinsForTerminal == true) && (Serial1.available() > 0)) { - incoming = SerialLog.read(); + incoming = Serial1.read(); if (updateDZSERIAL) { - DSERIAL = &SerialLog; - ZSERIAL = &SerialLog; + DSERIAL = &Serial1; + ZSERIAL = &Serial1; } // SerialPrint(F("byte: 0x")); // Serial.println(incoming, HEX); // if (settings.useTxRxPinsForTerminal == true) -// SerialLog.println(incoming, HEX); +// Serial1.println(incoming, HEX); if (incoming >= 'a' && incoming <= 'z') break; if (incoming >= 'A' && incoming <= 'Z') break; if (incoming >= '0' && incoming <= '9') break; @@ -141,7 +155,7 @@ int64_t getNumber(int numberOfSeconds) while (Serial.available() > 0) Serial.read(); //Clear buffer if (settings.useTxRxPinsForTerminal == true) - while (SerialLog.available() > 0) SerialLog.read(); //Clear buffer + while (Serial1.available() > 0) Serial1.read(); //Clear buffer //Get input from user char cleansed[20]; //Good for very large numbers: 123,456,789,012,345,678\0 @@ -156,7 +170,7 @@ int64_t getNumber(int numberOfSeconds) if (Serial.available()) serialAvailable = true; - if ((settings.useTxRxPinsForTerminal == true) && (SerialLog.available())) + if ((settings.useTxRxPinsForTerminal == true) && (Serial1.available())) serialAvailable = true; checkBattery(); @@ -188,7 +202,7 @@ int64_t getNumber(int numberOfSeconds) incoming = Serial.read(); else - incoming = SerialLog.read(); + incoming = Serial1.read(); if (incoming == '\n' || incoming == '\r') { @@ -201,7 +215,7 @@ int64_t getNumber(int numberOfSeconds) Serial.write(incoming); //Echo user's typing if (settings.useTxRxPinsForTerminal == true) - SerialLog.write(incoming); //Echo user's typing + Serial1.write(incoming); //Echo user's typing cleansed[spot++] = (char)incoming; } @@ -246,7 +260,7 @@ double getDouble(int numberOfSeconds) while (Serial.available() > 0) Serial.read(); //Clear buffer if (settings.useTxRxPinsForTerminal == true) - while (SerialLog.available() > 0) SerialLog.read(); //Clear buffer + while (Serial1.available() > 0) Serial1.read(); //Clear buffer //Get input from user char cleansed[20]; //Good for very large numbers: 123,456,789,012,345,678\0 @@ -262,7 +276,7 @@ double getDouble(int numberOfSeconds) if (Serial.available()) serialAvailable = true; - if ((settings.useTxRxPinsForTerminal == true) && (SerialLog.available())) + if ((settings.useTxRxPinsForTerminal == true) && (Serial1.available())) serialAvailable = true; checkBattery(); @@ -294,7 +308,7 @@ double getDouble(int numberOfSeconds) incoming = Serial.read(); else - incoming = SerialLog.read(); + incoming = Serial1.read(); if (incoming == '\n' || incoming == '\r') { @@ -307,7 +321,7 @@ double getDouble(int numberOfSeconds) Serial.write(incoming); //Echo user's typing if (settings.useTxRxPinsForTerminal == true) - SerialLog.write(incoming); //Echo user's typing + Serial1.write(incoming); //Echo user's typing cleansed[spot++] = (char)incoming; } @@ -352,3 +366,287 @@ double getDouble(int numberOfSeconds) } return (largeNumber); } + +//***************************************************************************** +// +// Divide an unsigned 32-bit value by 10. +// +// Note: Adapted from Ch10 of Hackers Delight (hackersdelight.org). +// +//***************************************************************************** +static uint64_t divu64_10(uint64_t ui64Val) +{ + uint64_t q64, r64; + uint32_t q32, r32, ui32Val; + + // + // If a 32-bit value, use the more optimal 32-bit routine. + // + if ( ui64Val >> 32 ) + { + q64 = (ui64Val>>1) + (ui64Val>>2); + q64 += (q64 >> 4); + q64 += (q64 >> 8); + q64 += (q64 >> 16); + q64 += (q64 >> 32); + q64 >>= 3; + r64 = ui64Val - q64*10; + return q64 + ((r64 + 6) >> 4); + } + else + { + ui32Val = (uint32_t)(ui64Val & 0xffffffff); + q32 = (ui32Val>>1) + (ui32Val>>2); + q32 += (q32 >> 4); + q32 += (q32 >> 8); + q32 += (q32 >> 16); + q32 >>= 3; + r32 = ui32Val - q32*10; + return (uint64_t)(q32 + ((r32 + 6) >> 4)); + } +} + +//***************************************************************************** +// +// Converts ui64Val to a string. +// Note: pcBuf[] must be sized for a minimum of 21 characters. +// +// Returns the number of decimal digits in the string. +// +// NOTE: If pcBuf is NULL, will compute a return ui64Val only (no chars +// written). +// +//***************************************************************************** +static int uint64_to_str(uint64_t ui64Val, char *pcBuf) +{ + char tbuf[25]; + int ix = 0, iNumDig = 0; + unsigned uMod; + uint64_t u64Tmp; + + do + { + // + // Divide by 10 + // + u64Tmp = divu64_10(ui64Val); + + // + // Get modulus + // + uMod = ui64Val - (u64Tmp * 10); + + tbuf[ix++] = uMod + '0'; + ui64Val = u64Tmp; + } while ( ui64Val ); + + // + // Save the total number of digits + // + iNumDig = ix; + + // + // Now, reverse the buffer when saving to the caller's buffer. + // + if ( pcBuf ) + { + while ( ix-- ) + { + *pcBuf++ = tbuf[ix]; + } + + // + // Terminate the caller's buffer + // + *pcBuf = 0x00; + } + + return iNumDig; +} + +//***************************************************************************** +// +// Float to ASCII text. A basic implementation for providing support for +// single-precision %f. +// +// param +// fValue = Float value to be converted. +// pcBuf = Buffer to place string AND input of buffer size. +// iPrecision = Desired number of decimal places. +// bufSize = The size (in bytes) of the buffer. +// The recommended size is at least 16 bytes. +// +// This function performs a basic translation of a floating point single +// precision value to a string. +// +// return Number of chars printed to the buffer. +// +//***************************************************************************** +#define OLA_FTOA_ERR_VAL_TOO_SMALL -1 +#define OLA_FTOA_ERR_VAL_TOO_LARGE -2 +#define OLA_FTOA_ERR_BUFSIZE -3 + +typedef union +{ + int32_t I32; + float F; +} ola_i32fl_t; + +static int olaftoa(float fValue, char *pcBuf, int iPrecision, int bufSize) +{ + ola_i32fl_t unFloatValue; + int iExp2, iBufSize; + int32_t i32Significand, i32IntPart, i32FracPart; + char *pcBufInitial, *pcBuftmp; + + iBufSize = bufSize; // *(uint32_t*)pcBuf; + if (iBufSize < 4) + { + return OLA_FTOA_ERR_BUFSIZE; + } + + if (fValue == 0.0f) + { + // "0.0" + *(uint32_t*)pcBuf = 0x00 << 24 | ('0' << 16) | ('.' << 8) | ('0' << 0); + return 3; + } + + pcBufInitial = pcBuf; + + unFloatValue.F = fValue; + + iExp2 = ((unFloatValue.I32 >> 23) & 0x000000FF) - 127; + i32Significand = (unFloatValue.I32 & 0x00FFFFFF) | 0x00800000; + i32FracPart = 0; + i32IntPart = 0; + + if (iExp2 >= 31) + { + return OLA_FTOA_ERR_VAL_TOO_LARGE; + } + else if (iExp2 < -23) + { + return OLA_FTOA_ERR_VAL_TOO_SMALL; + } + else if (iExp2 >= 23) + { + i32IntPart = i32Significand << (iExp2 - 23); + } + else if (iExp2 >= 0) + { + i32IntPart = i32Significand >> (23 - iExp2); + i32FracPart = (i32Significand << (iExp2 + 1)) & 0x00FFFFFF; + } + else // if (iExp2 < 0) + { + i32FracPart = (i32Significand & 0x00FFFFFF) >> -(iExp2 + 1); + } + + if (unFloatValue.I32 < 0) + { + *pcBuf++ = '-'; + } + + if (i32IntPart == 0) + { + *pcBuf++ = '0'; + } + else + { + if (i32IntPart > 0) + { + uint64_to_str(i32IntPart, pcBuf); + } + else + { + *pcBuf++ = '-'; + uint64_to_str(-i32IntPart, pcBuf); + } + while (*pcBuf) // Get to end of new string + { + pcBuf++; + } + } + + // + // Now, begin the fractional part + // + *pcBuf++ = '.'; + + if (i32FracPart == 0) + { + *pcBuf++ = '0'; + } + else + { + int jx, iMax; + + iMax = iBufSize - (pcBuf - pcBufInitial) - 1; + iMax = (iMax > iPrecision) ? iPrecision : iMax; + + for (jx = 0; jx < iMax; jx++) + { + i32FracPart *= 10; + *pcBuf++ = (i32FracPart >> 24) + '0'; + i32FracPart &= 0x00FFFFFF; + } + + // + // Per the printf spec, the number of digits printed to the right of the + // decimal point (i.e. iPrecision) should be rounded. + // Some examples: + // Value iPrecision Formatted value + // 1.36399 Unspecified (6) 1.363990 + // 1.36399 3 1.364 + // 1.36399 4 1.3640 + // 1.36399 5 1.36399 + // 1.363994 Unspecified (6) 1.363994 + // 1.363994 3 1.364 + // 1.363994 4 1.3640 + // 1.363994 5 1.36399 + // 1.363995 Unspecified (6) 1.363995 + // 1.363995 3 1.364 + // 1.363995 4 1.3640 + // 1.363995 5 1.36400 + // 1.996 Unspecified (6) 1.996000 + // 1.996 2 2.00 + // 1.996 3 1.996 + // 1.996 4 1.9960 + // + // To determine whether to round up, we'll look at what the next + // decimal value would have been. + // + if ( ((i32FracPart * 10) >> 24) >= 5 ) + { + // + // Yes, we need to round up. + // Go back through the string and make adjustments as necessary. + // + pcBuftmp = pcBuf - 1; + while ( pcBuftmp >= pcBufInitial ) + { + if ( *pcBuftmp == '.' ) + { + } + else if ( *pcBuftmp == '9' ) + { + *pcBuftmp = '0'; + } + else + { + *pcBuftmp += 1; + break; + } + pcBuftmp--; + } + } + } + + // + // Terminate the string and we're done + // + *pcBuf = 0x00; + + return (pcBuf - pcBufInitial); +} // ftoa() diff --git a/Firmware/OpenLog_Artemis/timeStamp.ino b/Firmware/OpenLog_Artemis/timeStamp.ino index e0288f2..ada44eb 100644 --- a/Firmware/OpenLog_Artemis/timeStamp.ino +++ b/Firmware/OpenLog_Artemis/timeStamp.ino @@ -10,11 +10,26 @@ void getTimeString(char timeStringBuffer[]) if (settings.logDate) { - char rtcDate[12]; //10/12/2019, + char rtcDate[12]; // 10/12/2019, + char rtcDay[3]; + char rtcMonth[3]; + char rtcYear[5]; + if (myRTC.dayOfMonth < 10) + sprintf(rtcDay, "0%d", myRTC.dayOfMonth); + else + sprintf(rtcDay, "%d", myRTC.dayOfMonth); + if (myRTC.month < 10) + sprintf(rtcMonth, "0%d", myRTC.month); + else + sprintf(rtcMonth, "%d", myRTC.month); + if (myRTC.year < 10) + sprintf(rtcYear, "200%d", myRTC.year); + else + sprintf(rtcYear, "20%d", myRTC.year); if (settings.americanDateStyle == true) - sprintf(rtcDate, "%02d/%02d/20%02d,", myRTC.month, myRTC.dayOfMonth, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); else - sprintf(rtcDate, "%02d/%02d/20%02d,", myRTC.dayOfMonth, myRTC.month, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); strcat(timeStringBuffer, rtcDate); } @@ -26,14 +41,63 @@ void getTimeString(char timeStringBuffer[]) { if (adjustedHour > 12) adjustedHour -= 12; } - sprintf(rtcTime, "%02d:%02d:%02d.%02d,", adjustedHour, myRTC.minute, myRTC.seconds, myRTC.hundredths); + char rtcHour[3]; + char rtcMin[3]; + char rtcSec[3]; + char rtcHundredths[3]; + if (adjustedHour < 10) + sprintf(rtcHour, "0%d", adjustedHour); + else + sprintf(rtcHour, "%d", adjustedHour); + if (myRTC.minute < 10) + sprintf(rtcMin, "0%d", myRTC.minute); + else + sprintf(rtcMin, "%d", myRTC.minute); + if (myRTC.seconds < 10) + sprintf(rtcSec, "0%d", myRTC.seconds); + else + sprintf(rtcSec, "%d", myRTC.seconds); + if (myRTC.hundredths < 10) + sprintf(rtcHundredths, "0%d", myRTC.hundredths); + else + sprintf(rtcHundredths, "%d", myRTC.hundredths); + sprintf(rtcTime, "%s:%s:%s.%s,", rtcHour, rtcMin, rtcSec, rtcHundredths); strcat(timeStringBuffer, rtcTime); } if (settings.logMicroseconds) { - char microseconds[11]; // - sprintf(microseconds, "%lu,", micros()); + // Convert uint64_t to string + // Based on printLLNumber by robtillaart + // https://forum.arduino.cc/index.php?topic=143584.msg1519824#msg1519824 + char microsecondsRev[20]; // Char array to hold to microseconds (reversed order) + char microseconds[20]; // Char array to hold to microseconds (correct order) + uint64_t microsNow = micros(); + unsigned int i = 0; + + if (microsNow == 0ULL) // if usBetweenReadings is zero, set tempTime to "0" + { + microseconds[0] = '0'; + microseconds[1] = ','; + microseconds[2] = 0; + } + + else + { + while (microsNow > 0) + { + microsecondsRev[i++] = (microsNow % 10) + '0'; // divide by 10, convert the remainder to char + microsNow /= 10; // divide by 10 + } + unsigned int j = 0; + while (i > 0) + { + microseconds[j++] = microsecondsRev[--i]; // reverse the order + microseconds[j] = ','; + microseconds[j+1] = 0; // mark the end with a NULL + } + } + strcat(timeStringBuffer, microseconds); } } diff --git a/Firmware/OpenLog_Artemis/zmodem.ino b/Firmware/OpenLog_Artemis/zmodem.ino index b46ce74..db44eeb 100644 --- a/Firmware/OpenLog_Artemis/zmodem.ino +++ b/Firmware/OpenLog_Artemis/zmodem.ino @@ -267,7 +267,7 @@ void sdCardMenu(void) if (DSERIAL == &Serial) sd.ls("/", LS_DATE | LS_SIZE); // Do a non-recursive LS of the root directory showing file modification dates and sizes else - sd.ls(&SerialLog, "/", LS_DATE | LS_SIZE); + sd.ls(&Serial1, "/", LS_DATE | LS_SIZE); DSERIALprintln(F("End of Directory\r\n")); } @@ -412,7 +412,12 @@ void sdCardMenu(void) { settings.logA12 = false; //Disable analog readings on TX pin if (settings.useTxRxPinsForTerminal == false) - SerialLog.begin(settings.serialLogBaudRate); // (Re)start the serial port + { + //We need to manually restore the Serial1 TX and RX pins + configureSerial1TxRx(); + + Serial1.begin(settings.serialLogBaudRate); // (Re)start the serial port + } DSERIALprint(F("\r\nSending ")); DSERIAL->print(param); DSERIALprint(F(" to the TX pin at ")); DSERIAL->print(settings.serialLogBaudRate); DSERIALprintln(F(" baud")); @@ -420,7 +425,7 @@ void sdCardMenu(void) { char ch; if (fout.read(&ch, 1) == 1) // Read a single char - SerialLog.write(ch); // Send it via SerialLog (TX pin) + Serial1.write(ch); // Send it via SerialLog (TX pin) } fout.close(); diff --git a/Firmware/OpenLog_Artemis/zmodem_crc16.cpp b/Firmware/OpenLog_Artemis/zmodem_crc16.cpp index a975769..60da0d8 100644 --- a/Firmware/OpenLog_Artemis/zmodem_crc16.cpp +++ b/Firmware/OpenLog_Artemis/zmodem_crc16.cpp @@ -1,4 +1,4 @@ -#include +//#include - not supported in v2 of the Apollo3 core /* @@ -8,7 +8,8 @@ #define ZMODEM_CRC16_CPP /* crctab calculated by Mark G. Mendel, Network Systems Corporation */ // Dylan (monte_carlo_ecm, bitflipper, etc.) - Moved to PROGMEM -PROGMEM static const unsigned short crctab[256] = { +//PROGMEM static const unsigned short crctab[256] = { - not supported in v2 of the Apollo3 core +static const unsigned short crctab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, @@ -103,7 +104,8 @@ PROGMEM static const unsigned short crctab[256] = { // Pete (El_Supremo) add 'unsigned' // Dylan (monte_carlo_ecm, bitflipper, etc.) - Moved to PROGMEM -PROGMEM static const unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */ +//PROGMEM static const unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */ - not supported in v2 of the Apollo3 core +static const unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, @@ -158,4 +160,3 @@ long c; /* End of crctab.c */ #endif - diff --git a/Firmware/OpenLog_Artemis/zmodem_fixes.h b/Firmware/OpenLog_Artemis/zmodem_fixes.h index b5ec90d..9bbf97f 100644 --- a/Firmware/OpenLog_Artemis/zmodem_fixes.h +++ b/Firmware/OpenLog_Artemis/zmodem_fixes.h @@ -6,7 +6,7 @@ From: http://stackoverflow.com/questions/2607853/why-prototype-is-used-header-fi #ifndef ZMODEM_FIXES_H #define ZMODEM_FIXES_H -#define SERIAL_TX_BUFFER_SIZE AP3_UART_RINGBUFF_SIZE +#define SERIAL_TX_BUFFER_SIZE SERIAL_BUFFER_SIZE // AP3_UART_RINGBUFF_SIZE //////////////////////////////////////////////////////// diff --git a/Firmware/Test Sketches/IMU_DMP_Quat9/IMU_DMP_Quat9.ino b/Firmware/Test Sketches/IMU_DMP_Quat9/IMU_DMP_Quat9.ino index 757d2d0..0c25663 100644 --- a/Firmware/Test Sketches/IMU_DMP_Quat9/IMU_DMP_Quat9.ino +++ b/Firmware/Test Sketches/IMU_DMP_Quat9/IMU_DMP_Quat9.ino @@ -53,6 +53,15 @@ void setup() { digitalWrite(PIN_IMU_CHIP_SELECT, HIGH); //Be sure IMU is deselected pinMode(PIN_IMU_INT, INPUT_PULLUP); + //There is a quirk in v2.1 of the Apollo3 mbed core which means that the first SPI transaction will + //disable the pull-up on CIPO. We need to do a fake transaction and then re-enable the pull-up + //to work around this... +#if defined(ARDUINO_ARCH_MBED) + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); // Do a fake transaction + SPI.endTransaction(); + enableCIPOpullUp(); // Re-enable the CIPO pull-up +#endif + //Reset ICM by power cycling it imuPowerOff(); @@ -86,7 +95,7 @@ void setup() { // Initialize the ICM-20948 // If the DMP is enabled, .begin performs a minimal startup. We need to configure the sample mode etc. manually. - myICM.begin( CS_PIN, SPI_PORT ); + myICM.begin( CS_PIN, SPI_PORT, 4000000); //Set IMU SPI rate to 4MHz #ifndef QUAT_ANIMATION SERIAL_PORT.print( F("Initialization of the sensor returned: ") ); @@ -279,16 +288,27 @@ void imuPowerOff() digitalWrite(PIN_IMU_POWER, LOW); } +#if defined(ARDUINO_ARCH_MBED) // updated for v2.1.0 of the Apollo3 core +bool enableCIPOpullUp() +{ + //Add 1K5 pull-up on CIPO + am_hal_gpio_pincfg_t cipoPinCfg = g_AM_BSP_GPIO_IOM0_MISO; + cipoPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; + pin_config(D6, cipoPinCfg); + return (true); +} +#else bool enableCIPOpullUp() { //Add CIPO pull-up ap3_err_t retval = AP3_OK; am_hal_gpio_pincfg_t cipoPinCfg = AP3_GPIO_DEFAULT_PINCFG; cipoPinCfg.uFuncSel = AM_HAL_PIN_6_M0MISO; + cipoPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; cipoPinCfg.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA; cipoPinCfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL; cipoPinCfg.uIOMnum = AP3_SPI_IOM; - cipoPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K; padMode(MISO, cipoPinCfg, &retval); return (retval == AP3_OK); } +#endif