mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-28 10:42:08 +00:00
WIP new adafruit eink display lib at least starts
This commit is contained in:
parent
17a1262382
commit
659286f738
@ -362,6 +362,7 @@ src_filter = ${nrf52_base.src_filter} +<../variants/t-echo>
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
${nrf52840_base.lib_deps}
|
${nrf52840_base.lib_deps}
|
||||||
https://github.com/geeksville/GxEPD2.git
|
https://github.com/geeksville/GxEPD2.git
|
||||||
|
adafruit/Adafruit BusIO
|
||||||
;upload_protocol = fs
|
;upload_protocol = fs
|
||||||
|
|
||||||
; First prototype eink/nrf52840/sx1262 device (removed from build because didn't ship in quantity)
|
; First prototype eink/nrf52840/sx1262 device (removed from build because didn't ship in quantity)
|
||||||
|
@ -1,152 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#ifdef HAS_EINK
|
|
||||||
#include "EInkDisplay.h"
|
|
||||||
#include "SPILock.h"
|
|
||||||
#include "epd1in54.h" // Screen specific library
|
|
||||||
#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_RAWMODE, EPD_WIDTH, EPD_HEIGHT);
|
|
||||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
|
||||||
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME quick hack to limit drawing to a very slow rate
|
|
||||||
uint32_t lastDrawMsec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force a display update if we haven't drawn within the specified msecLimit
|
|
||||||
*/
|
|
||||||
bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|
||||||
{
|
|
||||||
// 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 > msecLimit || 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 < displayHeight; y++) {
|
|
||||||
for (uint8_t x = 0; x < displayWidth; x++) {
|
|
||||||
|
|
||||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
|
||||||
auto b = buffer[x + (y / 8) * displayWidth];
|
|
||||||
auto isset = b & (1 << (y & 7));
|
|
||||||
frame.drawPixel(x, y, isset ? INK : PAPER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ePaper.Reset(); // wake the screen from sleep
|
|
||||||
|
|
||||||
DEBUG_MSG("Updating eink... ");
|
|
||||||
updateDisplay(); // Send image to display and refresh
|
|
||||||
DEBUG_MSG("done\n");
|
|
||||||
|
|
||||||
// Put screen to sleep to save power
|
|
||||||
ePaper.Sleep();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// DEBUG_MSG("Skipping eink display\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the buffer to the display memory
|
|
||||||
void EInkDisplay::display(void)
|
|
||||||
{
|
|
||||||
// We don't allow regular 'dumb' display() calls to draw on eink until we've shown
|
|
||||||
// at least one forceDisplay() keyframe. This prevents flashing when we should the critical
|
|
||||||
// bootscreen (that we want to look nice)
|
|
||||||
if (lastDrawMsec)
|
|
||||||
forceDisplay(slowUpdateMsec); // Show the first screen a few seconds after boot, then slower
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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_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
|
|
||||||
// backlight power, HIGH is backlight on, LOW is off
|
|
||||||
digitalWrite(PIN_EINK_EN, LOW);
|
|
||||||
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
|
|
@ -1,48 +0,0 @@
|
|||||||
#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
|
|
||||||
{
|
|
||||||
/// How often should we update the display
|
|
||||||
/// thereafter we do once per 5 minutes
|
|
||||||
uint32_t slowUpdateMsec = 5 * 60 * 1000;
|
|
||||||
|
|
||||||
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 (for eink we only do this occasionally)
|
|
||||||
virtual void display(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force a display update if we haven't drawn within the specified msecLimit
|
|
||||||
*
|
|
||||||
* @return true if we did draw the screen
|
|
||||||
*/
|
|
||||||
bool forceDisplay(uint32_t msecLimit = 1000);
|
|
||||||
|
|
||||||
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();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#ifdef HAS_EINK2
|
#ifdef HAS_EINK
|
||||||
#include "EInkDisplay.h"
|
#include "EInkDisplay2.h"
|
||||||
#include "SPILock.h"
|
#include "SPILock.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
#include "GxEPD2_BW.h"
|
||||||
|
|
||||||
#define COLORED 0
|
#define COLORED GxEPD_BLACK
|
||||||
#define UNCOLORED 1
|
#define UNCOLORED GxEPD_WHITE
|
||||||
|
|
||||||
#define INK COLORED // Black ink
|
|
||||||
#define PAPER UNCOLORED // 'paper' background colour
|
|
||||||
|
|
||||||
#define EPD_WIDTH 200 // FIXME
|
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67
|
||||||
#define EPD_HEIGHT 200
|
|
||||||
|
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
||||||
|
|
||||||
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
|
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl)
|
||||||
{
|
{
|
||||||
setGeometry(GEOMETRY_RAWMODE, EPD_WIDTH, EPD_HEIGHT);
|
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
|
||||||
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
// setGeometry(GEOMETRY_RAWMODE, 128, 64); // old resolution
|
||||||
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
// setGeometry(GEOMETRY_128_64); // We originally used this because I wasn't sure if rawmode worked - it does
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
uint32_t sinceLast = now - lastDrawMsec;
|
uint32_t sinceLast = now - lastDrawMsec;
|
||||||
|
|
||||||
if (sinceLast > msecLimit || lastDrawMsec == 0) {
|
if (false && adafruitDisplay && (sinceLast > msecLimit || 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)
|
||||||
@ -46,15 +46,15 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|||||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||||
auto b = buffer[x + (y / 8) * displayWidth];
|
auto b = buffer[x + (y / 8) * displayWidth];
|
||||||
auto isset = b & (1 << (y & 7));
|
auto isset = b & (1 << (y & 7));
|
||||||
// frame.drawPixel(x, y, isset ? INK : PAPER);
|
adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_MSG("Updating eink... ");
|
DEBUG_MSG("Updating eink... ");
|
||||||
// ePaper.Reset(); // wake the screen from sleep
|
// ePaper.Reset(); // wake the screen from sleep
|
||||||
// updateDisplay(); // Send image to display and refresh
|
adafruitDisplay->display(false); // FIXME, use partial update mode
|
||||||
// Put screen to sleep to save power
|
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
|
||||||
// ePaper.Sleep();
|
// adafruitDisplay->hibernate();
|
||||||
DEBUG_MSG("done\n");
|
DEBUG_MSG("done\n");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -97,14 +97,20 @@ bool EInkDisplay::connect()
|
|||||||
pinMode(PIN_EINK_EN, OUTPUT);
|
pinMode(PIN_EINK_EN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialise the ePaper library
|
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS,
|
||||||
// FIXME - figure out how to use lut_partial_update
|
PIN_EINK_DC,
|
||||||
if (false) {
|
PIN_EINK_RES,
|
||||||
DEBUG_MSG("ePaper init failed\n");
|
PIN_EINK_BUSY);
|
||||||
return false;
|
|
||||||
} else {
|
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||||
|
adafruitDisplay->init();
|
||||||
|
adafruitDisplay->setRotation(1);
|
||||||
|
adafruitDisplay->setFullWindow();
|
||||||
|
adafruitDisplay->fillScreen(UNCOLORED);
|
||||||
|
adafruitDisplay->drawCircle(100, 100, 20, COLORED);
|
||||||
|
adafruitDisplay->display(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,7 +30,7 @@ class Screen
|
|||||||
#include <SSD1306Wire.h>
|
#include <SSD1306Wire.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "EInkDisplay.h"
|
#include "EInkDisplay2.h"
|
||||||
#include "TFTDisplay.h"
|
#include "TFTDisplay.h"
|
||||||
#include "TypedQueue.h"
|
#include "TypedQueue.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
|
@ -213,7 +213,7 @@ External serial flash WP25R1635FZUIL0
|
|||||||
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
|
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
|
||||||
#define PIN_EINK_PWR_ON (0 + 12)
|
#define PIN_EINK_PWR_ON (0 + 12)
|
||||||
|
|
||||||
#define HAS_EINK2
|
#define HAS_EINK
|
||||||
|
|
||||||
// No screen wipes on eink
|
// No screen wipes on eink
|
||||||
#define SCREEN_TRANSITION_MSECS 0
|
#define SCREEN_TRANSITION_MSECS 0
|
||||||
|
Loading…
Reference in New Issue
Block a user