在两次传输之间禁用 STM32H7 上的 SPI 外设?

Disabling SPI peripheral on STM32H7 between two transmissions?

我还在做两块 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 位)并且我卡在 while 中的函数 SPI_ReceiveResponseFullDuplex 中.

是否有必要在两次传输之间禁用 SPI 还是我配置有误?

参考手册中SPE位的行为不是很清楚。例如,是否清楚地写明,在半双工模式下,必须禁用 SPI 才能更改通信方向。但是在全双工模式下什么都没有(或者我错过了)。

此勘误表项目可能与此处相关。

Master data transfer stall at system clock much faster than SCK

Description

With the system clock (spi_pclk) substantially faster than SCK (spi_ker_ck divided by a prescaler), SPI/I2S master data transfer can stall upon setting the CSTART bit within one SCK cycle after the EOT event (EOT flag raise) signaling the end of the previous transfer.

Workaround

Apply one of the following measures:

• Disable then enable SPI/I2S after each EOT event.

• Upon EOT event, wait for at least one SCK cycle before setting CSTART.

• Prevent EOT events from occurring, by setting transfer size to undefined (TSIZE = 0) and by triggering transmission exclusively by TXFIFO writes.

你的SCK频率是25MHz,系统时钟可以是400或者480MHz,是SCK的16或者19倍。当您删除清除和设置SPE行时,只有这些行在检测到EOT

后仍然有效
*IFCR = 0xFFFFFFFF;
*CR2 = 5;
*CR1 |= SPI_CR1_CSTART;

当这个序列(很可能)花费少于16个时钟周期时,就会出现上述问题。看起来有人在 SPI 时钟系统上又做了一个草率的工作。您首先执行的操作是清除和设置 SPE 是推荐的解决方法之一。

我会在开始时设置TSIZE=9,然后一次写入命令和虚拟字节,在全双工模式下没有区别。

请记住,在全双工模式下,还会收到另外 4 个字节,在获得真正的答案之前必须读取并丢弃这些字节。这不是您原始代码的问题,因为清除 SPE 会丢弃仍在接收 FIFO 中的数据,但如果修改后的代码有效,它会变成一个,例如,在再次启用 CSTART 之前会有更多延迟.