From d92cb8d4352165e1adf1b1fcfdd24bd58f80f3e5 Mon Sep 17 00:00:00 2001 From: Jonas Niesner Date: Sun, 6 Jul 2025 17:45:46 +0200 Subject: [PATCH] Better low power functions (#13) --- NRF_firmware/platformio.ini | 16 +- NRF_firmware/src/main.cpp | 453 ++++++++++++++++++++++++++++-------- NRF_firmware/src/main.h | 15 +- 3 files changed, 384 insertions(+), 100 deletions(-) diff --git a/NRF_firmware/platformio.ini b/NRF_firmware/platformio.ini index 213e740..cb862ac 100644 --- a/NRF_firmware/platformio.ini +++ b/NRF_firmware/platformio.ini @@ -1,3 +1,13 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + [env:hgd4] platform = nordicnrf52 board = hgd4 @@ -8,11 +18,11 @@ lib_deps = adafruit/Adafruit Unified Sensor@^1.1.15 adafruit/Adafruit LIS3DH@^1.3.0 sparkfun/SparkFun Ambient Light Sensor Arduino Library@^1.0.4 - https://github.com/stm32duino/LPS22HB vshymanskyy/TinyGSM@^0.12.0 koendv/RTT Stream@^1.4.1 arduino-libraries/ArduinoHttpClient@^0.6.1 bblanchon/ArduinoJson@^6.21.4 + sodaqmoja/Sodaq_LPS22HB@^1.0.0 build_unflags = -DNRF52 -DUSE_LFXO build_flags = -DNRF52840_XXAA -DUSE_LFRC -DNRF52_S140 lib_compat_mode = soft @@ -20,5 +30,5 @@ upload_protocol = jlink debug_tool = jlink monitor_port = socket://localhost:19021 extra_scripts = - generate_production_image.py - custom_upload.py \ No newline at end of file + generate_production_image.py + custom_upload.py diff --git a/NRF_firmware/src/main.cpp b/NRF_firmware/src/main.cpp index 218eaec..6861808 100644 --- a/NRF_firmware/src/main.cpp +++ b/NRF_firmware/src/main.cpp @@ -10,8 +10,9 @@ void setup() { rtt.trimDownBufferFull(); rtt.println("|---------Starting setup---------|"); gpioinit(); + scanI2C(); + collectAllSensorData(); sensorData.wakeup_reason = NRF_POWER->RESETREAS; - delay(200); initializeModem(); sensorpwr(true); blinkLED(1, 200, 200, true); @@ -237,7 +238,7 @@ void scanforbeacons(){ while (bleScanning && bleBeaconsFound < deviceConfig.ble_scan_max_beacons && (millis() - scanStartTime) < deviceConfig.ble_scan_duration) { - delay(100); + delay(10); // Check if scan duration has expired if (millis() - bleScanStartTime > deviceConfig.ble_scan_duration) { @@ -295,15 +296,6 @@ void displaySensorDataSummary() { rtt.println(" sats"); } -void resetI2CBus() { - rtt.println("Resetting I2C bus..."); - Wire.end(); - delay(100); - Wire.begin(); - delay(100); - rtt.println("I2C bus reset completed"); -} - void sensorpwr(bool onoff){ if(!onoff){ rtt.println("Power down sensors"); @@ -321,9 +313,8 @@ void sensorpwr(bool onoff){ rtt.println("Power up sensors"); pinMode(SENSOR_PWR,OUTPUT); digitalWrite(SENSOR_PWR,HIGH); - delay(100); + delay(20); Wire.begin(); - delay(50); } } @@ -342,15 +333,6 @@ void collectAllSensorData(){ sensorData.watchdog_counter = wdcounter; sensorData.battery_voltage = readBatteryVoltage(); sensorData.lux = readLightSensor(0.5, 200); - if (sensorData.lux < 0) { - rtt.println("Light sensor failed, resetting I2C bus and retrying..."); - resetI2CBus(); - sensorData.lux = readLightSensor(0.5, 200); - if (sensorData.lux < 0) { - rtt.println("Light sensor failed after retry, using default value"); - sensorData.lux = 0.0; - } - } float temp, hum; if (readTemperatureHumidity(temp, hum)) { sensorData.case_temperature = temp; @@ -377,6 +359,8 @@ void powerdownmodem(){ rtt.println("Modem already off"); return; } + SerialAT.flush(); + SerialAT.end(); rtt.println("Powering down modem"); rtt.println("Pressing modem power button"); digitalWrite(MODEM_PWRKEY,HIGH); @@ -392,23 +376,6 @@ void powerdownmodem(){ } } -void powerdownesp(){ - if(!espon){ - rtt.println("ESP already off"); - return; - } - rtt.println("Powering esp down"); - digitalWrite(MODEM_ESP_PWR,LOW); - delay(50); - espon = false; - if(!modemon){ - rtt.println("Powering down espmodem rail"); - digitalWrite(MODEM_ESP_PWR,LOW); - delay(50); - espmodemrail = false; - } -} - void softpwrup(){ digitalWrite(MODEM_ESP_PWR,HIGH); delay(1); @@ -423,7 +390,7 @@ void softpwrup(){ digitalWrite(MODEM_ESP_PWR,LOW); delay(2); digitalWrite(MODEM_ESP_PWR,HIGH); - delay(500); + delay(200); } void gpioinit(){ @@ -457,13 +424,13 @@ void gpioinit(){ digitalWrite(MODEM_CON_A,LOW); digitalWrite(MODEM_CON_B,LOW); //this is not nice and needs to be done get one initial watchdog pulse. This is also time sensitive so dont mess around with it - delay(600); - for (size_t i = 0; i < 50; i++) + delay(20); + for (size_t i = 0; i < 10; i++) { digitalWrite(DONE,HIGH); - delay(20); + delay(2); digitalWrite(DONE,LOW); - delay(20); + delay(2); } } @@ -482,7 +449,6 @@ void powerupesp(){ softpwrup(); } digitalWrite(ESP_PWR,HIGH); - delay(50); espmodemrail = true; espon = true; } @@ -560,10 +526,9 @@ bool readTemperatureHumidity(float& temperature, float& humidity) { } bool readPressure(float& pressure, float& sensorTemp) { - lps22hb.begin(); - lps22hb.GetPressure(&pressure); - lps22hb.GetTemperature(&sensorTemp); - lps22hb.end(); + barometricSensor.init(); + pressure = barometricSensor.readPressureHPA(); + sensorTemp = barometricSensor.readTemperature(); return (pressure != 0.0 || sensorTemp != 0.0); } @@ -571,16 +536,38 @@ bool readAccelerometers(float& acc1_x, float& acc1_y, float& acc1_z, float& acc2 if (!acc1.begin() || !acc2.begin()) { return false; } + + // Set range for both accelerometers acc1.setRange(LIS3DH_RANGE_2_G); acc2.setRange(LIS3DH_RANGE_2_G); + + // Read data from both accelerometers acc1.read(); acc2.read(); + + // Extract values acc1_x = acc1.x; acc1_y = acc1.y; acc1_z = acc1.z; acc2_x = acc2.x; acc2_y = acc2.y; acc2_z = acc2.z; + + // Power optimization: Put accelerometers in low power mode + acc1.enableDRDY(false); // Disable data ready interrupt + acc2.enableDRDY(false); // Disable data ready interrupt + + // Power optimization: Disable SPI after use to reduce power consumption + // This prevents SPI from staying active and consuming power + SPI.end(); + + // Power optimization: Set SPI pins to input to reduce leakage current + //pinMode(SPI_CLK, INPUT); + //pinMode(SPI_MISO, INPUT); + //pinMode(SPI_MOSI, INPUT); + //pinMode(ACCL1_CS, INPUT); + //pinMode(ACCL2_CS, INPUT); + return true; } @@ -590,7 +577,6 @@ bool readGPS(float& latitude, float& longitude, float& speed, float& altitude, i } unsigned long startTime = millis(); modem.enableGPS(); - delay(5000L); int gps_year, gps_month, gps_day, gps_hour, gps_minute, gps_second; for (int8_t i = 3; i; i--) { if (millis() - startTime > deviceConfig.gps_timeout) { @@ -605,8 +591,8 @@ bool readGPS(float& latitude, float& longitude, float& speed, float& altitude, i modem.disableGPS(); return true; } else { - rtt.println("Couldn't get GPS/GNSS/GLONASS location, retrying in 5s."); - delay(5000L); + rtt.println("Couldn't get GPS/GNSS/GLONASS location, retrying in 2s."); + delay(2000); } } modem.disableGPS(); @@ -619,7 +605,6 @@ bool initializeModem() { } powerupmodem(); SerialAT.begin(115200); - delay(10); if (!modem.init()) { rtt.println("Modem init failed"); powerdownmodem(); @@ -716,19 +701,19 @@ bool sendSensorDataToServer(const SensorData& data, const ServerConfig& config) // Build JSON object efficiently doc["ts"] = data.timestamp; doc["lx"] = data.lux; - doc["bat"] = round(data.battery_voltage * 100) / 100.0; - doc["tmp"] = round(data.case_temperature * 10) / 10.0; - doc["hum"] = round(data.case_humidity * 10) / 10.0; - doc["prs"] = round(data.pressure * 100) / 100.0; - doc["pt"] = round(data.pressure_sensor_temp * 100) / 100.0; + doc["bat"] = data.battery_voltage; + doc["tmp"] = data.case_temperature; + doc["hum"] = data.case_humidity; + doc["prs"] = data.pressure; + doc["pt"] = data.pressure_sensor_temp; doc["a1x"] = data.acc1_x; doc["a1y"] = data.acc1_y; doc["a1z"] = data.acc1_z; doc["a2x"] = data.acc2_x; doc["a2y"] = data.acc2_y; doc["a2z"] = data.acc2_z; - doc["glt"] = round(data.gps_latitude * 100000000) / 100000000.0; - doc["gln"] = round(data.gps_longitude * 100000000) / 100000000.0; + doc["glt"] = data.gps_latitude; + doc["gln"] = data.gps_longitude; doc["gsp"] = data.gps_speed; doc["gal"] = data.gps_altitude; doc["gsv"] = data.gps_visible_satellites; @@ -737,7 +722,7 @@ bool sendSensorDataToServer(const SensorData& data, const ServerConfig& config) doc["wkr"] = data.wakeup_reason; doc["wdc"] = data.watchdog_counter; doc["mid"] = data.modem_id.length() > 0 ? data.modem_id : "unknown"; - doc["mt"] = round(data.modem_temperature * 10) / 10.0; + doc["mt"] = data.modem_temperature; doc["sid"] = data.sim_card_id.length() > 0 ? data.sim_card_id : "unknown"; doc["nn"] = data.network_name.length() > 0 ? data.network_name : "unknown"; doc["nid"] = data.network_id.length() > 0 ? data.network_id : "unknown"; @@ -897,7 +882,7 @@ bool sendSensorDataToServer(const SensorData& data, const ServerConfig& config) rtt.print("HTTP error: "); rtt.println(statusCode); if (attempt < 3) { rtt.println("Retrying..."); - delay(3000); // Longer delay between retries + delay(2000); continue; } } @@ -935,7 +920,6 @@ void manageModemLifecycle() { return; } } - collectAllSensorData(); readModemInfo(); if (deviceConfig.enable_gps) { rtt.println("Acquiring GPS data..."); @@ -962,7 +946,6 @@ void manageModemLifecycle() { readNetworkInfo(); if (sendSensorDataToServer(sensorData)) { rtt.println("Data transmission successful"); - blinkLED(4, 200, 400, true); } else { rtt.println("Data transmission failed"); blinkLED(4, 200, 400, false); @@ -1102,9 +1085,6 @@ bool modemFileOpen(const String& filename, int mode) { // rtt.print("Opening file: "); rtt.print(filename); rtt.print(" mode: "); rtt.println(mode); modem.sendAT(GF("+QFOPEN="), filename, GF(","), mode); - // Add delay before reading response - delay(200); - String response = modem.stream.readString(); // rtt.println("Open response: " + response); @@ -1617,11 +1597,8 @@ bool initializeESPSerial() { } rtt.println("Initializing ESP serial communication..."); Serial2.begin(115200); - //pinMode(ESP_TXD, OUTPUT); - //pinMode(ESP_RXD, INPUT); powerupESP(); - delay(2000); - //digitalWrite(ESP_TXD, HIGH); + delay(200); espSerialInitialized = true; return true; } @@ -1650,6 +1627,9 @@ void powerdownESP() { return; } rtt.println("Powering down ESP microcontroller..."); + Serial2.flush(); + Serial2.end(); + pinMode(ESP_GPIO0, INPUT); digitalWrite(ESP_PWR, LOW); delay(50); espon = false; @@ -2178,26 +2158,6 @@ void optimizeScanData(DynamicJsonDocument& doc, size_t maxSize) { rtt.print("After WiFi removal: "); rtt.print(currentSize); rtt.println(" bytes"); } - // If still too large, reduce precision of sensor data - if (currentSize > maxSize) { - rtt.println("Reducing sensor data precision"); - - // Reduce GPS precision - if (doc.containsKey("glt")) doc["glt"] = round(doc["glt"].as() * 1000000) / 1000000.0; - if (doc.containsKey("gln")) doc["gln"] = round(doc["gln"].as() * 1000000) / 1000000.0; - - // Reduce accelerometer precision - if (doc.containsKey("a1x")) doc["a1x"] = round(doc["a1x"].as() * 100) / 100.0; - if (doc.containsKey("a1y")) doc["a1y"] = round(doc["a1y"].as() * 100) / 100.0; - if (doc.containsKey("a1z")) doc["a1z"] = round(doc["a1z"].as() * 100) / 100.0; - if (doc.containsKey("a2x")) doc["a2x"] = round(doc["a2x"].as() * 100) / 100.0; - if (doc.containsKey("a2y")) doc["a2y"] = round(doc["a2y"].as() * 100) / 100.0; - if (doc.containsKey("a2z")) doc["a2z"] = round(doc["a2z"].as() * 100) / 100.0; - - currentSize = measureJson(doc); - rtt.print("After precision reduction: "); rtt.print(currentSize); rtt.println(" bytes"); - } - if (currentSize <= maxSize) { rtt.println("Optimization successful"); } else { @@ -2275,7 +2235,7 @@ void performBackgroundTasks() { lastMotionCheck = millis(); } - delay(10); + delay(100); } // Function to parse JSON response from server @@ -2440,4 +2400,313 @@ void logPowerManagementStatus() { rtt.print(globalMotionDetected ? "Yes" : "No"); rtt.print(", Keep Modem On: "); rtt.println(shouldKeepModemPowered() ? "Yes" : "No"); +} + +void checkAllInterruptFlags() { + rtt.println("=== Interrupt Status Check ==="); + + // Check NVIC pending interrupts + bool hasPending = false; + for (int i = 0; i < 8; i++) { + if (NVIC->ISPR[i] != 0) { + rtt.print("NVIC pending in word "); rtt.print(i); rtt.print(": 0x"); rtt.println(NVIC->ISPR[i], HEX); + + // Identify specific interrupt sources + uint32_t pending = NVIC->ISPR[i]; + for (int bit = 0; bit < 32; bit++) { + if (pending & (1 << bit)) { + int irq_num = i * 32 + bit; + rtt.print(" IRQ "); rtt.print(irq_num); rtt.print(" (bit "); rtt.print(bit); rtt.print("): "); + + // Map IRQ numbers to peripherals + switch (irq_num) { + case 38: rtt.println("UARTE0"); break; + case 39: rtt.println("UARTE1"); break; + case 40: rtt.println("UARTE2"); break; + case 41: rtt.println("UARTE3"); break; + case 42: rtt.println("SWI2 (BLE)"); break; + case 43: rtt.println("SWI3 (BLE)"); break; + case 44: rtt.println("SWI4 (BLE)"); break; + case 45: rtt.println("SWI5 (BLE)"); break; + case 6: rtt.println("GPIOTE"); break; + case 7: rtt.println("SAADC"); break; + case 8: rtt.println("TIMER0"); break; + case 9: rtt.println("TIMER1"); break; + case 10: rtt.println("TIMER2"); break; + case 11: rtt.println("RTC0"); break; + case 12: rtt.println("TEMP"); break; + case 13: rtt.println("RNG"); break; + case 14: rtt.println("ECB"); break; + case 15: rtt.println("CCM_AAR"); break; + case 16: rtt.println("WDT"); break; + case 17: rtt.println("RTC1"); break; + case 18: rtt.println("QDEC"); break; + case 19: rtt.println("COMP_LPCOMP"); break; + case 20: rtt.println("SWI0_EGU0"); break; + case 21: rtt.println("SWI1_EGU1"); break; + case 22: rtt.println("SWI2_EGU2"); break; + case 23: rtt.println("SWI3_EGU3"); break; + case 24: rtt.println("SWI4_EGU4"); break; + case 25: rtt.println("SWI5_EGU5"); break; + case 26: rtt.println("TIMER3"); break; + case 27: rtt.println("TIMER4"); break; + case 28: rtt.println("PWM0"); break; + case 29: rtt.println("PDM"); break; + case 30: rtt.println("MWU"); break; + case 31: rtt.println("PWM1"); break; + case 32: rtt.println("PWM2"); break; + case 33: rtt.println("SPIM2_SPIS2_SPI2"); break; + case 34: rtt.println("RTC2"); break; + case 35: rtt.println("I2S"); break; + case 36: rtt.println("FPU"); break; + case 37: rtt.println("USBD"); break; + default: rtt.println("Unknown peripheral"); break; + } + } + } + hasPending = true; + } + } + if(hasPending){ + + // Check UART interrupts with detailed event analysis + if (NRF_UARTE0->INTENSET != 0) { + rtt.print("UARTE0 interrupts enabled: 0x"); rtt.println(NRF_UARTE0->INTENSET, HEX); + + // Check specific UARTE0 events + rtt.println("UARTE0 Event Analysis:"); + + // Check ENDRX (End of RX buffer transfer) + if (NRF_UARTE0->EVENTS_ENDRX) { + rtt.println(" - ENDRX event: PENDING"); + } + + // Check ENDTX (End of TX buffer transfer) + if (NRF_UARTE0->EVENTS_ENDTX) { + rtt.println(" - ENDTX event: PENDING"); + } + + // Check ERROR event + if (NRF_UARTE0->EVENTS_ERROR) { + rtt.println(" - ERROR event: PENDING"); + rtt.print(" Error source: 0x"); rtt.println(NRF_UARTE0->ERRORSRC, HEX); + } + + // Check RXTO (RX timeout) + if (NRF_UARTE0->EVENTS_RXTO) { + rtt.println(" - RXTO event: PENDING"); + } + + // Check RXSTARTED + if (NRF_UARTE0->EVENTS_RXSTARTED) { + rtt.println(" - RXSTARTED event: PENDING"); + } + + // Check TXSTARTED + if (NRF_UARTE0->EVENTS_TXSTARTED) { + rtt.println(" - TXSTARTED event: PENDING"); + } + + // Check TXSTOPPED + if (NRF_UARTE0->EVENTS_TXSTOPPED) { + rtt.println(" - TXSTOPPED event: PENDING"); + } + + // Show enabled interrupts vs pending events + rtt.print(" Enabled interrupts: "); + if (NRF_UARTE0->INTENSET & UARTE_INTENSET_ENDRX_Msk) rtt.print("ENDRX "); + if (NRF_UARTE0->INTENSET & UARTE_INTENSET_ENDTX_Msk) rtt.print("ENDTX "); + if (NRF_UARTE0->INTENSET & UARTE_INTENSET_ERROR_Msk) rtt.print("ERROR "); + if (NRF_UARTE0->INTENSET & UARTE_INTENSET_RXTO_Msk) rtt.print("RXTO "); + if (NRF_UARTE0->INTENSET & UARTE_INTENSET_RXSTARTED_Msk) rtt.print("RXSTARTED "); + if (NRF_UARTE0->INTENSET & UARTE_INTENSET_TXSTARTED_Msk) rtt.print("TXSTARTED "); + if (NRF_UARTE0->INTENSET & UARTE_INTENSET_TXSTOPPED_Msk) rtt.print("TXSTOPPED "); + rtt.println(); + + // Show pending events + rtt.print(" Pending events: "); + if (NRF_UARTE0->EVENTS_ENDRX) rtt.print("ENDRX "); + if (NRF_UARTE0->EVENTS_ENDTX) rtt.print("ENDTX "); + if (NRF_UARTE0->EVENTS_ERROR) rtt.print("ERROR "); + if (NRF_UARTE0->EVENTS_RXTO) rtt.print("RXTO "); + if (NRF_UARTE0->EVENTS_RXSTARTED) rtt.print("RXSTARTED "); + if (NRF_UARTE0->EVENTS_TXSTARTED) rtt.print("TXSTARTED "); + if (NRF_UARTE0->EVENTS_TXSTOPPED) rtt.print("TXSTOPPED "); + rtt.println(); + } + + if (NRF_UARTE1->INTENSET != 0) { + rtt.print("UARTE1 interrupts enabled: 0x"); rtt.println(NRF_UARTE1->INTENSET, HEX); + + // Check specific UARTE1 events + rtt.println("UARTE1 Event Analysis:"); + if (NRF_UARTE1->EVENTS_ENDRX) rtt.println(" - ENDRX event: PENDING"); + if (NRF_UARTE1->EVENTS_ENDTX) rtt.println(" - ENDTX event: PENDING"); + if (NRF_UARTE1->EVENTS_ERROR) rtt.println(" - ERROR event: PENDING"); + if (NRF_UARTE1->EVENTS_RXTO) rtt.println(" - RXTO event: PENDING"); + if (NRF_UARTE1->EVENTS_RXSTARTED) rtt.println(" - RXSTARTED event: PENDING"); + if (NRF_UARTE1->EVENTS_TXSTARTED) rtt.println(" - TXSTARTED event: PENDING"); + if (NRF_UARTE1->EVENTS_TXSTOPPED) rtt.println(" - TXSTOPPED event: PENDING"); + } + + // Check I2C interrupts + if (NRF_TWIM0->INTENSET != 0) { + rtt.print("TWIM0 interrupts enabled: 0x"); rtt.println(NRF_TWIM0->INTENSET, HEX); + } + + // Check GPIO interrupts + if (NRF_GPIOTE->INTENSET != 0) { + rtt.print("GPIOTE interrupts enabled: 0x"); rtt.println(NRF_GPIOTE->INTENSET, HEX); + + // Show detailed GPIOTE analysis if there are pending interrupts + if (hasPending) { + rtt.println("GPIOTE Event Analysis:"); + + // Check each GPIOTE channel (0-7) + for (int ch = 0; ch < 8; ch++) { + if (NRF_GPIOTE->EVENTS_IN[ch]) { + rtt.print(" - Channel "); rtt.print(ch); rtt.println(" event: PENDING"); + + // Show channel configuration + uint32_t config = NRF_GPIOTE->CONFIG[ch]; + rtt.print(" Mode: "); + if ((config & GPIOTE_CONFIG_MODE_Msk) == GPIOTE_CONFIG_MODE_Disabled) { + rtt.print("Disabled"); + } else if ((config & GPIOTE_CONFIG_MODE_Msk) == GPIOTE_CONFIG_MODE_Event) { + rtt.print("Event"); + } else if ((config & GPIOTE_CONFIG_MODE_Msk) == GPIOTE_CONFIG_MODE_Task) { + rtt.print("Task"); + } + + rtt.print(", Pin: "); rtt.print((config & GPIOTE_CONFIG_PSEL_Msk) >> GPIOTE_CONFIG_PSEL_Pos); + + rtt.print(", Polarity: "); + if ((config & GPIOTE_CONFIG_POLARITY_Msk) == GPIOTE_CONFIG_POLARITY_None) { + rtt.print("None"); + } else if ((config & GPIOTE_CONFIG_POLARITY_Msk) == GPIOTE_CONFIG_POLARITY_LoToHi) { + rtt.print("LoToHi"); + } else if ((config & GPIOTE_CONFIG_POLARITY_Msk) == GPIOTE_CONFIG_POLARITY_HiToLo) { + rtt.print("HiToLo"); + } else if ((config & GPIOTE_CONFIG_POLARITY_Msk) == GPIOTE_CONFIG_POLARITY_Toggle) { + rtt.print("Toggle"); + } + + rtt.print(", OutInit: "); + if ((config & GPIOTE_CONFIG_OUTINIT_Msk) == GPIOTE_CONFIG_OUTINIT_Low) { + rtt.print("Low"); + } else { + rtt.print("High"); + } + rtt.println(); + } + } + + // Show enabled vs pending + rtt.print(" Enabled channels: "); + for (int ch = 0; ch < 8; ch++) { + if (NRF_GPIOTE->INTENSET & (1 << ch)) { + rtt.print(ch); rtt.print(" "); + } + } + rtt.println(); + + rtt.print(" Pending channels: "); + for (int ch = 0; ch < 8; ch++) { + if (NRF_GPIOTE->EVENTS_IN[ch]) { + rtt.print(ch); rtt.print(" "); + } + } + rtt.println(); + } + } + + // Check SoftDevice events + uint32_t evt_id; + if (sd_evt_get(&evt_id) == NRF_SUCCESS) { + rtt.print("SoftDevice event pending: 0x"); rtt.println(evt_id, HEX); + } else { + rtt.println("No SoftDevice events pending"); + } + + // Check BLE events - using correct function signature + uint8_t ble_evt_buffer[sizeof(ble_evt_t)]; + uint16_t ble_evt_len = sizeof(ble_evt_buffer); + if (sd_ble_evt_get(ble_evt_buffer, &ble_evt_len) == NRF_SUCCESS) { + rtt.print("BLE event pending, length: "); rtt.println(ble_evt_len); + } else { + rtt.println("No BLE events pending"); + } + } + if (!hasPending) { + rtt.println("No NVIC pending interrupts"); + } + rtt.println("=== End Interrupt Check ==="); +} + +void check1msInterruptSources() { + rtt.println("=== 1ms Interrupt Source Check ==="); + + // Check SysTick (most likely culprit) + rtt.print("SysTick enabled: "); rtt.println((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) ? "Yes" : "No"); + rtt.print("SysTick pending: "); rtt.println((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) ? "Yes" : "No"); + + // Check RTC0 (commonly used for 1ms timing) + rtt.print("RTC0 enabled: "); rtt.println(NRF_RTC0->INTENSET ? "Yes" : "No"); + rtt.print("RTC0 running: "); rtt.println(NRF_RTC0->TASKS_START ? "Yes" : "No"); + rtt.print("RTC0 prescaler: "); rtt.println(NRF_RTC0->PRESCALER); + rtt.print("RTC0 compare[0]: "); rtt.println(NRF_RTC0->CC[0]); + + // Check RTC1 (used by SoftDevice) + rtt.print("RTC1 enabled: "); rtt.println(NRF_RTC1->INTENSET ? "Yes" : "No"); + rtt.print("RTC1 running: "); rtt.println(NRF_RTC1->TASKS_START ? "Yes" : "No"); + rtt.print("RTC1 prescaler: "); rtt.println(NRF_RTC1->PRESCALER); + + // Check TIMER0 (often used by Arduino) + rtt.print("TIMER0 enabled: "); rtt.println(NRF_TIMER0->INTENSET ? "Yes" : "No"); + rtt.print("TIMER0 running: "); rtt.println(NRF_TIMER0->TASKS_START ? "Yes" : "No"); + rtt.print("TIMER0 prescaler: "); rtt.println(NRF_TIMER0->PRESCALER); + + // Check TIMER1 + rtt.print("TIMER1 enabled: "); rtt.println(NRF_TIMER1->INTENSET ? "Yes" : "No"); + rtt.print("TIMER1 running: "); rtt.println(NRF_TIMER1->TASKS_START ? "Yes" : "No"); + + // Check TIMER2 + rtt.print("TIMER2 enabled: "); rtt.println(NRF_TIMER2->INTENSET ? "Yes" : "No"); + rtt.print("TIMER2 running: "); rtt.println(NRF_TIMER2->TASKS_START ? "Yes" : "No"); + + rtt.println("=== End 1ms Interrupt Check ==="); +} + +void scanI2C(){ + rtt.println("=== I2C Scanner ==="); + rtt.println("Scanning I2C bus for devices..."); + int deviceCount = 0; + + // Scan only valid I2C addresses (0x08 to 0x77, excluding reserved addresses) + for (byte address = 8; address < 120; address++) { + // Try to communicate with device at this address + Wire.beginTransmission(address); + byte error = Wire.endTransmission(); + + if (error == 0) { + // Device found + deviceCount++; + + // Identify common devices + switch (address) { + case 0x29: rtt.println("(VEML6035 Light)"); break; + case 0x43: rtt.println("(ENS210 Temp/Hum)"); break; + case 0x5D: rtt.println("(ENS210 Pres)"); break; + default: rtt.println("(Unknown)"); break; + } + } + // Small delay to prevent overwhelming the bus + delay(1); + // Yield to prevent watchdog issues + if (address % 32 == 0) { + yield(); + } + } + rtt.print("I2C scan completed. Found "); rtt.print(deviceCount); rtt.println(" device(s)."); + rtt.println("=== End I2C Scanner ==="); } \ No newline at end of file diff --git a/NRF_firmware/src/main.h b/NRF_firmware/src/main.h index 63ba732..aeea941 100644 --- a/NRF_firmware/src/main.h +++ b/NRF_firmware/src/main.h @@ -3,24 +3,25 @@ #include #include #include -#include +#include #include #include #include #include #include -#include "ens210.h" #include "SparkFun_VEML6030_Ambient_Light_Sensor.h" #include "sensors.h" +#include "ens210.h" SparkFun_Ambient_Light light(AL_ADDR); -ENS210 ens210; -LPS22HBSensor lps22hb(&Wire); +Sodaq_LPS22HB barometricSensor; Adafruit_LIS3DH acc1 = Adafruit_LIS3DH(ACCL1_CS); Adafruit_LIS3DH acc2 = Adafruit_LIS3DH(ACCL2_CS); +ENS210 ens210; + RTTStream rtt; TinyGsm modem(SerialAT); @@ -222,4 +223,8 @@ void triggerMotionTransmission(); // Power management functions bool shouldKeepModemPowered(); -void logPowerManagementStatus(); \ No newline at end of file +void logPowerManagementStatus(); +void checkAllInterruptFlags(); +void clearInterruptFlags(); +void check1msInterruptSources(); +void scanI2C(); \ No newline at end of file