EPD Working
This commit is contained in:
parent
e1eae34dba
commit
0c2549d1df
|
@ -0,0 +1,108 @@
|
|||
#ifndef LIB_ADAFRUIT_SSD1675BX
|
||||
#define LIB_ADAFRUIT_SSD1675BX
|
||||
|
||||
#include <Adafruit_EPD.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
#define EPD_RAM_BW 0x10
|
||||
#define EPD_RAM_RED 0x13
|
||||
|
||||
#define SSD1675BX_DRIVER_CONTROL 0x01
|
||||
#define SSD1675BX_GATE_VOLTAGE 0x03
|
||||
#define SSD1675BX_SOURCE_VOLTAGE 0x04
|
||||
#define SSD1675BX_DEEP_SLEEP 0x10
|
||||
#define SSD1675BX_DATA_MODE 0x11
|
||||
#define SSD1675BX_SW_RESET 0x12
|
||||
#define SSD1675BX_HV_READY 0x14
|
||||
#define SSD1675BX_VCI_READY 0x15
|
||||
#define SSD1675BX_TEMP_SELECT 0x18
|
||||
#define SSD1675BX_TEMP_WRITE 0x1A
|
||||
#define SSD1675BX_MASTER_ACTIVATE 0x20
|
||||
#define SSD1675BX_DISP_CTRL1 0x21
|
||||
#define SSD1675BX_DISP_CTRL2 0x22
|
||||
#define SSD1675BX_WRITE_RAM1 0x24
|
||||
#define SSD1675BX_WRITE_RAM2 0x26
|
||||
#define SSD1675BX_WRITE_VCOM 0x2C
|
||||
#define SSD1675BX_READ_OTP 0x2D
|
||||
#define SSD1675BX_READ_STATUS 0x2F
|
||||
#define SSD1675BX_WRITE_LUT 0x32
|
||||
#define SSD1675BX_WRITE_DUMMY 0x3A
|
||||
#define SSD1675BX_WRITE_GATELINE 0x3B
|
||||
#define SSD1675BX_WRITE_BORDER 0x3C
|
||||
#define SSD1675BX_SET_RAMXPOS 0x44
|
||||
#define SSD1675BX_SET_RAMYPOS 0x45
|
||||
#define SSD1675BX_SET_RAMXCOUNT 0x4E
|
||||
#define SSD1675BX_SET_RAMYCOUNT 0x4F
|
||||
#define SSD1675BX_SET_ANALOGBLOCK 0x74
|
||||
#define SSD1675BX_SET_DIGITALBLOCK 0x7E
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Class for interfacing with SSD1675 (2020 BSides Badge EINK) EPD drivers
|
||||
*/
|
||||
/**************************************************************************/
|
||||
class Adafruit_SSD1675BX : public Adafruit_EPD {
|
||||
public:
|
||||
Adafruit_SSD1675BX(int width, int height, int8_t SID, int8_t SCLK, int8_t DC,
|
||||
int8_t RST, int8_t CS, int8_t SRCS, int8_t MISO,
|
||||
int8_t BUSY = -1);
|
||||
Adafruit_SSD1675BX(int width, int height, int8_t DC, int8_t RST, int8_t CS,
|
||||
int8_t SRCS, int8_t BUSY = -1, SPIClass *spi = &SPI);
|
||||
|
||||
void begin(bool reset = true);
|
||||
void powerUp();
|
||||
void update();
|
||||
void powerDown();
|
||||
|
||||
// faster drawing
|
||||
void fillScreen(uint16_t color);
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
void display();
|
||||
|
||||
// added so we can write white pixels
|
||||
void invertBuffers();
|
||||
void swapBuffers();
|
||||
|
||||
const static uint8_t kModeBlackWhiteRed = 0;
|
||||
const static uint8_t kModeFullBlackWhite = 1;
|
||||
const static uint8_t kModeNormalBlackWhite = 2;
|
||||
const static uint8_t kModeFasterBlackWhite = 3;
|
||||
const static uint8_t kModeFastestBlackWhite = 4;
|
||||
void setMode(uint8_t mode);
|
||||
uint8_t getMode() const { return mode_; };
|
||||
inline bool fastMode() { return ( mode_ == kModeFasterBlackWhite) || ( mode_ == kModeFastestBlackWhite); }
|
||||
|
||||
void thread();
|
||||
|
||||
protected:
|
||||
uint8_t writeRAMCommand(uint8_t index);
|
||||
void setRAMAddress(uint16_t x, uint16_t y);
|
||||
void busy_wait();
|
||||
|
||||
private:
|
||||
uint16_t einkColor(uint16_t color);
|
||||
|
||||
uint8_t mode_;
|
||||
uint16_t bw_red_color_;
|
||||
|
||||
// threading for speed (wait in background for hardware update to complete).
|
||||
void threadInit();
|
||||
void lock();
|
||||
void unlock();
|
||||
void renderBegin();
|
||||
void renderEnd();
|
||||
void uploadBegin();
|
||||
void uploadEnd();
|
||||
void displayBegin();
|
||||
void displayEnd();
|
||||
void displayQueuePush();
|
||||
bool displayQueuePop();
|
||||
bool displayQueueFull();
|
||||
QueueDefinition *lock_;
|
||||
bool render_in_progress_;
|
||||
bool upload_in_progress_;
|
||||
bool display_in_progress_;
|
||||
uint8_t refreshes_needed_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
|
@ -0,0 +1,17 @@
|
|||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:pico32]
|
||||
platform = espressif32
|
||||
board = pico32
|
||||
framework = arduino
|
||||
upload_port = /dev/ttyUSB0
|
||||
lib_deps =
|
||||
adafruit/Adafruit EPD@^4.5.3
|
|
@ -0,0 +1,870 @@
|
|||
#include "Adafruit_SSD1675BX.h"
|
||||
|
||||
// We use a thread for display updates when built for ESP32
|
||||
#ifdef ESP32
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/semphr.h>
|
||||
#endif
|
||||
|
||||
/** specification of display update instruction */
|
||||
struct badge_eink_lut_entry {
|
||||
/** the number of cycles the voltages are held; 0 = end of list */
|
||||
uint8_t length;
|
||||
|
||||
/** bitmapped value containing voltages for every (old-bit, new-bit) pair:
|
||||
* - bits 0,1: from 0 to 0
|
||||
* - bits 2,3: from 0 to 1
|
||||
* - bits 4,5: from 1 to 0
|
||||
* - bits 6,7: from 1 to 1
|
||||
*
|
||||
* allowed values:
|
||||
* - 0: VSS
|
||||
* - 1: VSH
|
||||
* - 2: VSL
|
||||
*/
|
||||
uint8_t voltages;
|
||||
};
|
||||
|
||||
/** filters to use on a badge_eink_lut_entry structure */
|
||||
enum badge_eink_lut_flags {
|
||||
LUT_FLAG_NONE = 0,
|
||||
LUT_FLAG_FIRST = 1, // do not depend on previous image
|
||||
LUT_FLAG_PARTIAL = 2, // do not touch already correct pixels
|
||||
LUT_FLAG_WHITE = 4, // white only
|
||||
LUT_FLAG_BLACK = 8, // black only
|
||||
LUT_FLAG_RED = 16, // red only
|
||||
};
|
||||
|
||||
// full, includes inverting
|
||||
const struct badge_eink_lut_entry badge_eink_lut_full[] = {
|
||||
{ .length = 23, .voltages = 0x02, },
|
||||
{ .length = 4, .voltages = 0x01, },
|
||||
{ .length = 11, .voltages = 0x11, },
|
||||
{ .length = 4, .voltages = 0x12, },
|
||||
{ .length = 6, .voltages = 0x22, },
|
||||
{ .length = 5, .voltages = 0x66, },
|
||||
{ .length = 4, .voltages = 0x69, },
|
||||
{ .length = 5, .voltages = 0x59, },
|
||||
{ .length = 1, .voltages = 0x58, },
|
||||
{ .length = 14, .voltages = 0x99, },
|
||||
{ .length = 1, .voltages = 0x88, },
|
||||
{ .length = 0 }
|
||||
};
|
||||
|
||||
// full, no inversion
|
||||
const struct badge_eink_lut_entry badge_eink_lut_normal[] = {
|
||||
{ .length = 3, .voltages = 0x10, },
|
||||
{ .length = 5, .voltages = 0x18, },
|
||||
{ .length = 1, .voltages = 0x08, },
|
||||
{ .length = 8, .voltages = 0x18, },
|
||||
{ .length = 2, .voltages = 0x08, },
|
||||
{ .length = 0 }
|
||||
};
|
||||
|
||||
// full, no inversion, needs 2 updates for full update
|
||||
const struct badge_eink_lut_entry badge_eink_lut_faster[] = {
|
||||
{ .length = 1, .voltages = 0x10, },
|
||||
{ .length = 8, .voltages = 0x18, },
|
||||
{ .length = 1, .voltages = 0x08, },
|
||||
{ .length = 0 }
|
||||
};
|
||||
|
||||
// full, no inversion, needs 4 updates for full update
|
||||
const struct badge_eink_lut_entry badge_eink_lut_fastest[] = {
|
||||
{ .length = 1, .voltages = 0x10, },
|
||||
{ .length = 3, .voltages = 0x18, },
|
||||
{ .length = 1, .voltages = 0x08, },
|
||||
{ .length = 0 }
|
||||
};
|
||||
|
||||
static uint8_t
|
||||
badge_eink_lut_conv(uint8_t voltages, enum badge_eink_lut_flags flags)
|
||||
{
|
||||
if (flags & LUT_FLAG_FIRST)
|
||||
{
|
||||
voltages |= voltages >> 4;
|
||||
voltages &= 15;
|
||||
if ((voltages & 3) == 3) // reserved
|
||||
voltages ^= 2; // set to '1': VSH (black)
|
||||
if ((voltages & 12) == 12) // reserved
|
||||
voltages ^= 4; // set to '2': VSL (white)
|
||||
voltages |= voltages << 4;
|
||||
}
|
||||
|
||||
if (flags & LUT_FLAG_PARTIAL)
|
||||
voltages &= 0x3c; // only keep 0->1 and 1->0
|
||||
|
||||
if (flags & LUT_FLAG_WHITE)
|
||||
voltages &= 0xcc; // only keep 0->1 and 1->1
|
||||
|
||||
if (flags & LUT_FLAG_BLACK)
|
||||
voltages &= 0x33; // only keep 0->0 and 1->0
|
||||
|
||||
return voltages;
|
||||
}
|
||||
|
||||
// DEPG0290B01
|
||||
int
|
||||
badge_eink_lut_generate_depg0290rws(const struct badge_eink_lut_entry *list, enum badge_eink_lut_flags flags, uint8_t *lut)
|
||||
{
|
||||
//ESP_LOGD(TAG, "flags = %d.", flags);
|
||||
|
||||
memset(lut, 0, 70);
|
||||
|
||||
int pos = 0;
|
||||
int spos = 0;
|
||||
while (list->length != 0)
|
||||
{
|
||||
int len = list->length;
|
||||
if (pos == 7)
|
||||
{
|
||||
//ESP_LOGE(TAG, "lut overflow.");
|
||||
return -1; // full
|
||||
}
|
||||
uint8_t voltages = badge_eink_lut_conv(list->voltages, flags);
|
||||
|
||||
lut[0*10 + pos] |= ((voltages >> 0) & 3) << ((3-spos)*2);
|
||||
lut[1*10 + pos] |= ((voltages >> 2) & 3) << ((3-spos)*2);
|
||||
lut[2*10 + pos] |= ((voltages >> 4) & 3) << ((3-spos)*2);
|
||||
lut[3*10 + pos] |= ((voltages >> 6) & 3) << ((3-spos)*2);
|
||||
lut[5*10 + pos*5 + spos] = len;
|
||||
lut[5*10 + pos*5 + spos] = len;
|
||||
|
||||
spos++;
|
||||
if (spos == 2)
|
||||
{
|
||||
spos = 0;
|
||||
pos++;
|
||||
}
|
||||
|
||||
list = &list[1];
|
||||
}
|
||||
|
||||
return 70;
|
||||
}
|
||||
|
||||
#define BUSY_WAIT 500
|
||||
#define BUSY_WAIT_FAST_MODE 120
|
||||
|
||||
#define FAST_MODE_REFRESHES_NEEDED 8
|
||||
|
||||
const unsigned char LUT_DATA[] = {
|
||||
0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03,
|
||||
0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x17, 0x41, 0x00, 0x32, 0x50, 0x2C, 0x0B,
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief constructor if using external SRAM chip and software SPI
|
||||
@param width the width of the display in pixels
|
||||
@param height the height of the display in pixels
|
||||
@param SID the SID pin to use
|
||||
@param SCLK the SCLK pin to use
|
||||
@param DC the data/command pin to use
|
||||
@param RST the reset pin to use
|
||||
@param CS the chip select pin to use
|
||||
@param SRCS the SRAM chip select pin to use
|
||||
@param MISO the MISO pin to use
|
||||
@param BUSY the busy pin to use
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_SSD1675BX::Adafruit_SSD1675BX(int width, int height, int8_t SID,
|
||||
int8_t SCLK, int8_t DC, int8_t RST,
|
||||
int8_t CS, int8_t SRCS, int8_t MISO,
|
||||
int8_t BUSY)
|
||||
: Adafruit_EPD(width, height, SID, SCLK, DC, RST, CS, SRCS, MISO, BUSY) {
|
||||
|
||||
mode_ = kModeBlackWhiteRed;
|
||||
bw_red_color_ = EPD_BLACK;
|
||||
|
||||
if ((height % 8) != 0) {
|
||||
height += 8 - (height % 8);
|
||||
}
|
||||
|
||||
buffer1_size = width * height / 8;
|
||||
buffer2_size = buffer1_size;
|
||||
|
||||
if (SRCS >= 0) {
|
||||
use_sram = true;
|
||||
buffer1_addr = 0;
|
||||
buffer2_addr = buffer1_size;
|
||||
buffer1 = buffer2 = NULL;
|
||||
} else {
|
||||
buffer1 = (uint8_t *)malloc(buffer1_size);
|
||||
buffer2 = (uint8_t *)malloc(buffer2_size);
|
||||
}
|
||||
|
||||
threadInit();
|
||||
}
|
||||
|
||||
// constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief constructor if using on-chip RAM and hardware SPI
|
||||
@param width the width of the display in pixels
|
||||
@param height the height of the display in pixels
|
||||
@param DC the data/command pin to use
|
||||
@param RST the reset pin to use
|
||||
@param CS the chip select pin to use
|
||||
@param SRCS the SRAM chip select pin to use
|
||||
@param BUSY the busy pin to use
|
||||
*/
|
||||
/**************************************************************************/
|
||||
Adafruit_SSD1675BX::Adafruit_SSD1675BX(int width, int height, int8_t DC,
|
||||
int8_t RST, int8_t CS, int8_t SRCS,
|
||||
int8_t BUSY, SPIClass *spi)
|
||||
: Adafruit_EPD(width, height, DC, RST, CS, SRCS, BUSY, spi) {
|
||||
|
||||
mode_ = kModeBlackWhiteRed;
|
||||
bw_red_color_ = EPD_BLACK;
|
||||
|
||||
if ((height % 8) != 0) {
|
||||
height += 8 - (height % 8);
|
||||
}
|
||||
|
||||
buffer1_size = width * height / 8;
|
||||
buffer2_size = buffer1_size;
|
||||
|
||||
if (SRCS >= 0) {
|
||||
use_sram = true;
|
||||
buffer1_addr = 0;
|
||||
buffer2_addr = buffer1_size;
|
||||
buffer1 = buffer2 = NULL;
|
||||
} else {
|
||||
buffer1 = (uint8_t *)malloc(buffer1_size);
|
||||
buffer2 = (uint8_t *)malloc(buffer2_size);
|
||||
}
|
||||
|
||||
threadInit();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief set display mode (sharp & colors VS fast black & white)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_SSD1675BX::setMode(uint8_t mode)
|
||||
{
|
||||
lock();
|
||||
refreshes_needed_ = 0;
|
||||
while ( upload_in_progress_ || display_in_progress_ )
|
||||
{
|
||||
unlock();
|
||||
delay(1);
|
||||
lock();
|
||||
}
|
||||
mode_ = mode;
|
||||
if ( fastMode() )
|
||||
{
|
||||
buffer2_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer2_size = buffer1_size;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief wait for busy signal to end
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_SSD1675BX::busy_wait(void) {
|
||||
if (_busy_pin >= 0) {
|
||||
// start of busy wait
|
||||
uint32_t start = (uint32_t)millis();
|
||||
// use 1ms delays for the first 20ms delays
|
||||
for ( uint8_t i = 0; i < 20; i++ )
|
||||
{
|
||||
if ( !digitalRead(_busy_pin) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
// wait for busy low
|
||||
while (digitalRead(_busy_pin)) {
|
||||
delay(10);
|
||||
if ( fastMode() && displayQueueFull() )
|
||||
{
|
||||
uint32_t tick = (uint32_t)millis();
|
||||
if ( (tick - start) > BUSY_WAIT_FAST_MODE )
|
||||
{
|
||||
// fast mode - stop this wait and start with "newer" data
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
delay(BUSY_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief begin communication with and set up the display.
|
||||
@param reset if true the reset pin will be toggled.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_SSD1675BX::begin(bool reset) {
|
||||
Adafruit_EPD::begin(reset);
|
||||
setBlackBuffer(0, true); // black defaults to inverted
|
||||
setColorBuffer(1, false);
|
||||
|
||||
powerDown();
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::invertBuffers() {
|
||||
setBlackBuffer(0, !blackInverted);
|
||||
setColorBuffer(1, !colorInverted);
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::swapBuffers() {
|
||||
uint8_t *tmp = buffer1;
|
||||
buffer1 = buffer2;
|
||||
buffer2 = tmp;
|
||||
uint16_t tmp_addr = buffer1_addr;
|
||||
buffer1_addr = buffer2_addr;
|
||||
buffer2_addr = tmp_addr;
|
||||
setBlackBuffer(0, blackInverted);
|
||||
setColorBuffer(1, colorInverted);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief faster drawing methods
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint16_t Adafruit_SSD1675BX::einkColor(uint16_t color)
|
||||
{
|
||||
if ( ( color & (0x8000 | 0x0400 | 0x0010) ) == 0 )
|
||||
{
|
||||
// high bits of RGB are all 0s, treat it as black
|
||||
color = EPD_BLACK;
|
||||
}
|
||||
else if ( ( color & (0x8000 | 0x0400 | 0x0010) ) == (0x8000 | 0x0400 | 0x0010) )
|
||||
{
|
||||
// high bits of RGB are all 1s, treat it as white
|
||||
color = EPD_WHITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// everything else is red
|
||||
color = EPD_RED;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::fillScreen(uint16_t color)
|
||||
{
|
||||
renderBegin();
|
||||
|
||||
color = einkColor(color);
|
||||
if ( mode_ != kModeBlackWhiteRed ) {
|
||||
if ( color == EPD_BLACK ) {
|
||||
bw_red_color_ = EPD_WHITE;
|
||||
} else if ( color == EPD_WHITE ) {
|
||||
bw_red_color_ = EPD_BLACK;
|
||||
} else {
|
||||
bw_red_color_ = EPD_BLACK;
|
||||
color = EPD_WHITE;
|
||||
}
|
||||
}
|
||||
uint8_t black_byte = ( (color == EPD_BLACK) ? 0x00 : 0xff );
|
||||
if ( !fastMode() ) {
|
||||
// slow mode - memset both BLACK and RED buffers.
|
||||
uint8_t color_byte = ( (color == EPD_RED) ? 0xff : 0x00 );
|
||||
if (use_sram) {
|
||||
if (buffer1_size != 0) {
|
||||
sram.erase(buffer1_addr, buffer1_size, black_byte);
|
||||
}
|
||||
if (buffer2_size != 0) {
|
||||
sram.erase(buffer2_addr, buffer2_size, color_byte);
|
||||
}
|
||||
} else {
|
||||
if (buffer1 && (buffer1_size != 0)) {
|
||||
memset(buffer1, black_byte, buffer1_size);
|
||||
}
|
||||
if (buffer2 && (buffer2_size != 0)) {
|
||||
memset(buffer2, color_byte, buffer2_size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// fast mode - render into buffer 2, display buffer 1, then swap etc.
|
||||
if (use_sram) {
|
||||
sram.erase(buffer2_addr, buffer1_size, black_byte);
|
||||
} else {
|
||||
memset(buffer2, black_byte, buffer1_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
if ( !fastMode() )
|
||||
{
|
||||
// fix color
|
||||
color = einkColor(color);
|
||||
// what to do with
|
||||
if ( mode_ != kModeBlackWhiteRed ) {
|
||||
color = ( color == EPD_RED ) ? bw_red_color_ : color;
|
||||
}
|
||||
// hack
|
||||
y = height() - 1 - y;
|
||||
// slow mode - use Adafruit_EPD to draw the pixel.
|
||||
if ( color == EPD_WHITE ) {
|
||||
invertBuffers();
|
||||
Adafruit_EPD::drawPixel(x, y, EPD_BLACK);
|
||||
Adafruit_EPD::drawPixel(x, y, EPD_RED);
|
||||
invertBuffers();
|
||||
return;
|
||||
}
|
||||
Adafruit_EPD::drawPixel(x, y, color);
|
||||
} else {
|
||||
// fast mode - almost a 1-to-1 copy of drawPixel from Adafruit_EPD - with some optimisations
|
||||
|
||||
// check bounds.
|
||||
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
|
||||
return;
|
||||
|
||||
if ( ( color & (0x8000 | 0x0400 | 0x0010) ) == 0 )
|
||||
{
|
||||
// high bits of RGB are all 0s, treat it as black
|
||||
color = EPD_BLACK;
|
||||
}
|
||||
else if ( ( color & (0x8000 | 0x0400 | 0x0010) ) == (0x8000 | 0x0400 | 0x0010) )
|
||||
{
|
||||
// high bits of RGB are all 1s, treat it as white
|
||||
color = EPD_WHITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// everything else is red
|
||||
color = bw_red_color_;
|
||||
}
|
||||
|
||||
uint8_t *pBuf;
|
||||
|
||||
// check rotation, move pixel around if necessary
|
||||
switch (getRotation()) {
|
||||
case 0:
|
||||
y = height() - 1 - y;
|
||||
break;
|
||||
case 1:
|
||||
EPD_swap(x, y);
|
||||
break;
|
||||
case 2:
|
||||
y = height() - 1 - y;
|
||||
x = WIDTH - x - 1;
|
||||
y = HEIGHT - y - 1;
|
||||
break;
|
||||
case 3:
|
||||
EPD_swap(x, y);
|
||||
x = WIDTH - x - 1;
|
||||
y = HEIGHT - y - 1;
|
||||
break;
|
||||
}
|
||||
uint16_t addr = ((uint32_t)(WIDTH - 1 - x) * (uint32_t)HEIGHT + y) >> 3;
|
||||
uint8_t c;
|
||||
|
||||
if (use_sram) {
|
||||
addr = buffer2_addr + addr;
|
||||
c = sram.read8(addr);
|
||||
pBuf = &c;
|
||||
if (color == EPD_BLACK) {
|
||||
*pBuf &= ~(1 << (7 - y & 0x7));
|
||||
} else {
|
||||
*pBuf |= (1 << (7 - y & 0x7));
|
||||
}
|
||||
sram.write8(addr, *pBuf);
|
||||
} else {
|
||||
pBuf = buffer2 + addr;
|
||||
if (color == EPD_BLACK) {
|
||||
*pBuf &= ~(1 << (7 - y & 0x7));
|
||||
} else {
|
||||
*pBuf |= (1 << (7 - y & 0x7));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief signal the display to update
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_SSD1675BX::update() {
|
||||
uint8_t mode_old = mode_;
|
||||
uploadEnd();
|
||||
if ( mode_old != mode_ )
|
||||
{
|
||||
// mode has changed, stop display.
|
||||
return;
|
||||
}
|
||||
displayBegin();
|
||||
|
||||
uint8_t buf[1];
|
||||
|
||||
uint8_t lut[70];
|
||||
memset(lut, 0, sizeof(lut));
|
||||
if ( mode_ != kModeBlackWhiteRed )
|
||||
{
|
||||
switch ( mode_ )
|
||||
{
|
||||
case kModeFullBlackWhite:
|
||||
badge_eink_lut_generate_depg0290rws(badge_eink_lut_full, LUT_FLAG_FIRST, lut);
|
||||
EPD_command(SSD1675BX_WRITE_LUT, lut, sizeof(lut));
|
||||
break;
|
||||
|
||||
case kModeNormalBlackWhite:
|
||||
badge_eink_lut_generate_depg0290rws(badge_eink_lut_normal, LUT_FLAG_FIRST, lut);
|
||||
EPD_command(SSD1675BX_WRITE_LUT, lut, sizeof(lut));
|
||||
break;
|
||||
|
||||
case kModeFasterBlackWhite:
|
||||
badge_eink_lut_generate_depg0290rws(badge_eink_lut_faster, LUT_FLAG_FIRST, lut);
|
||||
EPD_command(SSD1675BX_WRITE_LUT, lut, sizeof(lut));
|
||||
break;
|
||||
|
||||
case kModeFastestBlackWhite:
|
||||
badge_eink_lut_generate_depg0290rws(badge_eink_lut_fastest, LUT_FLAG_FIRST, lut);
|
||||
EPD_command(SSD1675BX_WRITE_LUT, lut, sizeof(lut));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// display update sequence
|
||||
buf[0] = 0xC7;
|
||||
EPD_command(SSD1675BX_DISP_CTRL2, buf, 1);
|
||||
|
||||
EPD_command(SSD1675BX_MASTER_ACTIVATE);
|
||||
|
||||
busy_wait();
|
||||
if (_busy_pin <= -1) {
|
||||
delay(3000);
|
||||
}
|
||||
|
||||
displayEnd();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief start up the display
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_SSD1675BX::powerUp() {
|
||||
uint8_t buf[5];
|
||||
|
||||
hardwareReset();
|
||||
delay(1);
|
||||
busy_wait();
|
||||
|
||||
// soft reset
|
||||
EPD_command(SSD1675BX_SW_RESET);
|
||||
busy_wait();
|
||||
|
||||
// set analog block control
|
||||
buf[0] = 0x54;
|
||||
EPD_command(SSD1675BX_SET_ANALOGBLOCK, buf, 1);
|
||||
|
||||
// set digital block control
|
||||
buf[0] = 0x3B;
|
||||
EPD_command(SSD1675BX_SET_DIGITALBLOCK, buf, 1);
|
||||
|
||||
// driver output control
|
||||
buf[0] = WIDTH - 1;
|
||||
buf[1] = (WIDTH - 1) >> 8;
|
||||
buf[2] = 0x00;
|
||||
EPD_command(SSD1675BX_DRIVER_CONTROL, buf, 3);
|
||||
|
||||
// Data entry sequence
|
||||
buf[0] = 0x01;
|
||||
EPD_command(SSD1675BX_DATA_MODE, buf, 1);
|
||||
|
||||
// Set ram X start/end postion
|
||||
buf[0] = 0x00;
|
||||
buf[1] = (HEIGHT / 8) - 1;
|
||||
EPD_command(SSD1675BX_SET_RAMXPOS, buf, 2);
|
||||
|
||||
// Set ram Y start/end postion
|
||||
buf[0] = WIDTH - 1;
|
||||
buf[1] = (WIDTH - 1) >> 8;
|
||||
buf[2] = 0x00;
|
||||
buf[3] = 0x00;
|
||||
EPD_command(SSD1675BX_SET_RAMYPOS, buf, 4);
|
||||
|
||||
// border color
|
||||
buf[0] = 0x01;
|
||||
EPD_command(SSD1675BX_WRITE_BORDER, buf, 1);
|
||||
|
||||
// Vcom Voltage
|
||||
buf[0] = 0x36;
|
||||
EPD_command(SSD1675BX_WRITE_VCOM, buf, 1);
|
||||
|
||||
// Set gate voltage
|
||||
buf[0] = LUT_DATA[100];
|
||||
EPD_command(SSD1675BX_GATE_VOLTAGE, buf, 1);
|
||||
|
||||
// Set source voltage
|
||||
buf[0] = LUT_DATA[101];
|
||||
buf[1] = LUT_DATA[102];
|
||||
buf[2] = LUT_DATA[103];
|
||||
EPD_command(SSD1675BX_SOURCE_VOLTAGE, buf, 3);
|
||||
|
||||
// Set dummy line period
|
||||
buf[0] = LUT_DATA[105];
|
||||
EPD_command(SSD1675BX_WRITE_DUMMY, buf, 1);
|
||||
|
||||
// Set gate line width
|
||||
buf[0] = LUT_DATA[106];
|
||||
EPD_command(SSD1675BX_WRITE_GATELINE, buf, 1);
|
||||
|
||||
EPD_command(SSD1675BX_WRITE_LUT, LUT_DATA, 99);
|
||||
|
||||
// Set internal temperature sensor
|
||||
buf[0] = 0x80;
|
||||
EPD_command(SSD1675BX_TEMP_SELECT, buf, 1);
|
||||
|
||||
if ( !fastMode() ) {
|
||||
// slow mode - needed steps (but can be skipped - with artifacts - in fast mode).
|
||||
|
||||
buf[0] = 0xB1;
|
||||
EPD_command(SSD1675BX_DISP_CTRL2, buf, 1);
|
||||
|
||||
EPD_command(SSD1675BX_MASTER_ACTIVATE);
|
||||
}
|
||||
|
||||
busy_wait();
|
||||
|
||||
uploadBegin();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief wind down the display
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_SSD1675BX::powerDown() {
|
||||
uint8_t buf[1];
|
||||
|
||||
// Only deep sleep if we can get out of it
|
||||
if (_reset_pin >= 0) {
|
||||
// deep sleep
|
||||
buf[0] = 0x01;
|
||||
EPD_command(SSD1675BX_DEEP_SLEEP, buf, 1);
|
||||
delay(1);
|
||||
} else {
|
||||
EPD_command(SSD1675BX_SW_RESET);
|
||||
busy_wait();
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Send the specific command to start writing to EPD display RAM
|
||||
@param index The index for which buffer to write (0 or 1 or tri-color
|
||||
displays) Ignored for monochrome displays.
|
||||
@returns The byte that is read from SPI at the same time as sending the
|
||||
command
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t Adafruit_SSD1675BX::writeRAMCommand(uint8_t index) {
|
||||
if (index == 0) {
|
||||
return EPD_command(SSD1675_WRITE_RAM1, false);
|
||||
}
|
||||
if (index == 1) {
|
||||
return EPD_command(SSD1675_WRITE_RAM2, false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Some displays require setting the RAM address pointer
|
||||
@param x X address counter value
|
||||
@param y Y address counter value
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_SSD1675BX::setRAMAddress(uint16_t x, uint16_t y) {
|
||||
uint8_t buf[2];
|
||||
|
||||
// Set RAM X address counter
|
||||
buf[0] = 0x00;
|
||||
EPD_command(SSD1675_SET_RAMXCOUNT, buf, 1);
|
||||
|
||||
// Set RAM Y address counter
|
||||
buf[0] = WIDTH - 1;
|
||||
buf[1] = (WIDTH - 1) >> 8;
|
||||
EPD_command(SSD1675_SET_RAMYCOUNT, buf, 2);
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
void display_thread(void *arg) {
|
||||
reinterpret_cast<Adafruit_SSD1675BX*>(arg)->thread();
|
||||
};
|
||||
#endif
|
||||
|
||||
void Adafruit_SSD1675BX::threadInit() {
|
||||
#ifdef ESP32
|
||||
lock_ = xSemaphoreCreateMutex();
|
||||
xTaskCreate(&display_thread, "display_thread", 8192, (void*)this, 5, NULL);
|
||||
#endif
|
||||
render_in_progress_ = false;
|
||||
upload_in_progress_ = false;
|
||||
display_in_progress_ = false;
|
||||
refreshes_needed_ = 0;
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::lock() {
|
||||
#ifdef ESP32
|
||||
xSemaphoreTake(lock_, portMAX_DELAY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::unlock() {
|
||||
#ifdef ESP32
|
||||
xSemaphoreGive(lock_);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::thread() {
|
||||
while(1) {
|
||||
delay(10);
|
||||
if ( fastMode() && displayQueuePop() )
|
||||
{
|
||||
Adafruit_EPD::display();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::displayQueuePush() {
|
||||
lock();
|
||||
refreshes_needed_ = FAST_MODE_REFRESHES_NEEDED;
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool Adafruit_SSD1675BX::displayQueuePop() {
|
||||
uint8_t refreshes_needed = 0;
|
||||
lock();
|
||||
refreshes_needed = refreshes_needed_;
|
||||
refreshes_needed_ = refreshes_needed_ > 0 ? refreshes_needed_ - 1 : 0;
|
||||
unlock();
|
||||
return refreshes_needed > 0;
|
||||
}
|
||||
|
||||
bool Adafruit_SSD1675BX::displayQueueFull() {
|
||||
uint8_t refreshes_needed = 0;
|
||||
lock();
|
||||
refreshes_needed = refreshes_needed_;
|
||||
unlock();
|
||||
return refreshes_needed == FAST_MODE_REFRESHES_NEEDED;
|
||||
}
|
||||
|
||||
static uint32_t main_tick_ = 0;
|
||||
|
||||
void Adafruit_SSD1675BX::display(void) {
|
||||
renderEnd();
|
||||
#ifdef ESP32
|
||||
if ( !fastMode() )
|
||||
{
|
||||
// slow mode - just display
|
||||
Adafruit_EPD::display();
|
||||
}
|
||||
else
|
||||
{
|
||||
// fast mode - queue display refresh
|
||||
displayQueuePush();
|
||||
}
|
||||
#else
|
||||
// non-esp32, just display (on esp32, this is handled in a thread)
|
||||
Adafruit_EPD::display();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::renderBegin() {
|
||||
lock();
|
||||
if ( render_in_progress_ ) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
render_in_progress_ = true;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::renderEnd() {
|
||||
lock();
|
||||
if ( !render_in_progress_ ) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
render_in_progress_ = false;
|
||||
if ( fastMode() )
|
||||
{
|
||||
// fast mode - wait for upload to complete before swapping buffers.
|
||||
while ( upload_in_progress_ )
|
||||
{
|
||||
unlock();
|
||||
delay(1);
|
||||
lock();
|
||||
}
|
||||
swapBuffers();
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::uploadBegin() {
|
||||
lock();
|
||||
if ( upload_in_progress_ ) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
upload_in_progress_ = true;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::uploadEnd() {
|
||||
lock();
|
||||
if ( !upload_in_progress_ ) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
upload_in_progress_ = false;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::displayBegin() {
|
||||
lock();
|
||||
if ( display_in_progress_ ) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
display_in_progress_ = true;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Adafruit_SSD1675BX::displayEnd() {
|
||||
lock();
|
||||
if ( !display_in_progress_ ) {
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
display_in_progress_ = false;
|
||||
unlock();
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/***************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Limor Fried/Ladyada for Adafruit Industries.
|
||||
MIT license, all text above must be included in any redistribution
|
||||
****************************************************/
|
||||
|
||||
#include "Adafruit_EPD.h"
|
||||
#include "Adafruit_SSD1675BX.h"
|
||||
#include <SPI.h>
|
||||
|
||||
//#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
//#define VSPI FSPI
|
||||
//#endif
|
||||
|
||||
//static const int spiClk = 10000000;
|
||||
|
||||
SPIClass SPI3(HSPI);
|
||||
|
||||
#define HSPI_MISO 12
|
||||
#define HSPI_MOSI 13
|
||||
#define HSPI_SCLK 14
|
||||
#define HSPI_SS 15
|
||||
|
||||
// DISPLAY
|
||||
#define DISPLAY_WIDTH ((int16_t)(296))
|
||||
#define DISPLAY_HEIGHT ((int16_t)(128))
|
||||
#define DISPLAY_COLOR_BLACK ((uint16_t)(0x0000))
|
||||
#define DISPLAY_COLOR_WHITE ((uint16_t)(0xffff))
|
||||
#define DISPLAY_COLOR_RED ((uint16_t)(0xf800))
|
||||
|
||||
|
||||
#define EPD_DC 25
|
||||
#define EPD_CS 27
|
||||
#define EPD_BUSY 35 // can set to -1 to not use a pin (will wait a fixed delay)
|
||||
#define SRAM_CS -1
|
||||
#define EPD_RESET 26 // can set to -1 and share with microcontroller Reset!
|
||||
#define EPD_SPI &SPI3
|
||||
|
||||
Adafruit_SSD1675BX display(DISPLAY_WIDTH, DISPLAY_HEIGHT, EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY, EPD_SPI);
|
||||
|
||||
#define COLOR1 EPD_BLACK
|
||||
#define COLOR2 EPD_RED
|
||||
|
||||
void testdrawtext(const char *text, uint16_t color) {
|
||||
display.setCursor(0, 0);
|
||||
display.setTextColor(color);
|
||||
display.setTextWrap(true);
|
||||
display.print(text);
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
// while (!Serial) { delay(10); }
|
||||
Serial.println("Adafruit EPD test");
|
||||
// Serial.println("Setting up extra SPI bits");
|
||||
// vspi = new SPIClass(VSPI);
|
||||
// hspi = new SPIClass(HSPI);
|
||||
// vspi->begin();
|
||||
// hspi->begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS);
|
||||
// pinMode(hspi->pinSS(), OUTPUT); //HSPI SS);
|
||||
|
||||
display.setRotation(1);
|
||||
display.clearBuffer();
|
||||
display.begin();
|
||||
|
||||
// large block of text
|
||||
display.clearBuffer();
|
||||
testdrawtext(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur "
|
||||
"adipiscing ante sed nibh tincidunt feugiat. Maecenas enim massa, "
|
||||
"fringilla sed malesuada et, malesuada sit amet turpis. Sed porttitor "
|
||||
"neque ut ante pretium vitae malesuada nunc bibendum. Nullam aliquet "
|
||||
"ultrices massa eu hendrerit. Ut sed nisi lorem. In vestibulum purus a "
|
||||
"tortor imperdiet posuere. ",
|
||||
COLOR1);
|
||||
display.display();
|
||||
|
||||
delay(5000);
|
||||
|
||||
display.clearBuffer();
|
||||
for (int16_t i = 0; i < display.width(); i += 4) {
|
||||
display.drawLine(0, 0, i, display.height() - 1, COLOR1);
|
||||
}
|
||||
|
||||
for (int16_t i = 0; i < display.height(); i += 4) {
|
||||
display.drawLine(display.width() - 1, 0, 0, i,
|
||||
COLOR2); // on grayscale this will be mid-gray
|
||||
}
|
||||
display.display();
|
||||
|
||||
|
||||
Serial.println("End of EPD Test");
|
||||
|
||||
display.setMode(Adafruit_SSD1675BX::kModeBlackWhiteRed);
|
||||
display.fillScreen(DISPLAY_COLOR_BLACK);
|
||||
display.display();
|
||||
display.fillScreen(DISPLAY_COLOR_RED);
|
||||
display.display();
|
||||
display.fillScreen(DISPLAY_COLOR_WHITE);
|
||||
display.display();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// don't do anything!
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
Loading…
Reference in New Issue