diff --git a/include/power.h b/include/power.h index c27daa6c..1ef571e1 100644 --- a/include/power.h +++ b/include/power.h @@ -9,16 +9,16 @@ #define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate #define NO_OF_SAMPLES 64 // we do some multisampling to get better values -#ifdef HAS_PMU -#include -void pover_event_IRQ(void); -void AXP192_power(bool on); -#endif - -void AXP192_init(void); -void AXP192_displaypower(void); uint16_t read_voltage(void); void calibrate_voltage(void); bool batt_sufficient(void); +#ifdef HAS_PMU +#include +void power_event_IRQ(void); +void AXP192_power(bool on); +void AXP192_init(void); +void AXP192_showstatus(void); +#endif // HAS_PMU + #endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 5dd08b65..ba1ef203 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 1.8.31 +release_version = 1.8.34 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 3 @@ -55,7 +55,7 @@ platform_espressif32 = espressif32@1.10.0 monitor_speed = 115200 upload_speed = 115200 lib_deps_lora = - ;MCCI LoRaWAN LMIC library@2.3.2 + ;MCCI LoRaWAN LMIC library@3.1.0 https://github.com/mcci-catena/arduino-lmic.git#852f348 lib_deps_display = U8g2@>=2.26.13 @@ -73,8 +73,9 @@ lib_deps_basic = 76@>=1.2.2 ;Timezone by Jack Christensen 274@>=2.3.3 ;RTC by Michael Miller SimpleButton - ;AXP202X_Library@^1.0.0 - https://github.com/cyberman54/AXP202X_Library.git + ;AXP202X_Library@^1.0.1 + https://github.com/lewisxhe/AXP202X_Library.git#8045ddf + ;https://github.com/cyberman54/AXP202X_Library.git#b7116de lib_deps_all = ${common.lib_deps_basic} ${common.lib_deps_lora} @@ -120,6 +121,4 @@ upload_protocol = esptool upload_protocol = esptool build_type = debug platform = https://github.com/platformio/platform-espressif32.git#develop -platform_packages = - ; use upstream Git version - framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git +platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git diff --git a/src/cyclic.cpp b/src/cyclic.cpp index d616d573..ef2ce200 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -62,10 +62,7 @@ void doHousekeeping() { else ESP_LOGI(TAG, "Battery: %dmV", batt_voltage); #ifdef HAS_PMU - if (I2C_MUTEX_LOCK()) { - AXP192_displaypower(); - I2C_MUTEX_UNLOCK(); - } + AXP192_showstatus(); #endif #endif diff --git a/src/display.cpp b/src/display.cpp index 4826b2a2..b89f551d 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -179,7 +179,10 @@ void draw_page(time_t t, uint8_t page) { // update Battery status (line 2) #if (defined BAT_MEASURE_ADC || defined HAS_PMU) u8x8.setCursor(0, 2); - u8x8.printf("B:%.2fV", batt_voltage / 1000.0); + if (batt_voltage == 0xffff) + u8x8.printf("B:USB "); + else + u8x8.printf("B:%.2fV", batt_voltage / 1000.0); #endif // update GPS status (line 2) @@ -204,10 +207,10 @@ void draw_page(time_t t, uint8_t page) { #endif #if (HAS_LORA) - u8x8.setCursor(11, 3); + u8x8.setCursor(12, 3); if (!cfg.adrmode) // if ADR=off then display SF value inverse u8x8.setInverseFont(1); - u8x8.printf("%4s", getSfName(updr2rps(LMIC.datarate))); + u8x8.printf("%-4s", getSfName(updr2rps(LMIC.datarate))); if (!cfg.adrmode) // switch off inverse if it was turned on u8x8.setInverseFont(0); #endif // HAS_LORA diff --git a/src/hal/ttgobeam10.h b/src/hal/ttgobeam10.h index dffe7c61..fa0b3ffa 100644 --- a/src/hal/ttgobeam10.h +++ b/src/hal/ttgobeam10.h @@ -7,9 +7,24 @@ #include -// Hardware related definitions for TTGO T-Beam board -// (only) for newer T-Beam version T22_V10 -// pinouts taken from https://github.com/lewisxhe/TTGO-T-Beam +/* +Hardware related definitions for TTGO T-Beam board +(only) for newer T-Beam version T22_V10 +pinouts taken from https://github.com/lewisxhe/TTGO-T-Beam + +/// Button functions: /// +Power, short press -> set device on (toggles display while device is on) +Power, long press -> set device off +User, short press -> flip display page +User, long press -> send LORA message +Reset -> reset device +*/ + +//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C +#define MY_OLED_SDA SDA +#define MY_OLED_SCL SCL +#define MY_OLED_RST U8X8_PIN_NONE +//#define DISPLAY_FLIP 1 // use if display is rotated #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 // HPD13A LoRa SoC @@ -30,16 +45,30 @@ //#define HAS_BME680 SDA, SCL //#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !! -// display (if connected) -//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C -//#define MY_OLED_SDA SDA -//#define MY_OLED_SCL SCL -//#define MY_OLED_RST U8X8_PIN_NONE -//#define DISPLAY_FLIP 1 // use if display is rotated - // user defined sensors (if connected) //#define HAS_SENSORS 1 // comment out if device has user defined sensors //#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature #endif + +/* + +// T-Beam V10 has on board power management by AXP192 PMU chip: +// +// DCDC1 0.7-3.5V @ 1200mA -> OLED +// DCDC3 0.7-3.5V @ 700mA -> ESP32 (keep this on!) +// LDO1 30mA -> GPS Backup +// LDO2 200mA -> LORA +// LDO3 200mA -> GPS + +// Wiring for I2C OLED display: +// +// Signal Header OLED +// 3V3 7 VCC +// GND 8 GND +// IO22(SCL) 9 SCL +// IO21(SDA) 10 SDA +// + +*/ diff --git a/src/irqhandler.cpp b/src/irqhandler.cpp index 74bcd29f..8d1be880 100644 --- a/src/irqhandler.cpp +++ b/src/irqhandler.cpp @@ -66,7 +66,7 @@ void irqHandler(void *pvParameters) { // do we have a power event? #if (HAS_PMU) if (InterruptStatus & PMU_IRQ) - pover_event_IRQ(); + power_event_IRQ(); #endif // is time to send the payload? diff --git a/src/power.cpp b/src/power.cpp index c7297123..83748286 100644 --- a/src/power.cpp +++ b/src/power.cpp @@ -9,9 +9,12 @@ static const char TAG[] = __FILE__; AXP20X_Class pmu; -void pover_event_IRQ(void) { - // block i2c bus access - if (I2C_MUTEX_LOCK()) { +void power_event_IRQ(void) { + + if (!I2C_MUTEX_LOCK()) + ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); + else { + pmu.readIRQ(); // put your power event handler code here @@ -36,61 +39,63 @@ void pover_event_IRQ(void) { if (pmu.isBattTempHighIRQ()) ESP_LOGI(TAG, "Battery low temperature."); - // wake up + // display on/off if (pmu.isPEKShortPressIRQ()) { - ESP_LOGI(TAG, "Power Button short pressed."); - AXP192_power(true); + cfg.screenon = !cfg.screenon; } - // enter sleep mode + + // shutdown power if (pmu.isPEKLongtPressIRQ()) { - ESP_LOGI(TAG, "Power Button long pressed."); - AXP192_power(false); - delay(20); - esp_sleep_enable_ext1_wakeup(GPIO_SEL_38, ESP_EXT1_WAKEUP_ALL_LOW); - esp_deep_sleep_start(); + AXP192_power(false); // switch off Lora, GPS, display + pmu.shutdown(); } pmu.clearIRQ(); - I2C_MUTEX_UNLOCK(); // release i2c bus access - } else - ESP_LOGI(TAG, "Unknown PMU event."); + I2C_MUTEX_UNLOCK(); + } // mutex + + // refresh stored voltage value + read_voltage(); } void AXP192_power(bool on) { - if (on) { - pmu.setPowerOutPut(AXP192_LDO2, AXP202_ON); // Lora on T-Beam V1.0 - pmu.setPowerOutPut(AXP192_LDO3, AXP202_ON); // Gps on T-Beam V1.0 - pmu.setPowerOutPut(AXP192_DCDC2, AXP202_ON); - pmu.setPowerOutPut(AXP192_EXTEN, AXP202_ON); - pmu.setPowerOutPut(AXP192_DCDC1, AXP202_ON); + pmu.setPowerOutPut(AXP192_LDO2, AXP202_ON); // Lora on T-Beam V1.0 + pmu.setPowerOutPut(AXP192_LDO3, AXP202_ON); // Gps on T-Beam V1.0 + pmu.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED on T-Beam v1.0 // pmu.setChgLEDMode(AXP20X_LED_LOW_LEVEL); pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ); } else { + pmu.setChgLEDMode(AXP20X_LED_OFF); pmu.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); - pmu.setPowerOutPut(AXP192_EXTEN, AXP202_OFF); - pmu.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF); pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF); - pmu.setChgLEDMode(AXP20X_LED_OFF); } } -void AXP192_displaypower(void) { - if (pmu.isBatteryConnect()) - if (pmu.isChargeing()) - ESP_LOGI(TAG, "Battery charging, %.2fV @ %.0fmAh", - pmu.getBattVoltage() / 1000, pmu.getBattChargeCurrent()); - else - ESP_LOGI(TAG, "Battery not charging"); - else - ESP_LOGI(TAG, "No Battery"); +void AXP192_showstatus(void) { - if (pmu.isVBUSPlug()) - ESP_LOGI(TAG, "USB present, %.2fV @ %.0fmA", pmu.getVbusVoltage() / 1000, - pmu.getVbusCurrent()); - else - ESP_LOGI(TAG, "USB not present"); + if (!I2C_MUTEX_LOCK()) + ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); + else { + + if (pmu.isBatteryConnect()) + if (pmu.isChargeing()) + ESP_LOGI(TAG, "Battery charging, %.2fV @ %.0fmAh", + pmu.getBattVoltage() / 1000, pmu.getBattChargeCurrent()); + else + ESP_LOGI(TAG, "Battery not charging"); + else + ESP_LOGI(TAG, "No Battery"); + + if (pmu.isVBUSPlug()) + ESP_LOGI(TAG, "USB powered, %.0fmW", + pmu.getVbusVoltage() / 1000 * pmu.getVbusCurrent()); + else + ESP_LOGI(TAG, "USB not present"); + + I2C_MUTEX_UNLOCK(); + } // mutex } void AXP192_init(void) { @@ -102,9 +107,10 @@ void AXP192_init(void) { ESP_LOGI(TAG, "AXP192 PMU initialization failed"); else { - // switch power on - pmu.setDCDC1Voltage(3300); // for external OLED display - AXP192_power(true); + // configure AXP192 + pmu.setDCDC1Voltage(3300); // for external OLED display + pmu.setTimeOutShutdown(false); // no automatic shutdown + pmu.setTSmode(AXP_TS_PIN_MODE_DISABLE); // TS pin mode off to save power // switch ADCs on pmu.adc1Enable(AXP202_BATT_VOL_ADC1, true); @@ -112,8 +118,8 @@ void AXP192_init(void) { pmu.adc1Enable(AXP202_VBUS_VOL_ADC1, true); pmu.adc1Enable(AXP202_VBUS_CUR_ADC1, true); - // set TS pin mode off to save power - pmu.setTSmode(AXP_TS_PIN_MODE_DISABLE); + // switch power rails on + AXP192_power(true); // I2C access of AXP202X library currently is not mutexable // so we better should disable AXP interrupts... ? @@ -121,13 +127,13 @@ void AXP192_init(void) { pinMode(PMU_INT, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(PMU_INT), PMUIRQ, FALLING); pmu.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | - AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ, + AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ | + AXP202_CHARGING_FINISHED_IRQ, 1); pmu.clearIRQ(); #endif // PMU_INT - ESP_LOGI(TAG, "AXP192 PMU initialized, chip temp %.1f°C", pmu.getTemp()); - AXP192_displaypower(); + ESP_LOGI(TAG, "AXP192 PMU initialized"); } I2C_MUTEX_UNLOCK(); // release i2c bus access } else @@ -157,7 +163,7 @@ void calibrate_voltage(void) { ESP_ERROR_CHECK(adc1_config_width(ADC_WIDTH_BIT_12)); ESP_ERROR_CHECK(adc1_config_channel_atten(adc_channel, atten)); #else // ADC2 - // ESP_ERROR_CHECK(adc2_config_width(ADC_WIDTH_BIT_12)); + // ESP_ERROR_CHECK(adc2_config_width(ADC_WIDTH_BIT_12)); ESP_ERROR_CHECK(adc2_config_channel_atten(adc_channel, atten)); #endif // calibrate ADC @@ -187,11 +193,15 @@ bool batt_sufficient() { } uint16_t read_voltage() { - uint16_t voltage = 0; #ifdef HAS_PMU - voltage = pmu.isVBUSPlug() ? 0xffff : pmu.getBattVoltage(); + if (!I2C_MUTEX_LOCK()) + ESP_LOGW(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0); + else { + voltage = pmu.isVBUSPlug() ? 0xffff : pmu.getBattVoltage(); + I2C_MUTEX_UNLOCK(); + } #else #ifdef BAT_MEASURE_ADC