Skip to content
Open
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e40fafa
del trailing spaces and add last line
FREEWING-JP Feb 21, 2023
d760234
SSD1306 display I2C bus For Wemos Lolin32 ESP32
FREEWING-JP Feb 22, 2023
63d5239
mod Difine OLED setBrightness
FREEWING-JP Feb 22, 2023
d880588
mod Difine Board Boot SW GPIO 0
FREEWING-JP Feb 22, 2023
a6f330c
mod Add Reset to Infinite Loop Demo !
FREEWING-JP Feb 22, 2023
dedd45f
mod More Accurate frame rate
FREEWING-JP Feb 24, 2023
e5bf036
fix No wait mode delay Bug and Optimize Button handring
FREEWING-JP Feb 24, 2023
1974d05
mod Add Frame counter and More Accurate frame rate
FREEWING-JP Feb 24, 2023
6d3a0d0
mod Disable heatshrink error checking
FREEWING-JP Feb 23, 2023
f60d4ea
mod Optimize readFile display.resetDisplay()
FREEWING-JP Feb 22, 2023
fc772eb
mod Optimize readFile file.read
FREEWING-JP Feb 22, 2023
87a7075
mod Optimize readFile delete Unused HSD_sink_res
FREEWING-JP Feb 22, 2023
20d1711
mod Optimize readFile decodeRLE rle_buf
FREEWING-JP Feb 22, 2023
0fb001b
mod Optimize int16_t to int32_t for Reduse Program size 12 byte (323…
FREEWING-JP Feb 24, 2023
c33224c
mod Optimize int16_t to int32_t for Reduse Program size 24 byte (323…
FREEWING-JP Feb 24, 2023
fab9458
mod I2C SCLK 700kHz to 4MHz (However, Actual measured value is 892 kHz)
FREEWING-JP Feb 27, 2023
1b53b91
mod Add Enable I2C Clock up 892kHz to 1.31MHz (It Actual measured value)
FREEWING-JP Feb 27, 2023
dbcd6fe
mod Optimize Direct Draw OLED buffer
FREEWING-JP Feb 27, 2023
d83deb9
mod More Optimize Direct Draw OLED buffer
FREEWING-JP Feb 22, 2023
a000af9
mod More Optimize Direct Draw OLED buffer Write 4 dot
FREEWING-JP Feb 23, 2023
416ffac
mod Change pImage uint8_t* to uint32_t*
FREEWING-JP Feb 23, 2023
d6e9927
mod More Optimize Direct Draw OLED buffer Skip black
FREEWING-JP Feb 23, 2023
0d8c4d5
mod More Optimize bit operation Reduse Program size 8 byte (323437 by…
FREEWING-JP Feb 24, 2023
fac4c48
mod More Optimize bit operation Reduse Program size 32 byte (323429 b…
FREEWING-JP Feb 24, 2023
be53378
Revert Skip black Reduse Program size 16 byte (323397 bytes to 323381…
FREEWING-JP Feb 27, 2023
9e8dc2f
mod Combine XY variable Reduse Program size 16 byte (323385 bytes to …
FREEWING-JP Feb 24, 2023
62f9c22
mod Change Compare logic
FREEWING-JP Feb 24, 2023
cf0e3c3
mod Del unnecessary Initialize variable Reduse Program size 28 byte (…
FREEWING-JP Feb 25, 2023
fad1689
mod Add Ending Message
FREEWING-JP Feb 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 189 additions & 59 deletions ESP32_BadApple.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,52 @@
#include "SSD1306.h"
#include "heatshrink_decoder.h"

// Hints:
// Board Boot SW GPIO 0
#define BOOT_SW 0

// Frame counter
#define ENABLE_FRAME_COUNTER

// Disable heatshrink error checking
#define DISABLE_HS_ERROR

// Hints:
// * Adjust the display pins below
// * After uploading to ESP32, also do "ESP32 Sketch Data Upload" from Arduino

SSD1306 display (0x3c, 4, 15); // For Heltec
//SSD1306 display (0x3c, 5, 4);
// SSD1306 display I2C bus
// For Heltec
// #define I2C_SCL 15
// #define I2C_SDA 4
// #define RESET_OLED 16

// For Wemos Lolin32 ESP32
#define I2C_SCL 4
#define I2C_SDA 5

#define OLED_BRIGHTNESS 16

// MAX freq for SCL is 4 MHz, However, Actual measured value is 892 kHz . (ESP32-D0WDQ6 (revision 1))
// see Inter-Integrated Circuit (I2C)
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html
#define I2C_SCLK_FREQ 4000000
#ifdef I2C_SCLK_FREQ
SSD1306 display (0x3c, I2C_SDA, I2C_SCL, GEOMETRY_128_64, I2C_ONE, I2C_SCLK_FREQ);
#else
SSD1306 display (0x3c, I2C_SDA, I2C_SCL);
#endif

// Enable I2C Clock up 892kHz to 1.31MHz (It Actual measured value with ESP32-D0WDQ6 (revision 1))
// #define ENABLE_EXTRA_I2C_CLOCK_UP

#if HEATSHRINK_DYNAMIC_ALLOC
#error HEATSHRINK_DYNAMIC_ALLOC must be false for static allocation test suite.
#endif

static heatshrink_decoder hsd;

// global storage for putPixels
int16_t curr_x = 0;
int16_t curr_y = 0;
// global storage for putPixels
int32_t curr_xy = 0;

// global storage for decodeRLE
int32_t runlength = -1;
Expand Down Expand Up @@ -56,38 +86,104 @@ void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
}
}

uint32_t lastRefresh = 0;
volatile unsigned long lastRefresh;
// 30 fps target rate = 33.333us
#define FRAME_DERAY_US 33333UL
#ifdef ENABLE_FRAME_COUNTER
int32_t frame = 0;
#endif
uint32_t* pImage;
uint32_t b = 0x01;

volatile bool isButtonPressing = false;

void ARDUINO_ISR_ATTR isr() {
lastRefresh = micros();
isButtonPressing = (digitalRead(BOOT_SW) == LOW);
}

void putPixels(uint32_t c, int32_t len) {
uint32_t d1;
uint32_t d2;

void putPixels(uint8_t c, int32_t len) {
uint8_t b = 0;
while(len--) {
b = 128;
for(int i=0; i<8; i++) {
if(c & b) {
display.setColor(WHITE);
// Direct Draw OLED buffer
// OLED Buffer Image Rotate 90 Convert X-Y and Byte structure
{
// 4 dot(Direct Access 4 byte, 32 bit)
d1 = 0;
d2 = 0;
if (c == 0xff) {
d1 = b; d1 <<= 8;
d1 |= b; d1 <<= 8;
d1 |= b; d1 <<= 8;
d1 |= b;

d2 = d1;
} else if (c != 0x00) {
// if ((c & 0xF0) != 0x00) {
if (c & 0x10) d1 = b<<24;
if (c & 0x20) d1 |= b<<16;
if (c & 0x40) d1 |= b<< 8;
if (c & 0x80) d1 |= b;
// }

// if ((c & 0x0F) != 0x00) {
if (c & 0x01) d2 = b<<24;
if (c & 0x02) d2 |= b<<16;
if (c & 0x04) d2 |= b<< 8;
if (c & 0x08) d2 |= b;
// }
}

if (b == 0x01) {
*pImage++ = d1;
*pImage = d2;
} else if (c != 0x00) {
*pImage++ |= d1;
*pImage |= d2;
} else {
display.setColor(BLACK);
pImage++;
}
b >>= 1;
display.setPixel(curr_x, curr_y);
curr_x++;
if(curr_x >= 128) {
curr_x = 0;
curr_y++;
if(curr_y >= 64) {
curr_y = 0;
pImage++;
}

// oyy_ybbb_xxxx X=0-15(4 bit), Bit=0-7(3 bit),Y=0-7(3 bit)
curr_xy++;
if((curr_xy & 0x0f) == 0) {
pImage -= 128/4;

b <<= 1;
if(b == 0x100) {
// Next Page
pImage += 128/4;
b = 0x01;

// oyy_ybbb_xxxx X=0-15(4 bit), Bit=0-7(3 bit),Y=0-7(3 bit)
// Check Overflow bit, It equivalent if((curr_xy & 0x400) != 0)
if((curr_xy & 0x3ff) == 0) {
pImage = (uint32_t*)display.buffer;

// Update Display frame
display.display();
//display.clear();
// 30 fps target rate
if(digitalRead(0)) while((millis() - lastRefresh) < 33) ;
lastRefresh = millis();

if(!isButtonPressing) {
// 30 fps target rate = 33.333us
lastRefresh += FRAME_DERAY_US;
#ifdef ENABLE_FRAME_COUNTER
// Adjust 33.334us every 3 frame
if ((++frame % 3) == 0) lastRefresh++;
#endif
while(micros() < lastRefresh) ;
}
}
}
}
}
}

void decodeRLE(uint8_t c) {
void decodeRLE(uint32_t c) {
if(c_to_dup == -1) {
if((c == 0x55) || (c == 0xaa)) {
c_to_dup = c;
Expand Down Expand Up @@ -116,8 +212,8 @@ void decodeRLE(uint8_t c) {
} else {
putPixels(255, runlength);
}
c_to_dup = -1;
runlength = -1;
c_to_dup = -1;
runlength = -1;
}
}
}
Expand All @@ -126,13 +222,13 @@ void decodeRLE(uint8_t c) {
#define READBUFSIZE 2048
void readFile(fs::FS &fs, const char * path){
static uint8_t rle_buf[RLEBUFSIZE];
size_t rle_bufhead = 0;
size_t rle_size = 0;
size_t filelen = 0;
uint8_t* p_rle_buf;
size_t rle_size;

size_t filelen;
size_t filesize;
static uint8_t compbuf[READBUFSIZE];

Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file || file.isDirectory()){
Expand All @@ -145,99 +241,132 @@ void readFile(fs::FS &fs, const char * path){
Serial.printf("File size: %d\n", filelen);

// init display, putPixels and decodeRLE
display.clear();
display.display();
curr_x = 0;
curr_y = 0;
runlength = -1;
c_to_dup = -1;
lastRefresh = millis();
display.resetDisplay();
// curr_xy = 0;
pImage = (uint32_t*)display.buffer;
// runlength = -1;
// c_to_dup = -1;

// init decoder
heatshrink_decoder_reset(&hsd);
size_t count = 0;
uint32_t sunk = 0;
size_t toRead;
size_t toSink = 0;
uint32_t sinkHead = 0;


lastRefresh = micros();

// Go through file...
while(filelen) {
if(toSink == 0) {
toRead = filelen;
if(toRead > READBUFSIZE) toRead = READBUFSIZE;
file.read(compbuf, toRead);
filelen -= toRead;
toSink = toRead;
toSink = file.read(compbuf, READBUFSIZE);
filelen -= toSink;
sinkHead = 0;
}

// uncompress buffer
HSD_sink_res sres;
sres = heatshrink_decoder_sink(&hsd, &compbuf[sinkHead], toSink, &count);
heatshrink_decoder_sink(&hsd, &compbuf[sinkHead], toSink, &count);
//Serial.print("^^ sinked ");
//Serial.println(count);
//Serial.println(count);
toSink -= count;
sinkHead = count;
sinkHead = count;
sunk += count;
if (sunk == filesize) {
heatshrink_decoder_finish(&hsd);
}

HSD_poll_res pres;
do {
rle_size = 0;
// rle_size = 0;
pres = heatshrink_decoder_poll(&hsd, rle_buf, RLEBUFSIZE, &rle_size);
//Serial.print("^^ polled ");
//Serial.println(rle_size);
#ifndef DISABLE_HS_ERROR
if(pres < 0) {
Serial.print("POLL ERR! ");
Serial.println(pres);
return;
}
#endif

rle_bufhead = 0;
p_rle_buf = rle_buf;
while(rle_size) {
rle_size--;
#ifndef DISABLE_HS_ERROR
if(rle_bufhead >= RLEBUFSIZE) {
Serial.println("RLE_SIZE ERR!");
return;
}
decodeRLE(rle_buf[rle_bufhead++]);
#endif
decodeRLE(*(p_rle_buf++));
}
} while (pres == HSDR_POLL_MORE);
}
file.close();
#ifdef ENABLE_FRAME_COUNTER
Serial.print("Done. ");
Serial.println(frame);
#else
Serial.println("Done.");
#endif

// 10 sec
delay(10000);
display.resetDisplay();
display.drawStringMaxWidth(0, 0, 128, "Optimize OLED Draw Performance version. modded By FREE WING");
display.drawStringMaxWidth(0, 40, 128, "http://www.neko.ne.jp/~freewing/"); display.display();
delay(10000);
// Reset to Infinite Loop Demo !
ESP.restart();
}



void setup(){
Serial.begin(115200);
#ifdef RESET_OLED
// Reset for some displays
pinMode(16,OUTPUT); digitalWrite(16, LOW); delay(50); digitalWrite(16, HIGH);
pinMode(RESET_OLED, OUTPUT); digitalWrite(RESET_OLED, LOW); delay(50); digitalWrite(RESET_OLED, HIGH);
#endif
display.init();
#ifdef OLED_BRIGHTNESS
display.setBrightness(OLED_BRIGHTNESS);
#endif
display.flipScreenVertically ();
display.clear();
display.setTextAlignment (TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_10);
display.setColor(WHITE);
display.drawString(0, 0, "Mounting SPIFFS... ");
display.display();
display.display();
if(!SPIFFS.begin()){
Serial.println("SPIFFS mount failed");
display.drawStringMaxWidth(0, 10, 128, "SPIFFS mount failed. Upload video.hs using ESP32 Sketch Upload."); display.display();
return;
}

pinMode(0, INPUT_PULLUP);
pinMode(BOOT_SW, INPUT_PULLUP);
attachInterrupt(BOOT_SW, isr, CHANGE);
Serial.print("totalBytes(): ");
Serial.println(SPIFFS.totalBytes());
Serial.print("usedBytes(): ");
Serial.println(SPIFFS.usedBytes());
listDir(SPIFFS, "/", 0);

#ifdef ENABLE_EXTRA_I2C_CLOCK_UP
// Direct Access I2C SCL frequency setting value
// It Tested ESP32-D0WDQ6 (revision 1)
uint32_t* ptr;
ptr = (uint32_t*)0x3FF53000; // I2C_SCL_LOW_PERIOD_REG
// *ptr = 30; // Don't work
// *ptr = 31; // Sometime Stop Frame drawing
// *ptr = 32; // Works
*ptr = 35; // Safety value
ptr = (uint32_t*)0x3FF53038; // I2C_SCL_HIGH_PERIOD_REG
// *ptr = 0; // Works
*ptr = 2; // Safety value
#endif

readFile(SPIFFS, "/video.hs");

//Serial.print("Format SPIFSS? (enter y for yes): ");
Expand All @@ -252,4 +381,5 @@ void setup(){

void loop(){

}
}