【发布时间】:2020-09-27 07:19:53
【问题描述】:
我已经在 SPI 设置上苦苦挣扎了一段时间。
设置如下:
- SPI Slave 是单工模式下的 Nucleo STM32H743,最大时钟(sysclk 400MHz,hclck 200Mhz,APB 时钟 100MHz)
- SPI 主控是另一个相同的 Nucleo,处于单工模式,时钟除以 2:sysclk 200MHz 等...且 spi_ker_clk = 100MHz
- 预分频器为 16 的 SPI 主机,即。时钟 SPI 约为 6MHz。启用 CRC。数据帧 8 位。 FIFO 阈值 4 字节
- SPI 从机:启用 CRC,8 位。 FIFO 阈值 4 字节
没有从机选择信号来控制从机。
这是主人的代码。一切都在轮询中完成,我增加了一些延迟,让奴隶有时间工作。以下函数在循环中被调用,Master 没有做任何其他事情(在我用于调试的这个简化版本中):
uint32_t SPI_EnvoiCommandeTest(void)
{
uint32_t resp;
uint8_t statut;
SPI1->CFG2 |= SPI_CFG2_COMM_0;
SPI1->CFG2 &= ~SPI_CFG2_COMM_1;
SPI1->CR2 = 4;
SPI1->CR1 |= SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_CSTART;
SPI1->TXDR = 0x12345678;
while ( (SPI1->SR & SPI_SR_EOT) == 0 );
if ( (SPI1->SR & SPI_SR_ERR_MASK) != 0 )
{
return ( SPI1->SR & SPI_SR_ERR_MASK);
}
SPI1->IFCR = 0xFFFFFFFF;
SPI1->CR1 &= ~SPI_CR1_SPE;
Delay(1000);
SPI1->CFG2 |= SPI_CFG2_COMM_1;
SPI1->CFG2 &= ~SPI_CFG2_COMM_0;
SPI1->CR2 = 5;
SPI1->CR1 |= SPI_CR1_SPE;
SPI1->CR1 |= SPI_CR1_CSTART;
while ( (SPI1->SR & SPI_SR_EOT) == 0 );
resp = SPI1->RXDR;
statut = *((__IO octet *)&(SPI1->RXDR));
if ( resp != 0x9ABCDEFF)
while(1);
if ( statut != 0x77)
while(1);
while ( (SPI1->SR & SPI_SR_EOT) == 0 );
if ( (SPI1->SR & SPI_SR_ERR_MASK) != 0 )
{
return ( SPI1->SR & SPI_SR_ERR_MASK);
}
SPI1->IFCR = 0xFFFFFFFF;
SPI1->CR1 &= ~SPI_CR1_SPE;
Delay(1000);
return 0;
}
对于从设备,接收由中断处理程序完成。主线程正在等待设置一个标志(由SPI_StopReception() 设置)并发送 5 个字节的应答。
static void SPI_GenericHandler(SpiId_e SpiId)
{
SPI_TypeDef *Spi = SpiMgt[SpiId].SpiInstance;
uint32_t trigger = Spi->IER & Spi->SR;
uint32_t cmd;
uint8_t stat;
if (trigger & SPI_SR_RXP)
{
cmd = Spi->RXDR;
if (cmd != 0x12345678)
while(1);
while((Spi->SR & SPI_SR_EOT) == 0);
if (Spi->SR & SPI_SR_CRCE)
while(1);
SPI_StopReception(SpiId);
}
}
(...)
我的问题如下。
通信正常工作数十万次,然后在从站端失败:我没有从 SPI FIFO 读取字节 78 56 34 12,而是读取例如 34 12 00 00 或 56 34 12 00。
乍一看,人们会说这只是 Slave 太慢并且丢失了一些字节,但奇怪的是:
- 我收到一个 RXP 中断,这意味着从设备在 4 个字节期间正确检测到 SPI 时钟并已对 4 个字节进行采样。
- 没有 CRC 错误,这意味着从站接收到了正确的位。例如,当我从 FIFO 中读取 56 34 12 00 时,RXCRC 为 0x08,这是完整帧 78 56 34 12 的 CRC
好像是读取FIFO有问题。
我使用了逻辑分析仪,没有发现任何电气问题。
在接收错误期间(更准确地说,我在 SPI RXP 中断处理程序中中断)期间在从机端注册值如下。在这种情况下,我读到 34 12 00 00:
- CR1=1 (SPE)
- CR2= 4 (TSIZE)
- CFG1:MBR 0x07,CRCEN,UDRCFG=2,FTHVL=3,DSIZE=7
- CFG2:SSM=1,COMM=2
- IER=1(RXPIE)
- SR=0x0001300A 即。 CTSIZE=1(奇怪但参考手册说“当总线上正在进行流量时,值不太可靠”),RXPLVL=1(??),EOT=1(预期),TXP=1(预期)
- RXCRC=0x08(预期为完整帧)。值得一提的是,调试器 (Keil) 没有正确读取寄存器,我在代码中读取了它。
CTSIZE 和 RXPLVL 的值并不是真正一致的(至少我不明白它们):因为 FTHVL=3 (4-data) 和 TSIZE=4 (在主端相同) ,当我收到 RXP 事件时,我应该至少收到 4 个字节。我看不出 CTSIZE 怎么可能是 1 ,也看不出为什么 FIFO 中还会剩下另一个字节(RXPLVL=1)。
有什么想法或建议吗?
【问题讨论】:
-
比赛条件?服务第一个时,您会受到第二次中断吗?嘿,对于 >1000 的评分,你能用
<!-- language: lang-c -->之类的东西标记你的代码吗? -
没有竞争条件。我对轮询中的两个代码进行了相同的测试,并且没有启用其他中断。
-
不明白您关于评分和标记代码的评论。