mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-08-06 14:14:44 +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)
|
||||
{
|
||||
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
|
||||
#ifdef RPI_ILI9486_DRIVER
|
||||
#define SEND_16_BITS
|
||||
#define CMD_BITS 16-1
|
||||
#else
|
||||
#define CMD_BITS 8-1
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
// 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.
|
||||
|
||||
// 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/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/Setup10_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 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 ESP32 and RPi TFT with touch
|
||||
//#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/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/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>
|
||||
|
||||
// ePaper #include <User_Setups/SetupX_Template.h> // Setup file template for copying/editting
|
||||
//#include <User_Setups/SetupX_Template.h>
|
||||
|
||||
|
||||
#endif // USER_SETUP_LOADED
|
||||
@@ -70,7 +69,7 @@
|
||||
#define TFT_DRIVER 0x6D02
|
||||
#elif defined (RPI_ILI9486_DRIVER)
|
||||
#include <TFT_Drivers/RPI_ILI9486_Defines.h>
|
||||
#define TFT_DRIVER 0x9481
|
||||
#define TFT_DRIVER 0x9486
|
||||
#elif defined (ILI9481_DRIVER)
|
||||
#include <TFT_Drivers/ILI9481_Defines.h>
|
||||
#define TFT_DRIVER 0x9481
|
||||
@@ -83,6 +82,11 @@
|
||||
#elif defined (EPD_DRIVER)
|
||||
#include "TFT_Drivers/EPD_Defines.h"
|
||||
#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
|
||||
|
||||
// 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