eink display now kinda works

This commit is contained in:
geeksville 2020-09-26 09:40:48 -07:00
parent b0bbf95b03
commit d88d2780f4
12 changed files with 213 additions and 28 deletions

View File

@ -234,9 +234,11 @@ 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

View File

@ -14,10 +14,16 @@ bool NMEAGPS::setup()
{
#ifdef PIN_GPS_WAKE
// FIXME, support using this pin to control GPS sleep
// digitalWrite(PIN_GPS_WAKE, LOW);
// digitalWrite(PIN_GPS_WAKE, HIGH);
// pinMode(PIN_GPS_WAKE, OUTPUT);
#endif
#ifdef PIN_GPS_PPS
// pulse per second
// FIXME - move into shared GPS code
pinMode(PIN_GPS_PPS, INPUT);
#endif
return true;
}

View File

@ -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

View File

@ -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();
};

View File

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

View File

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

View File

@ -232,7 +232,7 @@ void setup()
#endif
// 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();
#else
if (ssd1306_found)

View File

@ -1,6 +1,6 @@
#include "NRF52Bluetooth.h"
#include "configuration.h"
#include "graphics/TFT.h"
#include "graphics/TFTDisplay.h"
#include <assert.h>
#include <ble_gap.h>
#include <memory.h>

5
src/pgmspace.h Normal file
View File

@ -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))

View File

@ -38,4 +38,7 @@ void initVariant()
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
pinMode(PIN_LED3, OUTPUT);
ledOff(PIN_LED3);
}

View File

@ -27,18 +27,22 @@
/*
@geeksville eink TODO:
enable reset as a button
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
button not working
get pps blinking on second board
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
eink probably is // #include <GxGDEP015OC1/GxGDEP015OC1.h> // 1.54" b/w //G702-A
https://github.com/Xinyuan-LilyGO/LilyGO_T5_V24
200 x 200
feedback to ttgo:
are D10 and D8 backwards on the GPS schematic? gps comms no work?
leds don't work?
use pcf8563 part for waking CPU? or remove it
the mx25 flash chip is great!
name: TTGO LoraCard (nice googablity, unique name, sounds slick, implies lora and small)
@ -65,16 +69,16 @@ extern "C" {
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (0 + 13)
#define PIN_LED2 (0 + 14)
#define PIN_LED3 (0 + 15)
#define PIN_LED1 (0 + 13) // green
#define PIN_LED2 (0 + 14) // red
#define PIN_LED3 (0 + 15) // blue
#define LED_RED PIN_LED2
#define LED_GREEN PIN_LED1
#define LED_BLUE PIN_LED3
#define LED_BUILTIN LED_GREEN
#define LED_CONN LED_CONN
#define LED_CONN PIN_BLUE
#define LED_STATE_ON 0 // State when LED is lit
@ -171,21 +175,28 @@ FIXME define/FIX flash access
*/
#define PIN_EINK_EN (32 + 11)
#define PIN_EINK_CS (0 + 31)
#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 GPS
#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the CPU
#define PIN_GPS_TX (32 + 8) // This is for bits going TOWARDS the GPS
#define PIN_GPS_RX (32 + 9) // This is for bits going TOWARDS the CPU
#define PIN_SERIAL1_RX PIN_GPS_RX
#define PIN_SERIAL1_TX PIN_GPS_TX
@ -193,17 +204,17 @@ FIXME define/FIX flash access
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 1
#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)
static const uint8_t SS = SX1262_CS;
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
// static const uint8_t SS = SX1262_CS;
// static const uint8_t MOSI = PIN_SPI_MOSI;
// static const uint8_t MISO = PIN_SPI_MISO;
// static const uint8_t SCK = PIN_SPI_SCK;
// To debug via the segger JLINK console rather than the CDC-ACM serial device
#define USE_SEGGER