在开发一款智能化仪器时,需定时采集数据,并同时进行数据分析、储存和远距离光纤传送。因此选用了带有浮点运算功能的STM32F407高性能 MCU。也移植了许多STM32F4的标准例程。程序编译仿真等一切顺利。但试运行时不定时死机,多则几天,少则几小时,毫无规律。
死机的原因很多,如环境干扰;电路板设计不合理产生自激;中断冲突;中断程序中没有清除中断标志位;地址溢出;堆栈溢出;无条件的死循环等等。
因是试机时死机,所以首先考虑环境干扰问题,经屏蔽隔离,消除环境干扰后,故障依旧,机外因素排除。
认真检查了各中断优先等级,设置的中断时刻,中断服务函数等均无任何冲突。仿真检查也无异常。折腾了一天,程序梳理了几遍,也没发现蛛丝马迹,但故障依旧。
无奈之际,利用逐一停用程序模块的方法发现了问题,当停用sd卡模块后不再死机。可以断定问题出在SD卡模块上,但是SD卡模块程序是移植的标准例程,不会是标准例程有问题吧!
于是对sdio_sdcard.c文件逐句分析。在SD_Error SD_SelectDeselect(u32 addr)函数中发现如下加黑的语句:
while(SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)
{
*tempbuff=SDIO->FIFO;
tempbuff++;
}
INTX_ENABLE();
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
}else if(DeviceMode==SD_DMA_MODE)
{
TransferError=SD_OK;
StopCondition=0;
TransferEnd=0;
SDIO->MASK|=(1<<1)|(1<<3)|(1<<8)|(1<<5)|(1<<9);
SDIO->DCTRL|=1<<3;
SD_DMA_Config((u32*)buf,blksize,DMA_DIR_PeripheralToMemory);
while(((DMA2->LISR&(1<<27))==RESET)&&(TransferEnd==0)&&(TransferError==SD_OK)&&timeout)timeout--;
if(timeout==0)return SD_DATA_TIMEOUT;
if(TransferError!=SD_OK)errorstatus=TransferError;
}
return errorstatus;
}
汇编语言中
CPSID I PRIMASK=1 是关闭中断
CPSIE I PRIMASK=0 是开启中断
INTX_ENABLE()是在sys.h中用汇编语言定义的开启所有中断函数;
即:
_asm void INTX_ENABLE(void)
{
CPSIE I
BX LR
}
INTX_DISABLE()是在sys.h中用汇编语言定义的关闭所有中断函数;
即:
__asm void INTX_DISABLE(void)
{
CPSID I
BX LR
}
指令“CPSID I和CPSIE I”都是对状态寄存器CPSR中中断标志位进行操作,只是简单的不让CPU响应中断,并没有阻止中断的发生,也没有清除中断标志。
SDIO_ClearFlag(SDIO_STATIC_FLAGS)是在STM32f4xx_sdio.c 中定义的,是清除SDIO 挂起标志库函数。
至此不定时死机的机理就真相真相大白了:由于采集的数据各不相同,处理这些数据的耗时也不相同,处理数据后产生的中断时间也就不固定。虽然在程序编制时精心安排了各中断的优先等级,某些外设中断还会提前或延时到CF卡的读写时间段内。因在sdio_sdcard.c函数中,多次使用了INTX_DISABLE()与INTX_ENABLE()函数关闭和开启中断。由于这些函数没有阻止中断的发生,中断发生时同样会产生中断标志,只是暂时停止中断的执行。当开启所有中断时,就有可能出现多个中断标志,使中断发生冲突,这必定会引起死机。
解决办法是注销掉sdio_sdcard.c文件所有INTX_DISABLE()和INTX_ENABLE()函数,把cf卡的读写操作放入一个中断服务函数中,并把该中断设为最高等级,退出中断服务函数前,先清除所有中断标志。经此处理后再也没出现过死机。
|