我仍在两块Nucleo STM32H743板之间进行SPI实验。
我已将SPI配置为全双工模式,并且启用了CRC,且SPI频率为25MHz(因此从设备可以毫无问题地进行发送)。
DSIZE为8位,FIFO阈值为4。
在主设备端,我要发送4个字节,然后等待从设备中的5个字节。我知道我可以使用半双工或单工模式,但是我想了解全双工模式下的情况。
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;
unsigned long SPI_TransmitCommandFullDuplex(uint32_t Data)
{
// size of transfer (TSIZE)
*CR2 = 4;
/* Enable SPI peripheral */
*CR1 |= SPI_CR1_SPE;
/* Master transfer start */
*CR1 |= SPI_CR1_CSTART;
*TXDR = Data;
while ( ((*SR) & SPI_FLAG_EOT) == 0 );
// clear flags
*IFCR = 0xFFFFFFFF;
// disable SPI
*CR1 &= ~SPI_CR1_SPE;
return 0;
}
void SPI_ReceiveResponseFullDuplex(uint8_t *pData)
{
unsigned long temp;
// size of transfer (TSIZE)
*CR2 = 5;
/* Enable SPI peripheral */
*CR1 |= SPI_CR1_SPE;
/* Master transfer start */
*CR1 |= SPI_CR1_CSTART;
*TXDR = 0;
*((volatile uint8_t *)TXDR) = 0;
while ( ((*SR) & SPI_FLAG_EOT) == 0 );
*((uint32_t *)pData) = *RXDR;
*((uint8_t *)(pData+4)) = *((volatile uint8_t *)RXDR);
// clear flags
*IFCR = 0xFFFFFFFF;
// disable SPI
*CR1 &= ~SPI_CR1_SPE;
return temp;
}
这很好用(这两个函数只是在main
中依次调用)。
然后,我尝试删除两个步骤之间的SPI禁用功能(即,我没有清除并再次将SPE位置1),然后卡在SPI_ReceiveResponseFullDuplex
中的函数while
中。 / p>
是否有必要在两次传输之间禁用SPI,或者我在配置中出错了?
在参考手册中,SPE位的行为不是很清楚。例如,是否清楚地写到,在半双工模式下,必须禁用SPI才能更改通信方向。但是在双工模式下什么都没有(或者我错过了)。
答案 0 :(得分:1)
此勘误项可能与此处相关。
主数据传输在系统时钟处停顿的时间比SCK快得多
说明
由于系统时钟(spi_pclk)的速度明显快于SCK(spi_ker_ck除以预分频器),因此SPI / I2S主数据传输会在EOT事件(EOT标志上升)发出信号后,在一个SCK周期内将CSTART位置1,从而使传输停止。上次传输结束。
解决方法
应用以下措施之一:
•在每个EOT事件发生后禁用然后启用SPI / I2S。
•在发生EOT事件时,至少等待一个SCK周期,然后再设置CSTART。
•通过将传输大小设置为undefined(TSIZE = 0)来防止EOT事件发生 并通过TXFIFO写操作专门触发传输。
您的SCK频率为25 MHz,系统时钟可以为400或480MHz,是SCK的16或19倍。当您删除清除并设置SPE
的行时,只有在检测到EOT
*IFCR = 0xFFFFFFFF;
*CR2 = 5;
*CR1 |= SPI_CR1_CSTART;
当此序列(可能很多)少于16个时钟周期时,则存在上述问题。似乎有人再次在SPI时钟系统上进行了草率的工作。您首先要做的是清除并设置SPE
是推荐的解决方法之一。
我只需要在开始时设置TSIZE=9
,然后一次性写入命令和虚拟字节,这在全双工模式下没有区别。
请记住,在全双工模式下,必须先接收另外4个字节,然后才能读取并丢弃真正的答案。这不是您的原始代码的问题,因为清除SPE
会丢弃仍保留在接收FIFO中的数据,但是如果修改后的代码有效,它将变为1,例如,再次启用CSTART
之前会有更多延迟