为什么如果我们必须 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(®, 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(®, 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
我有一个关于 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(®, 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(®, 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 上发送。