From 619f0196154fd85878e7ba9969fa46d701d2c43f Mon Sep 17 00:00:00 2001 From: zouhaitao Date: Wed, 8 Jul 2026 16:20:26 +0800 Subject: [PATCH] feat: add timeout protection to all SPI waits and extend initial NOP delay to 30 to prevent write collisions and deadlocks --- App/main.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/App/main.c b/App/main.c index ea03be7..2f3c76a 100644 --- a/App/main.c +++ b/App/main.c @@ -146,6 +146,7 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) { u8 data buf[10]; u8 b0, b1, b2, b3, b4, b5, b6, b7, b8, b9; + u16 timeout; buf[0] = 0x00; // Prepend dummy 0x00 to absorb SPI hardware startup delay/glitch WS2812_EncodeByte(g, &buf[1]); @@ -166,24 +167,26 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) SPCTL = 0xD0; // Enable SPI at SYSCLK/4 (3.0 MHz actual clock on board) SPDAT = b0; // Start transmitting dummy 0x00 (absorbs startup delay at MOSI=0) - // Wait at least 16 CPU cycles to ensure b0 has moved to the shifter + // Wait 30 NOPs to ensure b0 has moved to the shifter _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); + _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); + _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SPDAT = b1; // Buffer b1 (zero gap!) - // Transmission loop unrolled with double-buffering (zero gap SCLK) - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b2; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b3; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b4; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b5; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b6; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b7; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b8; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b9; + // Transmission loop unrolled with double-buffering and timeout protection + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b2; + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b3; + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b4; + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b5; + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b6; + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b7; + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b8; + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; SPDAT = b9; - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; // Wait for b8 to finish shifting, b9 moves to shifter - while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; // Wait for b9 to finish shifting + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; // Wait for b8 to finish shifting, b9 moves to shifter + timeout = 2000; while (!(SPSTAT & 0x80) && --timeout); SPSTAT = 0xC0; // Wait for b9 to finish shifting SPCTL = 0x90; // Disable SPI WS2812_DI = 0;