我使用的是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函数的指针来解决此问题?
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;
}
此初始化假定Slave Select(NSS
或CS#
)由单独的GPIO引脚处理。如果您希望SPI外设管理CS#
,请在参考手册中查找从机选择(NSS)引脚管理。
请注意,全双工SPI连接不能只发送或接收,它始终同时进行。如果从器件需要一个命令字节,并且响应四个字节的数据,即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,交错写入和读取,可以在需要时进一步优化它,以便发送器始终保持忙碌状态。
如果速度至关重要,请不要使用通用函数,或确保在执行时可以内联。使用启用了链接时优化的编译器,并优化速度(非常明显)。
您可以使用HAL_SPI_TransmitReceive(&hspi2, ReadAddr, pBuffer, 1 + 4, HAL_MAX_DELAY);
而不是HAL_SPI_Transmit
和HAL_SPI_Receive
。这将避免发送和接收之间的时间。您还可以尝试更改编辑设置以优化速度。你也可以查看加速度计的数据表,也许你可以用一个框架读取所有的缓冲区,这就是这样的:HAL_SPI_TransmitReceive(&hspi2, ReadAddr, pBuffer, 1 + (4 * numOfSamples), HAL_MAX_DELAY);