From 1676b1d7177879a91c80d5316b64ace31d8c1f30 Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Wed, 14 Oct 2026 07:41:59 +0000 Subject: [PATCH] Panel_M5UnitLCD: fix ARGB image writes, reads after image writes and the first draw after reset writeImageARGB set a one-row window and sent the first w pixels of src_data, ignoring h and the source position. pushAlphaImage passes the whole clipped rectangle, so only the first row was drawn, and with clipping on the left or top the wrong pixels were sent. Rows are now sent in a window of h rows, each indexed through src_x32 / src_y32 and src_bitwidth as the pixel copy functions do. They are streamed as one raw command without checking the unit's buffer in between, as the single-row version did: the unit consumes raw pixel data faster than the bus delivers it (a full 135x240 ARGB frame sent at 1 MHz arrives intact). writeImageARGB also byte-swapped every source pixel as if it were argb8888_t, while pushAlphaImage accepts bgra8888_t too, which keeps the bytes in the reverse order, so its colors came out wrong. Sources tagged argb8888_4Byte (bgra8888_t) are now sent without the swap; every other source, including the one-row buffer of the anti-aliased rotate/zoom path, keeps the previous swapped send. After CMD_RESET the unit answers READ_ID and consumes a NOP at once, but its first drawing command takes about 250 ms more. Pixel data streamed in that period is dropped: an image drawn right after init() lost its rows after the first dozen (both raw ARGB and RLE), while short fill commands were unaffected. The reset path now queues a one-pixel fill and waits until the unit has consumed it, the same buffer-count wait readRect uses. init() with reset takes about 250 ms longer; init_without_reset() is unchanged. After an image write, a read whose column range equals the cached one returned zeros: _set_window() skipped CASET because the range was unchanged, and the unit then answers the read with zeros. Reading a full-width row right after a full-width pushImage() or pushAlphaImage() therefore gave all zeros. readRect() now invalidates the window cache so CASET and RASET are always sent; this costs a few bytes per read. --- src/lgfx/v1/panel/Panel_M5UnitLCD.inl | 36 ++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/lgfx/v1/panel/Panel_M5UnitLCD.inl b/src/lgfx/v1/panel/Panel_M5UnitLCD.inl index 1a9e7a51..8f854593 100644 --- a/src/lgfx/v1/panel/Panel_M5UnitLCD.inl +++ b/src/lgfx/v1/panel/Panel_M5UnitLCD.inl @@ -60,6 +60,16 @@ namespace lgfx startWrite(true); _bus->writeCommand(CMD_READ_ID, 8); } while (!(_bus->readBytes(buf, 4, true) && buf[0] == 0x77 && buf[1] == 0x89) && --retry); + // The unit answers READ_ID before it finishes starting up (about 250 ms more), and + // pixel data streamed in that period is dropped. Queue a one-pixel fill and wait until + // the unit has consumed it: a NOP is consumed at once and says nothing about drawing. + writeFillRectPreclipped(0, 0, 1, 1, 0); + _buff_free_count = 0; + retry = 4; + do + { + _check_repeat(0, 255); + } while (_buff_free_count < 255 && --retry); } } @@ -588,15 +598,30 @@ if (bytelen != rleDecode(dest, res, bytes)*bytes) { void Panel_M5UnitLCD::writeImageARGB(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t* param) { - _set_window(x, y, x + w - 1, y); - auto buf = (uint32_t*)param->src_data; + // The unit blends ARGB itself, so source pixels are sent as they are, row by row, + // starting from the clipped source position held in param. + _set_window(x, y, x + w - 1, y + h - 1); + auto src = (const uint32_t*)param->src_data; + // bgra8888_t (argb8888_4Byte) holds the bytes in the reverse order of argb8888_t, + // so its raw value already has the byte order the unit expects. + bool swap = (param->src_depth != argb8888_4Byte); if (!_check_repeat(CMD_WRITE_RAW_32)) { writeCommand(CMD_WRITE_RAW_32, 1); } - for (size_t i = 0; i < w; ++i) + for (;;) { - _bus->writeCommand(getSwap32(buf[i]), 32); + uint32_t x32 = param->src_x32; + uint32_t y32 = param->src_y32; + for (size_t i = 0; i < w; ++i) + { + uint32_t idx = (x32 >> pixelcopy_t::FP_SCALE) + (y32 >> pixelcopy_t::FP_SCALE) * param->src_bitwidth; + _bus->writeCommand(swap ? getSwap32(src[idx]) : src[idx], 32); + x32 += param->src_x32_add; + y32 += param->src_y32_add; + } + if (!--h) { break; } + param->src_y++; } _raw_color = ~0u; } @@ -608,6 +633,9 @@ if (bytelen != rleDecode(dest, res, bytes)*bytes) { do { _check_repeat(0, 255); } while (_buff_free_count < 255 && --retry); + // Always send the window: after an image write the unit returns zeros when the + // read reuses the cached column range, so CASET must not be skipped here. + _xs = _xe = _ys = _ye = INT16_MAX; _set_window(x, y, x+w-1, y+h-1); _bus->writeCommand(CMD_READ_RAW | ((_read_bits >> 3) & 3), 8);