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

Rearranging Serial Data into Parallel data in C

我正在构建一个系统来驱动大量需要配置高频 (800kHz) 数据信号的 WS2812 RGB LED。

我目前在 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 并在数据进入时对其进行基于中断的 reading/rearranging。

我唯一的其他选择是将 PC 的数据吞吐量增加到现在的 8 倍,基本上传递一堆 0。

有什么建议吗?

您可以尝试这样的操作:

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) bits: 0 0 0 0 0 0 0 0
array[1] (0x01) bits: 1 0 0 0 0 0 0 0
array[2] (0x02) bits: 0 1 0 0 0 0 0 0
array[3] (0x03) bits: 1 1 0 0 0 0 0 0
array[4] (0xa0) bits: 0 0 0 0 0 1 0 1
array[5] (0xa5) bits: 1 0 1 0 0 1 0 1

要反转位,请将内部循环替换为

for ( i = 7; i >= 0; i-- ) {
    printf("%d ", (array[j] >> i & 0x01) );
}

array[0] (0x00) bits: 0 0 0 0 0 0 0 0
array[1] (0x01) bits: 0 0 0 0 0 0 0 1
array[2] (0x02) bits: 0 0 0 0 0 0 1 0
array[3] (0x03) bits: 0 0 0 0 0 0 1 1
array[4] (0xa0) bits: 1 0 1 0 0 0 0 0
array[5] (0xa5) bits: 1 0 1 0 0 1 0 1

您不需要外循环。该循环模拟您的 DMA。基本上,内部循环动态创建一个掩码并检查该位,如果已设置则输出 1,否则输出 0。然后您可以将其输出到 GPIO。您应该能够设置一个中断,以便 DMA 的每个字节传输都在 ISR 中运行上面的代码。

更好的是,放弃 DMA,只在 UART 中断时发生这种情况。