From f115375fe2d01690fc9eb34900a1599cec4b8ed0 Mon Sep 17 00:00:00 2001 From: xhlsa <126936838+xhlsa@users.noreply.github.com> Date: Sun, 13 Sep 2026 19:36:24 -0700 Subject: [PATCH] MAX7456: bound the clear-display wait max7456RefreshAll() polls DMM bit 2 in an unbounded loop after issuing a clear. On an AT7456E-based board (NewBeeDrone LionBee, AT32F435) the bit never clears (DMM reads back 0x06), so the OSD task spins forever. The scheduler then starves the serial task: USB VCP enumerates but accepts no data, which is indistinguishable from a boot hang. Bound the wait to 2 ms (the datasheet clear time is ~20 us). Betaflight does not poll this bit at all. Co-Authored-By: Claude Opus 5 --- src/main/drivers/max7456.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/drivers/max7456.c b/src/main/drivers/max7456.c index 73493b50f6e..ac764a589a9 100644 --- a/src/main/drivers/max7456.c +++ b/src/main/drivers/max7456.c @@ -119,6 +119,7 @@ #define DMM_BLINK (1 << 4) #define DMM_INVERT_PIXEL_COLOR (1 << 3) #define DMM_CLEAR_DISPLAY (1 << 2) +#define MAX7456_CLEAR_TIMEOUT_US 2000 #define DMM_CLEAR_DISPLAY_VERT (DMM_CLEAR_DISPLAY | 1 << 1) #define DMM_AUTOINCREMENT (1 << 0) @@ -648,13 +649,23 @@ void max7456RefreshAll(void) busRead(state.dev, MAX7456ADD_DMM | MAX7456ADD_READ, &dmm); busWrite(state.dev, MAX7456ADD_DMM, state.registers.dmm | DMM_CLEAR_DISPLAY); - // Wait for clear to complete (20us) + // Wait for clear to complete (20us). Bounded: on the LionBee the OSD + // chip never reports the bit cleared (DMM reads back 0x06), and an + // unbounded wait here stalls the whole scheduler, USB/MSP included. + // Betaflight does not poll this bit at all. + const timeUs_t clearStart = micros(); while (1) { busRead(state.dev, MAX7456ADD_DMM | MAX7456ADD_READ, &dmm); if (!(dmm & DMM_CLEAR_DISPLAY)) { state.registers.dmm = dmm; break; } + if (cmpTimeUs(micros(), clearStart) > MAX7456_CLEAR_TIMEOUT_US) { + // Keep the shadow as written: the readback is not trustworthy here + // (0x06 has bit 1 set, which would turn every later clear into a + // deferred VSYNC clear that can erase freshly drawn characters). + break; + } } // Mark non-blank characters as dirty