我正在构建一个系统来驱动大量WS2812 RGB LED,这些LED需要配置高频(800kHz)数据信号。
我目前在STM32F3上实现的系统如下所示:
Input:
PC (UART) -> DMA -> Memory
Output:
Memory -> DMA -> GPIO
我遇到的问题是,目前我只通过USART传输单个LED条(单个GPIO)的数据,并将该数据存储在uint8_t的缓冲区中。但是,由于DMA将数据从存储器移动到GPIO需要至少1个字节的数据,因此我需要将USART位流转换为字节流。像这样:
USART Data:
R G B
{0xFF, 0xAA, 0x00}
DMA Source:
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, //R
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, //G
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} //B
现在,问题是我的时钟周期非常有限,无法重新安排DMA数据。
我希望某人有一些算法能够真正有效地进行内存重新排列。否则,我可能会尝试摆脱UART DMA并在数据进入时进行基于中断的读取/重新排列。
我唯一的另一个选择是将我的数据吞吐量从PC增加到现在的8倍,基本上是传递一堆0。
有什么建议吗?
答案 0 :(得分:1)
您可以尝试这样的事情:
unsigned char array[] = {0x00, 0x01, 0x02, 0x03, 0xa0, 0xa5};
int i,j;
for ( j = 0; j < sizeof(array); j++ ) {
printf("array[%d] (0x%02x) bits: ", j, array[j]);
for ( i = 0; i < 8; i++ ) {
printf("%d ", (array[j] >> i & 0x01) );
}
printf("\n");
}
输出:
array [0](0x00)位:0 0 0 0 0 0 0 0
array [1](0x01)位:1 0 0 0 0 0 0 0
array [2](0x02)位:0 1 0 0 0 0 0 0
array [3](0x03)位:1 1 0 0 0 0 0 0
array [4](0xa0)位:0 0 0 0 0 1 0 1
array [5](0xa5)位:1 0 1 0 0 1 0 1
反转位用
替换内循环for ( i = 7; i >= 0; i-- ) {
printf("%d ", (array[j] >> i & 0x01) );
}
array [0](0x00)位:0 0 0 0 0 0 0 0
array [1](0x01)位:0 0 0 0 0 0 0 1
array [2](0x02)位:0 0 0 0 0 0 1 0
array [3](0x03)位:0 0 0 0 0 0 1 1
array [4](0xa0)位:1 0 1 0 0 0 0 0
array [5](0xa5)位:1 0 1 0 0 1 0 1
您不需要外循环。该循环模拟您的DMA。基本上,内部循环动态地创建一个掩码并检查该位,如果设置则输出1,如果不设置则输出0。然后,您可以将其输出到GPIO。您应该能够设置一个中断,以便DMA的每个字节传输都运行ISR中的上述代码。
更好的是,抛弃DMA并在UART中断上发生这种情况。