mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-08-07 14:44:43 +02:00
Added Waveshare ePaper support
Also added ability to push 1bpp bitmaps to a Sprite to support rendering images on an EPaper screen. Floyd-Steinberg dithering and basic graphics example added as first ePaper demo.
This commit is contained in:
@@ -304,7 +304,42 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO Currently does nothing for 1 bpp
|
|
||||||
|
else // 1bpp
|
||||||
|
{
|
||||||
|
// Move coordinate rotation to support fn
|
||||||
|
if (_rotation == 1)
|
||||||
|
{
|
||||||
|
int32_t tx = x;
|
||||||
|
x = _dwidth - y - 1;
|
||||||
|
y = tx;
|
||||||
|
}
|
||||||
|
else if (_rotation == 2)
|
||||||
|
{
|
||||||
|
x = _dwidth - x - 1;
|
||||||
|
y = _dheight - y - 1;
|
||||||
|
}
|
||||||
|
else if (_rotation == 3)
|
||||||
|
{
|
||||||
|
int32_t tx = x;
|
||||||
|
x = y;
|
||||||
|
y = _dheight - tx - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* pdata = (uint8_t*) data;
|
||||||
|
uint32_t ww = (w+7) & 0xFFF8;
|
||||||
|
for (int32_t yp = 0; yp<h; yp++)
|
||||||
|
{
|
||||||
|
for (int32_t xp = 0; xp<ww; xp+=8)
|
||||||
|
{
|
||||||
|
uint8_t pbyte = *pdata++;
|
||||||
|
for (uint8_t xc = 0; xc < 8; xc++)
|
||||||
|
{
|
||||||
|
if (xp+xc<w) drawPixel(x+xp+xc, y+yp, (pbyte<<xc) & 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -329,6 +364,7 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (_bpp == 8)
|
else if (_bpp == 8)
|
||||||
{
|
{
|
||||||
for (uint32_t yp = y; yp < y + h; yp++)
|
for (uint32_t yp = y; yp < y + h; yp++)
|
||||||
@@ -341,7 +377,42 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO Currently does nothing for 1 bpp
|
|
||||||
|
else // 1bpp
|
||||||
|
{
|
||||||
|
// Move coordinate rotation to support fn
|
||||||
|
if (_rotation == 1)
|
||||||
|
{
|
||||||
|
int32_t tx = x;
|
||||||
|
x = _dwidth - y - 1;
|
||||||
|
y = tx;
|
||||||
|
}
|
||||||
|
else if (_rotation == 2)
|
||||||
|
{
|
||||||
|
x = _dwidth - x - 1;
|
||||||
|
y = _dheight - y - 1;
|
||||||
|
}
|
||||||
|
else if (_rotation == 3)
|
||||||
|
{
|
||||||
|
int32_t tx = x;
|
||||||
|
x = y;
|
||||||
|
y = _dheight - tx - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* pdata = (const uint8_t* ) data;
|
||||||
|
uint32_t ww = (w+7) & 0xFFF8;
|
||||||
|
for (int32_t yp = 0; yp<h; yp++)
|
||||||
|
{
|
||||||
|
for (int32_t xp = 0; xp<ww; xp+=8)
|
||||||
|
{
|
||||||
|
uint8_t pbyte = pgm_read_byte(pdata++);
|
||||||
|
for (uint8_t xc = 0; xc < 8; xc++)
|
||||||
|
{
|
||||||
|
if (xp+xc<w) drawPixel(x+xp+xc, y+yp, (pbyte<<xc) & 0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
// If it is a 16bit serial display we must transfer 16 bits every time
|
// If it is a 16bit serial display we must transfer 16 bits every time
|
||||||
#ifdef RPI_ILI9486_DRIVER
|
#ifdef RPI_ILI9486_DRIVER
|
||||||
#define SEND_16_BITS
|
|
||||||
#define CMD_BITS 16-1
|
#define CMD_BITS 16-1
|
||||||
#else
|
#else
|
||||||
#define CMD_BITS 8-1
|
#define CMD_BITS 8-1
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
// Customised User_Setup files are stored in the "User_Setups" folder.
|
// Customised User_Setup files are stored in the "User_Setups" folder.
|
||||||
|
|
||||||
#ifndef USER_SETUP_LOADED // Lets PlatformIO users define user settings in
|
#ifndef USER_SETUP_LOADED // Lets PlatformIO users define settings in
|
||||||
// platformio.ini, see notes in "Tools" folder.
|
// platformio.ini, see notes in "Tools" folder.
|
||||||
|
|
||||||
// Only ONE line below should be uncommented. Add extra lines and files as needed.
|
// Only ONE line below should be uncommented. Add extra lines and files as needed.
|
||||||
@@ -30,17 +30,16 @@
|
|||||||
//#include <User_Setups/Setup7_ST7735_128x128.h> // Setup file configured for my ST7735 128x128 display
|
//#include <User_Setups/Setup7_ST7735_128x128.h> // Setup file configured for my ST7735 128x128 display
|
||||||
//#include <User_Setups/Setup8_ILI9163_128x128.h> // Setup file configured for my ILI9163 128x128 display
|
//#include <User_Setups/Setup8_ILI9163_128x128.h> // Setup file configured for my ILI9163 128x128 display
|
||||||
//#include <User_Setups/Setup9_ST7735_Overlap.h> // Setup file configured for my ST7735
|
//#include <User_Setups/Setup9_ST7735_Overlap.h> // Setup file configured for my ST7735
|
||||||
//#include <User_Setups/Setup10_RPi_touch_ILI9486.h> // Setup file configured for my stock RPi TFT with touch
|
//#include <User_Setups/Setup10_RPi_touch_ILI9486.h> // Setup file configured for ESP8266 and RPi TFT with touch
|
||||||
//#include <User_Setups/Setup11_RPi_touch_ILI9486.h> // Setup file configured for my stock RPi TFT with touch
|
//#include <User_Setups/Setup11_RPi_touch_ILI9486.h> // Setup file configured for ESP32 and RPi TFT with touch
|
||||||
//#include <User_Setups/Setup12_M5Stack.h> // Setup file for the ESP32 based M5Stack
|
//#include <User_Setups/Setup12_M5Stack.h> // Setup file for the ESP32 based M5Stack
|
||||||
//#include <User_Setups/Setup13_ILI9481_Parallel.h> // Setup file for the ESP32 with parallel bus TFT
|
//#include <User_Setups/Setup13_ILI9481_Parallel.h> // Setup file for the ESP32 with parallel bus TFT
|
||||||
//#include <User_Setups/Setup14_ILI9341_Parallel.h> // Setup file for the ESP32 with parallel bus TFT
|
//#include <User_Setups/Setup14_ILI9341_Parallel.h> // Setup file for the ESP32 with parallel bus TFT
|
||||||
//#include <User_Setups/Setup15_HX8357D.h> // Setup file configured for HX8357D (untested)
|
//#include <User_Setups/Setup15_HX8357D.h> // Setup file configured for HX8357D (untested)
|
||||||
//#include <User_Setups/Setup16_ILI9488_Parallel.h> // Setup file for the ESP32 with parallel bus TFT
|
//#include <User_Setups/Setup16_ILI9488_Parallel.h> // Setup file for the ESP32 with parallel bus TFT
|
||||||
|
//#include <User_Setups/Setup17_ePaper.h> // Setup file for any Waveshare ePaper display
|
||||||
|
|
||||||
//#include <User_Setups/Setup99.h>
|
//#include <User_Setups/SetupX_Template.h>
|
||||||
|
|
||||||
// ePaper #include <User_Setups/SetupX_Template.h> // Setup file template for copying/editting
|
|
||||||
|
|
||||||
|
|
||||||
#endif // USER_SETUP_LOADED
|
#endif // USER_SETUP_LOADED
|
||||||
@@ -70,7 +69,7 @@
|
|||||||
#define TFT_DRIVER 0x6D02
|
#define TFT_DRIVER 0x6D02
|
||||||
#elif defined (RPI_ILI9486_DRIVER)
|
#elif defined (RPI_ILI9486_DRIVER)
|
||||||
#include <TFT_Drivers/RPI_ILI9486_Defines.h>
|
#include <TFT_Drivers/RPI_ILI9486_Defines.h>
|
||||||
#define TFT_DRIVER 0x9481
|
#define TFT_DRIVER 0x9486
|
||||||
#elif defined (ILI9481_DRIVER)
|
#elif defined (ILI9481_DRIVER)
|
||||||
#include <TFT_Drivers/ILI9481_Defines.h>
|
#include <TFT_Drivers/ILI9481_Defines.h>
|
||||||
#define TFT_DRIVER 0x9481
|
#define TFT_DRIVER 0x9481
|
||||||
@@ -83,6 +82,11 @@
|
|||||||
#elif defined (EPD_DRIVER)
|
#elif defined (EPD_DRIVER)
|
||||||
#include "TFT_Drivers/EPD_Defines.h"
|
#include "TFT_Drivers/EPD_Defines.h"
|
||||||
#define TFT_DRIVER 0xE9D
|
#define TFT_DRIVER 0xE9D
|
||||||
|
#elif defined (XYZZY_DRIVER) // <<<<<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVER HERE
|
||||||
|
#include "TFT_Drivers/XYZZY_Defines.h"
|
||||||
|
#define TFT_DRIVER 0x0000
|
||||||
|
#else
|
||||||
|
#define TFT_DRIVER 0x0000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// These are the pins for all ESP8266 boards
|
// These are the pins for all ESP8266 boards
|
||||||
|
94
User_Setups/Setup17_ePaper.h
Normal file
94
User_Setups/Setup17_ePaper.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// USER DEFINED SETTINGS
|
||||||
|
// Set driver type, fonts to be loaded etc
|
||||||
|
//
|
||||||
|
// See the User_Setup_Select.h file if you wish to be able to define multiple
|
||||||
|
// setups and then easily select which setup file is used by the compiler.
|
||||||
|
//
|
||||||
|
// If this file is edited correctly then all the library example sketches should
|
||||||
|
// run without the need to make any more changes for a particular hardware setup!
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 0. Call up the right driver file and any options for it
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
#define EPD_DRIVER // ePaper driver
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 1. Define the pins that are used to interface with the display here
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
// READ THIS READ THIS READ THIS READ THIS READ THIS READ THIS
|
||||||
|
// Install the ePaper library for your own display size and type
|
||||||
|
// from here:
|
||||||
|
// https://github.com/Bodmer/EPD_Libraries
|
||||||
|
|
||||||
|
// Note: Pin allocations for the ePaper signals are defined in
|
||||||
|
// the ePaper library's epdif.h file. There follows the default
|
||||||
|
// pins already included in epdif.h file for the ESP8266:
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
// For ESP8266 connect as follows: //
|
||||||
|
// Display 3.3V to NodeMCU 3V3 //
|
||||||
|
// Display GND to NodeMCU GND //
|
||||||
|
// //
|
||||||
|
// Display GPIO NodeMCU pin //
|
||||||
|
// BUSY 5 D1 //
|
||||||
|
// RESET 4 D2 //
|
||||||
|
// DC 0 D3 //
|
||||||
|
// CS 2 D4 //
|
||||||
|
// CLK 14 D5 //
|
||||||
|
// D6 (MISO not connected to display) //
|
||||||
|
// DIN 13 D7 //
|
||||||
|
// //
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 2. Not used
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 3. Define the fonts that are to be used here
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
// Comment out the #defines below with // to stop that font being loaded
|
||||||
|
// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
|
||||||
|
// normally necessary. If all fonts are loaded the extra FLASH space required is
|
||||||
|
// about 17Kbytes. To save FLASH space only enable the fonts you need!
|
||||||
|
|
||||||
|
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
|
||||||
|
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
|
||||||
|
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
|
||||||
|
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
|
||||||
|
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
|
||||||
|
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 below, slightly narrower, so 3 digits fit a 160 pixel TFT
|
||||||
|
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
|
||||||
|
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
|
||||||
|
|
||||||
|
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
|
||||||
|
// this will save ~20kbytes of FLASH
|
||||||
|
#define SMOOTH_FONT
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 4. Not used
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
// ##################################################################################
|
||||||
|
//
|
||||||
|
// Section 5. Not used
|
||||||
|
//
|
||||||
|
// ##################################################################################
|
||||||
|
|
105
examples/ePaper/Floyd_Steinberg/EPD_Support.h
Normal file
105
examples/ePaper/Floyd_Steinberg/EPD_Support.h
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/* Support definitions and functions for ePaper examples
|
||||||
|
* These tailor the library and screen settings
|
||||||
|
* Must be a header file to ensure #defines are established first
|
||||||
|
*
|
||||||
|
* Created by Bodmer 30/3/18 for TFT_eSPI library:
|
||||||
|
* https://github.com/Bodmer/TFT_eSPI
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
EPD_WIDTH and EPD_HEIGHT are automatically defined here based on the library selected
|
||||||
|
|
||||||
|
For 2 colour ePaper displays create one frame pointer in sketch:
|
||||||
|
uint8_t* framePtr;
|
||||||
|
|
||||||
|
For 3 colour ePaper displays create two frame pointers in sketch:
|
||||||
|
uint8_t* blackFramePtr;
|
||||||
|
uint8_t* redFramePtr;
|
||||||
|
|
||||||
|
Call this function to update whole display:
|
||||||
|
updateDisplay();
|
||||||
|
*/
|
||||||
|
// Install the ePaper library for your own display size and type
|
||||||
|
// from here:
|
||||||
|
// https://github.com/Bodmer/EPD_Libraries
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// Define which colour values are paper and ink
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#if defined (EPD2IN7B_H)
|
||||||
|
#define COLORED 1 // EPD2IN7B is opposite to all others!
|
||||||
|
#define UNCOLORED 0
|
||||||
|
#else
|
||||||
|
#define COLORED 0
|
||||||
|
#define UNCOLORED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// Define the width and height of the different displays
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#if defined (EPD1IN54_H) || defined (EPD1IN54B_H)
|
||||||
|
#define EPD_WIDTH 200 // Frame buffer is 5000 bytes
|
||||||
|
#define EPD_HEIGHT 200
|
||||||
|
|
||||||
|
#elif defined (EPD1IN54C_H)
|
||||||
|
#define EPD_WIDTH 152 // 2 frame buffers of 2888 bytes each
|
||||||
|
#define EPD_HEIGHT 152
|
||||||
|
|
||||||
|
#elif defined (EPD2IN7_H) || defined (EPD2IN7B_H)
|
||||||
|
#define EPD_WIDTH 176 // Frame buffer is 5808 bytes
|
||||||
|
#define EPD_HEIGHT 264
|
||||||
|
|
||||||
|
#elif defined (EPD2IN9_H) || defined (EPD2IN9B_H)
|
||||||
|
#define EPD_WIDTH 128 // Frame buffer is 4736 bytes
|
||||||
|
#define EPD_HEIGHT 296
|
||||||
|
|
||||||
|
#elif defined (EPD2IN13_H)
|
||||||
|
#define EPD_WIDTH 122 // Frame buffer is 4000 bytes
|
||||||
|
#define EPD_HEIGHT 250
|
||||||
|
|
||||||
|
#elif defined (EPD2IN13B_H)
|
||||||
|
#define EPD_WIDTH 104 // 2 frame buffers of 2756 bytes each
|
||||||
|
#define EPD_HEIGHT 212
|
||||||
|
|
||||||
|
#elif defined (EPD4IN2_H)
|
||||||
|
#define EPD_WIDTH 400 // Frame buffer is 15000 bytes
|
||||||
|
#define EPD_HEIGHT 300
|
||||||
|
|
||||||
|
// ESP8266 has just enough RAM for a 2 color 7.5" display full screen buffer
|
||||||
|
// ESP32 has just enough RAM for 2 or 3 color 7.5" display
|
||||||
|
// (Without using partial screen updates)
|
||||||
|
#elif defined (EPD7IN5_H) || defined (EPD7IN5B_H)
|
||||||
|
#define EPD_WIDTH 640 // 2 colour frame buffer is 30720 bytes
|
||||||
|
#define EPD_HEIGHT 384 // 2 colour frame buffer is 61440 bytes
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error "Selected ePaper library is not supported"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error "Selected ePaper library is not supported"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
187
examples/ePaper/Floyd_Steinberg/Floyd_Steinberg.ino
Normal file
187
examples/ePaper/Floyd_Steinberg/Floyd_Steinberg.ino
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
// Display grey-scale images on a Monchrome ePaper display using
|
||||||
|
// Floyd-Steinberg dithering
|
||||||
|
// https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering
|
||||||
|
|
||||||
|
// Example created by Bodmer 31/3/18 for TFT_eSPI library:
|
||||||
|
// https://github.com/Bodmer/TFT_eSPI
|
||||||
|
// Select the ePaper setup in library's "User_Setup_Select.h" file
|
||||||
|
|
||||||
|
// This sketch supports Waveshare 2 colour ePaper displays
|
||||||
|
// https://www.waveshare.com/product/modules/oleds-lcds/e-paper.htm
|
||||||
|
|
||||||
|
// Test images are in the Data folder with sketch (press Ctrl+k)
|
||||||
|
// Upload using the Tools menu "ESP8266 Sketch Data Upload" option
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
// For ESP8266 connect as follows: //
|
||||||
|
// Display 3.3V to NodeMCU 3V3 //
|
||||||
|
// Display GND to NodeMCU GND //
|
||||||
|
// //
|
||||||
|
// Display GPIO NodeMCU pin //
|
||||||
|
// BUSY 5 D1 //
|
||||||
|
// RESET 4 D2 //
|
||||||
|
// DC 0 D3 //
|
||||||
|
// CS 2 D4 //
|
||||||
|
// CLK 14 D5 //
|
||||||
|
// D6 (MISO not connected to display) //
|
||||||
|
// DIN 13 D7 //
|
||||||
|
// //
|
||||||
|
// Note: Pin allocations for the ePaper signals are defined in //
|
||||||
|
// ePaper library's epdif.h file, above are the default pins //
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// READ THIS READ THIS READ THIS READ THIS READ THIS READ THIS
|
||||||
|
// Install the ePaper library for your own display size and type
|
||||||
|
// from here:
|
||||||
|
// https://github.com/Bodmer/EPD_Libraries
|
||||||
|
|
||||||
|
// The following is for the Waveshare 2.7" colour ePaper display
|
||||||
|
// include <epd?in?.h> where ?.?? is screen size in inches
|
||||||
|
|
||||||
|
#include <epd2in7.h> // Screen specific library
|
||||||
|
Epd ePaper; // Create an instance ePaper
|
||||||
|
|
||||||
|
#include <TFT_eSPI.h> // Graphics library and Sprite class
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
#define INK COLORED // Black ink
|
||||||
|
#define PAPER UNCOLORED // 'paper' background colour
|
||||||
|
|
||||||
|
uint16_t epd_width = EPD_WIDTH; // Set the initial values, these are swapped
|
||||||
|
uint16_t epd_height = EPD_HEIGHT; // in different landscape/portrait rotations
|
||||||
|
// so call frame.width() or frame.height() to get new values
|
||||||
|
|
||||||
|
#define EPD_BUFFER 1 // Label for the black frame buffer 1
|
||||||
|
|
||||||
|
uint8_t* framePtr = NULL; // Pointer for the black frame buffer
|
||||||
|
|
||||||
|
#include "EPD_Support.h" // Include sketch EPD support functions last!
|
||||||
|
|
||||||
|
int8_t limit = 5; // Limit the number of loops before halting
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// Setup
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(250000); // Used for messages
|
||||||
|
|
||||||
|
// Initialise the ePaper library
|
||||||
|
if (ePaper.Init() != 0) {
|
||||||
|
Serial.print("ePaper init failed");
|
||||||
|
while (1) yield(); // Wait here until re-boot
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("\r\n ePaper initialisation OK");
|
||||||
|
|
||||||
|
// Initialise the SPIFFS filing system
|
||||||
|
if (!SPIFFS.begin()) {
|
||||||
|
Serial.println("SPIFFS initialisation failed!");
|
||||||
|
while (1) yield(); // Stay here twiddling thumbs
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(" SPIFFS initialisation OK");
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Serial.println("\r\nInitialisation done.");
|
||||||
|
|
||||||
|
listFiles(); // List all the files in the SPIFFS
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// Loop
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
frame.setRotation(random(4)); // Set the rotation to 0, 1, 2 or 3 ( 1 & 3 = landscape)
|
||||||
|
|
||||||
|
frame.fillSprite(PAPER);
|
||||||
|
|
||||||
|
// Draw 8 bit grey-scale bitmap using Floyd-Steinberg dithering at x,y
|
||||||
|
// /File name x y
|
||||||
|
//drawFSBmp("/TestCard.bmp", 0, 0); // 176 x 264 pixels
|
||||||
|
|
||||||
|
drawFSBmp("/Tiger.bmp", (frame.width()-176)/2, (frame.height()-234)/2); // 176 x 234 pixels
|
||||||
|
|
||||||
|
updateDisplay(); // Send image to display and refresh
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
|
||||||
|
frame.fillSprite(PAPER); // Fill frame with white
|
||||||
|
|
||||||
|
// Draw circle in frame buffer (x, y, r, color) in center of screen
|
||||||
|
frame.drawCircle(frame.width()/2, frame.height()/2, frame.width()/6, INK);
|
||||||
|
|
||||||
|
// Draw diagonal lines
|
||||||
|
frame.drawLine(0 , 0, frame.width()-1, frame.height()-1, INK);
|
||||||
|
frame.drawLine(0 , frame.height()-1, frame.width()-1, 0, INK);
|
||||||
|
|
||||||
|
updateDisplay(); // Send image to display and refresh
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
// Run a rotation test
|
||||||
|
rotateTest();
|
||||||
|
|
||||||
|
// Put screen to sleep to save power (if wanted)
|
||||||
|
ePaper.Sleep();
|
||||||
|
|
||||||
|
if (--limit <= 0) while(1) yield(); // Wait here
|
||||||
|
|
||||||
|
delay(20000); // Wait here for 20s
|
||||||
|
|
||||||
|
// Wake up ePaper display so we can talk to it
|
||||||
|
Serial.println("Waking up!");
|
||||||
|
ePaper.Init();
|
||||||
|
|
||||||
|
} // end of loop()
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// setRotation() actually rotates the drawing coordinates, not the whole display frame
|
||||||
|
// buffer so we can use this to draw text at right angles or upside down
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
void rotateTest(void)
|
||||||
|
{
|
||||||
|
//frame.fillSprite(PAPER); // Fill buffer with white to clear old graphics
|
||||||
|
|
||||||
|
// Draw some text in frame buffer
|
||||||
|
frame.setTextFont(4); // Select font 4
|
||||||
|
frame.setTextColor(INK); // Set colour to ink
|
||||||
|
frame.setTextDatum(TC_DATUM); // Middle centre text datum
|
||||||
|
|
||||||
|
frame.setRotation(0); // Set the display rotation to 0, 1, 2 or 3 ( 1 & 3 = landscape)
|
||||||
|
epd_width = frame.width(); // Get the values for the current rotation
|
||||||
|
epd_height = frame.height(); // epd_height is not used in this sketch
|
||||||
|
|
||||||
|
frame.drawString("Rotation 0", epd_width / 2, 10);
|
||||||
|
|
||||||
|
frame.setRotation(1); // Set the display rotation to 1
|
||||||
|
epd_width = frame.width(); // Get the values for the current rotation
|
||||||
|
epd_height = frame.height(); // epd_height is not used in this sketch
|
||||||
|
|
||||||
|
frame.drawString("Rotation 1", epd_width / 2, 10);
|
||||||
|
|
||||||
|
frame.setRotation(2); // Set the display rotation to 2
|
||||||
|
epd_width = frame.width(); // Get the values for the current rotation
|
||||||
|
epd_height = frame.height(); // epd_height is not used in this sketch
|
||||||
|
|
||||||
|
frame.drawString("Rotation 2", epd_width / 2, 10);
|
||||||
|
|
||||||
|
frame.setRotation(3); // Set the display rotation to 3
|
||||||
|
epd_width = frame.width(); // Get the values for the current rotation
|
||||||
|
epd_height = frame.height(); // epd_height is not used in this sketch
|
||||||
|
|
||||||
|
frame.drawString("Rotation 3", epd_width / 2, 10);
|
||||||
|
|
||||||
|
Serial.println("Updating display");
|
||||||
|
updateDisplay(); // Update display
|
||||||
|
}
|
198
examples/ePaper/Floyd_Steinberg/Floyd_Steinberg_BMP.ino
Normal file
198
examples/ePaper/Floyd_Steinberg/Floyd_Steinberg_BMP.ino
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
Support function for Floyd-Steinberg dithering of an 8bit grey-scale BMP image
|
||||||
|
on a Monochrome display:
|
||||||
|
https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering
|
||||||
|
|
||||||
|
Bitmap format:
|
||||||
|
https://en.wikipedia.org/wiki/BMP_file_format
|
||||||
|
|
||||||
|
Example for https://github.com/Bodmer/TFT_eSPI
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
Copyright (c) 2015 by Bodmer
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYBR_DATUM HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Note: drawFSBmp() is a simplified function and does not handle all possible
|
||||||
|
BMP file header variants. It works OK with 8 bit per pixel grey-scale images
|
||||||
|
generated by MS Paint and IrfanView.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://github.com/Bodmer/TFT_eSPI
|
||||||
|
|
||||||
|
//====================================================================================
|
||||||
|
// Draw an 8 bit grey-scale bitmap (*.BMP) on a Monochrome display using dithering
|
||||||
|
//====================================================================================
|
||||||
|
// Uses RAM for buffers (3 * width + 4) ( 532 bytes for 176 pixels)
|
||||||
|
|
||||||
|
// Image must be stored in ESP8266 or ESP32 SPIFFS
|
||||||
|
|
||||||
|
// Quantisation error distribution for pixel X
|
||||||
|
// (This is for bottum up drawing of the BMP)
|
||||||
|
// |-------|-------|-------|
|
||||||
|
// | +3/16 | +5/16 | +1/16 |
|
||||||
|
// |-------|-------|-------|
|
||||||
|
// | | X | +7/16 |
|
||||||
|
// |-------|-------|-------|
|
||||||
|
//
|
||||||
|
|
||||||
|
void drawFSBmp(const char *filename, int16_t x, int16_t y) {
|
||||||
|
|
||||||
|
if ((x >= frame.width()) || (y >= frame.height())) return;
|
||||||
|
|
||||||
|
fs::File bmpFS;
|
||||||
|
|
||||||
|
// Open requested file
|
||||||
|
bmpFS = SPIFFS.open( filename, "r");
|
||||||
|
|
||||||
|
if (!bmpFS)
|
||||||
|
{
|
||||||
|
Serial.print("File not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t seekOffset, dib_size;
|
||||||
|
uint16_t w, h, row, col, num_colors;
|
||||||
|
uint8_t r, g, b;
|
||||||
|
|
||||||
|
if (read16(bmpFS) == 0x4D42) // Check it is a valid bitmap header
|
||||||
|
{
|
||||||
|
read32(bmpFS);
|
||||||
|
read32(bmpFS);
|
||||||
|
seekOffset = read32(bmpFS); // Pointer to image start
|
||||||
|
dib_size = read32(bmpFS); // DIB header size, typically 40 bytes
|
||||||
|
|
||||||
|
w = read32(bmpFS); // Get width and height of image
|
||||||
|
h = read32(bmpFS);
|
||||||
|
|
||||||
|
// Check it is 1 plane and 8 bits per pixel and no compression
|
||||||
|
if ((read16(bmpFS) == 1) && (read16(bmpFS) == 8) && (read32(bmpFS) == 0))
|
||||||
|
{
|
||||||
|
read32(bmpFS); // Throw away image size
|
||||||
|
read32(bmpFS); // Throw away x pixels per meter
|
||||||
|
read32(bmpFS); // Throw away y pixels per meter
|
||||||
|
|
||||||
|
num_colors = read32(bmpFS); // Number of colours in colour table (usually 256)
|
||||||
|
|
||||||
|
uint8_t pixel_color[num_colors]; // Lookup table for grey-scale
|
||||||
|
|
||||||
|
bmpFS.seek(14 + dib_size); // Seek to start of colour table
|
||||||
|
|
||||||
|
// Capture the colour lookup table
|
||||||
|
for (uint16_t i = 0; i < num_colors; i++)
|
||||||
|
{
|
||||||
|
uint32_t abgr = read32(bmpFS); // Assume 4 byte, RGB colours in LS 3 bytes
|
||||||
|
pixel_color[i] = (uint8_t) abgr; // For grey-scale R, G, B are same value
|
||||||
|
}
|
||||||
|
|
||||||
|
bmpFS.seek(seekOffset); // Seek to start of image
|
||||||
|
|
||||||
|
uint16_t padding = (4 - (w & 3)) & 3; // Calculate the BMP line padding
|
||||||
|
|
||||||
|
// Create an zero an 8 bit pixel line buffer
|
||||||
|
uint8_t* lineBuffer = ( uint8_t*) calloc(w , sizeof(uint8_t));
|
||||||
|
|
||||||
|
// Create a 16 bit signed line buffer for the quantisation error
|
||||||
|
// Diffusion spreads to x-1 and x+1 so w + 2 avoids a bounds check
|
||||||
|
int16_t* qerrBuffer = ( int16_t*) calloc((w + 2)<<1, sizeof(uint8_t));
|
||||||
|
|
||||||
|
y += h - 1; // Start from bottom (assumes bottum up!)
|
||||||
|
|
||||||
|
// Draw row by row from bottom up
|
||||||
|
for (row = 0; row < h; row++) {
|
||||||
|
|
||||||
|
// Read a row of pixels
|
||||||
|
bmpFS.read(lineBuffer, w);
|
||||||
|
|
||||||
|
// Prep variables
|
||||||
|
uint16_t dx = 0;
|
||||||
|
uint8_t* bptr = lineBuffer;
|
||||||
|
int16_t* qptr = qerrBuffer + 1; // + 1 because diffusion spreads to x-1
|
||||||
|
|
||||||
|
// Lookup color, add quantisation error, clip and clear error buffer
|
||||||
|
while(dx < w)
|
||||||
|
{
|
||||||
|
int16_t depixel = pixel_color[(uint8_t)*bptr] + *qptr;
|
||||||
|
if (depixel >255) depixel = 255; // Clip pixel to 0-255
|
||||||
|
else if (depixel < 0) depixel = 0;
|
||||||
|
*bptr++ = (uint8_t) depixel; // Save new value, inc pointer
|
||||||
|
*qptr++ = 0; // Zero error, inc pointer
|
||||||
|
dx++; // Next pixel
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = 0; // Reset varaibles to start of line
|
||||||
|
bptr = lineBuffer;
|
||||||
|
qptr = qerrBuffer + 1;
|
||||||
|
int32_t qerr = 0;
|
||||||
|
int32_t qerr16 = 0;
|
||||||
|
|
||||||
|
// Push the pixel row to screen
|
||||||
|
while(dx < w)
|
||||||
|
{
|
||||||
|
// Add 7/16 of error (error = 0 on first entry)
|
||||||
|
int16_t pixel = *bptr + (qerr>>1) - qerr16;
|
||||||
|
|
||||||
|
// Do not clip here so quantisation error accumulates correctly?
|
||||||
|
// Draw pixel (black or white) and determine new error
|
||||||
|
if (pixel < 128) { frame.drawPixel(x + dx, y, INK); qerr = pixel; }
|
||||||
|
else qerr = pixel - 255;
|
||||||
|
|
||||||
|
// Diffuse into error buffer for next pixel line
|
||||||
|
qerr16 = qerr>>4; // 1/16 of error
|
||||||
|
*(qptr - 1) += (qerr>>2) - qerr16; // Add 3/16 of error
|
||||||
|
*(qptr ) += (qerr>>2) + qerr16; // Add 5/16 of error
|
||||||
|
*(qptr + 1) += qerr16; // Add 1/16 of error
|
||||||
|
|
||||||
|
*bptr++; // Move along pixel and error buffers
|
||||||
|
*qptr++;
|
||||||
|
dx++; // Move coordinate along
|
||||||
|
}
|
||||||
|
y--;
|
||||||
|
|
||||||
|
// Read any line padding (saves a slow seek)
|
||||||
|
if (padding) bmpFS.read(lineBuffer, padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else Serial.println("BMP format not recognized.");
|
||||||
|
}
|
||||||
|
bmpFS.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================================================================================
|
||||||
|
// Read a 16 bit value from the filing system
|
||||||
|
//====================================================================================
|
||||||
|
uint16_t read16(fs::File &f) {
|
||||||
|
uint16_t result;
|
||||||
|
((uint8_t *)&result)[0] = f.read(); // LSB
|
||||||
|
((uint8_t *)&result)[1] = f.read(); // MSB
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================================================================================
|
||||||
|
// Read a 32 bit value from the filing system
|
||||||
|
//====================================================================================
|
||||||
|
uint32_t read32(fs::File &f) {
|
||||||
|
uint32_t result;
|
||||||
|
((uint8_t *)&result)[0] = f.read(); // LSB
|
||||||
|
((uint8_t *)&result)[1] = f.read();
|
||||||
|
((uint8_t *)&result)[2] = f.read();
|
||||||
|
((uint8_t *)&result)[3] = f.read(); // MSB
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add support for colour images by converting RGB to grey-scale
|
||||||
|
// grey = (R+G+B)/3
|
||||||
|
|
92
examples/ePaper/Floyd_Steinberg/SPIFFS.ino
Normal file
92
examples/ePaper/Floyd_Steinberg/SPIFFS.ino
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
// Call up the SPIFFS FLASH filing system
|
||||||
|
#define FS_NO_GLOBALS
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
#include "SPIFFS.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*====================================================================================
|
||||||
|
This sketch supports the ESP6266 and ESP32 SPIFFS filing system
|
||||||
|
|
||||||
|
Created by Bodmer 15th Jan 2017
|
||||||
|
==================================================================================*/
|
||||||
|
|
||||||
|
//====================================================================================
|
||||||
|
// Print a SPIFFS directory list (root directory)
|
||||||
|
//====================================================================================
|
||||||
|
|
||||||
|
void listFiles(void) {
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("SPIFFS files found:");
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
listDir(SPIFFS, "/", true);
|
||||||
|
#else
|
||||||
|
fs::Dir dir = SPIFFS.openDir("/"); // Root directory
|
||||||
|
String line = "=====================================";
|
||||||
|
|
||||||
|
Serial.println(line);
|
||||||
|
Serial.println(" File name Size");
|
||||||
|
Serial.println(line);
|
||||||
|
|
||||||
|
while (dir.next()) {
|
||||||
|
String fileName = dir.fileName();
|
||||||
|
Serial.print(fileName);
|
||||||
|
int spaces = 25 - fileName.length(); // Tabulate nicely
|
||||||
|
if (spaces < 0) spaces = 1;
|
||||||
|
while (spaces--) Serial.print(" ");
|
||||||
|
fs::File f = dir.openFile("r");
|
||||||
|
Serial.print(f.size()); Serial.println(" bytes");
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(line);
|
||||||
|
#endif
|
||||||
|
Serial.println();
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
//====================================================================================
|
||||||
|
|
||||||
|
#ifdef ESP32
|
||||||
|
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
|
||||||
|
Serial.printf("Listing directory: %s\n", dirname);
|
||||||
|
|
||||||
|
fs::File root = fs.open(dirname);
|
||||||
|
if (!root) {
|
||||||
|
Serial.println("Failed to open directory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!root.isDirectory()) {
|
||||||
|
Serial.println("Not a directory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::File file = root.openNextFile();
|
||||||
|
while (file) {
|
||||||
|
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
Serial.print("DIR : ");
|
||||||
|
String fileName = file.name();
|
||||||
|
Serial.print(fileName);
|
||||||
|
if (levels) {
|
||||||
|
listDir(fs, file.name(), levels - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String fileName = file.name();
|
||||||
|
Serial.print(" " + fileName);
|
||||||
|
int spaces = 32 - fileName.length(); // Tabulate nicely
|
||||||
|
if (spaces < 1) spaces = 1;
|
||||||
|
while (spaces--) Serial.print(" ");
|
||||||
|
String fileSize = (String) file.size();
|
||||||
|
spaces = 8 - fileSize.length(); // Tabulate nicely
|
||||||
|
if (spaces < 1) spaces = 1;
|
||||||
|
while (spaces--) Serial.print(" ");
|
||||||
|
Serial.println(fileSize + " bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
file = root.openNextFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
BIN
examples/ePaper/Floyd_Steinberg/data/TestCard.bmp
Normal file
BIN
examples/ePaper/Floyd_Steinberg/data/TestCard.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
BIN
examples/ePaper/Floyd_Steinberg/data/Tiger.bmp
Normal file
BIN
examples/ePaper/Floyd_Steinberg/data/Tiger.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
Reference in New Issue
Block a user