我正在使用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函数的任何指针?
答案 0 :(得分:2)
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;
}
此初始化假定从设备选择(NSS
或CS#
)由单独的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;
}
}
可以在需要时通过使用SPI fifo进一步优化它,对写入和读取进行交织,从而使发送器始终保持忙碌状态。
如果速度至关重要,请不要使用通用函数,或确保在使用时可以内联它们。使用启用了链接时优化的编译器,并进行速度优化(显然是很不错的。)。
答案 1 :(得分:2)
您可以使用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);
答案 2 :(得分:0)