STM32F407 SPI带CRC与DMA传输:如何检测CRC传输结束?
STM32F407 SPI CRC传输后NSS释放的解决方案
针对你遇到的CRC传输完成后无法触发NSS拉高的问题,核心是利用SPI内置的状态标志和中断机制精准判断CRC传输结束时机,以下是具体实现方法:
关键触发信号与判断逻辑
CRC传输完成的核心标志是SPI状态寄存器(SPI_SR)中的RXNE(接收缓冲区非空)位,结合CRCERR(CRC错误)位可同时完成校验结果判断。当DMA完成数据传输后启动CRC交互,待对方的CRC值被接收后,RXNE会自动置位,此时即可安全拉高NSS。
配置与执行流程
预配置SPI寄存器
- 确保
SPI_CR1.CRCEN位置1,开启CRC功能; - 开启SPI的
RXNE中断(SPI_CR2.RXNEIE置1),确保CRC接收完成后能触发中断。
- 确保
DMA+SPI中断协同处理
- DMA数据传输完成触发DMA中断:在中断函数中置位
SPI_CR1.CRCNEXT,启动CRC传输,保持NSS低电平; - SPI中断响应
RXNE事件:- 读取
SPI_DR获取对方发送的CRC值; - 检查
SPI_SR.CRCERR位判断校验是否通过; - 确认后操作GPIO拉高NSS;
- 清除
CRCERR标志(通过向SPI_SR对应位写入0)。
- 读取
- DMA数据传输完成触发DMA中断:在中断函数中置位
寄存器级代码示例
// DMA传输完成中断服务函数(以SPI1_TX_DMA为例) void DMA2_Stream3_IRQHandler(void) { // 清除DMA传输完成标志 DMA2->IFCR |= DMA_IFCR_CTCIF3; // 启动CRC传输 SPI1->CR1 |= SPI_CR1_CRCNEXT; } // SPI1中断服务函数 void SPI1_IRQHandler(void) { if (SPI1->SR & SPI_SR_RXNE) { // 读取接收的CRC值 uint16_t received_crc = SPI1->DR; // 处理CRC校验结果 if (SPI1->SR & SPI_SR_CRCERR) { // CRC校验失败,执行错误处理 } else { // CRC校验通过,拉高NSS引脚(假设NSS接PA4) GPIOA->BSRR = GPIO_BSRR_BS4; } // 清除CRC错误标志 SPI1->SR &= ~SPI_SR_CRCERR; } }
注意事项
- 调整中断优先级:确保SPI中断优先级高于DMA中断,避免CRC传输启动后无法及时响应
RXNE中断; - 从机端逻辑:若从机需参与NSS控制,需在自身
TXE(CRC已发送)和RXNE(主机CRC已接收)均置位后再处理NSS; - 时序匹配:严格遵循RM0090中CRC传输的时序要求,NSS低电平需覆盖数据传输、CRC发送、CRC接收的全流程,直到
RXNE置位后再释放。
内容的提问来源于stack exchange,提问作者user1771706
相关产品推荐
相关产品推荐

