Jm Casler 2020-09-26 23:38:22 -07:00
commit 5ebac0cd54
21 zmienionych plików z 680 dodań i 141 usunięć

Wyświetl plik

@ -53,6 +53,7 @@
}, },
"cSpell.words": [ "cSpell.words": [
"Blox", "Blox",
"EINK",
"HFSR", "HFSR",
"Meshtastic", "Meshtastic",
"NEMAGPS", "NEMAGPS",

61
boards/eink.json 100644
Wyświetl plik

@ -0,0 +1,61 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_LORA_RELAY_V1 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x4405"
]
],
"usb_product": "TTGO_eink",
"mcu": "nrf52840",
"variant": "eink",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": [
"jlink"
],
"svd_path": "nrf52840.svd"
},
"frameworks": [
"arduino"
],
"name": "TTGO eink (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": [
"jlink",
"nrfjprog",
"stlink"
]
},
"url": "FIXME",
"vendor": "TTGO"
}

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -227,6 +227,20 @@ lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
UC1701 UC1701
; Prototype eink/nrf52840/sx1262 device
[env:eink]
extends = nrf52_base
board = eink
# add our variants files to the include and src paths
# define build flags for the TFT_eSPI library
build_flags = ${nrf52_base.build_flags} -Ivariants/eink
-DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
src_filter = ${nrf52_base.src_filter} +<../variants/eink>
lib_deps =
${arduino_base.lib_deps}
https://github.com/geeksville/EPD_Libraries.git
TFT_eSPI
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus ; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
[env:lora-relay-v1] [env:lora-relay-v1]
extends = nrf52_base extends = nrf52_base

Wyświetl plik

@ -1,126 +1,98 @@
#pragma once #pragma once
#include <Arduino.h>
#include "Status.h" #include "Status.h"
#include "configuration.h" #include "configuration.h"
#include <Arduino.h>
namespace meshtastic { namespace meshtastic
{
/// Describes the state of the GPS system. /// Describes the state of the GPS system.
class GPSStatus : public Status class GPSStatus : public Status
{
private:
CallbackObserver<GPSStatus, const GPSStatus *> statusObserver =
CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus);
bool hasLock = false; // default to false, until we complete our first read
bool isConnected = false; // Do we have a GPS we are talking to
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
// scaling before use)
uint32_t heading = 0;
uint32_t numSatellites = 0;
public:
GPSStatus() { statusType = STATUS_TYPE_GPS; }
GPSStatus(bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop,
uint32_t heading, uint32_t numSatellites)
: Status()
{ {
this->hasLock = hasLock;
this->isConnected = isConnected;
this->latitude = latitude;
this->longitude = longitude;
this->altitude = altitude;
this->dop = dop;
this->heading = heading;
this->numSatellites = numSatellites;
}
GPSStatus(const GPSStatus &);
GPSStatus &operator=(const GPSStatus &);
private: void observe(Observable<const GPSStatus *> *source) { statusObserver.observe(source); }
CallbackObserver<GPSStatus, const GPSStatus *> statusObserver = CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus);
bool hasLock = false; // default to false, until we complete our first read bool getHasLock() const { return hasLock; }
bool isConnected = false; // Do we have a GPS we are talking to
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use)
uint32_t heading = 0;
uint32_t numSatellites = 0;
public: bool getIsConnected() const { return isConnected; }
GPSStatus() { int32_t getLatitude() const { return latitude; }
statusType = STATUS_TYPE_GPS;
} int32_t getLongitude() const { return longitude; }
GPSStatus( bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop, uint32_t heading, uint32_t numSatellites ) : Status()
int32_t getAltitude() const { return altitude; }
uint32_t getDOP() const { return dop; }
uint32_t getHeading() const { return heading; }
uint32_t getNumSatellites() const { return numSatellites; }
bool matches(const GPSStatus *newStatus) const
{
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->latitude != latitude ||
newStatus->longitude != longitude || newStatus->altitude != altitude || newStatus->dop != dop ||
newStatus->heading != heading || newStatus->numSatellites != numSatellites);
}
int updateStatus(const GPSStatus *newStatus)
{
// Only update the status if values have actually changed
bool isDirty;
{ {
this->hasLock = hasLock; isDirty = matches(newStatus);
this->isConnected = isConnected; initialized = true;
this->latitude = latitude; hasLock = newStatus->hasLock;
this->longitude = longitude; isConnected = newStatus->isConnected;
this->altitude = altitude; latitude = newStatus->latitude;
this->dop = dop; longitude = newStatus->longitude;
this->heading = heading; altitude = newStatus->altitude;
this->numSatellites = numSatellites; dop = newStatus->dop;
heading = newStatus->heading;
numSatellites = newStatus->numSatellites;
} }
GPSStatus(const GPSStatus &); if (isDirty) {
GPSStatus &operator=(const GPSStatus &); if (hasLock)
DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f, heading=%f, sats=%d\n", latitude * 1e-7, longitude * 1e-7,
void observe(Observable<const GPSStatus *> *source) altitude, dop * 1e-2, heading * 1e-5, numSatellites);
{ else
statusObserver.observe(source); DEBUG_MSG("No GPS lock\n");
onNewStatus.notifyObservers(this);
} }
return 0;
}
};
bool getHasLock() const } // namespace meshtastic
{
return hasLock;
}
bool getIsConnected() const
{
return isConnected;
}
int32_t getLatitude() const
{
return latitude;
}
int32_t getLongitude() const
{
return longitude;
}
int32_t getAltitude() const
{
return altitude;
}
uint32_t getDOP() const
{
return dop;
}
uint32_t getHeading() const
{
return heading;
}
uint32_t getNumSatellites() const
{
return numSatellites;
}
bool matches(const GPSStatus *newStatus) const
{
return (
newStatus->hasLock != hasLock ||
newStatus->isConnected != isConnected ||
newStatus->latitude != latitude ||
newStatus->longitude != longitude ||
newStatus->altitude != altitude ||
newStatus->dop != dop ||
newStatus->heading != heading ||
newStatus->numSatellites != numSatellites
);
}
int updateStatus(const GPSStatus *newStatus) {
// Only update the status if values have actually changed
bool isDirty;
{
isDirty = matches(newStatus);
initialized = true;
hasLock = newStatus->hasLock;
isConnected = newStatus->isConnected;
latitude = newStatus->latitude;
longitude = newStatus->longitude;
altitude = newStatus->altitude;
dop = newStatus->dop;
heading = newStatus->heading;
numSatellites = newStatus->numSatellites;
}
if(isDirty) {
DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f, heading=%f, sats=%d\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5, numSatellites);
onNewStatus.notifyObservers(this);
}
return 0;
}
};
}
extern meshtastic::GPSStatus *gpsStatus; extern meshtastic::GPSStatus *gpsStatus;

Wyświetl plik

@ -66,7 +66,10 @@ bool Power::analogInit()
{ {
#ifdef BATTERY_PIN #ifdef BATTERY_PIN
DEBUG_MSG("Using analog input for battery level\n"); DEBUG_MSG("Using analog input for battery level\n");
#ifndef NO_ESP32
// ESP32 needs special analog stuff
adcAttachPin(BATTERY_PIN); adcAttachPin(BATTERY_PIN);
#endif
// adcStart(BATTERY_PIN); // adcStart(BATTERY_PIN);
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution. analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
batteryLevel = &analogLevel; batteryLevel = &analogLevel;

Wyświetl plik

@ -11,16 +11,7 @@
static void sdsEnter() static void sdsEnter()
{ {
/* // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
// Don't deepsleep if we have USB power or if the user as pressed a button recently
// !isUSBPowered <- doesn't work yet because the axp192 isn't letting the battery fully charge when we are awake - FIXME
if (millis() - lastPressMs > radioConfig.preferences.mesh_sds_timeout_secs)
{
doDeepSleep(radioConfig.preferences.sds_secs);
}
*/
doDeepSleep(radioConfig.preferences.sds_secs * 1000LL); doDeepSleep(radioConfig.preferences.sds_secs * 1000LL);
} }

Wyświetl plik

@ -145,7 +145,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define FLIP_SCREEN_VERTICALLY #define FLIP_SCREEN_VERTICALLY
// DEBUG LED // DEBUG LED
#ifndef LED_INVERTED
#define LED_INVERTED 0 // define as 1 if LED is active low (on) #define LED_INVERTED 0 // define as 1 if LED is active low (on)
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// GPS // GPS

Wyświetl plik

@ -1,6 +1,51 @@
#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
6Command: 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 12 ,
ON time in msecs
Arg3:(), Arg1 12 ,
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)
{ {
int32_t degMult = 10000000; // 1e7 int32_t degMult = 10000000; // 1e7
@ -10,12 +55,27 @@ static int32_t toDegInt(RawDegrees d)
return r; return r;
} }
bool NMEAGPS::setup()
{
#ifdef PIN_GPS_PPS
// pulse per second
// FIXME - move into shared GPS code
pinMode(PIN_GPS_PPS, INPUT);
#endif
return true;
}
void NMEAGPS::loop() void NMEAGPS::loop()
{ {
while (_serial_gps->available() > 0) { while (_serial_gps->available() > 0) {
int c = _serial_gps->read(); int c = _serial_gps->read();
// Serial.write(c); // DEBUG_MSG("%c", c);
reader.encode(c); bool isValid = reader.encode(c);
// if we have received valid NMEA claim we are connected
if (isValid)
isConnected = true;
} }
uint32_t now = millis(); uint32_t now = millis();
@ -39,8 +99,6 @@ void NMEAGPS::loop()
t.tm_year = d.year() - 1900; t.tm_year = d.year() - 1900;
t.tm_isdst = false; t.tm_isdst = false;
perhapsSetRTC(t); perhapsSetRTC(t);
isConnected = true; // we seem to have a real GPS (but not necessarily a lock)
} }
uint8_t fixtype = reader.fixQuality(); uint8_t fixtype = reader.fixQuality();
@ -68,7 +126,7 @@ 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=%f, 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);
} }

Wyświetl plik

@ -17,5 +17,7 @@ class NMEAGPS : public GPS
uint32_t lastUpdateMsec = 0; uint32_t lastUpdateMsec = 0;
public: public:
virtual bool setup();
virtual void loop(); virtual void loop();
}; };

Wyświetl plik

@ -0,0 +1,125 @@
#include "configuration.h"
#ifdef HAS_EINK
#include "EInkDisplay.h"
#include "SPILock.h"
#include "epd1in54.h" // Screen specific library
#include "graphics/configs.h"
#include <SPI.h>
#include <TFT_eSPI.h> // Graphics library and Sprite class
Epd ePaper; // Create an instance ePaper
TFT_eSPI glc = TFT_eSPI(); // Invoke the graphics library class
TFT_eSprite frame = TFT_eSprite(&glc); // Invoke the Sprite class for the image frame buffer
uint8_t *framePtr; // Pointer for the black frame buffer
#define COLORED 0
#define UNCOLORED 1
#define INK COLORED // Black ink
#define PAPER UNCOLORED // 'paper' background colour
//------------------------------------------------------------------------------------
// Update display - different displays have different function names in the default
// Waveshare libraries :-(
//------------------------------------------------------------------------------------
#if defined(EPD1IN54B_H) || defined(EPD1IN54C_H) || defined(EPD2IN13B_H) || defined(EPD2IN7B_H) || defined(EPD2IN9B_H) || \
defined(EPD4IN2_H)
void updateDisplay(uint8_t *blackFrame = blackFramePtr, uint8_t *redFrame = redFramePtr)
{
ePaper.DisplayFrame(blackFrame, redFrame); // Update 3 colour display
#else
void updateDisplay(uint8_t *blackFrame = framePtr)
{
#if defined(EPD2IN7_H) || defined(EPD4IN2_H)
ePaper.DisplayFrame(blackFrame); // Update 2 color display
#elif defined(EPD1IN54_H) || defined(EPD2IN13_H) || defined(EPD2IN9_H)
ePaper.SetFrameMemory(blackFrame); // Update 2 colour display
ePaper.DisplayFrame();
#else
#error "Selected ePaper library is not supported"
#endif
#endif
}
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
{
setGeometry(GEOMETRY_128_64); // FIXME - currently we lie and claim 128x64 because I'm not yet sure other resolutions will
// work ie GEOMETRY_RAWMODE
}
// FIXME quick hack to limit drawing to a very slow rate
uint32_t lastDrawMsec;
// Write the buffer to the display memory
void EInkDisplay::display(void)
{
concurrency::LockGuard g(spiLock);
uint32_t now = millis();
uint32_t sinceLast = now - lastDrawMsec;
if (framePtr && (sinceLast > 30 * 1000 || lastDrawMsec == 0)) {
lastDrawMsec = now;
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto b = buffer[x + (y / 8) * SCREEN_WIDTH];
auto isset = b & (1 << (y & 7));
frame.drawPixel(x, y, isset ? INK : PAPER);
}
}
updateDisplay(); // Send image to display and refresh
// Put screen to sleep to save power (if wanted)
// ePaper.Sleep();
}
}
// Send a command to the display (low level function)
void EInkDisplay::sendCommand(uint8_t com)
{
(void)com;
// Drop all commands to device (we just update the buffer)
}
// Connect to the display
bool EInkDisplay::connect()
{
DEBUG_MSG("Doing EInk init\n");
#ifdef PIN_EINK_EN
digitalWrite(PIN_EINK_EN, HIGH);
pinMode(PIN_EINK_EN, OUTPUT);
#endif
// Initialise the ePaper library
// FIXME - figure out how to use lut_partial_update
if (ePaper.Init(lut_full_update) != 0) {
DEBUG_MSG("ePaper init failed\n");
return false;
} else {
frame.setColorDepth(1); // Must set the bits per pixel to 1 for ePaper displays
// Set bit depth BEFORE creating Sprite, default is 16!
// Create a frame buffer in RAM of defined size and save the pointer to it
// RAM needed is about (EPD_WIDTH * EPD_HEIGHT)/8 , ~5000 bytes for 200 x 200 pixels
// Note: always create the Sprite before setting the Sprite rotation
framePtr = (uint8_t *)frame.createSprite(EPD_WIDTH, EPD_HEIGHT);
frame.fillSprite(PAPER); // Fill frame with white
/* frame.drawLine(0, 0, frame.width() - 1, frame.height() - 1, INK);
frame.drawLine(0, frame.height() - 1, frame.width() - 1, 0, INK);
updateDisplay(); */
return true;
}
}
#endif

Wyświetl plik

@ -0,0 +1,35 @@
#pragma once
#include <OLEDDisplay.h>
/**
* An adapter class that allows using the TFT_eSPI library as if it was an OLEDDisplay implementation.
*
* Remaining TODO:
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
* implement displayOn/displayOff to turn off the TFT device (and backlight)
* Use the fast NRF52 SPI API rather than the slow standard arduino version
*
* turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
*/
class EInkDisplay : public OLEDDisplay
{
public:
/* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/
EInkDisplay(uint8_t address, int sda, int scl);
// Write the buffer to the display memory
virtual void display(void);
protected:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) { return 0; }
// Send a command to the display (low level function)
virtual void sendCommand(uint8_t com);
// Connect to the display
virtual bool connect();
};

Wyświetl plik

@ -10,7 +10,8 @@
#include <SSD1306Wire.h> #include <SSD1306Wire.h>
#endif #endif
#include "TFT.h" #include "EInkDisplay.h"
#include "TFTDisplay.h"
#include "TypedQueue.h" #include "TypedQueue.h"
#include "commands.h" #include "commands.h"
#include "concurrency/LockGuard.h" #include "concurrency/LockGuard.h"
@ -48,7 +49,6 @@ class DebugInfo
void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
std::string channelName; std::string channelName;
/// Protects all of internal state. /// Protects all of internal state.
@ -240,6 +240,8 @@ class Screen : public concurrency::PeriodicTask
/** FIXME cleanup display abstraction */ /** FIXME cleanup display abstraction */
#ifdef ST7735_CS #ifdef ST7735_CS
TFTDisplay dispdev; TFTDisplay dispdev;
#elif defined(HAS_EINK)
EInkDisplay dispdev;
#elif defined(USE_SH1106) #elif defined(USE_SH1106)
SH1106Wire dispdev; SH1106Wire dispdev;
#else #else

Wyświetl plik

@ -2,7 +2,7 @@
#ifdef ST7735_CS #ifdef ST7735_CS
#include "SPILock.h" #include "SPILock.h"
#include "TFT.h" #include "TFTDisplay.h"
#include "graphics/configs.h" #include "graphics/configs.h"
#include <SPI.h> #include <SPI.h>
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip #include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
@ -20,7 +20,6 @@ void TFTDisplay::display(void)
{ {
concurrency::LockGuard g(spiLock); concurrency::LockGuard g(spiLock);
#if 1
// 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)
// tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK); // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) { for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
@ -32,7 +31,6 @@ void TFTDisplay::display(void)
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK); tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
} }
} }
#endif
} }
// Send a command to the display (low level function) // Send a command to the display (low level function)
@ -52,12 +50,10 @@ bool TFTDisplay::connect()
pinMode(ST7735_BACKLIGHT_EN, OUTPUT); pinMode(ST7735_BACKLIGHT_EN, OUTPUT);
#endif #endif
#if 1
tft.init(); tft.init();
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
tft.fillScreen(TFT_BLACK); tft.fillScreen(TFT_BLACK);
// tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left // tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left
#endif
return true; return true;
} }

Wyświetl plik

@ -213,16 +213,16 @@ void setup()
esp32Setup(); esp32Setup();
#endif #endif
#ifdef NRF52_SERIES
nrf52Setup();
#endif
// Currently only the tbeam has a PMU // Currently only the tbeam has a PMU
power = new Power(); power = new Power();
power->setStatusHandler(powerStatus); power->setStatusHandler(powerStatus);
powerStatus->observe(&power->newStatus); powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
#ifdef NRF52_SERIES
nrf52Setup();
#endif
// Init our SPI controller (must be before screen and lora) // Init our SPI controller (must be before screen and lora)
initSPI(); initSPI();
#ifdef NO_ESP32 #ifdef NO_ESP32
@ -234,7 +234,7 @@ void setup()
#endif #endif
// Initialize the screen first so we can show the logo while we start up everything else. // Initialize the screen first so we can show the logo while we start up everything else.
#ifdef ST7735_CS #if defined(ST7735_CS) || defined(HAS_EINK)
screen.setup(); screen.setup();
#else #else
if (ssd1306_found) if (ssd1306_found)

Wyświetl plik

@ -1,6 +1,6 @@
#include "NRF52Bluetooth.h" #include "NRF52Bluetooth.h"
#include "configuration.h" #include "configuration.h"
#include "graphics/TFT.h" #include "graphics/TFTDisplay.h"
#include <assert.h> #include <assert.h>
#include <ble_gap.h> #include <ble_gap.h>
#include <memory.h> #include <memory.h>
@ -49,14 +49,19 @@ void getMacAddr(uint8_t *dmac)
NRF52Bluetooth *nrf52Bluetooth; NRF52Bluetooth *nrf52Bluetooth;
static bool bleOn = false; static bool bleOn = false;
static const bool enableBle = true; // Set to false for easier debugging
void setBluetoothEnable(bool on) void setBluetoothEnable(bool on)
{ {
if (on != bleOn) { if (on != bleOn) {
if (on) { if (on) {
if (!nrf52Bluetooth) { if (!nrf52Bluetooth) {
// DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); if (!enableBle)
nrf52Bluetooth = new NRF52Bluetooth(); DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n");
nrf52Bluetooth->setup(); else {
nrf52Bluetooth = new NRF52Bluetooth();
nrf52Bluetooth->setup();
}
} }
} else { } else {
DEBUG_MSG("FIXME: implement BLE disable\n"); DEBUG_MSG("FIXME: implement BLE disable\n");
@ -88,6 +93,11 @@ 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();

Wyświetl plik

@ -0,0 +1,5 @@
#pragma once
// dummy file to keep old arduino code happy
#define PROGMEM
#define pgm_read_byte(addr) (*((unsigned const char *)addr))

Wyświetl plik

@ -0,0 +1,44 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "variant.h"
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
// P0 - pins 0 and 1 are hardwired for xtal and should never be enabled
0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
// P1
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
void initVariant()
{
// LED1 & LED2
pinMode(PIN_LED1, OUTPUT);
ledOff(PIN_LED1);
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
pinMode(PIN_LED3, OUTPUT);
ledOff(PIN_LED3);
}

Wyświetl plik

@ -0,0 +1,218 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _VARIANT_TTGO_EINK_V1_
#define _VARIANT_TTGO_EINK_V1_
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
/*
@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)
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
enable gps sleep mode
use new flash chip
add factory/power on self test
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Number of pins defined in PinDescription array
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (1)
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (0 + 13) // green (but red on my prototype)
#define PIN_LED2 (0 + 15) // blue (but red on my prototype)
#define PIN_LED3 (0 + 14) // red (not functional on my prototype)
#define LED_RED PIN_LED3
#define LED_GREEN PIN_LED1
#define LED_BLUE PIN_LED2
#define LED_BUILTIN LED_GREEN
#define LED_CONN PIN_BLUE
#define LED_STATE_ON 0 // State when LED is lit
#define LED_INVERTED 1
/*
* Buttons
*/
#define PIN_BUTTON1 (32 + 10)
/*
* Analog pins
*/
#define PIN_A0 (4) // Battery ADC
#define BATTERY_PIN PIN_A0
static const uint8_t A0 = PIN_A0;
#define ADC_RESOLUTION 14
#define PIN_NFC1 (9)
#define PIN_NFC2 (10)
/*
* Serial interfaces
*/
/*
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.
*/
#define PIN_SERIAL2_RX (0 + 6)
#define PIN_SERIAL2_TX (0 + 8)
// #define PIN_SERIAL2_EN (0 + 17)
/**
Wire Interfaces
*/
#define WIRE_INTERFACES_COUNT 1
#define PIN_WIRE_SDA (26) // Not connected on board?
#define PIN_WIRE_SCL (27)
/* touch sensor, active high */
#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
// 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
// On-board QSPI Flash
#define EXTERNAL_FLASH_DEVICES MX25R6435F
#define EXTERNAL_FLASH_USE_QSPI
*/
/*
* Lora radio
*/
#define SX1262_CS (0 + 24) // FIXME - we really should define LORA_CS instead
#define SX1262_DIO1 (0 + 20)
// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching
#define SX1262_DIO3 \
(0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the main
// CPU?
#define SX1262_BUSY (0 + 17)
#define SX1262_RESET (0 + 25)
#define SX1262_E22 // Not really an E22 but TTGO seems to be trying to clone that
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
// code)
// #define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...)
/*
* eink display pins
*/
#define PIN_EINK_EN (32 + 11)
#define PIN_EINK_CS (0 + 30)
#define PIN_EINK_BUSY (0 + 3)
#define PIN_EINK_DC (0 + 28)
#define PIN_EINK_RES (0 + 2)
#define PIN_EINK_SCLK (0 + 31)
#define PIN_EINK_MOSI (0 + 29) // also called SDI
#define HAS_EINK
#define PIN_SPI1_MISO \
(32 + 7) // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO
#define PIN_SPI1_MOSI PIN_EINK_MOSI
#define PIN_SPI1_SCK PIN_EINK_SCLK
/*
* 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_SERIAL1_RX PIN_GPS_TX
#define PIN_SERIAL1_TX PIN_GPS_RX
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 2
// For LORA
#define PIN_SPI_MISO (0 + 23)
#define PIN_SPI_MOSI (0 + 22)
#define PIN_SPI_SCK (0 + 19)
// To debug via the segger JLINK console rather than the CDC-ACM serial device
#define USE_SEGGER
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif