文章目录
- 前言
- CubeMX设置
- SPI设置
- NSS设置
- SPI从机代码
- SPI主机代码
前言
关于如何简单的写一个稳定的SPI主从机通讯,思路很简单
1、SPI高速传输的时候很容易出现错位之类的问题,CRC的校验首先是必要的。在STM32中SPI使用DMA通讯可以自动执行CRC的校验,只需要在CubeMX设置SPI的CRC和DMA
2、从机的NSS用硬件模式不是很好用,使用外部中断可以提供更多灵活的编写方式
3、有个很坑的点,如果中间出现断连等问题,很容易出现数据错位,而且错了一次会一直错下去,所以检测到CRC错误后要自己将SPI模块的时钟重置
CubeMX设置
SPI设置
我选的16bit传输,具体可以根据自己的硬件需求再改
NSS设置
选一个引脚做外部中断触发,上下沿都要
注意这个代码生成后要手动在gpio.c文件中把HAL_NVIC_EnableIRQ(XXX);给屏蔽掉,不然刚开机这个端口就开始跳中断,提前跑了一些不该跑的,会出一些比较操蛋的错误
SPI从机代码
放在哪里都行
//下降沿触发接收分析,校验数据是否正确
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)//虚函数定义,HAL库会自动调用过来
{if(GPIO_Pin == SPI1_NSS_Pin){if((HAL_SPI_GetState(&hspi1) == HAL_SPI_STATE_READY) && HAL_SPI_GetError(&hspi1) == HAL_SPI_ERROR_NONE){//数据正确,执行数据搬运}else//数据错误,重置SPI时钟{HAL_NVIC_DisableIRQ(EXTI4_15_IRQn);//注意改成自己的触发源HAL_SPI_DMAStop(&hspi1);__HAL_RCC_SPI1_FORCE_RESET();__HAL_RCC_SPI1_RELEASE_RESET();//HAL_SPI_DeInit(&hspi1);HAL_SPI_Init(&hspi1);HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);}}
}
//上降沿触发准备接收
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == SPI1_NSS_Pin){HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t*)spi1_tx_buf, (uint8_t*)spi1_rx_buf, 4);//1-2us}
}
SPI主机代码
主机直接定时跑就够了
HAL_GPIO_WritePin(GPIOX, GPIO_PIN_X, GPIO_PIN_RESET);
HAL_Delay(1);
HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t*)spi1_tx_buf, (uint8_t*)spi1_rx_buf, 4);
HAL_GPIO_WritePin(GPIOX, GPIO_PIN_X, GPIO_PIN_SET);
CRC校验会自动在DMA传输完后自动再传输