我还在两个STM32H743板之间做SPI实验。
我已经在全双工模式下配置了SPI,启用了CRC,SPI频率为25‘ve(所以从服务器可以不发出任何问题)。
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),我被卡在函数SPI_ReceiveResponseFullDuplex
中的while
中。
是否有必要在两个传输之间禁用SPI,还是在配置中出错?
SPE钻头的行为在参考手册中并不十分清楚。例如,在半双工模式下,为了改变通信方向,必须禁用SPI。但在模糊双工模式下没有什么(或者我错过了)。
发布于 2019-09-13 14:04:08
这个勘误表项目在这里可能是相关的。
主数据传输失速在系统时钟上比SCK快得多 描述 由于系统时钟(spi_pclk)大大快于SCK (spi_ker_ck除以预分频器),SPI/I2S主数据传输可以在一个SCK周期内设置CSTART比特时停止,此时EOT事件(EOT标志提升)发出信号结束前一次传输的信号。 解决方案 采取下列措施之一: ·禁用每个EOT事件后启用SPI/I2S。 ·在EOT事件发生时,在设置CSTART之前至少要等待一个SCK周期。 ·防止EOT事件发生,将传输大小设置为未定义(TSIZE = 0),并仅通过TXFIFO写入触发传输。
您的SCK频率是25 MHz,系统时钟可以是400或480 MHz,16或19倍SCK。删除清除和设置SPE
的行时,只有这些行在检测到EOT
后仍然有效。
*IFCR = 0xFFFFFFFF;
*CR2 = 5;
*CR1 |= SPI_CR1_CSTART;
当这个序列(很可能)花费不到16个时钟周期时,就会出现上面描述的问题。看来有人又在SPI时钟系统做了一次草率的工作。首先,清除和设置SPE
是推荐的解决方法之一。
我会在开始时设置TSIZE=9
,然后一次编写命令和虚拟字节,这在全双工模式下没有什么区别。
请记住,在全双工模式下,另有4个字节必须被读取和丢弃,才能得到真正的答案。这并不是原始代码的问题,因为清除SPE
会丢弃仍在接收FIFO中的数据,但是如果修改后的代码有效,那么它将成为一个问题,例如,在再次启用CSTART
之前还有一些延迟。
https://stackoverflow.com/questions/57919896
复制相似问题