877 lines
21 KiB
C++
877 lines
21 KiB
C++
#include <stdlib.h>
|
||
|
||
#include "Adafruit_GFX.h"
|
||
#include "Inkplate.h"
|
||
Adafruit_MCP23017 mcp;
|
||
|
||
Inkplate::Inkplate(uint8_t _mode) : Adafruit_GFX(E_INK_WIDTH, E_INK_HEIGHT) {
|
||
_displayMode = _mode;
|
||
}
|
||
|
||
Inkplate::Inkplate() : Adafruit_GFX(E_INK_WIDTH, E_INK_HEIGHT) {
|
||
}
|
||
|
||
void Inkplate::begin(void) {
|
||
Wire.begin();
|
||
mcp.begin(0);
|
||
mcp.pinMode(VCOM, OUTPUT);
|
||
mcp.pinMode(PWRUP, OUTPUT);
|
||
mcp.pinMode(WAKEUP, OUTPUT);
|
||
mcp.pinMode(GPIO0_ENABLE, OUTPUT);
|
||
mcp.digitalWrite(GPIO0_ENABLE, HIGH);
|
||
|
||
//CONTROL PINS
|
||
pinMode(0, OUTPUT);
|
||
pinMode(2, OUTPUT);
|
||
pinMode(32, OUTPUT);
|
||
pinMode(33, OUTPUT);
|
||
mcp.pinMode(OE, OUTPUT);
|
||
mcp.pinMode(GMOD, OUTPUT);
|
||
mcp.pinMode(SPV, OUTPUT);
|
||
|
||
//DATA PINS
|
||
pinMode(4, OUTPUT); //D0
|
||
pinMode(5, OUTPUT);
|
||
pinMode(18, OUTPUT);
|
||
pinMode(19, OUTPUT);
|
||
pinMode(23, OUTPUT);
|
||
pinMode(25, OUTPUT);
|
||
pinMode(26, OUTPUT);
|
||
pinMode(27, OUTPUT); //D7
|
||
|
||
//TOUCHPAD PINS
|
||
mcp.pinMode(10, INPUT);
|
||
mcp.pinMode(11, INPUT);
|
||
mcp.pinMode(12, INPUT);
|
||
|
||
//Battery voltage Switch MOSFET
|
||
mcp.pinMode(9, OUTPUT);
|
||
|
||
//1 bit per pixel mode (monochrome mode)
|
||
if (_displayMode == 0) {
|
||
D_memory_new = (uint8_t*)ps_malloc(600 * 100);
|
||
_partial = (uint8_t*)ps_malloc(600*100);
|
||
_pBuffer = (uint8_t*) ps_malloc(120000);
|
||
if (D_memory_new == NULL || _partial == NULL || _pBuffer == NULL) {
|
||
do {
|
||
delay(100);
|
||
} while (true);
|
||
}
|
||
memset(D_memory_new, 0, 60000);
|
||
memset(_partial, 0, 60000);
|
||
}
|
||
|
||
//3 bit per pixel mode (8 level grayscale mode)
|
||
if (_displayMode == 1) {
|
||
D_memory4Bit = (uint8_t*)ps_malloc(240000);
|
||
if (D_memory4Bit == NULL ) {
|
||
do {
|
||
delay(100);
|
||
} while (true);
|
||
}
|
||
memset(D_memory4Bit, 255, 240000);
|
||
}
|
||
}
|
||
|
||
void Inkplate::clearDisplay() {
|
||
//Clear 1 bit per pixel display buffer
|
||
if (_displayMode == 0) memset(_partial, 0, 60000);
|
||
|
||
//Clear 3 bit per pixel display buffer
|
||
if (_displayMode == 1) memset(D_memory4Bit, 255, 240000);
|
||
}
|
||
|
||
void Inkplate::draw_mode_on() {
|
||
einkOn();
|
||
SPH_SET;
|
||
SPV_SET;
|
||
delay(1);
|
||
OE_SET;
|
||
delay(1);
|
||
GMOD_SET;
|
||
CKV_SET;
|
||
delay(5);
|
||
}
|
||
|
||
void Inkplate::draw_mode_off() {
|
||
CKV_CLOCK;
|
||
GMOD_CLEAR;
|
||
CKV_CLOCK;
|
||
GPIO.out &= ~DATA;
|
||
CL_CLEAR;
|
||
LE_CLEAR;
|
||
OE_CLEAR;
|
||
SPV_CLEAR;
|
||
CKV_CLEAR;
|
||
SPH_CLEAR;
|
||
einkOff();
|
||
}
|
||
|
||
void Inkplate::advance_line() {
|
||
CKV_CLEAR;
|
||
usleep1();
|
||
CKV_SET;
|
||
usleep1();
|
||
}
|
||
|
||
void Inkplate::begin_frame() {
|
||
|
||
SPV_SET;
|
||
delayMicroseconds(100); //usleep(500);
|
||
SPV_CLEAR;
|
||
//usleep1();
|
||
CKV_CLEAR;
|
||
usleep1();
|
||
//delayMicroseconds(20); //usleep(25);
|
||
CKV_SET
|
||
usleep1();
|
||
SPV_SET;
|
||
usleep1();
|
||
//delayMicroseconds(20); //usleep(25);
|
||
|
||
|
||
//SPV_SET; //STV=1
|
||
//int loop = 2;
|
||
//while(loop--)
|
||
//{
|
||
// CKV_CLEAR; //CPV=0
|
||
// usleep1();
|
||
// CKV_SET; //CPV=1
|
||
// usleep1();
|
||
//}
|
||
//SPV_CLEAR; //STV=0
|
||
//loop = 2;
|
||
//while(loop--)
|
||
//{
|
||
// CKV_CLEAR; //CPV=0
|
||
// usleep1();
|
||
// CKV_SET; //CPV=1
|
||
// usleep1();
|
||
//}
|
||
//SPV_SET; //STV=1
|
||
//loop = 2;
|
||
//while(loop--)
|
||
//{
|
||
// CKV_CLEAR; //CPV=0
|
||
// usleep1();
|
||
// CKV_SET; //CPV=1
|
||
// usleep1();
|
||
//}
|
||
|
||
//Skip three lines to get to the start of the screen
|
||
advance_line();
|
||
advance_line();
|
||
advance_line();
|
||
}
|
||
|
||
void Inkplate::end_frame() {
|
||
|
||
}
|
||
|
||
void Inkplate::begin_line() {
|
||
SPH_CLEAR;
|
||
usleep1();
|
||
// LE_SET; //LE =1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//LE_CLEAR; //LE=0
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//EPD_OE_H; //OE =1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//SPH_CLEAR; //SPH=0
|
||
}
|
||
|
||
void Inkplate::end_line() {
|
||
|
||
SPH_SET;
|
||
//usleep1();
|
||
|
||
CKV_CLEAR;
|
||
//CL_SET;
|
||
usleep1();
|
||
CL_CLEAR;
|
||
//usleep1();
|
||
CKV_SET;
|
||
usleep1();
|
||
LE_SET;
|
||
//usleep1();
|
||
LE_CLEAR;
|
||
//usleep1();
|
||
|
||
|
||
// SPH_SET; //STH=1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//CKV_CLEAR; //CPV=0 – zegar taktujacy bufor GATE
|
||
//EPD_OE_L; //OE =0
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//CL_CLEAR; //CL=0
|
||
//CL_SET; //CL=1
|
||
//CKV_SET; //CPV=1
|
||
}
|
||
|
||
void Inkplate::end_line_slow() {
|
||
SPH_SET;
|
||
//usleep1();
|
||
CKV_CLEAR;
|
||
CL_SET;
|
||
delayMicroseconds(20);
|
||
//usleep1();
|
||
CL_CLEAR;
|
||
CKV_SET;
|
||
delayMicroseconds(4);
|
||
LE_SET;
|
||
//usleep1();
|
||
LE_CLEAR;
|
||
//usleep1();
|
||
}
|
||
|
||
//For precise 1uS timing, we cannot use delayMicroseconds(), instead we use ASM with nop command. Initial Z value will be difeerent on different CPU speeds! (for 240 MHz CPU Clock z = 25)
|
||
void usleep1() {
|
||
int z = 27;
|
||
while (z--) {
|
||
asm("NOP");
|
||
};
|
||
}
|
||
|
||
//Draw function, used by Adafruit GFX.
|
||
void Inkplate::drawPixel(int16_t x0, int16_t y0, uint16_t color) {
|
||
if (x0 > 799 || y0 > 599 || x0 < 0 || y0 < 0) return;
|
||
|
||
switch (_rotation) {
|
||
case 1:
|
||
_swap_int16_t(x0, y0);
|
||
x0 = _width - x0 - 1;
|
||
break;
|
||
case 2:
|
||
x0 = _width - x0 - 1;
|
||
y0 = _height - y0 - 1;
|
||
break;
|
||
case 3:
|
||
_swap_int16_t(x0, y0);
|
||
y0 = _width - y0 - 1;
|
||
break;
|
||
}
|
||
|
||
if (_displayMode == 0) {
|
||
int x = x0 / 8;
|
||
int x_sub = x0 % 8;
|
||
uint8_t temp = *(_partial + 100 * y0 + x); //D_memory_new[99 * y0 + x]; //-->> Doesn't work with index
|
||
//D_memory_new[100 * y0 + x] = ~pixelMaskLUT[x_sub] & temp | (color ? pixelMaskLUT[x_sub] : 0); //-->> Doesn't work with index
|
||
*(_partial + 100 * y0 + x) = ~pixelMaskLUT[x_sub] & temp | (color ? pixelMaskLUT[x_sub] : 0);
|
||
} else {
|
||
color &= 7;
|
||
int x = x0 / 2;
|
||
int x_sub = x0 % 2;
|
||
uint8_t temp;
|
||
temp = *(D_memory4Bit + 400 * y0 + x);
|
||
*(D_memory4Bit + 400 * y0 + x) = pixelMaskGLUT[x_sub] & temp | (x_sub ? color : color << 4);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//Function that displays content from RAM to screen
|
||
void Inkplate::display() {
|
||
if (_displayMode == 0) display1b();
|
||
if (_displayMode == 1) display3b();
|
||
}
|
||
|
||
//Display content from RAM to display (1 bit per pixel,. monochrome picture).
|
||
void Inkplate::display1b() {
|
||
for(int i = 0; i<60000; i++) {
|
||
*(D_memory_new+i) &= *(_partial+i);
|
||
*(D_memory_new+i) |= (*(_partial+i));
|
||
}
|
||
uint16_t _pos;
|
||
uint32_t _send;
|
||
uint8_t data;
|
||
draw_mode_on();
|
||
SPV_SET;
|
||
delayMicroseconds(500);
|
||
|
||
//cleanFast(2);
|
||
cleanFast(2);
|
||
for(int i = 0; i<8; i++) {
|
||
cleanFast(0);
|
||
delayMicroseconds(500);
|
||
}
|
||
for(int i = 0; i<8; i++) {
|
||
cleanFast(1);
|
||
delayMicroseconds(500);
|
||
}
|
||
for(int i = 0; i<8; i++) {
|
||
cleanFast(0);
|
||
delayMicroseconds(500);
|
||
}
|
||
//for(int i = 0; i<2; i++) {
|
||
//cleanFast(2);
|
||
//}
|
||
//for (int i = 0; i < 6; i++) {
|
||
// cleanFast(1);
|
||
// delayMicroseconds(500);
|
||
//}
|
||
|
||
//for (int i = 0; i < 6; i++) {
|
||
// cleanFast(0);
|
||
// delayMicroseconds(500);
|
||
//}
|
||
|
||
//for (int i = 0; i < 1; i++) {
|
||
// cleanFast(1);
|
||
//delayMicroseconds(500);
|
||
//}
|
||
|
||
for (int k = 0; k < 6; k++) {
|
||
begin_frame();
|
||
_pos = 59999;
|
||
for (int i = 0; i < 600; i++) {
|
||
//data = 10101010;
|
||
//_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
|
||
GPIO.out_w1tc = DATA;
|
||
//GPIO.out_w1ts = _send;
|
||
//CL_SET;
|
||
CL_CLEAR;
|
||
begin_line();
|
||
for (int j = 0; j < 100; j++) {
|
||
data = LUTB[(*(D_memory_new + _pos) >> 4)];
|
||
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
|
||
GPIO.out_w1tc = DATA | CL;
|
||
GPIO.out_w1ts = (_send) | CL;
|
||
data = LUTB[*(D_memory_new + _pos) & 0x0F];
|
||
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
|
||
GPIO.out_w1tc = DATA | CL;
|
||
GPIO.out_w1ts = (_send) | CL;
|
||
_pos--;
|
||
}
|
||
end_line();
|
||
}
|
||
end_frame();
|
||
delayMicroseconds(500);
|
||
}
|
||
cleanFast(2);
|
||
cleanFast(2);
|
||
delayMicroseconds(500);
|
||
draw_mode_off();
|
||
}
|
||
|
||
void Inkplate::partialUpdate() {
|
||
if(_displayMode == 1) return;
|
||
uint16_t _pos = 59999;
|
||
uint32_t _send;
|
||
uint8_t data;
|
||
uint8_t diffw, diffb;
|
||
uint32_t n = 119999;
|
||
|
||
draw_mode_on();
|
||
SPV_SET;
|
||
delayMicroseconds(500);
|
||
|
||
for (int i = 0; i < 600; i++) {
|
||
for (int j = 0; j < 100; j++) {
|
||
diffw = ((*(D_memory_new+_pos))^(*(_partial+_pos)))&(~(*(_partial+_pos)));
|
||
diffb = ((*(D_memory_new+_pos))^(*(_partial+_pos)))&((*(_partial+_pos)));
|
||
_pos--;
|
||
*(_pBuffer+n) = LUTW[diffw>>4] & (LUTB[diffb>>4]);
|
||
n--;
|
||
*(_pBuffer+n) = LUTW[diffw&0x0F] & (LUTB[diffb&0x0F]);
|
||
n--;
|
||
}
|
||
}
|
||
|
||
for (int k = 0; k < 7; k++) {
|
||
begin_frame();
|
||
n = 119999;
|
||
for (int i = 0; i < 600; i++) {
|
||
//data = 10101010;
|
||
//_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
|
||
GPIO.out_w1tc = DATA;
|
||
//GPIO.out_w1ts = _send;
|
||
//CL_SET;
|
||
CL_CLEAR;
|
||
begin_line();
|
||
for (int j = 0; j < 200; j++) {
|
||
//_pos = i * 200 + j;
|
||
////diffw = ((*(D_memory_new+_pos))^(*(_partial+_pos)))&(~(*(_partial+_pos)));
|
||
////diffb = ((*(D_memory_new+_pos))^(*(_partial+_pos)))&((*(_partial+_pos)));
|
||
////data = LUTW[diffw>>4] & (LUTB[diffb>>4]);
|
||
//data = LUT2[(*(D_memory_new + _pos) >> 4)];
|
||
data = *(_pBuffer + n);
|
||
_send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
|
||
GPIO.out_w1tc = DATA | CL;
|
||
GPIO.out_w1ts = (_send) | CL;
|
||
//data = LUT2[*(D_memory_new + _pos) & 0x0F];
|
||
////data = LUTW[diffw&0x0F] & (LUTB[diffb&0x0F]);
|
||
////_send = ((_pBuffer & B00000011) << 4) | (((_pBuffer & B00001100) >> 2) << 18) | (((_pBuffer & B00010000) >> 4) << 23) | (((_pBuffer & B11100000) >> 5) << 25);
|
||
////GPIO.out_w1tc = DATA | CL;
|
||
////GPIO.out_w1ts = _send;
|
||
////GPIO.out_w1ts = CL;
|
||
n--;
|
||
}
|
||
end_line();
|
||
}
|
||
end_frame();
|
||
delayMicroseconds(500);
|
||
}
|
||
for(int i = 0; i<60000; i++) {
|
||
*(D_memory_new+i) &= *(_partial+i);
|
||
*(D_memory_new+i) |= (*(_partial+i));
|
||
}
|
||
|
||
cleanFast(2);
|
||
delayMicroseconds(500);
|
||
draw_mode_off();
|
||
}
|
||
|
||
//Display content from RAM to display (3 bit per pixel,. 8 level of grayscale, STILL IN PROGRESSS, we need correct wavefrom to get good picture, use it only for pictures not for GFX).
|
||
void Inkplate::display3b() {
|
||
draw_mode_on();
|
||
SPV_SET;
|
||
delayMicroseconds(500);
|
||
cleanFast(2);
|
||
//cleanFast(2);
|
||
//for(int i = 0; i<5; i++) {
|
||
// cleanFast(0);
|
||
//}
|
||
for(int i = 0; i<5; i++) {
|
||
cleanFast(0);
|
||
//delay(1);
|
||
}
|
||
delay(5);
|
||
for(int i = 0; i<5; i++) {
|
||
cleanFast(0);
|
||
//delay(1);
|
||
}
|
||
delay(5);
|
||
for(int i = 0; i<7; i++) {
|
||
cleanFast(1);
|
||
//delay(1);
|
||
}
|
||
delay(5);
|
||
for(int i = 0; i<7; i++) {
|
||
cleanFast(0);
|
||
//delay(1);
|
||
}
|
||
delay(5);
|
||
//cleanFast(1);
|
||
cleanFast(2);
|
||
//cleanFast(0);
|
||
//for(int i = 0; i<3; i++) {
|
||
// cleanFast(2);
|
||
//}
|
||
|
||
for (int k = 0; k < 12; k++) {
|
||
//for (int k = 0; k < sz_contrast_cycles; ++k) {
|
||
//for (int contrast_cnt = 0; contrast_cnt < contrast_cycles[k]; ++contrast_cnt) {
|
||
begin_frame();
|
||
uint8_t *dp = D_memory4Bit + 239999;
|
||
uint32_t _send;
|
||
uint8_t pix1;
|
||
uint8_t pix2;
|
||
uint8_t pix3;
|
||
uint8_t pix4;
|
||
|
||
for (int i = 0; i < 600; i++) {
|
||
//CL_SET;
|
||
//GPIO.out_w1tc = DATA;
|
||
//CL_CLEAR;
|
||
begin_line();
|
||
//portDISABLE_INTERRUPTS();
|
||
for (int j = 0; j < 100; j++) {
|
||
|
||
uint8_t pixel = 0B00000000;
|
||
uint8_t pixel2 = 0B00000000;
|
||
|
||
//4 bit mode (non-reversed bits)
|
||
//pix1 = (*(dp) >> k) & 1; //4, 5, 6, 7
|
||
//pix2 = (*(dp--) >> k + 4) & 1; //0, 1, 2, 3
|
||
//pix3 = (*(dp) >> k) & 1;
|
||
//pix4 = (*(dp--) >> k + 4) & 1;
|
||
|
||
//pix1 = (*(dp)) & 0x07; //4, 5, 6, 7
|
||
//pix2 = (*(dp--) >> 4)& 0x07; //0, 1, 2, 3
|
||
//pix3 = (*(dp)) & 0x07;
|
||
//pix4 = (*(dp--) >> 4)& 0x07;
|
||
pix1 = *(dp--);
|
||
pix2 = *(dp--);
|
||
pix3 = *(dp--);
|
||
pix4 = *(dp--);
|
||
//pixel |= ( pixel_to_epd_cmd[pix1] << 6) | ( pixel_to_epd_cmd[pix2] << 4) | ( pixel_to_epd_cmd[pix3] << 2) | ( pixel_to_epd_cmd[pix4] << 0);
|
||
//pixel |= ( waveform3Bit[pix1][k] << 6) | ( waveform3Bit[pix2][k] << 4) | ( waveform3Bit[pix3][k] << 2) | ( waveform3Bit[pix4][k] << 0);
|
||
pixel |= ( waveform3Bit[pix1&0x07][k] << 6) | ( waveform3Bit[(pix1>>4)&0x07][k] << 4) | ( waveform3Bit[pix2&0x07][k] << 2) | ( waveform3Bit[(pix2>>4)&0x07][k] << 0);
|
||
pixel2 |= ( waveform3Bit[pix3&0x07][k] << 6) | ( waveform3Bit[(pix3>>4)&0x07][k] << 4) | ( waveform3Bit[pix4&0x07][k] << 2) | ( waveform3Bit[(pix4>>4)&0x07][k] << 0);
|
||
|
||
_send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | (((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25);
|
||
GPIO.out_w1tc = DATA | CL;
|
||
GPIO.out_w1ts = (_send) | CL;
|
||
//GPIO.out_w1ts = CL;
|
||
|
||
//4 bit mode (non-reversed bits)
|
||
//pix1 = (*(dp) >> k) & 1; //4, 5, 6, 7
|
||
//pix2 = (*(dp--) >> k + 4) & 1; //0, 1, 2, 3
|
||
//pix3 = (*(dp) >> k) & 1;
|
||
//pix4 = (*(dp--) >> k + 4) & 1;
|
||
|
||
//pixel2 |= ( pixel_to_epd_cmd[pix1] << 6);
|
||
//pixel2 |= ( pixel_to_epd_cmd[pix2] << 4);
|
||
//pixel2 |= ( pixel_to_epd_cmd[pix3] << 2);
|
||
//pixel2 |= ( pixel_to_epd_cmd[pix4] << 0);
|
||
|
||
//pix1 = (*(dp)) & 0x07; //4, 5, 6, 7
|
||
//pix2 = (*(dp--) >> 4)& 0x07; //0, 1, 2, 3
|
||
//pix3 = (*(dp)) & 0x07;
|
||
//pix4 = (*(dp--) >> 4)& 0x07;
|
||
|
||
//pixel |= ( pixel_to_epd_cmd[pix1] << 6) | ( pixel_to_epd_cmd[pix2] << 4) | ( pixel_to_epd_cmd[pix3] << 2) | ( pixel_to_epd_cmd[pix4] << 0);
|
||
//pixel2 |= ( waveform3Bit[pix1][k] << 6) | ( waveform3Bit[pix2][k] << 4) | ( waveform3Bit[pix3][k] << 2) | ( waveform3Bit[pix4][k] << 0);
|
||
|
||
_send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | (((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25);
|
||
GPIO.out_w1tc = DATA | CL;
|
||
GPIO.out_w1ts = (_send) | CL;
|
||
//GPIO.out_w1ts = CL;
|
||
}
|
||
//portENABLE_INTERRUPTS();
|
||
end_line();
|
||
}
|
||
end_frame();
|
||
//}
|
||
}
|
||
|
||
cleanFast(2);
|
||
delayMicroseconds(500);
|
||
draw_mode_off();
|
||
}
|
||
|
||
void ckvClock() {
|
||
CKV_CLEAR;
|
||
usleep1();
|
||
CKV_SET;
|
||
usleep1();
|
||
}
|
||
|
||
void Inkplate::drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char* _p, int16_t _w, int16_t _h) {
|
||
if (_displayMode != INKPLATE_3BIT) return;
|
||
uint8_t _rem = _w % 2;
|
||
int i, j;
|
||
int xSize = _w / 2 + _rem;
|
||
|
||
//if (_shiftX == 0) {
|
||
// for (int i = _y; i < _y + _h; i++) {
|
||
// memcpy(D_memory4Bit + (400 * i) + _x/2, _p + _w/2 * (i-_y), _w / 2);
|
||
// }
|
||
//}
|
||
|
||
for (i = 0; i < _h; i++) {
|
||
for (j = 0; j < xSize - 1; j++) {
|
||
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4)>>1);
|
||
drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff)>>1);
|
||
}
|
||
drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4)>>1);
|
||
if (_rem == 0) drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff)>>1);
|
||
}
|
||
}
|
||
|
||
//Clears contenst from display (slower, some epaper panels needs slower cleaning process from others).
|
||
void Inkplate::fillScreen(uint8_t c) {
|
||
uint8_t data = c == 0 ? B10101010 : B01010101;
|
||
uint32_t _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
|
||
draw_mode_on();
|
||
SPV_SET;
|
||
delayMicroseconds(500); //usleep(500);
|
||
for (int k = 0; k < REF_RATE; k++) {
|
||
begin_frame();
|
||
for (int i = 0; i < 600; i++) {
|
||
|
||
begin_line();
|
||
for (int j = 0; j < 100; j++) {
|
||
GPIO.out &= ~DATA;
|
||
GPIO.out |= _send;
|
||
CL_SET;
|
||
CL_CLEAR;
|
||
GPIO.out &= ~DATA;
|
||
GPIO.out |= _send;
|
||
CL_SET;
|
||
CL_CLEAR;
|
||
}
|
||
end_line();
|
||
}
|
||
end_frame();
|
||
}
|
||
draw_mode_off();
|
||
}
|
||
|
||
//Clear screan before new screen update using waveform
|
||
void Inkplate::clean() {
|
||
draw_mode_on();
|
||
SPV_SET; //dspv_gpio::set::set(1 << DSPV_BIT);
|
||
delayMicroseconds(500); //usleep(500);
|
||
int m = 0;
|
||
cleanFast(0); //white
|
||
m++;
|
||
for (int i = 0; i < 8; i++) {
|
||
cleanFast((waveform[m] >> 30) & 3); //White to white
|
||
m++;
|
||
delay(1);
|
||
}
|
||
//cleanFast(0);
|
||
cleanFast((waveform[m] >> 24) & 3); //white to black
|
||
m++;
|
||
for (int i = 0; i < 8; i++) {
|
||
cleanFast((waveform[m]) & 3); //Black to black
|
||
m++;
|
||
delay(1);
|
||
}
|
||
cleanFast((waveform[m] >> 6) & 3); //Black to white
|
||
m++;
|
||
for (int i = 0; i < 8; i++) {
|
||
cleanFast((waveform[m] >> 30) & 3); //White to white
|
||
m++;
|
||
delay(1);
|
||
}
|
||
//cleanFast(2);
|
||
//delay(1);
|
||
draw_mode_off();
|
||
}
|
||
|
||
//Clears content from epaper diplay as fast as ESP32 can.
|
||
void Inkplate::cleanFast(uint8_t c) {
|
||
uint8_t data;
|
||
if (c == 0) {
|
||
data = B10101010; //White
|
||
} else if (c == 1) {
|
||
data = B01010101; //Black
|
||
} else if (c == 2) {
|
||
data = B00000000; //Discharge
|
||
}
|
||
uint32_t _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25);
|
||
begin_frame();
|
||
for (int i = 0; i < 600; i++) {
|
||
|
||
begin_line();
|
||
for (int j = 0; j < 100; j++) {
|
||
GPIO.out_w1tc = DATA | CL;
|
||
GPIO.out_w1ts = (_send) | CL;
|
||
//GPIO.out_w1ts = CL;
|
||
GPIO.out_w1tc = DATA | CL;
|
||
GPIO.out_w1ts = (_send) | CL;
|
||
//GPIO.out_w1ts = CL;
|
||
}
|
||
end_line();
|
||
}
|
||
end_frame();
|
||
}
|
||
|
||
//Turn on supply for epaper display (TPS65186) [+15 VDC, -15VDC, +22VDC, -20VDC, +3.3VDC, VCOM]
|
||
void Inkplate::einkOn() {
|
||
_panelOn = 1;
|
||
pinsAsOutputs();
|
||
WAKEUP_SET;
|
||
PWRUP_SET;
|
||
//Enable all rails
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x01);
|
||
Wire.write(B00111111);
|
||
Wire.endTransmission();
|
||
//Set out voltage on LDO outputs
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x02);
|
||
Wire.write(B00100011);
|
||
Wire.endTransmission();
|
||
//Set VCOM Voltage
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x03);
|
||
Wire.write(150);
|
||
Wire.endTransmission();
|
||
//Set power up times (all on 3mS)
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x0A);
|
||
Wire.write(0);
|
||
Wire.endTransmission();
|
||
//Set Power Down Seq.
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x0B);
|
||
Wire.write(B00011011);
|
||
Wire.endTransmission();
|
||
//Set Power Down Times (all on 6mS)
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x0C);
|
||
Wire.write(0);
|
||
Wire.endTransmission();
|
||
|
||
delay(20);
|
||
|
||
VCOM_SET;
|
||
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x0D);
|
||
Wire.write(B10000000);
|
||
Wire.endTransmission();
|
||
|
||
delay(2);
|
||
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x00);
|
||
Wire.endTransmission();
|
||
|
||
Wire.requestFrom(0x48, 1);
|
||
_temperature = Wire.read();
|
||
|
||
|
||
}
|
||
|
||
//Turn off epapewr supply and put all digital IO pins in high Z state
|
||
void Inkplate::einkOff() {
|
||
_panelOn = 0;
|
||
GPIO.out &= ~(DATA | CL | LE);
|
||
SPH_CLEAR;
|
||
OE_CLEAR;
|
||
GMOD_CLEAR;
|
||
SPV_CLEAR;
|
||
|
||
PWRUP_CLEAR;
|
||
//Enable all rails
|
||
Wire.beginTransmission(0x48);
|
||
Wire.write(0x01);
|
||
Wire.write(B00000000);
|
||
Wire.endTransmission();
|
||
//delay(250);
|
||
WAKEUP_CLEAR;
|
||
VCOM_CLEAR;
|
||
|
||
pinsZstate();
|
||
}
|
||
|
||
void Inkplate::setRotation(uint8_t r) {
|
||
_rotation = r % 4;
|
||
switch (rotation) {
|
||
case 0:
|
||
_width = E_INK_WIDTH;
|
||
_height = E_INK_HEIGHT;
|
||
break;
|
||
case 1:
|
||
_width = E_INK_HEIGHT;
|
||
_height = E_INK_WIDTH;
|
||
break;
|
||
case 2:
|
||
_width = E_INK_WIDTH;
|
||
_height = E_INK_HEIGHT;
|
||
break;
|
||
case 3:
|
||
_width = E_INK_HEIGHT;
|
||
_height = E_INK_WIDTH;
|
||
break;
|
||
}
|
||
}
|
||
|
||
uint8_t Inkplate::getPanelState() {
|
||
return _panelOn;
|
||
}
|
||
|
||
void Inkplate::pinsZstate() {
|
||
//CONTROL PINS
|
||
pinMode(0, INPUT);
|
||
pinMode(2, INPUT);
|
||
pinMode(32, INPUT);
|
||
pinMode(33, INPUT);
|
||
mcp.pinMode(OE, INPUT);
|
||
mcp.pinMode(GMOD, INPUT);
|
||
mcp.pinMode(SPV, INPUT);
|
||
|
||
//DATA PINS
|
||
pinMode(4, INPUT); //D0
|
||
pinMode(5, INPUT);
|
||
pinMode(18, INPUT);
|
||
pinMode(19, INPUT);
|
||
pinMode(23, INPUT);
|
||
pinMode(25, INPUT);
|
||
pinMode(26, INPUT);
|
||
pinMode(27, INPUT); //D7
|
||
}
|
||
|
||
void Inkplate::pinsAsOutputs() {
|
||
//CONTROL PINS
|
||
pinMode(0, OUTPUT);
|
||
pinMode(2, OUTPUT);
|
||
pinMode(32, OUTPUT);
|
||
pinMode(33, OUTPUT);
|
||
mcp.pinMode(OE, OUTPUT);
|
||
mcp.pinMode(GMOD, OUTPUT);
|
||
mcp.pinMode(SPV, OUTPUT);
|
||
|
||
//DATA PINS
|
||
pinMode(4, OUTPUT); //D0
|
||
pinMode(5, OUTPUT);
|
||
pinMode(18, OUTPUT);
|
||
pinMode(19, OUTPUT);
|
||
pinMode(23, OUTPUT);
|
||
pinMode(25, OUTPUT);
|
||
pinMode(26, OUTPUT);
|
||
pinMode(27, OUTPUT); //D7
|
||
}
|
||
|
||
void Inkplate::selectDisplayMode(uint8_t _mode) {
|
||
if (_mode == INKPLATE_1BIT) {
|
||
if (D_memory_new != NULL) return;
|
||
if (D_memory4Bit != NULL) free(D_memory4Bit);
|
||
//1 bit per pixel mode (monochrome mode)
|
||
D_memory_new = (uint8_t*)ps_malloc(600 * 100);
|
||
_partial = (uint8_t*)ps_malloc(600 * 100);
|
||
_pBuffer = (uint8_t*) ps_malloc(120000);
|
||
if (D_memory_new == NULL || _partial == NULL || _pBuffer == NULL) {
|
||
do {
|
||
delay(100);
|
||
} while (true);
|
||
}
|
||
memset(D_memory_new, 0, 60000);
|
||
_displayMode = INKPLATE_1BIT;
|
||
}
|
||
|
||
if (_mode == INKPLATE_3BIT) {
|
||
if (D_memory4Bit != NULL) return;
|
||
if (D_memory_new != NULL) {
|
||
free(D_memory_new);
|
||
free(_partial);
|
||
free(_pBuffer);
|
||
}
|
||
//3 bit per pixel mode (8 level grayscale mode)
|
||
D_memory4Bit = (uint8_t*)ps_malloc(240000);
|
||
if (D_memory4Bit == NULL ) {
|
||
do {
|
||
delay(100);
|
||
} while (true);
|
||
}
|
||
memset(D_memory4Bit, 255, 240000);
|
||
_displayMode = INKPLATE_3BIT;
|
||
}
|
||
}
|
||
|
||
uint8_t Inkplate::getDisplayMode() {
|
||
return _displayMode;
|
||
}
|
||
|
||
uint8_t Inkplate::readTouchpad(uint8_t _pad) {
|
||
return mcp.digitalRead((_pad&3)+10);
|
||
}
|
||
|
||
int8_t Inkplate::readTemperature() {
|
||
return _temperature;
|
||
}
|
||
|
||
double Inkplate::readBattery() {
|
||
mcp.digitalWrite(9, HIGH);
|
||
delay(1);
|
||
int adc = analogRead(35);
|
||
mcp.digitalWrite(9, LOW);
|
||
return (double(adc) / 4095 * 3.3 * 2);
|
||
} |