sforkowany z mirror/meshtastic-firmware
Merge branch 'eink' into power
commit
d66cede7fc
|
@ -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
|
|
@ -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
|
|
@ -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]
|
|
@ -77,6 +77,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#define BUTTON_PIN PIN_BUTTON1
|
#define BUTTON_PIN PIN_BUTTON1
|
||||||
#endif
|
#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)
|
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
|
||||||
#elif defined(CubeCell_BoardPlus)
|
#elif defined(CubeCell_BoardPlus)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include "Air530GPS.h"
|
||||||
|
#include <assert.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<CR><LF>
|
||||||
|
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
|
||||||
|
}
|
|
@ -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);
|
||||||
|
};
|
|
@ -85,3 +85,20 @@ uint32_t getValidTime()
|
||||||
{
|
{
|
||||||
return timeSetFromGPS ? getTime() : 0;
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,8 @@ class GPS
|
||||||
protected:
|
protected:
|
||||||
bool hasValidLocation = false; // default to false, until we complete our first read
|
bool hasValidLocation = false; // default to false, until we complete our first read
|
||||||
|
|
||||||
|
bool wantNewLocation = false; // true if we want a location right now
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** If !NULL we will use this serial port to construct our GPS */
|
/** If !NULL we will use this serial port to construct our GPS */
|
||||||
static HardwareSerial *_serial_gps;
|
static HardwareSerial *_serial_gps;
|
||||||
|
@ -62,10 +64,24 @@ class GPS
|
||||||
/// Returns ture if we have acquired GPS lock.
|
/// Returns ture if we have acquired GPS lock.
|
||||||
bool hasLock() const { return hasValidLocation; }
|
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
|
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
|
||||||
* called after the CPU wakes from light-sleep state */
|
* called after the CPU wakes from light-sleep state */
|
||||||
virtual void startLock() {}
|
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;
|
extern GPS *gps;
|
||||||
|
|
|
@ -1,50 +1,6 @@
|
||||||
#include "NMEAGPS.h"
|
#include "NMEAGPS.h"
|
||||||
#include "configuration.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<CR><LF>
|
|
||||||
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)
|
static int32_t toDegInt(RawDegrees d)
|
||||||
{
|
{
|
||||||
|
@ -68,6 +24,7 @@ bool NMEAGPS::setup()
|
||||||
|
|
||||||
void NMEAGPS::loop()
|
void NMEAGPS::loop()
|
||||||
{
|
{
|
||||||
|
// First consume any chars that have piled up at the receiver
|
||||||
while (_serial_gps->available() > 0) {
|
while (_serial_gps->available() > 0) {
|
||||||
int c = _serial_gps->read();
|
int c = _serial_gps->read();
|
||||||
// DEBUG_MSG("%c", c);
|
// DEBUG_MSG("%c", c);
|
||||||
|
@ -78,11 +35,18 @@ void NMEAGPS::loop()
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are overdue for an update, turn on the GPS and at least publish the current status
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
if ((now - lastUpdateMsec) > 20 * 1000) { // Ugly hack for now - limit update checks to once every 20 secs (but still consume
|
bool mustPublishUpdate = false;
|
||||||
// serial chars at whatever rate)
|
if ((now - lastUpdateMsec) > 30 * 1000 && !wantNewLocation) {
|
||||||
lastUpdateMsec = now;
|
// 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 ti = reader.time;
|
||||||
auto d = reader.date;
|
auto d = reader.date;
|
||||||
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
|
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
|
||||||
|
@ -105,6 +69,8 @@ void NMEAGPS::loop()
|
||||||
hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
|
hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
|
||||||
|
|
||||||
if (reader.location.isUpdated()) {
|
if (reader.location.isUpdated()) {
|
||||||
|
lastUpdateMsec = now;
|
||||||
|
|
||||||
if (reader.altitude.isValid())
|
if (reader.altitude.isValid())
|
||||||
altitude = reader.altitude.meters();
|
altitude = reader.altitude.meters();
|
||||||
|
|
||||||
|
@ -112,6 +78,9 @@ void NMEAGPS::loop()
|
||||||
auto loc = reader.location.value();
|
auto loc = reader.location.value();
|
||||||
latitude = toDegInt(loc.lat);
|
latitude = toDegInt(loc.lat);
|
||||||
longitude = toDegInt(loc.lng);
|
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
|
// 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()) {
|
if (reader.hdop.isValid()) {
|
||||||
|
@ -128,11 +97,14 @@ void NMEAGPS::loop()
|
||||||
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
// 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,
|
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);
|
altitude, dop * 1e-2, heading * 1e-5);
|
||||||
|
mustPublishUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mustPublishUpdate) {
|
||||||
// Notify any status instances that are observing us
|
// Notify any status instances that are observing us
|
||||||
const meshtastic::GPSStatus status =
|
const meshtastic::GPSStatus status =
|
||||||
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
||||||
newStatus.notifyObservers(&status);
|
newStatus.notifyObservers(&status);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -183,11 +183,11 @@ void UBloxGPS::doTask()
|
||||||
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
||||||
{
|
{
|
||||||
if (hasValidLocation) {
|
if (hasValidLocation) {
|
||||||
wantNewLocation = false;
|
setWantLocation(false);
|
||||||
// ublox.powerOff();
|
// ublox.powerOff();
|
||||||
}
|
}
|
||||||
} else // we didn't get a location update, go back to sleep and hope the characters show up
|
} 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
|
// Notify any status instances that are observing us
|
||||||
const meshtastic::GPSStatus status =
|
const meshtastic::GPSStatus status =
|
||||||
|
|
|
@ -14,8 +14,6 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
||||||
{
|
{
|
||||||
SFE_UBLOX_GPS ublox;
|
SFE_UBLOX_GPS ublox;
|
||||||
|
|
||||||
bool wantNewLocation = true;
|
|
||||||
|
|
||||||
CallbackObserver<UBloxGPS, void *> notifySleepObserver = CallbackObserver<UBloxGPS, void *>(this, &UBloxGPS::prepareSleep);
|
CallbackObserver<UBloxGPS, void *> notifySleepObserver = CallbackObserver<UBloxGPS, void *>(this, &UBloxGPS::prepareSleep);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -56,12 +56,13 @@ uint32_t lastDrawMsec;
|
||||||
// Write the buffer to the display memory
|
// Write the buffer to the display memory
|
||||||
void EInkDisplay::display(void)
|
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 now = millis();
|
||||||
uint32_t sinceLast = now - lastDrawMsec;
|
uint32_t sinceLast = now - lastDrawMsec;
|
||||||
|
|
||||||
if (framePtr && (sinceLast > 30 * 1000 || lastDrawMsec == 0)) {
|
if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) {
|
||||||
lastDrawMsec = now;
|
lastDrawMsec = now;
|
||||||
|
|
||||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
// 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)
|
DEBUG_MSG("Updating eink... ");
|
||||||
// ePaper.Sleep();
|
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");
|
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
|
#ifdef PIN_EINK_EN
|
||||||
digitalWrite(PIN_EINK_EN, HIGH);
|
digitalWrite(PIN_EINK_EN, HIGH);
|
||||||
pinMode(PIN_EINK_EN, OUTPUT);
|
pinMode(PIN_EINK_EN, OUTPUT);
|
||||||
|
|
|
@ -241,16 +241,15 @@ 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)
|
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||||
{
|
{
|
||||||
String displayLine = "";
|
String displayLine = "";
|
||||||
if (!gps->getIsConnected()) {
|
if (!gps->getIsConnected()) {
|
||||||
//displayLine = "No GPS Module";
|
// displayLine = "No GPS Module";
|
||||||
//display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||||
} else if (!gps->getHasLock()) {
|
} else if (!gps->getHasLock()) {
|
||||||
//displayLine = "No GPS Lock";
|
// displayLine = "No GPS Lock";
|
||||||
//display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
displayLine = "Altitude: " + String(gps->getAltitude()) + "m";
|
displayLine = "Altitude: " + String(gps->getAltitude()) + "m";
|
||||||
|
@ -1009,10 +1008,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||||
display->drawString(x, y, String("USB"));
|
display->drawString(x, y, String("USB"));
|
||||||
}
|
}
|
||||||
|
|
||||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)),
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)), y,
|
||||||
y, "Mode " + String(channelSettings.modem_config));
|
"Mode " + String(channelSettings.modem_config));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Line 2
|
// Line 2
|
||||||
uint32_t currentMillis = millis();
|
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(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
|
||||||
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
|
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
|
||||||
|
|
||||||
|
// Line 3
|
||||||
drawGPSAltitude(display, x, y + FONT_HEIGHT * 2, gpsStatus);
|
drawGPSAltitude(display, x, y + FONT_HEIGHT * 2, gpsStatus);
|
||||||
|
|
||||||
// Line 4
|
// Line 4
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NMEAGPS.h"
|
#include "Air530GPS.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "UBloxGPS.h"
|
#include "UBloxGPS.h"
|
||||||
|
@ -259,10 +259,14 @@ void setup()
|
||||||
if (GPS::_serial_gps) {
|
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
|
// 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.
|
// assume NMEA at 9600 baud.
|
||||||
|
// dumb NMEA access only work for serial GPSes)
|
||||||
DEBUG_MSG("Hoping that NMEA might work\n");
|
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();
|
gps = new NMEAGPS();
|
||||||
|
#endif
|
||||||
gps->setup();
|
gps->setup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num,
|
||||||
power);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -25,8 +25,8 @@ bool isWifiAvailable()
|
||||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||||
|
|
||||||
//strcpy(radioConfig.preferences.wifi_ssid, "");
|
// strcpy(radioConfig.preferences.wifi_ssid, "");
|
||||||
//strcpy(radioConfig.preferences.wifi_password, "");
|
// strcpy(radioConfig.preferences.wifi_password, "");
|
||||||
|
|
||||||
if (*wifiName && *wifiPsw) {
|
if (*wifiName && *wifiPsw) {
|
||||||
|
|
||||||
|
|
|
@ -93,11 +93,6 @@ void nrf52Setup()
|
||||||
// This is the recommended setting for Monitor Mode Debugging
|
// This is the recommended setting for Monitor Mode Debugging
|
||||||
NVIC_SetPriority(DebugMonitor_IRQn, 6UL);
|
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
|
// Not yet on board
|
||||||
// pmu.init();
|
// pmu.init();
|
||||||
|
|
||||||
|
|
|
@ -27,25 +27,59 @@
|
||||||
/*
|
/*
|
||||||
@geeksville eink TODO:
|
@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
|
soonish:
|
||||||
(I bet it will). If this happens recommended fix is to add an external pullup on PWR_ON GPIO.
|
DONE hook cdc acm device to debug output
|
||||||
|
DONE fix bootloader to use two buttons - remove bootloader hacks
|
||||||
fix bootloader to use two buttons - remove bootloader hacks
|
DONE get second button working in app load
|
||||||
fix battery voltage sensing
|
DONE use tp_ser_io as a button, it goes high when pressed unify eink display classes
|
||||||
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
|
fix display width and height
|
||||||
clean up eink drawing to not have the nasty timeout hack
|
clean up eink drawing to not have the nasty timeout hack
|
||||||
put eink to sleep when we think the screen is off
|
measure current draws
|
||||||
enable flash on spi0, share chip selects on spi1.
|
DONE put eink to sleep when we think the screen is off
|
||||||
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
|
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
|
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
|
* Buttons
|
||||||
*/
|
*/
|
||||||
#define PIN_BUTTON1 (32 + 10)
|
#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
|
* 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
|
No longer populated on PCB
|
||||||
work.
|
|
||||||
*/
|
*/
|
||||||
#define PIN_SERIAL2_RX (0 + 6)
|
//#define PIN_SERIAL2_RX (0 + 6)
|
||||||
#define PIN_SERIAL2_TX (0 + 8)
|
//#define PIN_SERIAL2_TX (0 + 8)
|
||||||
// #define PIN_SERIAL2_EN (0 + 17)
|
// #define PIN_SERIAL2_EN (0 + 17)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,29 +156,24 @@ work.
|
||||||
|
|
||||||
#define TP_SER_IO (0 + 11)
|
#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
|
#define PIN_RTC_INT (0 + 16) // Interrupt from the PCF8563 RTC
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
External serial flash WP25R1635FZUIL0
|
||||||
FIXME define/FIX flash access
|
*/
|
||||||
|
|
||||||
// QSPI Pins
|
// QSPI Pins
|
||||||
#define PIN_QSPI_SCK 19
|
#define PIN_QSPI_SCK (32 + 14)
|
||||||
#define PIN_QSPI_CS 17
|
#define PIN_QSPI_CS (32 + 15)
|
||||||
#define PIN_QSPI_IO0 20
|
#define PIN_QSPI_IO0 (32 + 12) // MOSI if using two bit interface
|
||||||
#define PIN_QSPI_IO1 21
|
#define PIN_QSPI_IO1 (32 + 13) // MISO if using two bit interface
|
||||||
#define PIN_QSPI_IO2 22
|
//#define PIN_QSPI_IO2 22 // WP if using two bit interface (i.e. not used)
|
||||||
#define PIN_QSPI_IO3 23
|
//#define PIN_QSPI_IO3 23 // HOLD if using two bit interface (i.e. not used)
|
||||||
|
|
||||||
// On-board QSPI Flash
|
// On-board QSPI Flash
|
||||||
#define EXTERNAL_FLASH_DEVICES MX25R6435F
|
#define EXTERNAL_FLASH_DEVICES MX25R1635F
|
||||||
#define EXTERNAL_FLASH_USE_QSPI
|
#define EXTERNAL_FLASH_USE_QSPI
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lora radio
|
* Lora radio
|
||||||
*/
|
*/
|
||||||
|
@ -175,6 +204,9 @@ FIXME define/FIX flash access
|
||||||
#define PIN_EINK_SCLK (0 + 31)
|
#define PIN_EINK_SCLK (0 + 31)
|
||||||
#define PIN_EINK_MOSI (0 + 29) // also called SDI
|
#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 HAS_EINK
|
||||||
|
|
||||||
#define PIN_SPI1_MISO \
|
#define PIN_SPI1_MISO \
|
||||||
|
@ -186,11 +218,13 @@ FIXME define/FIX flash access
|
||||||
* Air530 GPS pins
|
* Air530 GPS pins
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PIN_GPS_WAKE (32 + 2)
|
#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)
|
#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_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_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_RX PIN_GPS_TX
|
||||||
#define PIN_SERIAL1_TX PIN_GPS_RX
|
#define PIN_SERIAL1_TX PIN_GPS_RX
|
||||||
|
|
||||||
|
@ -199,7 +233,7 @@ FIXME define/FIX flash access
|
||||||
*/
|
*/
|
||||||
#define SPI_INTERFACES_COUNT 2
|
#define SPI_INTERFACES_COUNT 2
|
||||||
|
|
||||||
// For LORA
|
// For LORA, spi 0
|
||||||
#define PIN_SPI_MISO (0 + 23)
|
#define PIN_SPI_MISO (0 + 23)
|
||||||
#define PIN_SPI_MOSI (0 + 22)
|
#define PIN_SPI_MOSI (0 + 22)
|
||||||
#define PIN_SPI_SCK (0 + 19)
|
#define PIN_SPI_SCK (0 + 19)
|
||||||
|
|
Ładowanie…
Reference in New Issue