AVR SPI_transfer函数仅能正常工作一次,二次调用陷入死循环求助
问题重现
用户提供的SPI传输代码:
u8 SPI_transfer(u8 copy_u8Reciever) { SPDR=copy_u8Reciever; while (GET_BIT(SPSR,7)==0); return SPDR; }
调用该函数仅能成功执行一次,第二次调用时会卡在while (GET_BIT(SPSR,7)==0);循环中,此前代码运行正常,当前出现异常。
可能的原因及解决方法
SPI中断标志未正确清除
若开启了SPI中断(SPIE位被置1),SPIF标志位触发中断后,必须通过先读SPSR再读SPDR的操作清除标志。如果中断服务函数里没做这个操作,第二次传输时SPIF会处于异常状态,导致循环无法退出。检查中断服务函数,确保完成处理后正确清除标志。SPDR寄存器读取被优化或忽略
第一次传输完成后,SPIF标志的清除依赖于对SPDR的读取。如果函数返回的SPDR值没被实际使用,编译器可能会优化掉读取操作,导致SPIF未被清除,第二次传输时硬件不会重新置位SPIF。可以在函数里显式增加读取步骤,或者确保返回值被代码实际调用。硬件连接异常
检查SPI总线的硬件连线:CS片选线是否在两次传输之间正确切换电平?如果CS一直处于选中状态但外设无响应,总线会陷入异常。另外排查SCK、MOSI、MISO的连线是否松动,外设是否掉电或复位异常,这些都会导致第二次传输时外设无回应,SPIF无法置位。外设状态未复位
部分SPI外设单次传输后需要特定操作才能进入下一次传输状态,比如发送复位命令、清空缓冲区。查外设的数据手册,确认是否需要在两次传输之间执行额外的状态恢复操作。SPI时钟超出外设承受范围
如果SCK时钟频率超过外设的最大支持值,第一次传输可能侥幸成功,但第二次外设无法及时响应,导致SPIF无法置位。重新核对SPI时钟分频配置,确保频率在硬件允许范围内。
内容的提问来源于stack exchange,提问作者Omar A. Abdelazim

