如何减少STM32L4 HAL库的SPI开销时间 [英] How to decrease SPI overhead time for STM32L4 HAL library

查看:945
本文介绍了如何减少STM32L4 HAL库的SPI开销时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using a STM32L476RG board and HAL SPI functions:

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

我需要以最快的速度从加速度计的缓冲区接收数据,但这些功能存在延迟问题。如您在示波器屏幕截图中所见,在几微秒内什么都没有发生。我不知道如何最小化传输间隙。

I need to receive data from accelerometer's buffer with maximum speed and I have a problem with delay in these functions. As you can see on the oscilloscope screenshots, there are several microseconds during which nothing happens. I have no idea how to minimize the transmission gap.

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

I tried using HAL_SPI_Receive_DMA function and this delay was even bigger. Do you have any idea how to solve this problem using HAL functions or any pointers on how I could write my SPI function without these delays?

推荐答案

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

TL;DR Don't use HAL, write your transfer functions using the Reference Manual.

对于时间紧迫的任务(尤其是HAL),HAL毫无希望地过于复杂。只需查看 HAL_SPI_Transmit()函数,它需要60多行代码,直到可以真正接触到数据寄存器为止。即使没有多任务操作系统,HAL也会首先将端口访问结构标记为忙,验证功能参数,将其存储在 hspi 结构中,而没有明显的原因,然后继续找出SPI处于哪种模式,等等。也不必在SPI主模式下检查超时,因为主控制所有总线时序,如果在有限的时间内不能输出一个字节,则该端口

HAL is hopelessly overcomplicated for time-critical tasks (among others). Just look at the HAL_SPI_Transmit() function, it's over 60 lines of code till it gets to actually touching the Data Register. HAL will first mark the port access structure as busy even when there is no multitasking OS in sight, validates the function parameters, stores them in the hspi structure for no apparent reason, then goes on figuring out what mode SPI is in, etc. It's not necessary to check timeouts in SPI master mode either, because master controls all bus timings, if it can't get out a byte in a finite amount of time, then the port initialization is wrong, period.

没有HAL,它要简单得多。首先,弄清楚应放入控制寄存器中的内容,并分别设置 CR1 CR2

Without HAL, it's a lot simpler. First, figure out what should go into the control registers, set CR1 and CR2 accordingly.

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;
}

此初始化假定从属选择( NSS CS#)由单独的GPIO引脚处理。如果要通过SPI外设管理 CS#,请在《参考手册》中查找从站选择(NSS)引脚管理

This initialization assumes that Slave Select (NSS or CS#) is handled by separate GPIO pins. If you want CS# managed by the SPI peripheral, then look up Slave select (NSS) pin management in the Reference Manual.

请注意,全双工SPI连接不仅可以发送或接收,而且总是同时进行。如果从站期望一个命令字节,并回答四个字节的数据,即5字节传输,则从站将忽略最后4个字节,而主站则应忽略第一个字节。

Note that a full duplex SPI connection can not just transmit or receive, it always does both simultaneously. If the slave expects one command byte, and answers with four bytes of data, that's a 5-byte transfer, the slave will ignore the last 4 bytes, the master should ignore the first one.

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

A very simple transfer function would be

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;
    }
}

可以在需要时通过使用进行进一步优化

It can be further optimized when needed, by making use of the SPI fifo, interleaving writes and reads so that the transmitter is always kept busy.

如果速度很关键,请不要使用通用函数,或确保它们可以进行读写操作,以使发送器始终处于繁忙状态。在执行操作时内联。使用启用了链接时优化的编译器,并进行速度优化(很明显)。

If speed is critical, don't use generalized functions, or make sure they can be inlined when you do. Use a compiler with link-time optimization enabled, and optimize for speed (quite obviously).

这篇关于如何减少STM32L4 HAL库的SPI开销时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆