SPI是一种非常简单易用的全双工主从式通信协议。
本文使用两片STM32F429,一个作为主机,一个作为从机完成SPI的全双工通信测试。
在STM32的HAL库中简化了SPI主机端的发送接收,但是HAL库没有提供一个简单的SPI从机代码接口,这样就需要自己拼接接口来完成全双工的通信。以下都以实现全双工通信为目的进行配置和编写:
禁止使用SPI的硬件片选信号,因为这个信号是SPI使能了之后就一直为低,直到禁止了SPI之后才为高。可以使用某一个普通IO来充当片选信号。
这里选用一个较低的速率来通信,在HAL库的spi头文件中有说明各个模式下SPI的最大速度。
主从的速率要一样,从机打开SPI中断
主机 从机
CS CS
CLK CLK
MISO MISO
MOSI MOSI
接收和发送都是直连不需要交叉。
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, txbuf, rxbuf, 1, 0xFF);
HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);
HAL_Delay(500);
}
/* USER CODE END 3 */
现在while之前打开spi接收中断:
/* USER CODE BEGIN 2 */
HAL_SPI_Receive_IT(&hspi1, rxbuf, 1);
/* USER CODE END 2 */
在中断中使用阻塞函数把数据发送出去:
/* USER CODE BEGIN 4 */
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi == &hspi1)
{
HAL_SPI_Transmit(&hspi1, txbuf, 1, 0xFFFF);
HAL_SPI_Receive_IT(&hspi1, rxbuf, 1);
}
}
/* USER CODE END 4 */
使用逻辑分析仪可以看到主机在发送的同时也收到了从机返回的数据。
可能在中断里调用阻塞发送不是很好,如果有更好的方法欢迎指正。
另外在一片stm32上使用两个SPI接口模拟主从机通信好像不能正常工作。
------------------------------------------------20181212------------------------------------------------
最后需要注意的是如果你使用了以上方法,能测试spi通信成功,但是当主程序有其他任务的时候就会非常卡顿,因为在中断中调用了阻塞发送的函数。为了让程序更加流畅一种方法是减小HAL_SPI_Transmit的等待时间,另外一种方法就是使用DMA.
因为这里我只需要用DMA回复SPI master数据,所以我只开启了从机的SPI发送DMA,而且没有使能DMA中断。配置如下图:
将spi.c中的代码更改如下:
/* USER CODE BEGIN 1 */
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi == &hspi1)
{
HAL_SPI_Transmit_DMA(&hspi1, p_phase_buf, 1);
//HAL_SPI_Transmit(&hspi1, p_phase_buf, 1, 0xFFF);
HAL_SPI_Receive_IT(&hspi1, p_pwm_freq, 1);
}
}
/* USER CODE END 1 */
添加DMA就是这么简单,由此就看到HAL库高效的地方了,使用起来确实能大幅提高工作效率
------------------------------------------------20181213------------------------------------------------
测试使用DMA发送还是巨卡,放弃spi通信改用串口通信。