From e5d4fbb164347b18dc7112341fabd9ffdf3b6f16 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 13:03:37 -0700 Subject: [PATCH 01/10] fix pins per email eink --- bin/install-bootloader.sh | 29 +++++++++++++++++++++++++ src/graphics/EInkDisplay.cpp | 5 +++++ src/nrf52/main-nrf52.cpp | 5 ----- variants/eink/variant.h | 42 ++++++++++++++++++++---------------- 4 files changed, 57 insertions(+), 24 deletions(-) create mode 100755 bin/install-bootloader.sh diff --git a/bin/install-bootloader.sh b/bin/install-bootloader.sh new file mode 100755 index 0000000000..3c7db57396 --- /dev/null +++ b/bin/install-bootloader.sh @@ -0,0 +1,29 @@ +# You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board + +BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader + +nrfjprog --eraseall -f nrf52 + +#echo Programming soft device +#nrfjprog --program $BOOTDIR/lib/softdevice/s140_nrf52_6.1.1/s140_nrf52_6.1.1_softdevice.hex -f nrf52 + +echo Programming bootloader and soft device +# the following ling incorrectly enables reset pin, because the running code rewrites it +nrfjprog --program $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-122-gf6bfaac-dirty_s140_6.1.1.hex -f nrf52 + +# this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid +# Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000 +# first 4 bytes should be 0x01 to indicate valid app image +# second 4 bytes should be 0x00 to indicate no CRC required for image +echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin +srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel + +echo Programming meshtastic app load +nrfjprog --program .pio/build/eink/firmware.hex -f nrf52 + +echo Telling bootloader app region is valid and telling CPU to run +nrfjprog --program /tmp/bootconf.hex -f nrf52 --reset + +# nrfjprog --readuicr /tmp/uicr.hex; objdump -s /tmp/uicr.hex | less + +echo FIXME use hexmerge diff --git a/src/graphics/EInkDisplay.cpp b/src/graphics/EInkDisplay.cpp index 2156f59190..da468af38b 100644 --- a/src/graphics/EInkDisplay.cpp +++ b/src/graphics/EInkDisplay.cpp @@ -95,6 +95,11 @@ bool EInkDisplay::connect() { DEBUG_MSG("Doing EInk init\n"); +#ifdef EINK_PIN_PWR_ON + digitalWrite(EINK_PIN_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals + pinMode(EINK_PIN_PWR_ON, OUTPUT); +#endif + #ifdef PIN_EINK_EN digitalWrite(PIN_EINK_EN, HIGH); pinMode(PIN_EINK_EN, OUTPUT); diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index 4a5c93f75f..867cdeefcc 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -93,11 +93,6 @@ void nrf52Setup() // This is the recommended setting for Monitor Mode Debugging NVIC_SetPriority(DebugMonitor_IRQn, 6UL); -#ifdef PIN_PWR_ON - digitalWrite(PIN_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals - pinMode(PIN_PWR_ON, OUTPUT); -#endif - // Not yet on board // pmu.init(); diff --git a/variants/eink/variant.h b/variants/eink/variant.h index e0cdda0d25..0c6f4eab36 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -27,25 +27,29 @@ /* @geeksville eink TODO: -confirm that watchdog reset (i.e. all pins now become inputs) won't cause the board to power down when we are not connected to USB -(I bet it will). If this happens recommended fix is to add an external pullup on PWR_ON GPIO. - +soonish: +hook cdc acm device to debug output fix bootloader to use two buttons - remove bootloader hacks -fix battery voltage sensing -fix floating point SEGGER printf on nrf52 - see "new NMEA GPS pos" get second button working in app load -if battery falls too low deassert PWR_ON (to force board to shutdown) fix display width and height clean up eink drawing to not have the nasty timeout hack +measure current draws put eink to sleep when we think the screen is off -enable flash on spi0, share chip selects on spi1. -https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fspi.html enable reset as a button in -bootloader fix battery pin usage drive TCXO DIO3 enable high whenever we want the clock use PIN_GPS_WAKE to sleep the GPS use -tp_ser_io as a button, it goes high when pressed unify eink display classes -make screen.adjustBrightness() a nop on eink screens enable gps sleep mode -use new flash chip +https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fspi.html enable reset as a button +make screen.adjustBrightness() a nop on eink screens + +later: +confirm that watchdog reset (i.e. all pins now become inputs) won't cause the board to power down when we are not connected to USB +(I bet it will). If this happens recommended fix is to add an external pullup on PWR_ON GPIO. +enable flash on spi0, share chip selects on spi1. +fix floating point SEGGER printf on nrf52 - see "new NMEA GPS pos" add factory/power on self test +use tp_ser_io as a button, it goes high when pressed unify eink display classes + +feedback to give: +remove ipx connector for nfc, instead use two caps and loop traces on the back of the board as an antenna? + */ /*---------------------------------------------------------------------------- @@ -122,9 +126,6 @@ work. #define TP_SER_IO (0 + 11) -// Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON -#define PIN_PWR_ON (0 + 12) - #define PIN_RTC_INT (0 + 16) // Interrupt from the PCF8563 RTC /* @@ -175,6 +176,9 @@ FIXME define/FIX flash access #define PIN_EINK_SCLK (0 + 31) #define PIN_EINK_MOSI (0 + 29) // also called SDI +// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON +#define PIN_EINK_PWR_ON (0 + 12) + #define HAS_EINK #define PIN_SPI1_MISO \ @@ -186,10 +190,10 @@ FIXME define/FIX flash access * Air530 GPS pins */ -#define PIN_GPS_WAKE (32 + 2) -#define PIN_GPS_PPS (32 + 4) -#define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU -#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS +#define PIN_GPS_WAKE (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake +#define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS +#define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU +#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS #define PIN_SERIAL1_RX PIN_GPS_TX #define PIN_SERIAL1_TX PIN_GPS_RX From a0fd83428f2c0c3945234a2ebc920e8cb70712f4 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 13:10:27 -0700 Subject: [PATCH 02/10] eink use RESET button as regular button instead --- src/configuration.h | 4 ++++ variants/eink/variant.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/configuration.h b/src/configuration.h index 026bb1880c..ad783d0d5c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -77,6 +77,10 @@ along with this program. If not, see . #define BUTTON_PIN PIN_BUTTON1 #endif +#ifdef PIN_BUTTON2 +#define BUTTON_PIN_ALT PIN_BUTTON2 +#endif + // FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets) #elif defined(CubeCell_BoardPlus) diff --git a/variants/eink/variant.h b/variants/eink/variant.h index 0c6f4eab36..6ab4e073b3 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -87,6 +87,7 @@ extern "C" { * Buttons */ #define PIN_BUTTON1 (32 + 10) +#define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular GPIO /* * Analog pins From 6a4ef7e1d12dc209a6aeaacefecedd8047877c37 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 14:09:19 -0700 Subject: [PATCH 03/10] eink board serial flash seems to work --- bin/qspi-flash-test.sh | 6 ++++ nrf52/ttgo_eink_qpsi.ini | 69 ++++++++++++++++++++++++++++++++++++++++ variants/eink/variant.h | 37 +++++++++++---------- 3 files changed, 95 insertions(+), 17 deletions(-) create mode 100755 bin/qspi-flash-test.sh create mode 100644 nrf52/ttgo_eink_qpsi.ini diff --git a/bin/qspi-flash-test.sh b/bin/qspi-flash-test.sh new file mode 100755 index 0000000000..7fc186b5d3 --- /dev/null +++ b/bin/qspi-flash-test.sh @@ -0,0 +1,6 @@ +# You probably don't need this - it is a basic test of the serial flash on the TTGO eink board + +nrfjprog -qspiini nrf52/ttgo_eink_qpsi.ini --qspieraseall +nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --memwr 0x12000000 --val 0xdeadbeef --verify +nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --readqspi spi.hex +objdump -s spi.hex | less diff --git a/nrf52/ttgo_eink_qpsi.ini b/nrf52/ttgo_eink_qpsi.ini new file mode 100644 index 0000000000..d477db8ef7 --- /dev/null +++ b/nrf52/ttgo_eink_qpsi.ini @@ -0,0 +1,69 @@ +; nrfjprog.exe configuration file. + +; Note: QSPI flash is mapped into memory at address 0x12000000 + +[DEFAULT_CONFIGURATION] +; Define the capacity of the flash memory device in bytes. Set to 0 if no external memory device is present in your board. +; MX25R1635F is 16Mbit/2Mbyte +MemSize = 0x200000 + +; Define the desired ReadMode. Valid options are FASTREAD, READ2O, READ2IO, READ4O and READ4IO +ReadMode = READ2IO + +; Define the desired WriteMode. Valid options are PP, PP2O, PP4O and PP4IO +WriteMode = PP + +; Define the desired AddressMode. Valid options are BIT24 and BIT32 +AddressMode = BIT24 + +; Define the desired Frequency. Valid options are M2, M4, M8, M16 and M32 +Frequency = M16 + +; Define the desired SPI mode. Valid options are MODE0 and MODE3 +SpiMode = MODE0 + +; Define the desired SckDelay. Valid options are in the range 0 to 255 +SckDelay = 0x80 + +; Define the desired IO level for DIO2 and DIO3 during a custom instruction. Valid options are LEVEL_HIGH and LEVEL_LOW +CustomInstructionIO2Level = LEVEL_LOW +CustomInstructionIO3Level = LEVEL_HIGH + +; Define the assigned pins for the QSPI peripheral. Valid options are those existing in your device +CSNPin = 15 +CSNPort = 1 +SCKPin = 14 +SCKPort = 1 +DIO0Pin = 12 +DIO0Port = 1 +DIO1Pin = 13 +DIO1Port = 1 + +;These two pins are not connected, but we must name something +DIO2Pin = 3 +DIO2Port = 1 +DIO3Pin = 5 +DIO3Port = 1 + +; Define the Index of the Write In Progress (WIP) bit in the status register. Valid options are in the range of 0 to 7. +WIPIndex = 0 + +; Define page size for commands. Valid sizes are PAGE256 and PAGE512. +PPSize = PAGE256 + +; Custom instructions to send to the external memory after initialization. Format is instruction code plus data to send in between optional brakets. +; These instructions will be executed each time the qspi peripheral is initiated by nrfjprog. +; To improve execution speed on consecutive interations with QSPI, you can run nrfjprog once with custom initialization, and then comment out the lines below. +; Numbers can be given in decimal, hex (starting with either 0x or 0X) and binary (starting with either 0b or 0B) formats. +; The custom instructions will be executed in the order found. + +; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) enabling the Quad Operation and the High Performance +; mode for the MX25R6435F memory present in the nRF52840 DK. +;InitializationCustomInstruction = 0x06 +;InitializationCustomInstruction = 0x01, [0x40, 0, 0x2] + +; For MX25R1635F on TTGO board, only two data lines are connected +; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) disabling Quad Operation and the High Performance +; mode. For normal operation you might want low power mode instead. +InitializationCustomInstruction = 0x06 +InitializationCustomInstruction = 0x01, [0x00, 0, 0x2] diff --git a/variants/eink/variant.h b/variants/eink/variant.h index 6ab4e073b3..c1781c84e4 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -30,7 +30,7 @@ soonish: hook cdc acm device to debug output fix bootloader to use two buttons - remove bootloader hacks -get second button working in app load +DONE get second button working in app load fix display width and height clean up eink drawing to not have the nasty timeout hack measure current draws @@ -48,8 +48,14 @@ add factory/power on self test use tp_ser_io as a button, it goes high when pressed unify eink display classes feedback to give: -remove ipx connector for nfc, instead use two caps and loop traces on the back of the board as an antenna? +* remove ipx connector for nfc, instead use two caps and loop traces on the back of the board as an antenna? + +* I've made the serial flash chip work, but if you do a new spin of the board I recommend: +connect pin 3 and pin 7 of U4 to spare GPIOs on the processor (instead of their current connections), +This would allow using 4 bit wide interface mode to the serial flash. +doubling the transfer speed! see example here: +https://infocenter.nordicsemi.com/topic/ug_nrf52840_dk/UG/nrf52840_DK/hw_external_memory.html?cp=4_0_4_7_4 */ /*---------------------------------------------------------------------------- @@ -108,11 +114,10 @@ static const uint8_t A0 = PIN_A0; */ /* -This serial port is _also_ connected to the incoming D+/D- pins from the USB header. FIXME, figure out how that is supposed to -work. +No longer populated on PCB */ -#define PIN_SERIAL2_RX (0 + 6) -#define PIN_SERIAL2_TX (0 + 8) +//#define PIN_SERIAL2_RX (0 + 6) +//#define PIN_SERIAL2_TX (0 + 8) // #define PIN_SERIAL2_EN (0 + 17) /** @@ -130,23 +135,21 @@ work. #define PIN_RTC_INT (0 + 16) // Interrupt from the PCF8563 RTC /* - -FIXME define/FIX flash access +External serial flash WP25R1635FZUIL0 +*/ // QSPI Pins -#define PIN_QSPI_SCK 19 -#define PIN_QSPI_CS 17 -#define PIN_QSPI_IO0 20 -#define PIN_QSPI_IO1 21 -#define PIN_QSPI_IO2 22 -#define PIN_QSPI_IO3 23 +#define PIN_QSPI_SCK (32 + 14) +#define PIN_QSPI_CS (32 + 15) +#define PIN_QSPI_IO0 (32 + 12) // MOSI if using two bit interface +#define PIN_QSPI_IO1 (32 + 13) // MISO if using two bit interface +//#define PIN_QSPI_IO2 22 // WP if using two bit interface (i.e. not used) +//#define PIN_QSPI_IO3 23 // HOLD if using two bit interface (i.e. not used) // On-board QSPI Flash -#define EXTERNAL_FLASH_DEVICES MX25R6435F +#define EXTERNAL_FLASH_DEVICES MX25R1635F #define EXTERNAL_FLASH_USE_QSPI -*/ - /* * Lora radio */ From 116fe6d109b828800199f3cc452c05ddc16bc384 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 15:18:32 -0700 Subject: [PATCH 04/10] eink bootloader finished --- bin/install-bootloader.sh | 4 +++- variants/eink/variant.h | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/install-bootloader.sh b/bin/install-bootloader.sh index 3c7db57396..4d99af45b6 100755 --- a/bin/install-bootloader.sh +++ b/bin/install-bootloader.sh @@ -1,5 +1,7 @@ # You probably don't want to use this script, it programs a custom bootloader build onto a nrf52 board +set -e + BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader nrfjprog --eraseall -f nrf52 @@ -9,7 +11,7 @@ nrfjprog --eraseall -f nrf52 echo Programming bootloader and soft device # the following ling incorrectly enables reset pin, because the running code rewrites it -nrfjprog --program $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-122-gf6bfaac-dirty_s140_6.1.1.hex -f nrf52 +nrfjprog --program $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-123-g4f9022d-dirty_s140_6.1.1.hex -f nrf52 # this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid # Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000 diff --git a/variants/eink/variant.h b/variants/eink/variant.h index c1781c84e4..c4e1a77955 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -51,11 +51,14 @@ feedback to give: * remove ipx connector for nfc, instead use two caps and loop traces on the back of the board as an antenna? +* the i2c RTC seems to talk fine on the i2c bus + * I've made the serial flash chip work, but if you do a new spin of the board I recommend: connect pin 3 and pin 7 of U4 to spare GPIOs on the processor (instead of their current connections), -This would allow using 4 bit wide interface mode to the serial flash. -doubling the transfer speed! see example here: +This would allow using 4 bit wide interface mode to the serial flash - doubling the transfer speed! see example here: https://infocenter.nordicsemi.com/topic/ug_nrf52840_dk/UG/nrf52840_DK/hw_external_memory.html?cp=4_0_4_7_4 +Once again - I'm glad you added that external flash chip. + */ /*---------------------------------------------------------------------------- From 158e3edbe74f5de53dfb9c0ebc2db4242aa1d1af Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 15:21:54 -0700 Subject: [PATCH 05/10] eink generate full image --- bin/install-bootloader.sh | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/bin/install-bootloader.sh b/bin/install-bootloader.sh index 4d99af45b6..842a64bc31 100755 --- a/bin/install-bootloader.sh +++ b/bin/install-bootloader.sh @@ -6,13 +6,6 @@ BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader nrfjprog --eraseall -f nrf52 -#echo Programming soft device -#nrfjprog --program $BOOTDIR/lib/softdevice/s140_nrf52_6.1.1/s140_nrf52_6.1.1_softdevice.hex -f nrf52 - -echo Programming bootloader and soft device -# the following ling incorrectly enables reset pin, because the running code rewrites it -nrfjprog --program $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-123-g4f9022d-dirty_s140_6.1.1.hex -f nrf52 - # this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid # Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000 # first 4 bytes should be 0x01 to indicate valid app image @@ -20,12 +13,10 @@ nrfjprog --program $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-12 echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel -echo Programming meshtastic app load -nrfjprog --program .pio/build/eink/firmware.hex -f nrf52 +echo Generating merged hex file +mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-123-g4f9022d-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex echo Telling bootloader app region is valid and telling CPU to run -nrfjprog --program /tmp/bootconf.hex -f nrf52 --reset +nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset # nrfjprog --readuicr /tmp/uicr.hex; objdump -s /tmp/uicr.hex | less - -echo FIXME use hexmerge From bc50b39a3b34370e4a3f2ad2a73eb73460c20afa Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 16:08:52 -0700 Subject: [PATCH 06/10] put eink screen to sleep to save power --- src/graphics/EInkDisplay.cpp | 17 +++++++++++------ variants/eink/variant.h | 30 ++++++++++++++++++------------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/graphics/EInkDisplay.cpp b/src/graphics/EInkDisplay.cpp index da468af38b..56363c1929 100644 --- a/src/graphics/EInkDisplay.cpp +++ b/src/graphics/EInkDisplay.cpp @@ -56,7 +56,8 @@ uint32_t lastDrawMsec; // Write the buffer to the display memory void EInkDisplay::display(void) { - concurrency::LockGuard g(spiLock); + // No need to grab this lock because we are on our own SPI bus + // concurrency::LockGuard g(spiLock); uint32_t now = millis(); uint32_t sinceLast = now - lastDrawMsec; @@ -76,10 +77,14 @@ void EInkDisplay::display(void) } } + ePaper.Reset(); // wake the screen from sleep + + DEBUG_MSG("Updating eink... "); updateDisplay(); // Send image to display and refresh + DEBUG_MSG("done\n"); - // Put screen to sleep to save power (if wanted) - // ePaper.Sleep(); + // Put screen to sleep to save power + ePaper.Sleep(); } } @@ -95,9 +100,9 @@ bool EInkDisplay::connect() { DEBUG_MSG("Doing EInk init\n"); -#ifdef EINK_PIN_PWR_ON - digitalWrite(EINK_PIN_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals - pinMode(EINK_PIN_PWR_ON, OUTPUT); +#ifdef PIN_EINK_PWR_ON + digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals + pinMode(PIN_EINK_PWR_ON, OUTPUT); #endif #ifdef PIN_EINK_EN diff --git a/variants/eink/variant.h b/variants/eink/variant.h index c4e1a77955..c0738746df 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -28,36 +28,42 @@ @geeksville eink TODO: soonish: -hook cdc acm device to debug output -fix bootloader to use two buttons - remove bootloader hacks +DONE hook cdc acm device to debug output +DONE fix bootloader to use two buttons - remove bootloader hacks DONE get second button working in app load +DONE use tp_ser_io as a button, it goes high when pressed unify eink display classes fix display width and height clean up eink drawing to not have the nasty timeout hack measure current draws -put eink to sleep when we think the screen is off +DONE put eink to sleep when we think the screen is off enable gps sleep mode -https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fspi.html enable reset as a button +turn off txco on lora? make screen.adjustBrightness() a nop on eink screens later: -confirm that watchdog reset (i.e. all pins now become inputs) won't cause the board to power down when we are not connected to USB -(I bet it will). If this happens recommended fix is to add an external pullup on PWR_ON GPIO. -enable flash on spi0, share chip selects on spi1. +enable flash on qspi. fix floating point SEGGER printf on nrf52 - see "new NMEA GPS pos" add factory/power on self test -use tp_ser_io as a button, it goes high when pressed unify eink display classes feedback to give: +* bootloader is finished + +* the capacitive touch sensor works, though I'm not sure what use you are intending for it + * remove ipx connector for nfc, instead use two caps and loop traces on the back of the board as an antenna? -* the i2c RTC seems to talk fine on the i2c bus +* the i2c RTC seems to talk fine on the i2c bus. However, I'm not sure of the utility of that part. Instead I'd be in favor of the following: + +* move BAT1 to power the GPS VBACKUP instead per page 6 of the Air530 datasheet. And remove the i2c RTC entirely. + +* remove the cp2014 chip. * I've made the serial flash chip work, but if you do a new spin of the board I recommend: -connect pin 3 and pin 7 of U4 to spare GPIOs on the processor (instead of their current connections), +connect pin 3 and pin 7 of U4 to spare GPIOs on the processor (instead of their current connections), This would allow using 4 bit wide interface mode to the serial flash - doubling the transfer speed! see example here: https://infocenter.nordicsemi.com/topic/ug_nrf52840_dk/UG/nrf52840_DK/hw_external_memory.html?cp=4_0_4_7_4 -Once again - I'm glad you added that external flash chip. +Once again - I'm glad you added that external flash chip. */ @@ -210,7 +216,7 @@ External serial flash WP25R1635FZUIL0 */ #define SPI_INTERFACES_COUNT 2 -// For LORA +// For LORA, spi 0 #define PIN_SPI_MISO (0 + 23) #define PIN_SPI_MOSI (0 + 22) #define PIN_SPI_SCK (0 + 19) From fec7a6bf173ce6eb4d631a766d10a35438ec3309 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 17:04:19 -0700 Subject: [PATCH 07/10] add air530 gps sleep support --- src/gps/Air530GPS.cpp | 87 ++++++++++++++++++++++++++++++++++++ src/gps/Air530GPS.h | 22 +++++++++ src/gps/GPS.cpp | 17 +++++++ src/gps/GPS.h | 16 +++++++ src/gps/NMEAGPS.cpp | 74 ++++++++++-------------------- src/gps/UBloxGPS.cpp | 4 +- src/gps/UBloxGPS.h | 2 - src/graphics/EInkDisplay.cpp | 2 +- src/main.cpp | 8 +++- variants/eink/variant.h | 2 + 10 files changed, 176 insertions(+), 58 deletions(-) create mode 100644 src/gps/Air530GPS.cpp create mode 100644 src/gps/Air530GPS.h diff --git a/src/gps/Air530GPS.cpp b/src/gps/Air530GPS.cpp new file mode 100644 index 0000000000..6223c1fc7e --- /dev/null +++ b/src/gps/Air530GPS.cpp @@ -0,0 +1,87 @@ +#include "Air530GPS.h" +#include + +/* +Helpful translations from the Air530 GPS datasheet + +Sat acquision mode +捕获电流值@3.3v 42.6 mA + +sat tracking mode +跟踪电流值@3.3v 36.7 mA + +Low power mode +低功耗模式@3.3V 0.85 mA +(发送指令:$PGKC051,0) + +Super low power mode +超低功耗模式@3.3V 31 uA +(发送指令:$PGKC105,4) + +To exit sleep use WAKE pin + +Commands to enter sleep +6、Command: 105 +进入周期性低功耗模式 +Arguments: + +Arg1: “0”,正常运行模式 (normal mode) +“1”,周期超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (periodic low power tracking mode - keeps sat positions, use wake to wake up) +“2”,周期低功耗模式 (periodic low power mode) +“4”,直接进入超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (super low power consumption mode immediately, need WAKE to resume) +“8”,自动低功耗模式,可以通过串口唤醒 (automatic low power mode, wake by sending characters to serial port) +“9”, 自动超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (automatic low power tracking when possible, need wake pin to resume) + +(Arg 2 & 3 only valid if Arg1 is "1" or "2") +Arg2:运行时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用 +ON time in msecs + +Arg3:睡眠时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用 +Sleep time in msecs + +Example: +$PGKC105,8*3F +This will set automatic low power mode with waking when we send chars to the serial port. Possibly do this as soon as we get a +new location. When we wake again in a minute we send a character to wake up. + +*/ + + +void Air530GPS::sendCommand(const char *cmd) { + uint8_t sum = 0; + + // Skip the $ + assert(cmd[0] == '$'); + const char *p = cmd + 1; + while(*p) + sum ^= *p++; + + assert(_serial_gps); + + _serial_gps->write(cmd); + _serial_gps->printf("*%02x\r\n", sum); + + // DEBUG_MSG("xsum %02x\n", sum); +} + +void Air530GPS::sleep() { +#ifdef PIN_GPS_WAKE + digitalWrite(PIN_GPS_WAKE, 0); + pinMode(PIN_GPS_WAKE, OUTPUT); + sendCommand("$PGKC105,4"); +#endif +} + +/// wake the GPS into normal operation mode +void Air530GPS::wake() +{ +#if 0 +#ifdef PIN_GPS_WAKE + digitalWrite(PIN_GPS_WAKE, 1); + pinMode(PIN_GPS_WAKE, OUTPUT); +#endif +#else + // For power testing + sleep(); +#endif +} \ No newline at end of file diff --git a/src/gps/Air530GPS.h b/src/gps/Air530GPS.h new file mode 100644 index 0000000000..bbb9f80038 --- /dev/null +++ b/src/gps/Air530GPS.h @@ -0,0 +1,22 @@ +#pragma once + +#include "NMEAGPS.h" + +/** + * A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading) + * + * When new data is available it will notify observers. + */ +class Air530GPS : public NMEAGPS +{ + protected: + /// If possible force the GPS into sleep/low power mode + virtual void sleep(); + + /// wake the GPS into normal operation mode + virtual void wake(); + + private: + /// Send a NMEA cmd with checksum + void sendCommand(const char *str); +}; diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index b3ab28d290..f8b29de3dc 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -85,3 +85,20 @@ uint32_t getValidTime() { return timeSetFromGPS ? getTime() : 0; } + +/** + * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode + * + * calls sleep/wake + */ +void GPS::setWantLocation(bool on) +{ + if (wantNewLocation != on) { + wantNewLocation = on; + DEBUG_MSG("WANT GPS=%d\n", on); + if (on) + wake(); + else + sleep(); + } +} \ No newline at end of file diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 409c6da9db..3b81b54f7e 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -30,6 +30,8 @@ class GPS protected: bool hasValidLocation = false; // default to false, until we complete our first read + bool wantNewLocation = false; // true if we want a location right now + public: /** If !NULL we will use this serial port to construct our GPS */ static HardwareSerial *_serial_gps; @@ -62,10 +64,24 @@ class GPS /// Returns ture if we have acquired GPS lock. bool hasLock() const { return hasValidLocation; } + /** + * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode + * + * calls sleep/wake + */ + void setWantLocation(bool on); + /** * Restart our lock attempt - try to get and broadcast a GPS reading ASAP * called after the CPU wakes from light-sleep state */ virtual void startLock() {} + +protected: + /// If possible force the GPS into sleep/low power mode + virtual void sleep() {} + + /// wake the GPS into normal operation mode + virtual void wake() {} }; extern GPS *gps; diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp index 08918d6d85..2d8af6d72a 100644 --- a/src/gps/NMEAGPS.cpp +++ b/src/gps/NMEAGPS.cpp @@ -1,50 +1,6 @@ #include "NMEAGPS.h" #include "configuration.h" -/* -Helpful translations from the Air530 GPS datasheet - -Sat acquision mode -捕获电流值@3.3v 42.6 mA - -sat tracking mode -跟踪电流值@3.3v 36.7 mA - -Low power mode -低功耗模式@3.3V 0.85 mA -(发送指令:$PGKC051,0) - -Super low power mode -超低功耗模式@3.3V 31 uA -(发送指令:$PGKC105,4) - -To exit sleep use WAKE pin - -Commands to enter sleep -6、Command: 105 -进入周期性低功耗模式 -Arguments: - -Arg1: “0”,正常运行模式 (normal mode) -“1”,周期超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (periodic low power tracking mode - keeps sat positions, use wake to wake up) -“2”,周期低功耗模式 (periodic low power mode) -“4”,直接进入超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (super low power consumption mode immediately, need WAKE to resume) -“8”,自动低功耗模式,可以通过串口唤醒 (automatic low power mode, wake by sending characters to serial port) -“9”, 自动超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (automatic low power tracking when possible, need wake pin to resume) - -(Arg 2 & 3 only valid if Arg1 is "1" or "2") -Arg2:运行时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用 -ON time in msecs - -Arg3:睡眠时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用 -Sleep time in msecs - -Example: -$PGKC105,8*3F -This will set automatic low power mode with waking when we send chars to the serial port. Possibly do this as soon as we get a new -location. When we wake again in a minute we send a character to wake up. - -*/ static int32_t toDegInt(RawDegrees d) { @@ -68,6 +24,7 @@ bool NMEAGPS::setup() void NMEAGPS::loop() { + // First consume any chars that have piled up at the receiver while (_serial_gps->available() > 0) { int c = _serial_gps->read(); // DEBUG_MSG("%c", c); @@ -78,11 +35,18 @@ void NMEAGPS::loop() isConnected = true; } + // If we are overdue for an update, turn on the GPS and at least publish the current status uint32_t now = millis(); - if ((now - lastUpdateMsec) > 20 * 1000) { // Ugly hack for now - limit update checks to once every 20 secs (but still consume - // serial chars at whatever rate) - lastUpdateMsec = now; + bool mustPublishUpdate = false; + if ((now - lastUpdateMsec) > 30 * 1000 && !wantNewLocation) { + // Ugly hack for now - limit update checks to once every 30 secs + setWantLocation(true); + mustPublishUpdate = + true; // Even if we don't have an update this time, we at least want to occasionally publish the current state + } + // Only bother looking at GPS state if we are interested in what it has to say + if (wantNewLocation) { auto ti = reader.time; auto d = reader.date; if (ti.isUpdated() && ti.isValid() && d.isValid()) { @@ -105,6 +69,8 @@ void NMEAGPS::loop() hasValidLocation = ((fixtype >= 1) && (fixtype <= 5)); if (reader.location.isUpdated()) { + lastUpdateMsec = now; + if (reader.altitude.isValid()) altitude = reader.altitude.meters(); @@ -112,6 +78,9 @@ void NMEAGPS::loop() auto loc = reader.location.value(); latitude = toDegInt(loc.lat); longitude = toDegInt(loc.lng); + + // Once we get a location we no longer desperately want an update + setWantLocation(false); } // Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it if (reader.hdop.isValid()) { @@ -128,11 +97,14 @@ void NMEAGPS::loop() // expect gps pos lat=37.520825, lon=-122.309162, alt=158 DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5); + mustPublishUpdate = true; } - // Notify any status instances that are observing us - const meshtastic::GPSStatus status = - meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites); - newStatus.notifyObservers(&status); + if (mustPublishUpdate) { + // Notify any status instances that are observing us + const meshtastic::GPSStatus status = + meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites); + newStatus.notifyObservers(&status); + } } } \ No newline at end of file diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index 93e8a01cfe..0d133891e2 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -183,11 +183,11 @@ void UBloxGPS::doTask() if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only { if (hasValidLocation) { - wantNewLocation = false; + setWantLocation(false); // ublox.powerOff(); } } else // we didn't get a location update, go back to sleep and hope the characters show up - wantNewLocation = true; + setWantLocation(true); // Notify any status instances that are observing us const meshtastic::GPSStatus status = diff --git a/src/gps/UBloxGPS.h b/src/gps/UBloxGPS.h index 7a2d3cdba3..03f2d2a1c0 100644 --- a/src/gps/UBloxGPS.h +++ b/src/gps/UBloxGPS.h @@ -14,8 +14,6 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask { SFE_UBLOX_GPS ublox; - bool wantNewLocation = true; - CallbackObserver notifySleepObserver = CallbackObserver(this, &UBloxGPS::prepareSleep); public: diff --git a/src/graphics/EInkDisplay.cpp b/src/graphics/EInkDisplay.cpp index 56363c1929..7a6e02df0d 100644 --- a/src/graphics/EInkDisplay.cpp +++ b/src/graphics/EInkDisplay.cpp @@ -62,7 +62,7 @@ void EInkDisplay::display(void) uint32_t now = millis(); uint32_t sinceLast = now - lastDrawMsec; - if (framePtr && (sinceLast > 30 * 1000 || lastDrawMsec == 0)) { + if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) { lastDrawMsec = now; // FIXME - only draw bits have changed (use backbuf similar to the other displays) diff --git a/src/main.cpp b/src/main.cpp index c53fdfeffe..37e9077df5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,7 +23,7 @@ #include "MeshRadio.h" #include "MeshService.h" -#include "NMEAGPS.h" +#include "Air530GPS.h" #include "NodeDB.h" #include "PowerFSM.h" #include "UBloxGPS.h" @@ -259,10 +259,14 @@ void setup() if (GPS::_serial_gps) { // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just // assume NMEA at 9600 baud. + // dumb NMEA access only work for serial GPSes) DEBUG_MSG("Hoping that NMEA might work\n"); - // dumb NMEA access only work for serial GPSes) +#ifdef HAS_AIR530_GPS + gps = new Air530GPS(); +#else gps = new NMEAGPS(); +#endif gps->setup(); } } diff --git a/variants/eink/variant.h b/variants/eink/variant.h index c0738746df..a399d51a7b 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -208,6 +208,8 @@ External serial flash WP25R1635FZUIL0 #define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU #define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS +#define HAS_AIR530_GPS + #define PIN_SERIAL1_RX PIN_GPS_TX #define PIN_SERIAL1_TX PIN_GPS_RX From 124a82888dbc62a3e4114b776dab5a3849a400a5 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 28 Sep 2020 17:38:36 -0700 Subject: [PATCH 08/10] add power testing notes for eink --- src/gps/Air530GPS.cpp | 4 ++-- variants/eink/variant.h | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/gps/Air530GPS.cpp b/src/gps/Air530GPS.cpp index 6223c1fc7e..db0ddd445c 100644 --- a/src/gps/Air530GPS.cpp +++ b/src/gps/Air530GPS.cpp @@ -75,13 +75,13 @@ void Air530GPS::sleep() { /// wake the GPS into normal operation mode void Air530GPS::wake() { -#if 0 +#if 1 #ifdef PIN_GPS_WAKE digitalWrite(PIN_GPS_WAKE, 1); pinMode(PIN_GPS_WAKE, OUTPUT); #endif #else - // For power testing + // For power testing - keep GPS sleeping forever sleep(); #endif } \ No newline at end of file diff --git a/variants/eink/variant.h b/variants/eink/variant.h index a399d51a7b..1dd2e9dc2a 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -53,7 +53,8 @@ feedback to give: * remove ipx connector for nfc, instead use two caps and loop traces on the back of the board as an antenna? -* the i2c RTC seems to talk fine on the i2c bus. However, I'm not sure of the utility of that part. Instead I'd be in favor of the following: +* the i2c RTC seems to talk fine on the i2c bus. However, I'm not sure of the utility of that part. Instead I'd be in favor of +the following: * move BAT1 to power the GPS VBACKUP instead per page 6 of the Air530 datasheet. And remove the i2c RTC entirely. @@ -65,6 +66,20 @@ This would allow using 4 bit wide interface mode to the serial flash - doubling https://infocenter.nordicsemi.com/topic/ug_nrf52840_dk/UG/nrf52840_DK/hw_external_memory.html?cp=4_0_4_7_4 Once again - I'm glad you added that external flash chip. +* Power measurements +When powered by 4V battery + +CPU on, lora radio RX mode, bluetooth enabled, GPS trying to lock. total draw 43mA +CPU on, lora radio RX mode, bluetooth enabled, GPS super low power sleep mode. Total draw 20mA +CPU on, lora radio TX mode, bluetooth enabled, GPS super low power sleep mode. Total draw 132mA + +Note: power consumption while connected via BLE to a phone almost identical. + +Note: eink display for all tests was in sleep mode most of the time. Current draw during the brief periods while the eink was being drawn was not +measured (but it was low). + +Note: Turning off EINK PWR_ON produces no noticeable power savings over just putting the eink display into sleep mode. + */ /*---------------------------------------------------------------------------- From 7f3217d69e0939e15ad36d486439c027a98af280 Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 29 Sep 2020 14:12:26 -0700 Subject: [PATCH 09/10] update image build script --- bin/install-bootloader.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/install-bootloader.sh b/bin/install-bootloader.sh index 842a64bc31..5dde70505b 100755 --- a/bin/install-bootloader.sh +++ b/bin/install-bootloader.sh @@ -14,7 +14,7 @@ echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel echo Generating merged hex file -mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-123-g4f9022d-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex +mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-124-g69bd8eb-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex echo Telling bootloader app region is valid and telling CPU to run nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset From f7ffd196e338752d27865505d576f3034ebb16f5 Mon Sep 17 00:00:00 2001 From: Stefan Venz Date: Thu, 1 Oct 2020 11:22:41 +0200 Subject: [PATCH 10/10] Fix update/install instructions --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6017774620..6663c4d27b 100644 --- a/README.md +++ b/README.md @@ -103,10 +103,10 @@ Hard resetting via RTS pin... ``` 5. cd into the directory where the release zip file was expanded. -6. Install the correct firmware for your board with `device-install.sh firmware-_board_-_country_.bin`. - - Example: `./device-install.sh firmware-HELTEC-US-0.0.3.bin`. -7. To update run `device-update.sh firmware-_board_-_country_.bin` - - Example: `./device-update.sh firmware-HELTEC-US-0.0.3.bin`. +6. Install the correct firmware for your board with `device-install.sh -f firmware-_board_-_country_.bin`. + - Example: `./device-install.sh -f firmware-HELTEC-US-0.0.3.bin`. +7. To update run `device-update.sh -f firmware-_board_-_country_.bin` + - Example: `./device-update.sh -f firmware-HELTEC-US-0.0.3.bin`. Note: If you have previously installed meshtastic, you don't need to run this full script instead just run `esptool.py --baud 921600 write_flash 0x10000 firmware-_board_-_country_-_version_.bin`. This will be faster, also all of your current preferences will be preserved.