diff --git a/bin/install-bootloader.sh b/bin/install-bootloader.sh
new file mode 100755
index 00000000..5dde7050
--- /dev/null
+++ b/bin/install-bootloader.sh
@@ -0,0 +1,22 @@
+# 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
+
+# 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 Generating merged hex file
+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
+
+# nrfjprog --readuicr /tmp/uicr.hex; objdump -s /tmp/uicr.hex | less
diff --git a/bin/qspi-flash-test.sh b/bin/qspi-flash-test.sh
new file mode 100755
index 00000000..7fc186b5
--- /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 00000000..d477db8e
--- /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/src/configuration.h b/src/configuration.h
index 026bb188..ad783d0d 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/src/gps/Air530GPS.cpp b/src/gps/Air530GPS.cpp
new file mode 100644
index 00000000..db0ddd44
--- /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 1
+#ifdef PIN_GPS_WAKE
+ digitalWrite(PIN_GPS_WAKE, 1);
+ pinMode(PIN_GPS_WAKE, OUTPUT);
+#endif
+#else
+ // For power testing - keep GPS sleeping forever
+ 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 00000000..bbb9f800
--- /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 b3ab28d2..f8b29de3 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 409c6da9..3b81b54f 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 08918d6d..2d8af6d7 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 93e8a01c..0d133891 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 7a2d3cdb..03f2d2a1 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 2156f591..7a6e02df 100644
--- a/src/graphics/EInkDisplay.cpp
+++ b/src/graphics/EInkDisplay.cpp
@@ -56,12 +56,13 @@ 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;
- 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)
@@ -76,10 +77,14 @@ void EInkDisplay::display(void)
}
}
- updateDisplay(); // Send image to display and refresh
+ ePaper.Reset(); // wake the screen from sleep
- // Put screen to sleep to save power (if wanted)
- // ePaper.Sleep();
+ DEBUG_MSG("Updating eink... ");
+ updateDisplay(); // Send image to display and refresh
+ DEBUG_MSG("done\n");
+
+ // Put screen to sleep to save power
+ ePaper.Sleep();
}
}
@@ -95,6 +100,11 @@ bool EInkDisplay::connect()
{
DEBUG_MSG("Doing EInk init\n");
+#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
digitalWrite(PIN_EINK_EN, HIGH);
pinMode(PIN_EINK_EN, OUTPUT);
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index beec7082..2ea03c63 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -241,18 +241,17 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
}
}
-//asdf
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{
String displayLine = "";
if (!gps->getIsConnected()) {
- //displayLine = "No GPS Module";
- //display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
+ // displayLine = "No GPS Module";
+ // display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else if (!gps->getHasLock()) {
- //displayLine = "No GPS Lock";
- //display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
+ // displayLine = "No GPS Lock";
+ // display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else {
-
+
displayLine = "Altitude: " + String(gps->getAltitude()) + "m";
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
}
@@ -905,8 +904,8 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Lost");
} else if (WiFi.status() == WL_CONNECT_FAILED) {
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed");
- //} else if (WiFi.status() == WL_DISCONNECTED) {
- // display->drawString(x, y + FONT_HEIGHT * 1, "Disconnected");
+ //} else if (WiFi.status() == WL_DISCONNECTED) {
+ // display->drawString(x, y + FONT_HEIGHT * 1, "Disconnected");
} else if (WiFi.status() == WL_IDLE_STATUS) {
display->drawString(x, y + FONT_HEIGHT * 1, "Idle ... Reconnecting");
} else {
@@ -1009,10 +1008,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->drawString(x, y, String("USB"));
}
- display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)),
- y, "Mode " + String(channelSettings.modem_config));
-
-
+ display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)), y,
+ "Mode " + String(channelSettings.modem_config));
// Line 2
uint32_t currentMillis = millis();
@@ -1029,6 +1026,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
+ // Line 3
drawGPSAltitude(display, x, y + FONT_HEIGHT * 2, gpsStatus);
// Line 4
diff --git a/src/main.cpp b/src/main.cpp
index c53fdfef..37e9077d 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/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index 1fcee0dc..4ab07103 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -162,6 +162,11 @@ void RadioInterface::applyModemConfig()
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num,
power);
+ DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
+ DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
+ DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
+ DEBUG_MSG("Radio channel_num: %d\n", channel_num);
+ DEBUG_MSG("Radio frequency: %f\n", freq);
}
/**
diff --git a/src/meshwifi/meshwifi.cpp b/src/meshwifi/meshwifi.cpp
index b03ccede..b7a8dace 100644
--- a/src/meshwifi/meshwifi.cpp
+++ b/src/meshwifi/meshwifi.cpp
@@ -25,8 +25,8 @@ bool isWifiAvailable()
const char *wifiName = radioConfig.preferences.wifi_ssid;
const char *wifiPsw = radioConfig.preferences.wifi_password;
- //strcpy(radioConfig.preferences.wifi_ssid, "");
- //strcpy(radioConfig.preferences.wifi_password, "");
+ // strcpy(radioConfig.preferences.wifi_ssid, "");
+ // strcpy(radioConfig.preferences.wifi_password, "");
if (*wifiName && *wifiPsw) {
diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp
index 4a5c93f7..867cdeef 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 e0cdda0d..1dd2e9dc 100644
--- a/variants/eink/variant.h
+++ b/variants/eink/variant.h
@@ -27,25 +27,59 @@
/*
@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.
-
-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)
+soonish:
+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
-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
+measure current draws
+DONE put eink to sleep when we think the screen is off
enable gps sleep mode
-use new flash chip
+turn off txco on lora?
+make screen.adjustBrightness() a nop on eink screens
+
+later:
+enable flash on qspi.
+fix floating point SEGGER printf on nrf52 - see "new NMEA GPS pos"
add factory/power on self test
+
+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. 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),
+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.
+
+* 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.
+
*/
/*----------------------------------------------------------------------------
@@ -83,6 +117,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
@@ -103,11 +138,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)
/**
@@ -122,29 +156,24 @@ 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
/*
-
-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
*/
@@ -175,6 +204,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 +218,12 @@ 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 HAS_AIR530_GPS
#define PIN_SERIAL1_RX PIN_GPS_TX
#define PIN_SERIAL1_TX PIN_GPS_RX
@@ -199,7 +233,7 @@ FIXME define/FIX flash access
*/
#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)