在C中将串行数据重新排列为并行数据

时间:2015-07-28 02:06:29

标签: stm32 dma

我正在构建一个系统来驱动大量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。

有什么建议吗?

1 个答案:

答案 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中断上发生这种情况。