如何减少 STM32L4 HAL 库的 SPI 开销时间

awy*_*lin 5 hal accelerometer spi stm32

我正在使用 STM32L476RG 板和 HAL SPI 功能:

HAL_SPI_Transmit(&hspi2, &ReadAddr, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi2, pBuffer, 4, HAL_MAX_DELAY);
Run Code Online (Sandbox Code Playgroud)

我需要以最大速度从加速度计的缓冲区接收数据,但这些功能存在延迟问题。正如您在示波器屏幕截图中看到的那样,有几微秒没有任何反应。我不知道如何最小化传输间隙。

在此处输入图片说明

我尝试使用 HAL_SPI_Receive_DMA 函数,这个延迟更大。您知道如何使用 HAL 函数或有关如何在没有这些延迟的情况下编写 SPI 函数的任何指针来解决此问题吗?

ber*_*ing 5

TL;DR 不要使用 HAL,使用参考手册编写你的传递函数。

HAL 对于时间紧迫的任务(除其他外)来说过于复杂。看看这个HAL_SPI_Transmit()函数,它有 60 多行代码,直到它真正接触到数据寄存器。即使没有多任务操作系统,HAL 也会首先将端口访问结构标记为忙碌,验证函数参数,hspi无缘无故地将它们存储在结构中,然后继续弄清楚 SPI 处于什么模式,等等。它不是在SPI主机模式下也需要检查超时,因为主机控制所有总线时序,如果在有限的时间内不能取出一个字节,那么端口初始化是错误的,周期。

没有HAL,事情就简单多了。首先,弄清楚应该进入控制寄存器的内容,CR1并进行CR2相应的设置。

void SPIx_Init() {
    /* full duplex master, 8 bit transfer, default phase and polarity */
    SPIx->CR1 = SPI_CR1_MSTR | SPI_CR1_SPE | SPI_CR1_SSM | SPI_CR1_SSI;
    /* Disable receive FIFO, it'd complicate things when there is an odd number of bytes to transfer */
    SPIx->CR2 = SPI_CR2_FRXTH;
}
Run Code Online (Sandbox Code Playgroud)

此初始化假定 Slave Select(NSSCS#)由单独的 GPIO 引脚处理。如果您希望CS#由 SPI 外设管理,请在参考手册中查找从设备选择 (NSS) 引脚管理

请注意,全双工 SPI 连接不能只是发送或接收,它总是同时进行。如果从机需要一个命令字节,并以 4 个字节的数据作为应答,即 5 字节传输,从机将忽略最后 4 个字节,主机应忽略第一个。

一个非常简单的传递函数是

void SPIx_Transfer(uint8_t *outp, uint8_t *inp, int count) {
    while(count--) {
        while(!(SPIx->SR & SPI_SR_TXE))
            ;
        *(volatile uint8_t *)&SPIx->DR = *outp++;
        while(!(SPIx->SR & SPI_SR_RXNE))
            ;
        *inp++ = *(volatile uint8_t *)&SPIx->DR;
    }
}
Run Code Online (Sandbox Code Playgroud)

它可以在需要时进一步优化,通过使用 SPI fifo,交错写入和读取,以便发送器始终保持忙碌。

如果速度很重要,请不要使用通用函数,或者确保在使用时可以内联它们。使用启用链接时优化的编译器,并优化速度(很明显)。

  • 您可以使用低层 API 代替 HAL。样板代码少了很多。 (3认同)
  • 其功能不是很适合SPI。更高速度的 SPI 需要 DMA 高效,没有其他方法。 (3认同)
  • DMA 可以加速长 SPI 事务的传输。您的交易只有五个字节。我怀疑您是否可以通过 DMA 传输获得任何收益。 (2认同)