我正在两个Nucleo STM32H743板之间实现SPI通信。
我已将SPI配置为全双工模式,并且已启用CRC,且最大SPI频率(SCK频率为100MHz)。
只要我只进行从主方发送和从从方接收的接收,就可以正常工作。
这是我用来从主机发送和从机接收的代码。请注意,我知道它是快速又肮脏的代码,它仅是概念证明,因此请不要注释编码风格(我知道,硬编码值,寄存器指针等)。出于记录目的,我还使用了具有相同行为的STMicro HAL函数HAL_SPI_Transmit
和HAL_SPI_Receive
。
volatile unsigned long *CR1 = (unsigned long *)0x40013000;
volatile unsigned long *CR2 = (unsigned long *)0x40013004;
volatile unsigned long *TXDR = (unsigned long *)0x40013020;
volatile unsigned long *RXDR = (unsigned long *)0x40013030;
volatile unsigned long *SR = (unsigned long *)0x40013014;
volatile unsigned long *IFCR = (unsigned long *)0x40013018;
volatile unsigned long *TXCRC = (unsigned long *)0x40013044;
volatile unsigned long *RXCRC = (unsigned long *)0x40013048;
volatile unsigned long *CFG2 = (unsigned long *)0x4001300C;
void HAL_SPI_TransmitRegister(uint32_t Data, uint32_t Dummy)
{
// size of transfer (TSIZE)
*CR2 = 2;
// Enable SPI peripheral
*CR1 |= 1;
// Master transfer start
*CR1 |= SPI_CR1_CSTART;
// Fill the FIFO
*TXDR = Data;
*TXDR = Dummy;
while ( ((*SR) & SPI_FLAG_EOT) == 0 );
// clear flags
*IFCR = 0xFFFFFFFF;
// disable SPI
*CR1 &= ~1;
}
void HAL_SPI_ReceiveRegister(uint32_t *pData)
{
// two 32 bits words to be received
*CR2 = 2;
// Enable SPI peripheral
*CR1 |= 1;
while ( ((*SR) & (SPI_FLAG_EOT | SPI_FLAG_RXWNE)) == 0 );
*(pData) = (*RXDR);
while ( ((*SR) & (SPI_FLAG_EOT | SPI_FLAG_RXWNE)) == 0 );
*(pData+1) = (*RXDR);
// clear flags
*IFCR = 0xFFFFFFFF;
// disable SPI
*CR1 &= ~1;
}
所以上面的代码工作正常。现在,这开始变得有趣起来:我想从奴隶那里传递一些东西。我对代码进行了如下修改(也尝试了具有相同行为的功能HAL_SPI_TransmitReceive
):
void HAL_SPI_ReceiveRegister(uint32_t *pData)
{
unsigned long response = 0xABCDEF99;
*CR2 = 2;
/* Enable SPI peripheral */
*CR1 |= 1;
// write response in advance
*TXDR = 0;
*TXDR = response;
// first 4 bytes are the command
while ( ((*SR) & (SPI_FLAG_EOT | SPI_FLAG_RXWNE)) == 0 );
*(pData) = (*RXDR);
// next 4 bytes are the dummy bytes used to send response
while ( ((*SR) & (SPI_FLAG_EOT | SPI_FLAG_RXWNE)) == 0 );
*(pData+1) = (*RXDR);
// clear flags
*IFCR = 0xFFFFFFFF;
// disable SPI
*CR1 &= ~1;
}
主人收到废话,但奴隶收到正确的数据。
现在,STM32H7x3的数据表中确实提到了从模式下SPI的局限性,但我不明白“从模式发送器”的含义:
我的问题是:
数据表“从模式发送器”是什么意思?
我不明白为什么从站能够以100Mhz的速度接收但不能发送,因为通信是全双工的。
答案 0 :(得分:2)
如果数据仅是单向传输,则SPI不必是全双工的。
当只有主设备正在发送给从设备,而从设备没有要发送的数据时,软件不会在发送数据寄存器中写入任何内容,因此仍然有东西发送出去,因为根据定义,当 master 脉冲时钟线时,输出位是MISO线上的任何东西。 SPI从设备无法像I 2 C从设备那样延长时钟,当时钟脉冲到达时,数据必须准备发送。当发送寄存器为空时,SPI控制器可能发送全0,全1,最后一个字节重复发送,或者只是发送垃圾邮件。
可以将STM32H7 SPI控制器配置为执行以上任何一项(或更多操作),也可以将其配置为仅接收从设备,并使用MASTER=0
和{{1 }}在COMM[1:0]=10
中,那么它将不会在MISO上输出任何内容,除非重新分配给其他外围功能,否则该引脚将处于悬空状态。
相反,如果从设备在时钟脉冲时不关心主设备正在发送的内容,则可以将其配置为仅发送从设备,而忽略MOSI。在这种情况下,当没有人读取接收数据寄存器时,控制器既不会产生接收中断,也不会产生溢出错误。
作为SPI从设备,作为主设备要复杂得多
因为从站有两个时钟要坚持。来自主机的外部时钟控制发送和接收移位器,以及用于访问寄存器的内部总线时钟。确保跨这些时钟域的数据完整性,即没有中途写入的数据从一个内部寄存器传输到另一个内部寄存器并不是一件容易的事。 这就是为什么主模式和从模式有不同的限制。
发送和接收移位器不相同。
他们有不同的任务要做,一个将数据移出,另一个将数据移入。可能有可能一次实现同时使用同一组触发器的两个操作,但是双重操作可能会变得太复杂上面的时钟要求,所以有两个。 ST的工程师发现其中一个移位器在29-31 MHz以上不能可靠工作。只有他们才能知道这是一个意料之外的限制,还是这样做更简单(即更便宜),而且他们中没有一个大客户真正想要此功能(即愿意为此多付0.0003美元)。