为什么如果我们必须 read/write 使用 SPI 我们必须这样做?

Why if we have to read/write using SPI we have to do like this?

我有一个关于 SPI 总线的问题。我经常在一些图书馆看到 我找到了,但我不明白它是如何工作的。

我找到的一个库中的快速示例。 SPI 写入:

static void nRF24_WriteRegister(uint8_t reg, uint8_t val)
{
    uint8_t tmp[2];

    tmp[0] = NRF24_CMD_W_REGISTER | reg;
    tmp[1] = val;

    NRF24_CSN_LOW;

    nRF24_SendSpi(tmp, 2);

    NRF24_CSN_HIGH;
}

如果我们将相同的帧寄存器(我们正在写入)和数据放入相同的帧寄存器,它是如何工作的 到这个寄存器?

但更让我困惑的是从 SPI 读取:

static uint8_t nRF24_ReadRegister(uint8_t reg)
{
    uint8_t result;

    reg = NRF24_CMD_R_REGISTER | reg;

    NRF24_CSN_LOW;
    nRF24_SendSpi(&reg, 1);
    nRF24_ReadSpi(&result, 1);
    NRF24_CSN_HIGH;

    return result;
}

为什么我们必须先发送一些信息然后阅读?

SPI slave不产生时钟信号,只有master。所以 Slave 传输任何东西都需要来自 Master 的时钟信号。这就是为什么主机必须发送虚拟数据来为从机生成时钟信号的原因。

SPI 设备包含一组寄存器。每个寄存器都有一个地址和一个值。寄存器值可以由主机读取and/or写入。 SPI设备需要知道master是哪个寄存器地址reading/writing。所以协议是主机首先写入寄存器地址,然后 reads/writes 寄存器值。有关可用寄存器和 read/write 协议的详细信息,请参阅设备数据表。

在您的第一个示例中,nRF24_SendSpi(tmp, 2); 写入两个字节,首先是寄存器地址,然后是寄存器值。

在您的第二个示例中,nRF24_SendSpi(&reg, 1); 写入一个字节,即寄存器地址。然后nRF24_ReadSpi(&result, 1);读取一个字节,即寄存器值。

如果协议不是从写入寄存器地址开始的,那么 SPI 设备将不知道主机正在尝试访问哪个寄存器read/write。

也许您的问题是关于特定设备的行为而不是一般的 SPI。但是首先回答:

Why do we have to send first some info and then read?

您在这种情况下发送的“信息”是一个命令,指定要读取的寄存器。

SPI 是一个“Master/Slave”通信接口。从属设备无法自行发起通信。 SPI 设备包含一个移位寄存器。在时钟边沿,一位从 MOSI (Master-Out/Slave-In) 移入寄存器,一位从寄存器移出到 MISO (Master-In/Slave-Out)。主机驱动时钟,因此要从设备读取,主机必须将数据输入设备,以便数据[=36] =]从设备输出。这本质上是一个“双工”操作(即数据同时输入和输出。即使你只想读,你也必须写,这通常是通过在 MOSI 上发送“虚拟”数据来完成的。

因此在您的第二个片段中:NRF24_CMD_R_REGISTER | reg 是读取寄存器索引 reg 的命令。数据输出将是发送命令时移位寄存器中的任何内容,因此不会是实际读取的结果,因为尚未收到该命令。当设备接收到完整的命令时,它会将寄存器reg中的值加载到移位寄存器,然后必须通过第二次总线操作将数据读取,这将时钟虚拟数据到 MOSI 以便从 MOSI 检索读取指令的结果。

关于:

How it works, if we are putting to the same frame register(which we are writing to) and data to this register?

在关联片段中,第一个字节包含:NRF24_CMD_W_REGISTER | reg 是一个命令,表示:将以下字节值写入寄存器reg。第二个字节val是要写入reg的数据。当 nRF24_SendSpi(tmp, 2); 调用时,两个字节都通过为 SCLK 线计时 16 次而在 MOSI 上发送。

归因CBurnett from https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#/media/File:SPI_8-bit_circular_transfer.svg