perf: unused TinyUSB classes off on nRF52, SSD1306 sends only changed blocks, ESP32 loop yields when idle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-12 19:30:46 +02:00
co-authored by Claude Opus 5.5
parent 2b9e013071
commit ec42a74ab6
5 changed files with 85 additions and 2 deletions
+47 -1
View File
@@ -17,6 +17,7 @@ bool SSD1306Display::begin() {
#ifdef DISPLAY_ROTATION
display.setRotation(DISPLAY_ROTATION);
#endif
_force_redraw = true;
return display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS, true, false) && i2c_probe(Wire, DISPLAY_ADDRESS);
}
@@ -27,6 +28,7 @@ void SSD1306Display::turnOn() {
if (_peripher_power) begin(); // re-init display after power was cut
}
display.ssd1306_command(SSD1306_DISPLAYON);
_force_redraw = true; // panel was off -- guarantee the next endFrame() flushes
}
void SSD1306Display::turnOff() {
@@ -45,6 +47,7 @@ void SSD1306Display::turnOff() {
void SSD1306Display::clear() {
display.clearDisplay();
display.display();
_force_redraw = true; // next endFrame() must flush even if its hash matches a pre-clear frame
}
void SSD1306Display::startFrame(Color bkg) {
@@ -107,6 +110,49 @@ uint16_t SSD1306Display::getTextWidth(const char* str) {
#endif
}
void SSD1306Paged::sendBlock(uint8_t page, uint8_t col, uint8_t len) {
const uint8_t cmd[] = { SSD1306_PAGEADDR, page, page, SSD1306_COLUMNADDR, col, (uint8_t)(col + len - 1) };
const uint8_t* ptr = buffer + (uint16_t)page * WIDTH + col;
ssd1306_commandList(cmd, sizeof(cmd));
while (len) { // 32 data bytes a transfer fit every core's Wire buffer
uint8_t n = len < 32 ? len : 32;
wire->beginTransmission(i2caddr);
wire->write((uint8_t)0x40);
wire->write(ptr, n);
wire->endTransmission();
ptr += n; len -= n;
}
}
void SSD1306Display::endFrame() {
display.display();
const uint8_t* buf = display.getBuffer();
const uint8_t per_page = 128 / BLOCK_W;
bool any = false;
bool dirty[BLOCKS];
for (uint8_t i = 0; i < BLOCKS; i++) {
const uint8_t* q = buf + (uint16_t)i * BLOCK_W; // blocks run along each page in buffer order
uint32_t h = 2166136261u;
for (uint8_t j = 0; j < BLOCK_W; j++) { h ^= q[j]; h *= 16777619u; }
dirty[i] = _force_redraw || h != _block_hash[i];
_block_hash[i] = h;
any |= dirty[i];
}
if (!any) return;
if (_force_redraw || !display.canSendBlocks()) {
_force_redraw = false;
display.display(); // whole frame; also resets the panel's address window
return;
}
display.blocksBegin();
for (uint8_t page = 0; page < 64 / 8; page++) {
// runs of neighbouring dirty blocks go out as one transfer
for (uint8_t b = 0; b < per_page; ) {
if (!dirty[page * per_page + b]) { b++; continue; }
uint8_t e = b;
while (e + 1 < per_page && dirty[page * per_page + e + 1]) e++;
display.sendBlock(page, b * BLOCK_W, (e - b + 1) * BLOCK_W);
b = e + 1;
}
}
display.blocksEnd();
}
+21 -1
View File
@@ -15,12 +15,32 @@
#define DISPLAY_ADDRESS 0x3C
#endif
// Adafruit's display() always sends the whole frame (1 KB, ~25 ms at 400 kHz),
// and startFrame() clears the whole buffer, so every frame went out in full.
// As on the SH1106 (SH1106Display.h): a sender for single 32-column blocks.
class SSD1306Paged : public Adafruit_SSD1306 {
public:
using Adafruit_SSD1306::Adafruit_SSD1306;
bool canSendBlocks() const { return wire != nullptr; }
// A frame's blocks go out between these: the bus clock is set once.
void blocksBegin() { wire->setClock(wireClk); }
void blocksEnd() { wire->setClock(restoreClk); }
void sendBlock(uint8_t page, uint8_t col, uint8_t len);
};
class SSD1306Display : public DisplayDriver {
Adafruit_SSD1306 display;
SSD1306Paged display;
bool _isOn;
uint8_t _color;
int _text_sz = 1;
RefCountedDigitalPin* _peripher_power;
// Frame-skip: endFrame() hashes each 32-column block of each 8-px page and
// sends only the blocks whose hash changed; _force_redraw sends the frame
// after begin()/turnOn()/clear() whole.
static const uint8_t BLOCK_W = 32;
static const uint8_t BLOCKS = (128 / BLOCK_W) * (64 / 8);
uint32_t _block_hash[BLOCKS] = {};
bool _force_redraw = true;
bool i2c_probe(TwoWire& wire, uint8_t addr);
#ifdef OLED_MISC_FIXED_FONT