feat: restore unrolled 3-bit SPI driver with push-pull clock output to resolve byte gap and write collision issues

This commit is contained in:
2026-07-08 14:35:46 +08:00
parent 55409027b9
commit 299ab090f2

View File

@@ -128,25 +128,27 @@ void UI_ShowSosPage(void);
* WS2812B 幻彩 LED 单线驱动函数 (24MHz 1T 模式下精准时序控制) * WS2812B 幻彩 LED 单线驱动函数 (24MHz 1T 模式下精准时序控制)
* ========================================================================= */ * ========================================================================= */
void WS2812_EncodeByte4(u8 v, u8 *buf) 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)
{ {
// Encode 8 FCOB bits into 4 SPI bytes (2 FCOB bits per byte) u16 p1 = SPI_LUT[v >> 4];
// 0-code -> 1000 (binary), 1-code -> 1100 (binary) u16 p2 = SPI_LUT[v & 0x0F];
buf[0] = ((v & 0x80) ? 0xC0 : 0x80) | ((v & 0x40) ? 0x0C : 0x08); buf[0] = p1 >> 4;
buf[1] = ((v & 0x20) ? 0xC0 : 0x80) | ((v & 0x10) ? 0x0C : 0x08); buf[1] = ((p1 & 0x0F) << 4) | (p2 >> 8);
buf[2] = ((v & 0x08) ? 0xC0 : 0x80) | ((v & 0x04) ? 0x0C : 0x08); buf[2] = p2;
buf[3] = ((v & 0x02) ? 0xC0 : 0x80) | ((v & 0x01) ? 0x0C : 0x08);
} }
void WS2812_Write24Bit(u8 g, u8 r, u8 b) void WS2812_Write24Bit(u8 g, u8 r, u8 b)
{ {
u8 xdata buf[12]; u8 xdata buf[9];
u8 i;
u16 timeout;
WS2812_EncodeByte4(g, &buf[0]); WS2812_EncodeByte(g, &buf[0]);
WS2812_EncodeByte4(r, &buf[4]); WS2812_EncodeByte(r, &buf[3]);
WS2812_EncodeByte4(b, &buf[8]); WS2812_EncodeByte(b, &buf[6]);
EA = 0; EA = 0;
@@ -155,28 +157,17 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b)
P2M0 |= ((1 << 3) | (1 << 5)); P2M0 |= ((1 << 3) | (1 << 5));
SPCTL = 0xD0; // Enable SPI at SYSCLK/4 (3.0 MHz actual clock on board) SPCTL = 0xD0; // Enable SPI at SYSCLK/4 (3.0 MHz actual clock on board)
SPSTAT = 0xC0; // Clear flags
SPDAT = buf[0]; // Start transmitting buf[0] // Unrolled 9-byte transmission with minimal gap (~300ns)
// Wait 16 system cycles to ensure buf[0] has moved to shifter SPSTAT = 0xC0; SPDAT = buf[0]; while (!(SPSTAT & 0x80));
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SPSTAT = 0xC0; SPDAT = buf[1]; while (!(SPSTAT & 0x80));
_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SPSTAT = 0xC0; SPDAT = buf[2]; while (!(SPSTAT & 0x80));
SPDAT = buf[1]; // Buffer buf[1] SPSTAT = 0xC0; SPDAT = buf[3]; while (!(SPSTAT & 0x80));
SPSTAT = 0xC0; SPDAT = buf[4]; while (!(SPSTAT & 0x80));
for (i = 2; i < 12; i++) SPSTAT = 0xC0; SPDAT = buf[5]; while (!(SPSTAT & 0x80));
{ SPSTAT = 0xC0; SPDAT = buf[6]; while (!(SPSTAT & 0x80));
timeout = 2000; SPSTAT = 0xC0; SPDAT = buf[7]; while (!(SPSTAT & 0x80));
while (!(SPSTAT & 0x80) && --timeout); // Wait for buf[i-2] to finish, buf[i-1] moves to shifter SPSTAT = 0xC0; SPDAT = buf[8]; while (!(SPSTAT & 0x80));
SPSTAT = 0xC0;
SPDAT = buf[i]; // Buffer buf[i] (zero gap!)
}
timeout = 2000;
while (!(SPSTAT & 0x80) && --timeout); // Wait for buf[10] to finish, buf[11] moves to shifter
SPSTAT = 0xC0;
timeout = 2000;
while (!(SPSTAT & 0x80) && --timeout); // Wait for buf[11] to finish
SPSTAT = 0xC0; SPSTAT = 0xC0;
SPCTL = 0x90; // Disable SPI SPCTL = 0x90; // Disable SPI