feat: add timeout protection to all SPI waits and extend initial NOP delay to 30 to prevent write collisions and deadlocks

This commit is contained in:
2026-07-08 16:20:26 +08:00
parent e6e81f48c0
commit 619f019615

View File

@@ -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;