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

Posted

技术标签:

【中文标题】如何减少 STM32L4 HAL 库的 SPI 开销时间【英文标题】:How to decrease SPI overhead time for STM32L4 HAL library 【发布时间】:2019-03-19 05:31:54 【问题描述】:

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

HAL_SPI_Transmit(&hspi2, &ReadAddr, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi2, pBuffer, 4, HAL_MAX_DELAY);

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

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

【问题讨论】:

停止使用 HAL。 【参考方案1】:

什么对我有用:

    直接读取 SPI 寄存器 优化函数以提高速度

例如函数(代码);查看 ST- 社区中“JElli.1”的解决方案 >> ST Community answer

【讨论】:

【参考方案2】:

您可以使用HAL_SPI_TransmitReceive(&hspi2, ReadAddr, pBuffer, 1 + 4, HAL_MAX_DELAY); 代替HAL_SPI_TransmitHAL_SPI_Receive。这将避免发送和接收之间的时间。 您还可以尝试更改编译设置以优化速度。 您还可以查看加速度计的数据表,可能您可以用一帧读取所有缓冲区,这就是: HAL_SPI_TransmitReceive(&hspi2, ReadAddr, pBuffer, 1 + (4 * numOfSamples), HAL_MAX_DELAY);

【讨论】:

感谢您的建议,我尝试使用HAL_SPI_TransmitReceive(&hspi2, ReadAddr, pBuffer, 1 + 4, HAL_MAX_DELAY);,它的运行速度更快一些。不幸的是,它仍然太慢了。 @awyzlin 您可以更改编译设置以优化速度(-03)。如果加速度计有 FIFO,您可以同时使用和读取 N 个样本,或者您可以更改 HAL 代码以对其进行优化。【参考方案3】:

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

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

没有 HAL,它会简单得多。首先,弄清楚应该进入控制寄存器的内容,相应地设置CR1CR2

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;

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

请注意,全双工 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;
    

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

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

【讨论】:

您可以使用低层 API 代替 HAL。样板代码要少得多。 哪些功能不太适合SPI。高速的 SPI 需要 DMA 确实高效,没有其他办法。 您好,非常感谢您的提示!我在嵌入式编程方面没有太多经验。我将尝试自己编写这段代码,但如果有人分享一个现成的代码示例,它可以显着加快我的工作。你能给我举个 LL API 或 DMA 的例子吗? DMA 可以加快长 SPI 事务的传输。您的交易只有五个字节。我怀疑您可以通过 DMA 传输获得任何好处。 @awyzlin 在 DMA 请求映射表中查找流和通道号(用于发送和接收),设置除CCR 之外的 DMA 通道寄存器,然后按照 参考手册的SPI功能描述/数据传输和接收过程/使用DMA进行通信部分。

以上是关于如何减少 STM32L4 HAL 库的 SPI 开销时间的主要内容,如果未能解决你的问题,请参考以下文章

关于 STM32 HAL 质量和性能 [关闭]

如何使用 STM32 HAL_CAN 库生成格式正确的 TX CAN 帧?

stm32系列单片机都有哪些外设接口模块

STM32 HAL_CRC 16 位

如何使用STM32 HAL库驱动TFT-LCD实现手画板功能

STM32L4RGT6燒写