项目场景:
在炮台机器人项目中使用S3C244的IIC外设通讯时,频繁出现IIC挂死问题
问题描述:
在炮台机器人项目中使用S3C244的IIC外设中断方式通讯时,频繁出现IIC挂死问题,而且IIC数据线和时钟线都为零。IIC数据线和始终线都挂死的情况和以往不同。
IIC中断服务函数:
void Iic_ISP(void)
{
static U8 RxData;
U8 buf;
U8 iicstate=rIICSTAT;
OSIntEnter(); //进入中断服务函数,记录嵌套深度
buf=rIICDS;//读取iic数据寄存器以清除中断
switch(iicstate) //0x34->0x30->0x74->0x71
{
case 0x30:
RxData=buf;
OSMboxPost(IicBox,&RxData);
break;
case 0x74:
rIICDS=_iicTxData;
break;
case 0x71:
rIICSTAT&=~0xcf; //rIICSTAT = 0x10;
break;
default:
break;
}
rIICCON=0xaf;
ClearPending(BIT_IIC);
OSIntExit(); //退出中断服务函数,实现“抢占式”任务调度
}
原因分析:
在S3C2440外设中有两个挂起寄存器:中断挂起寄存器(INTPND)和中断源挂起寄存器(SRCPND)。当中断源向CPU申请中断时,SRCPND寄存器的相应位被置1,表明哪个中断源向CPU申请了中断;如果当前优先级与此中断源相等或更高的中断服务在执行,并且改中断位会被响应,INTPND相应位会被置1。因此一旦响应中断,要在中断服务函数中清除上面两个寄存器的置位,清除方法是向对应位写1。清除置位写1的方式和平时位操作置1的方式有所不同。如下是开发板厂家提供的位清除
void __irq Timer0_ISP(void)
{
rSRCPND = rSRCPND | (0x1<<10);
rINTPND = rINTPND | (0x1<<10);
if(direction)
pulse++;
else
pulse--;
}
如下是芯片官方提供的挂起位清除
```c
__inline void ClearPending(int bit)
{
// int i;
rSRCPND = bit;
rINTPND = bit;
// i = rINTPND;
}
对比可以发现,当有一个中断来临时,两段代码无处理无区别。但当有两个以上的中断同时来临时,SRCPND会有两个以上的位被置1,但只有一个中断提前响应,INTPND有1位置1。当提前进入中断服务函数中的那个中断,会做清除挂起位处理。在开发板厂家提供的代码中会将SRCPND的两个以上的中断位清除,那么接下来就不会响应低优先级中断。如果有两个中断,IIC中断来临后,先响应的是另一个中断,则IIC中断就不会响应。
解决方案:
采用芯片厂家提供的代码清除中断位。