Fix VCLK at half rate; chunk the DMA stream; cycle test images

PCNT measurement showed I2S0 BCK (VCLK) rising once per two bytes in 8-bit
LCD mode, so the panel saw every other byte. Each VCLK is now two identical
bytes at a 10 MHz byte rate (VCLK 5 MHz). The doubled ~142 KB stream is
allocated as 38 per-descriptor chunks.

The test sketch now cycles through 12 labelled test images.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-18 18:12:41 +02:00
1 parent e5b8dd9c50
commit df78b5e72c
6 files changed
+235 -91

No files matched your search

+131 -23
View File
@@ -1,4 +1,4 @@
// Test sketch: bring up the EL512.256-H and draw a test pattern with Adafruit GFX.
// Test sketch: bring up the EL512.256-H and slowly cycle through test images.
#include <Arduino.h>
#include <EL512.h>
@@ -15,27 +15,137 @@ static EL512Panel panel({
});
static EL512_GFX display(panel);
static void drawTestPattern() {
display.fillScreen(0);
display.drawRect(0, 0, display.width(), display.height(), 1);
display.drawLine(0, 0, display.width() - 1, display.height() - 1, 1);
display.drawLine(display.width() - 1, 0, 0, display.height() - 1, 1);
static constexpr uint32_t IMAGE_MS = 5000; // time per test image
// Checkerboard strip to check VID/TVID column ordering.
for (int16_t y = 8; y < 24; y++)
for (int16_t x = 8; x < 136; x++)
if ((x ^ y) & 1) display.drawPixel(x, y, 1);
static const int16_t W = EL512Panel::WIDTH;
static const int16_t H = EL512Panel::HEIGHT;
display.fillCircle(display.width() / 2, display.height() / 2, 40, 1);
// Name tag in the bottom-right corner so each image can be identified.
static void drawLabel(const char* name) {
int16_t bx, by;
uint16_t bw, bh;
display.setTextSize(1);
display.getTextBounds(name, 0, 0, &bx, &by, &bw, &bh);
const int16_t w = bw + 8, h = bh + 6;
const int16_t x = W - w - 4, y = H - h - 4;
display.fillRect(x, y, w, h, 0);
display.drawRect(x, y, w, h, 1);
display.setTextColor(1);
display.setCursor(x + 4, y + 3);
display.print(name);
}
static void drawOverview() {
display.drawRect(0, 0, W, H, 1);
display.drawLine(0, 0, W - 1, H - 1, 1);
display.drawLine(W - 1, 0, 0, H - 1, 1);
display.fillCircle(W / 2, H / 2, 40, 1);
display.setTextColor(1);
display.setTextSize(2);
display.setCursor(8, 32);
display.setCursor(8, 8);
display.print("EL512.256-H");
display.setTextSize(1);
display.setCursor(8, 56);
display.printf("%ux%u %.1f Hz", EL512Panel::WIDTH, EL512Panel::HEIGHT,
EL512Panel::refreshHz());
display.setCursor(8, 32);
display.printf("%ux%u %.1f Hz", W, H, EL512Panel::refreshHz());
}
static void drawAllOff() {}
static void drawAllOn() { display.fillScreen(1); }
// Datasheet columns are numbered from 1: x = 0 is column 1 (odd, TVID).
static void drawVidColumns() {
for (int16_t x = 1; x < W; x += 2) display.drawFastVLine(x, 0, H, 1);
}
static void drawTvidColumns() {
for (int16_t x = 0; x < W; x += 2) display.drawFastVLine(x, 0, H, 1);
}
static void drawRowStripes() {
for (int16_t y = 0; y < H; y += 2) display.drawFastHLine(0, y, W, 1);
}
static void drawCheckerboard() {
for (int16_t y = 0; y < H; y++)
for (int16_t x = 0; x < W; x++)
if ((x ^ y) & 1) display.drawPixel(x, y, 1);
}
static void drawBlocks() {
for (int16_t y = 0; y < H; y += 16)
for (int16_t x = 0; x < W; x += 16)
if (((x ^ y) >> 4) & 1) display.fillRect(x, y, 16, 16, 1);
}
static void drawGrid() {
display.setTextSize(1);
display.setTextColor(1);
for (int16_t x = 0; x < W; x += 32) display.drawFastVLine(x, 0, H, 1);
for (int16_t y = 0; y < H; y += 32) display.drawFastHLine(0, y, W, 1);
display.drawFastVLine(W - 1, 0, H, 1);
display.drawFastHLine(0, H - 1, W, 1);
for (int16_t y = 0; y < H; y += 64)
for (int16_t x = 0; x < W; x += 64) {
display.setCursor(x + 3, y + 3);
display.printf("%d,%d", x, y);
}
}
static void drawCircles() {
for (int16_t r = 8; r < W; r += 12) display.drawCircle(W / 2, H / 2, r, 1);
}
// Ordered 4x4 dither from left (dark) to right (bright).
static void drawDither() {
static const uint8_t bayer[4][4] = {
{0, 8, 2, 10}, {12, 4, 14, 6}, {3, 11, 1, 9}, {15, 7, 13, 5}};
for (int16_t y = 0; y < H; y++)
for (int16_t x = 0; x < W; x++)
if (bayer[y & 3][x & 3] < (x * 17) / W) display.drawPixel(x, y, 1);
}
static void drawText() {
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(0, 0);
for (int line = 0; line < 30; line++) {
for (char c = ' ' + (line % 3) * 32; c < ' ' + (line % 3) * 32 + 32 && c <= '~'; c++)
display.print(c);
display.print(" The quick brown fox jumps over the lazy dog.\n");
}
display.setTextSize(3);
display.setCursor(8, H - 40);
display.print("Size 3 text");
}
struct TestImage {
const char* name;
void (*draw)();
};
static const TestImage images[] = {
{"overview", drawOverview},
{"all off", drawAllOff},
{"all on", drawAllOn},
{"VID columns (even)", drawVidColumns},
{"TVID columns (odd)", drawTvidColumns},
{"row stripes", drawRowStripes},
{"checkerboard", drawCheckerboard},
{"16px blocks", drawBlocks},
{"grid 32px", drawGrid},
{"circles", drawCircles},
{"dither ramp", drawDither},
{"text", drawText},
};
static constexpr size_t IMAGE_COUNT = sizeof(images) / sizeof(images[0]);
static void showImage(size_t i) {
display.fillScreen(0);
images[i].draw();
drawLabel(images[i].name);
display.display();
Serial.printf("image %u/%u: %s\n", (unsigned)(i + 1), (unsigned)IMAGE_COUNT, images[i].name);
}
void setup() {
@@ -46,18 +156,16 @@ void setup() {
Serial.println("panel init failed (out of DMA memory?)");
while (true) delay(1000);
}
drawTestPattern();
Serial.printf("free heap: %u\n", ESP.getFreeHeap());
showImage(0);
}
void loop() {
static uint32_t last = 0;
static uint32_t seconds = 0;
if (millis() - last >= 1000) {
static size_t current = 0;
static uint32_t last = millis();
if (millis() - last >= IMAGE_MS) {
last = millis();
display.fillRect(8, 72, 120, 8, 0);
display.setCursor(8, 72);
display.printf("uptime %lus", (unsigned long)seconds++);
display.display();
current = (current + 1) % IMAGE_COUNT;
showImage(current);
}
}