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

时间:2019-09-13 08:25:42

标签: stm32 spi

我仍在两块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才能更改通信方向。但是在双工模式下什么都没有(或者我错过了)。

1 个答案:

答案 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之前会有更多延迟