1

我想知道是否有任何特别快速的方法可以在微控制器上使用 GPIO 调用(bitbanging)来读取或写入串行协议(例如 SPI)。最快的可能在某种程度上是特定于架构的,但在任何架构上,较少数量的操作可能会更快。假设端口读/写和任何按位整数操作发生在单个 cpu 时钟中是公平的;比较和跳转可能需要几个时钟。

举个简单的例子,考虑使用传统的 SPI 写入一个字节,给定一个带有串行时钟位掩码的端口(寄存器)、miso(输入)、mosi(输出)引脚。要在时钟的下降沿输出 1 位port |= CLOCK|OUTPUT; port &= ~CLOCK;并写入一个字节,需要在循环中对该字节中的每个位执行此操作(输出 0 或 1)。

像这样的东西:

uint8_t data;
// for each bit, msb first
for (i = 7; i >= 0; i--)
{
    if ((data >> i) & 0x01)
    {
        // set output pin to 1
        port |= OUTPUT;
    }
    else
    {
        // set output pin to 0
        port &= ~OUTPUT;
    }
    // strobe clock
    port |= CLOCK;
    port &= ~CLOCK;
}

对此的一些优化是显而易见的,例如展开循环。

一些优化可能不是那么明显:是否可以根据要写入的字节(或只是其中的一部分)进行切换,从而避免移位和屏蔽每一位?如何让这个分支免费?如何利用零或一的运行?(在这种情况下不需要改变输出,只需要改变时钟) 一次操作改变输出和时钟怎么样?

使用其中一些技巧的示例(尽可能在一个操作中更改输出和时钟,展开循环,但不是无分支): https ://github.com/FastLED/FastLED/blob/master/fastspi_bitbang.h

4

1 回答 1

0

SPI 每隔一个边沿对数据进行计时。在您的数据中包含时钟边缘可能会更快(相同或但保存一个分配)

port = CLOCK
for (i = 7; i >= 0; i--)
{
    if ((data >> i) & 0x01)
    {
        // set output pin to 1
        port |= OUTPUT | CLOCK;
    }
    else
    {
        // set output pin to 0
        port &= OUTPUT;
        port |= CLOCK;
    }
    // strobe clock
    port &= ~CLOCK;
}
于 2015-04-30T23:05:19.427 回答