From 486b225bb34467c109dc9d69c0334736a461dcf1 Mon Sep 17 00:00:00 2001 From: zouhaitao Date: Wed, 8 Jul 2026 13:21:32 +0800 Subject: [PATCH] feat: implement 4-bit SPI encoding at 3.0 MHz to align with byte boundaries and prevent gap stretching --- App/main.c | 48 ++++++++++++++---------------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/App/main.c b/App/main.c index 39e5aa1..ce93606 100644 --- a/App/main.c +++ b/App/main.c @@ -128,29 +128,25 @@ void UI_ShowSosPage(void); * WS2812B 幻彩 LED 单线驱动函数 (24MHz 1T 模式下精准时序控制) * ========================================================================= */ -const u16 code SPI_LUT[16] = { - 0x924, 0x926, 0x934, 0x936, 0x9A4, 0x9A6, 0x9B4, 0x9B6, - 0xD24, 0xD26, 0xD34, 0xD36, 0xDA4, 0xDA6, 0xDB4, 0xDB6 -}; - -void WS2812_EncodeByte(u8 v, u8 *buf) +void WS2812_EncodeByte4(u8 v, u8 *buf) { - u16 p1 = SPI_LUT[v >> 4]; - u16 p2 = SPI_LUT[v & 0x0F]; - buf[0] = p1 >> 4; - buf[1] = ((p1 & 0x0F) << 4) | (p2 >> 8); - buf[2] = p2; + // Encode 8 FCOB bits into 4 SPI bytes (2 FCOB bits per byte) + // 0-code -> 1000 (binary), 1-code -> 1100 (binary) + buf[0] = ((v & 0x80) ? 0xC0 : 0x80) | ((v & 0x40) ? 0x0C : 0x08); + buf[1] = ((v & 0x20) ? 0xC0 : 0x80) | ((v & 0x10) ? 0x0C : 0x08); + buf[2] = ((v & 0x08) ? 0xC0 : 0x80) | ((v & 0x04) ? 0x0C : 0x08); + buf[3] = ((v & 0x02) ? 0xC0 : 0x80) | ((v & 0x01) ? 0x0C : 0x08); } void WS2812_Write24Bit(u8 g, u8 r, u8 b) { - u8 xdata buf[9]; + u8 xdata buf[12]; u8 i; u16 timeout; - WS2812_EncodeByte(g, &buf[0]); - WS2812_EncodeByte(r, &buf[3]); - WS2812_EncodeByte(b, &buf[6]); + WS2812_EncodeByte4(g, &buf[0]); + WS2812_EncodeByte4(r, &buf[4]); + WS2812_EncodeByte4(b, &buf[8]); EA = 0; @@ -161,30 +157,14 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) SPCTL = 0xD0; // Enable SPI at SYSCLK/4 (3.0 MHz actual clock on board) SPSTAT = 0xC0; // Clear flags - SPDAT = buf[0]; // Goes to shift register immediately - // Wait about 20 system cycles to avoid WCOL - _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 - - for (i = 2; i < 9; i++) + for (i = 0; i < 12; i++) { + SPDAT = buf[i]; timeout = 2000; - while (!(SPSTAT & 0x80) && --timeout); // Wait with timeout + while (!(SPSTAT & 0x80) && --timeout); // Safe wait with timeout SPSTAT = 0xC0; - SPDAT = buf[i]; // Write buf[i] to transmit buffer (zero gap!) } - timeout = 2000; - while (!(SPSTAT & 0x80) && --timeout); // Wait for buf[7] - SPSTAT = 0xC0; - - timeout = 2000; - while (!(SPSTAT & 0x80) && --timeout); // Wait for buf[8] - SPSTAT = 0xC0; - SPCTL = 0x90; // Disable SPI WS2812_DI = 0; MOTOR = 0; // Ensure motor is off