fix: prevent SPI write collision and hanging by introducing 20-NOP buffer offset and timeout-protected loops in WS2812_Write24Bit

This commit is contained in:
2026-07-08 11:56:23 +08:00
parent 4a7c6c5b7b
commit 88dbb8f069

View File

@@ -150,6 +150,7 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b)
{ {
u8 xdata buf[15]; u8 xdata buf[15];
u8 i; u8 i;
u16 timeout;
WS2812_EncodeByte5(g, &buf[0]); WS2812_EncodeByte5(g, &buf[0]);
WS2812_EncodeByte5(r, &buf[5]); WS2812_EncodeByte5(r, &buf[5]);
@@ -165,20 +166,27 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b)
SPSTAT = 0xC0; // Clear flags SPSTAT = 0xC0; // Clear flags
SPDAT = buf[0]; // Goes to shift register immediately SPDAT = buf[0]; // Goes to shift register immediately
// Wait at least 1 SPI clock cycle (8 system cycles) to avoid WCOL // Wait about 20 system cycles (halfway through transmission) to avoid WCOL
_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 = buf[1]; // Goes to transmit buffer SPDAT = buf[1]; // Goes to transmit buffer
for (i = 2; i < 15; i++) for (i = 2; i < 15; i++)
{ {
while (!(SPSTAT & 0x80)); // Wait for buf[i-2] to finish, buf[i-1] moves to shifter timeout = 2000;
while (!(SPSTAT & 0x80) && --timeout); // Wait with timeout
SPSTAT = 0xC0; SPSTAT = 0xC0;
SPDAT = buf[i]; // Write buf[i] to transmit buffer (zero gap!) SPDAT = buf[i]; // Write buf[i] to transmit buffer
} }
while (!(SPSTAT & 0x80)); // Wait for buf[13] to finish, buf[14] moves to shifter timeout = 2000;
while (!(SPSTAT & 0x80) && --timeout); // Wait for buf[13]
SPSTAT = 0xC0; SPSTAT = 0xC0;
while (!(SPSTAT & 0x80)); // Wait for buf[14] to finish
timeout = 2000;
while (!(SPSTAT & 0x80) && --timeout); // Wait for buf[14]
SPSTAT = 0xC0; SPSTAT = 0xC0;
SPCTL = 0x90; // Disable SPI SPCTL = 0x90; // Disable SPI