硬件环境:两个CPU通过SPI通信,CPU型号为STM32F429,CPU1使用SPI1发送数据给CPU2的SPI2。
在使用中发现,当SPI速率较快时,使用中断接收会丢数据,因而想到使用DMA方式。但我的接收长度是不定长的,接收长度在18~34个字节,下面是我使用DMA方式接收不定长数据的方法。
1 使用STM32CubeMX配置SPI
1.1CPU1的配置
CPU1用于发送,因而这里设置为:
参数设置:
1.2CPU2的配置
CPU2用于接收,设置为:
参数设置:
DMA设置,使用Circular方式,在程序中只需调用一次HAL_SPI_Receive_DMA()函数:
中断设置:
2 SPI接收不定长数据的方法
2.1CPU2的接收处理
DMA中断有半传输中断(HTIF)和传输完成中断(TCIF),对应的SPI DMA接收的中断回调函数为:
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi);
因为我的接收长度为18~34个字节,因而我设置DMA接收缓存长度为36,如果接收为18字节时,则会发生半传输中断(HTIF),超过18字节时,只需略等一会儿就能接收到完整帧。算一下,5.625Mbps的速率,等待剩下的字节的时间是微秒级的。
我的程序使用了uCos嵌入式系统,在两个中断回调函数中发送信号量,就绪SPI接收任务。
(void)OSTaskSemPost((OS_TCB *)&SPI2_RxTaskTCB,
(OS_OPT )OS_OPT_POST_NONE,
(OS_ERR *)&os_err);
在SPI接收任务中:
#define SPI2_DMABUF_SIZE (36)
static volatile uint8_t s_Spi2RxDMABuf[SPI1_DMABUF_SIZE];
void SPI2_RxPktTask(void *pdata)
{
…
while(HAL_OK != HAL_SPI_Receive_DMA(phspi,(uint8_t*)&s_Spi2RxDMABuf, SPI2_DMABUF_SIZE))
{
OSTimeDlyHMSM(0u, 0u, 0u, 5u,
OS_OPT_TIME_HMSM_STRICT,
&os_err);
}
while(1) {
OSTaskSemPend ( timeout, OS_OPT_PEND_BLOCKING, (void*)0, &os_err);
if( OS_ERR_NONE != os_err)
{
continue;
}
OSTimeDlyHMSM(0u, 0u, 0u, 5u, /*等5ms*/
OS_OPT_TIME_HMSM_STRICT,
&os_err);
/* 根据DMA计数寄存器得到接收到的数据长度 */
rec_len = SPI2_DMABUF_SIZE - (uint8_t) __HAL_DMA_GET_COUNTER(phspi->hdmarx);
/* 缓存s_Spi2RxDMABuf是循环缓存,根据rec_len可以从中读出接收数据 */
} /* end of while(1) */
}