feat: implement 4-bit SPI encoding at 3.0 MHz to align with byte boundaries and prevent gap stretching
This commit is contained in:
48
App/main.c
48
App/main.c
@@ -128,29 +128,25 @@ void UI_ShowSosPage(void);
|
|||||||
* WS2812B 幻彩 LED 单线驱动函数 (24MHz 1T 模式下精准时序控制)
|
* WS2812B 幻彩 LED 单线驱动函数 (24MHz 1T 模式下精准时序控制)
|
||||||
* ========================================================================= */
|
* ========================================================================= */
|
||||||
|
|
||||||
const u16 code SPI_LUT[16] = {
|
void WS2812_EncodeByte4(u8 v, u8 *buf)
|
||||||
0x924, 0x926, 0x934, 0x936, 0x9A4, 0x9A6, 0x9B4, 0x9B6,
|
|
||||||
0xD24, 0xD26, 0xD34, 0xD36, 0xDA4, 0xDA6, 0xDB4, 0xDB6
|
|
||||||
};
|
|
||||||
|
|
||||||
void WS2812_EncodeByte(u8 v, u8 *buf)
|
|
||||||
{
|
{
|
||||||
u16 p1 = SPI_LUT[v >> 4];
|
// Encode 8 FCOB bits into 4 SPI bytes (2 FCOB bits per byte)
|
||||||
u16 p2 = SPI_LUT[v & 0x0F];
|
// 0-code -> 1000 (binary), 1-code -> 1100 (binary)
|
||||||
buf[0] = p1 >> 4;
|
buf[0] = ((v & 0x80) ? 0xC0 : 0x80) | ((v & 0x40) ? 0x0C : 0x08);
|
||||||
buf[1] = ((p1 & 0x0F) << 4) | (p2 >> 8);
|
buf[1] = ((v & 0x20) ? 0xC0 : 0x80) | ((v & 0x10) ? 0x0C : 0x08);
|
||||||
buf[2] = p2;
|
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)
|
void WS2812_Write24Bit(u8 g, u8 r, u8 b)
|
||||||
{
|
{
|
||||||
u8 xdata buf[9];
|
u8 xdata buf[12];
|
||||||
u8 i;
|
u8 i;
|
||||||
u16 timeout;
|
u16 timeout;
|
||||||
|
|
||||||
WS2812_EncodeByte(g, &buf[0]);
|
WS2812_EncodeByte4(g, &buf[0]);
|
||||||
WS2812_EncodeByte(r, &buf[3]);
|
WS2812_EncodeByte4(r, &buf[4]);
|
||||||
WS2812_EncodeByte(b, &buf[6]);
|
WS2812_EncodeByte4(b, &buf[8]);
|
||||||
|
|
||||||
EA = 0;
|
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)
|
SPCTL = 0xD0; // Enable SPI at SYSCLK/4 (3.0 MHz actual clock on board)
|
||||||
SPSTAT = 0xC0; // Clear flags
|
SPSTAT = 0xC0; // Clear flags
|
||||||
|
|
||||||
SPDAT = buf[0]; // Goes to shift register immediately
|
for (i = 0; i < 12; i++)
|
||||||
// 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++)
|
|
||||||
{
|
{
|
||||||
|
SPDAT = buf[i];
|
||||||
timeout = 2000;
|
timeout = 2000;
|
||||||
while (!(SPSTAT & 0x80) && --timeout); // Wait with timeout
|
while (!(SPSTAT & 0x80) && --timeout); // Safe wait with timeout
|
||||||
SPSTAT = 0xC0;
|
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
|
SPCTL = 0x90; // Disable SPI
|
||||||
WS2812_DI = 0;
|
WS2812_DI = 0;
|
||||||
MOTOR = 0; // Ensure motor is off
|
MOTOR = 0; // Ensure motor is off
|
||||||
|
|||||||
Reference in New Issue
Block a user