在两次传输之间禁用STM32H7上的SPI外围设备?
我还在两块核子STM32H743板之间做SPI实验 我已经在全双工模式下配置了SPI,启用了CRC,SPI频率为25MHz(因此从机可以无问题传输) DSIZE为8位,FIFO阈值为4 在主机端,我发送4个字节,然后等待从机发送5个字节。我知道我可以使用半双工或单工模式,但我想了解全双工模式下的情况在两次传输之间禁用STM32H7上的SPI外围设备?,stm32,spi,Stm32,Spi,我还在两块核子STM32H743板之间做SPI实验 我已经在全双工模式下配置了SPI,启用了CRC,SPI频率为25MHz(因此从机可以无问题传输) DSIZE为8位,FIFO阈值为4 在主机端,我发送4个字节,然后等待从机发送5个字节。我知道我可以使用半双工或单工模式,但我想了解全双工模式下的情况 volatile unsigned long *CR1 = (unsigned long *)0x40013000; volatile unsigned long *CR2 = (unsigned
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),我在的中陷入了函数SPI\u receiveresponseSelectalDuplex
是否有必要在两次传输之间禁用SPI,或者我在配置中犯了错误
SPE bit的行为在参考手册中不是很清楚。例如,在半双工模式下,必须禁用SPI以改变通信方向,这一点是否写得很清楚。但在fuill双工模式下没有任何内容(或者我错过了)。此勘误表项目可能与此相关
主数据传输在系统时钟时暂停,比SCK快得多
描述
由于系统时钟(spi_pclk)大大快于SCK(spi_ker_ck除以预分频器),在EOT事件(EOT标志升高)发出前一次传输结束信号后的一个SCK周期内设置CSTART位时,spi/I2S主数据传输可能会暂停
解决方法
采用以下措施之一:
•在每次EOT事件后禁用然后启用SPI/I2S
•在EOT事件发生时,在设置CSTART之前至少等待一个SCK循环
•通过将传输大小设置为未定义(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
,然后一次性写入命令和伪字节,在全双工模式下没有任何区别
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;
}
请记住,在全双工模式下,会收到另外4个字节,在得到真正的答案之前,必须读取并丢弃这些字节。这不是您原始代码的问题,因为清除SPE
会丢弃仍在接收FIFO中的数据,但如果修改后的代码起作用,它将变成一个数据,例如再次启用CSTART
之前还有一些延迟。非常有用,谢谢!关于你最后的评论,我认为分两步进行传输是有区别的:我的目标是首先发送一个包含CRC的命令,从机可以检查,然后响应,如果CRC错误,可能会使用错误代码。如果设置TSIZE=9,则末尾只有一个CRC。关于我必须在全双工模式下“刷新”4个虚拟字节这一事实的评论很好。对,我忘记了CRC。为了记录,我在3种模式(全双工、半双工和单工)下进行了一些时间测量,结果非常接近,但在全双工模式下速度稍快,尽管如此,我不必写入TX FIFO以在hald双工或单工模式下接收响应。我认为这是因为在切换方向时,外围设备必须进行一些内部重新配置。