STM32 SPI 在使用中断时丢弃数据
STM32 SPI dropping data while using interrupt
我正在尝试使用中断通过 SPI 发送可变大小的字节数组。该系统由两块nucleo STM32L432板组成。发送板工作正常,但接收板有问题。具体来说,我注意到经常会丢失一些字节。除了 CubeMX 提供的默认初始化之外,我的 init 函数中还有以下设置:
// Trigger RXNE when the FIFO is 1/4 full
LL_SPI_SetRxFIFOThreshold(sw.spi_sw2pc,LL_SPI_RX_FIFO_TH_QUARTER);
// Enable RXNE interrupt
LL_SPI_EnableIT_RXNE(sw.spi_sw2pc);
// Enable SPI
if((SPI3->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
{
// If disabled, I enable it
SET_BIT(sw.spi_sw2pc->CR1, SPI_CR1_SPE);
}
SPI 设置为工作在 10 Mbit/s。会不会是通讯速度太快了?
以下是 IRQ 处理程序和回调。
IRQ 处理程序
void SPI3_IRQHandler(void)
{
/* USER CODE BEGIN SPI3_IRQn 0 */
/* Check RXNE flag value in ISR register */
if(LL_SPI_IsActiveFlag_RXNE(SPI3))
{
/* Call function Slave Reception Callback */
SW_rx_callback();
}
/* USER CODE END SPI3_IRQn 0 */
/* USER CODE BEGIN SPI3_IRQn 1 */
/* USER CODE END SPI3_IRQn 1 */
}
回调
void SW_rx_callback(void)
{
// RXNE flag is cleared by reading data in DR register
while(LL_SPI_IsActiveFlag_RXNE(SPI3))
recv_buffer[recv_buffer_index++] = LL_SPI_ReceiveData8(SPI3);
if(LL_SPI_GetRxFIFOLevel(SPI3) == LL_SPI_RX_FIFO_EMPTY)
{
// If there are no more data
new_data_arrived = true;
memset(recv_buffer,'[=12=]',recv_buffer_index);
recv_buffer_index = 0;
}
}
提前感谢您的帮助。
10 Mbits 的 SPI 意味着每秒将有 125 万次中断(在 8 位传输的情况下),这足以通过中断处理,尤其是与 HAL 结合使用时。
STM32L4xx 速度相当快 (80MHz),但在这种情况下,这意味着每次中断调用的时间不能超过 64 个周期。但是调用中断需要 12 个周期,退出中断需要 10 个周期(它处于理想状态,总线上没有等待状态)所以如果你的中断代码需要 42 个或更多周期那么你可以确定你错过了一些字节。
以下是我的建议:
- 首先尝试启用一些编译器优化,以加速代码。
- 更改中断例程并从中断处理程序中删除所有不必要的内容(使用 SW FIFO 并在主循环中处理接收到的数据)
- 但您的最佳解决方案是使用 DMA 传输。
我正在尝试使用中断通过 SPI 发送可变大小的字节数组。该系统由两块nucleo STM32L432板组成。发送板工作正常,但接收板有问题。具体来说,我注意到经常会丢失一些字节。除了 CubeMX 提供的默认初始化之外,我的 init 函数中还有以下设置:
// Trigger RXNE when the FIFO is 1/4 full
LL_SPI_SetRxFIFOThreshold(sw.spi_sw2pc,LL_SPI_RX_FIFO_TH_QUARTER);
// Enable RXNE interrupt
LL_SPI_EnableIT_RXNE(sw.spi_sw2pc);
// Enable SPI
if((SPI3->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
{
// If disabled, I enable it
SET_BIT(sw.spi_sw2pc->CR1, SPI_CR1_SPE);
}
SPI 设置为工作在 10 Mbit/s。会不会是通讯速度太快了?
以下是 IRQ 处理程序和回调。
IRQ 处理程序
void SPI3_IRQHandler(void)
{
/* USER CODE BEGIN SPI3_IRQn 0 */
/* Check RXNE flag value in ISR register */
if(LL_SPI_IsActiveFlag_RXNE(SPI3))
{
/* Call function Slave Reception Callback */
SW_rx_callback();
}
/* USER CODE END SPI3_IRQn 0 */
/* USER CODE BEGIN SPI3_IRQn 1 */
/* USER CODE END SPI3_IRQn 1 */
}
回调
void SW_rx_callback(void)
{
// RXNE flag is cleared by reading data in DR register
while(LL_SPI_IsActiveFlag_RXNE(SPI3))
recv_buffer[recv_buffer_index++] = LL_SPI_ReceiveData8(SPI3);
if(LL_SPI_GetRxFIFOLevel(SPI3) == LL_SPI_RX_FIFO_EMPTY)
{
// If there are no more data
new_data_arrived = true;
memset(recv_buffer,'[=12=]',recv_buffer_index);
recv_buffer_index = 0;
}
}
提前感谢您的帮助。
10 Mbits 的 SPI 意味着每秒将有 125 万次中断(在 8 位传输的情况下),这足以通过中断处理,尤其是与 HAL 结合使用时。
STM32L4xx 速度相当快 (80MHz),但在这种情况下,这意味着每次中断调用的时间不能超过 64 个周期。但是调用中断需要 12 个周期,退出中断需要 10 个周期(它处于理想状态,总线上没有等待状态)所以如果你的中断代码需要 42 个或更多周期那么你可以确定你错过了一些字节。
以下是我的建议:
- 首先尝试启用一些编译器优化,以加速代码。
- 更改中断例程并从中断处理程序中删除所有不必要的内容(使用 SW FIFO 并在主循环中处理接收到的数据)
- 但您的最佳解决方案是使用 DMA 传输。