S3C6410——同一时刻来两个外部中断会怎么样?

时间:2022-03-24 12:21:03
发现一个很奇怪的问题:
S3C6410+WinCE6.0的系统,两个中断同一时刻来的时候,就出现丢数的现象。
详细情况是这样:做磁卡的驱动,有两个磁道:每个磁道有一个时钟线、一个数据线。
                磁卡驱动原理很简单,当时钟线下降沿触发中断时,就去读数据线上的电平就行。
                现在是:当只有一个磁道(禁止另一个时钟中断信号)时:读数正确;
                        当两个磁道同时打开时,两个磁道读数都错,出现丢数现象,偶尔有读对的时候,用示波器量,发
                        现有两个中断信号有统一时刻来的——很明显,这时候丢数了,只进入了一个ISR,另一个根本
                        没理。
请问,遇到这种情况S3C6410是怎么处理的?它干嘛要丢掉一个中断?另外,它俩在中断向量表VIC0里属于同一个中断源PHYIRQ_EINT1——我用的中断号是EINT10、EINT11.

12 个解决方案

#1


这个肯定是响应优先级高的了。

#2


这个只能增加 isr ist的效率来做。
楼主可以参考我 做外部串口驱动的办法,博客有。
还有这两个中断线程要互斥。

#3


回楼上:
    谢谢googoleman这么快就回复,谢谢!
    但我觉得问题没这么简单:
1、EINT10、EINT11都属于中断向量表VIC1的同一个物理中断PHYIRQ_EINT1,设置优先级只能针对    PHYIRQ_EINT1,所以它俩的优先级肯定一致;
2、因为从ISQ--->ISR--->IST的过程需要花费时间,另外两个IST切换的时间更长(1ms不止)如果我两个ISR分别对应一个IST的话那就更惨了,又因为怕进入IST再去读数据线上的电平就不是1ms以前的了,所以现在读电平的处理我放在了ISR中,只有ISR将所有的数据都处理完了(响应了N个中断),我才通知IST来处理,是通过共享内存来实现的。
3、所以问题应该还不是楼上说的。

#4


我觉得读取电平确实应该放在ISR中,但是读取电平速度很快的,理论上不会影响ISR的效率。并且你不应该让ISR响应N个中断之后才通知ISR,而是响应一个ISR之后立刻通知IST处理。或者引入DMA来读取数据。

#5


这个要学习一下 呵呵

#6


这个和isr里面判断中断源有关.举个例子.
if(int10)
{}
else if(int11)
{}
这种代码,如果两个中断同时来了,INT11就丢了.

会不会有这种现象发生.要不同时来中断,应该都会有响应.
if(int10)
{}
if(int11)
{}
这样判断就不会丢.

#7



//*****************added by haiou for magcard driver in 2010-04-20*****************************
    if(VirtualIRQ == IRQ_EINT10)                                      //Track3
    {
        //OALMSG(TRUE, (L"*********OEMInterruptHandler:IRQ_EINT8     haiou************\r\n"));
/*
g_pMAGBuf->primal_num_track3 = 0;
for(g_pMAGBuf->primal_num_track3; g_pMAGBuf->primal_num_track3<CARD_NUM_TRACK3; g_pMAGBuf->primal_num_track3++)
{
    g_pMAGBuf->card_data_track3[g_pMAGBuf->primal_num_track3] = g_pMAGBuf->primal_num_track3; 
}
        g_pMAGBuf->primal_num_track3 = 0;
    g_pGPIOReg->EINT0MASK &= ~(0x1<<8);    // Enable EINT8
g_pVIC0Reg->VICINTENABLE |= (0x1<<PHYIRQ_EINT1);  //(IRQ_EINT4~IRQ_EINT11)
*/
//OALMSG(TRUE, (L"*********OEMInterruptHandler:IRQ_EINT8     haiou************\r\n"));
if(0x02 == (UCHAR)(g_pMAGBuf->trans_flag & BRUSH_END))       //只有IST允许,中断处理才能有效
    {
        if((!(g_pGPIOReg->GPKDAT & CP_LOW)) && (g_pMAGBuf->primal_num_track3 < 1000))
        { 
            g_pMAGBuf->card_data_track3[g_pMAGBuf->primal_num_track3++] = (char)(g_pGPIOReg->GPKDAT & TRACK3);  //读出GPK2 bit
        }
                g_pMAGBuf->trans_flag |= BRUSH_BEGIN;
            g_pGPIOReg->EINT0MASK &= ~(0x1<<10);    // Enable EINT8
g_pVIC0Reg->VICINTENABLE |= (0x1<<PHYIRQ_EINT1);  //(IRQ_EINT4~IRQ_EINT11)
        }
    return SYSINTR_NOP;
    }

    if(VirtualIRQ == IRQ_EINT18)                                      //Track2
    {
//OALMSG(TRUE, (L"*********OEMInterruptHandler:IRQ_EINT9     haiou************\r\n"));
if(0x02 == (UCHAR)(g_pMAGBuf->trans_flag & BRUSH_END))    //只有IST允许,中断处理才能有效
    {
        if((!(g_pGPIOReg->GPKDAT & CP_LOW)) && (g_pMAGBuf->primal_num_track2 < 300))
        { 
            g_pMAGBuf->card_data_track2[g_pMAGBuf->primal_num_track2++] = (char)(g_pGPIOReg->GPKDAT & TRACK2);  //读出GPK3 bit
        }
            g_pMAGBuf->trans_flag |= BRUSH_BEGIN;
        g_pGPIOReg->EINT0MASK &= ~(0x1<<18);    // Enable EINT9
g_pVIC1Reg->VICINTENABLE |= (0x1<<(PHYIRQ_EINT2-32));  //(IRQ_EINT4~IRQ_EINT11)
        }
    return SYSINTR_NOP;
    }
//*******************end of magcard driver***************************************************/

引用 6 楼 paul85 的回复:
这个和isr里面判断中断源有关.举个例子.
if(int10)
{}
else if(int11)
{}
这种代码,如果两个中断同时来了,INT11就丢了.

会不会有这种现象发生.要不同时来中断,应该都会有响应.
if(int10)
{}
if(int11)
{}
这样判断就不会丢.

#8


有道理,ISR响应N个中断后通知的方法不是 return sys_intr的方式,是设置了g_pMAGBuf->trans_flag |= BRUSH_BEGIN(所在的内存空间由ISR和IST共享);这个全局变量,IST端每隔100ms就去读这个变量,然后再等1.5ms处理_pMAGBuf->card_data_track3中的数。
引入DMA读取数据,还真不会,能否详细说明下方法?
引用 4 楼 domworldjohn 的回复:
我觉得读取电平确实应该放在ISR中,但是读取电平速度很快的,理论上不会影响ISR的效率。并且你不应该让ISR响应N个中断之后才通知ISR,而是响应一个ISR之后立刻通知IST处理。或者引入DMA来读取数据。

#9


引用 8 楼 haiou_arm 的回复:
有道理,ISR响应N个中断后通知的方法不是 return sys_intr的方式,是设置了g_pMAGBuf->trans_flag |= BRUSH_BEGIN(所在的内存空间由ISR和IST共享);这个全局变量,IST端每隔100ms就去读这个变量,然后再等1.5ms处理_pMAGBuf->card_data_track3中的数。
引入DMA读取数据,还真不会,能否详细说明下方法?

引……

要使用DMA需要你的外部接口支持DMA,如果支持,那么你只需要将外部接口的中断方式设置为DMA处理即可。这样,到外部中断来的时候,DMA自动处理,不需要经过CPU

#10


回楼上,明白了,谢谢!~这个作为优化方案,我后面做下。

我现在比较怀疑的是这个:
S3C6410有两个中断向量表VIC0、VIC1。共对应64个interrupt sources。
其中有五个分别是INT_EINT0、INT_EINT1、INT_EINT2、INT_EINT3、INT_EINT4。
以INT_EINT0、INT_EINT1举例如下:
INT_EINT0又分别对应IRQ_EINT0,IRQ_EINT1,IRQ_EINT2,IRQ_EINT3四个外部中断;
INT_EINT1对应IRQ_EINT4~IRQ_EINT11;

现在有两种情况:
     1、如果IRQ_EINT0和IRQ_EINT1同时都来了会丢一个吗?
     2、如果IRQ_EINT0和IRQ_EINT4同时都来了会丢一个吗?

我记得S3C2410的中断和ARM7核的单片机中断处理机制有个SRCPND的寄存器,两个中断同时都来了,SRCPND中两个中断位都会同时置位,按照优先级一个先处理,另一个等先处理的处理完了总会处理。对吧?总之不会丢

S3C6410也是这样吗?它也有EINT0PND寄存器,还一样吗?不知道我上面的理解对不对?

#11


引用 10 楼 haiou_arm 的回复:
回楼上,明白了,谢谢!~这个作为优化方案,我后面做下。

我现在比较怀疑的是这个:
S3C6410有两个中断向量表VIC0、VIC1。共对应64个interrupt sources。
其中有五个分别是INT_EINT0、INT_EINT1、INT_EINT2、INT_EINT3、INT_EINT4。
以INT_EINT0、INT_EINT1举例如下:
INT_EINT0又分别对应IRQ……


今天该结贴了,看来我这个理解是有问题的,我引用所存在的问题是对一级中断和二级中断的理解有误。
后来我做了这样一个实验:
1、一个开关同时对应两个中断,模拟两个终端同时产生;
2、得到的结果是:只能产生一个syetem_intr;
3、其实这个不难理解:仔细看OEMInterruptHandle这个函数就能明白;
4、因为磁卡肯定有两个终端同时来的情况,后来换成了别的思路解决了这个问题,才磁卡CS信号作为中断,然后扫描读取二、三磁道的值,读值过程中CPU是独占的,但因为这个时间不到1S,目前应用是能接受的。

    最终得出的结论是:WinCE当有两个外部中断同时产生时,只返回一个逻辑中断号,也就是我会丢掉一个!

#12


引用 11 楼 haiou_arm 的回复:
引用 10 楼 haiou_arm 的回复:
回楼上,明白了,谢谢!~这个作为优化方案,我后面做下。

我现在比较怀疑的是这个:
S3C6410有两个中断向量表VIC0、VIC1。共对应64个interrupt sources。
其中有五个分别是INT_EINT0、INT_EINT1、INT_EINT2、INT_EINT3、INT_EINT4。
以INT_EINT0、INT_EINT1……


我的理解是,两个中断同时来的时候,没有丢一个中断,而是先处理了一个中断,而再处理另外一个中断。

“我记得S3C2410的中断和ARM7核的单片机中断处理机制有个SRCPND的寄存器,两个中断同时都来了,SRCPND中两个中断位都会同时置位,按照优先级一个先处理,另一个等先处理的处理完了总会处理。对吧?总之不会丢”

你的这个理解是对的啊,正因为如此才不会把另外一个中断给丢了,

如果你的读卡数据的时间比较长的话,且多于两倍的ISR处理的时间的话,应该是可以一前一后读到两个卡的数据,不会丢失的。

#1


这个肯定是响应优先级高的了。

#2


这个只能增加 isr ist的效率来做。
楼主可以参考我 做外部串口驱动的办法,博客有。
还有这两个中断线程要互斥。

#3


回楼上:
    谢谢googoleman这么快就回复,谢谢!
    但我觉得问题没这么简单:
1、EINT10、EINT11都属于中断向量表VIC1的同一个物理中断PHYIRQ_EINT1,设置优先级只能针对    PHYIRQ_EINT1,所以它俩的优先级肯定一致;
2、因为从ISQ--->ISR--->IST的过程需要花费时间,另外两个IST切换的时间更长(1ms不止)如果我两个ISR分别对应一个IST的话那就更惨了,又因为怕进入IST再去读数据线上的电平就不是1ms以前的了,所以现在读电平的处理我放在了ISR中,只有ISR将所有的数据都处理完了(响应了N个中断),我才通知IST来处理,是通过共享内存来实现的。
3、所以问题应该还不是楼上说的。

#4


我觉得读取电平确实应该放在ISR中,但是读取电平速度很快的,理论上不会影响ISR的效率。并且你不应该让ISR响应N个中断之后才通知ISR,而是响应一个ISR之后立刻通知IST处理。或者引入DMA来读取数据。

#5


这个要学习一下 呵呵

#6


这个和isr里面判断中断源有关.举个例子.
if(int10)
{}
else if(int11)
{}
这种代码,如果两个中断同时来了,INT11就丢了.

会不会有这种现象发生.要不同时来中断,应该都会有响应.
if(int10)
{}
if(int11)
{}
这样判断就不会丢.

#7



//*****************added by haiou for magcard driver in 2010-04-20*****************************
    if(VirtualIRQ == IRQ_EINT10)                                      //Track3
    {
        //OALMSG(TRUE, (L"*********OEMInterruptHandler:IRQ_EINT8     haiou************\r\n"));
/*
g_pMAGBuf->primal_num_track3 = 0;
for(g_pMAGBuf->primal_num_track3; g_pMAGBuf->primal_num_track3<CARD_NUM_TRACK3; g_pMAGBuf->primal_num_track3++)
{
    g_pMAGBuf->card_data_track3[g_pMAGBuf->primal_num_track3] = g_pMAGBuf->primal_num_track3; 
}
        g_pMAGBuf->primal_num_track3 = 0;
    g_pGPIOReg->EINT0MASK &= ~(0x1<<8);    // Enable EINT8
g_pVIC0Reg->VICINTENABLE |= (0x1<<PHYIRQ_EINT1);  //(IRQ_EINT4~IRQ_EINT11)
*/
//OALMSG(TRUE, (L"*********OEMInterruptHandler:IRQ_EINT8     haiou************\r\n"));
if(0x02 == (UCHAR)(g_pMAGBuf->trans_flag & BRUSH_END))       //只有IST允许,中断处理才能有效
    {
        if((!(g_pGPIOReg->GPKDAT & CP_LOW)) && (g_pMAGBuf->primal_num_track3 < 1000))
        { 
            g_pMAGBuf->card_data_track3[g_pMAGBuf->primal_num_track3++] = (char)(g_pGPIOReg->GPKDAT & TRACK3);  //读出GPK2 bit
        }
                g_pMAGBuf->trans_flag |= BRUSH_BEGIN;
            g_pGPIOReg->EINT0MASK &= ~(0x1<<10);    // Enable EINT8
g_pVIC0Reg->VICINTENABLE |= (0x1<<PHYIRQ_EINT1);  //(IRQ_EINT4~IRQ_EINT11)
        }
    return SYSINTR_NOP;
    }

    if(VirtualIRQ == IRQ_EINT18)                                      //Track2
    {
//OALMSG(TRUE, (L"*********OEMInterruptHandler:IRQ_EINT9     haiou************\r\n"));
if(0x02 == (UCHAR)(g_pMAGBuf->trans_flag & BRUSH_END))    //只有IST允许,中断处理才能有效
    {
        if((!(g_pGPIOReg->GPKDAT & CP_LOW)) && (g_pMAGBuf->primal_num_track2 < 300))
        { 
            g_pMAGBuf->card_data_track2[g_pMAGBuf->primal_num_track2++] = (char)(g_pGPIOReg->GPKDAT & TRACK2);  //读出GPK3 bit
        }
            g_pMAGBuf->trans_flag |= BRUSH_BEGIN;
        g_pGPIOReg->EINT0MASK &= ~(0x1<<18);    // Enable EINT9
g_pVIC1Reg->VICINTENABLE |= (0x1<<(PHYIRQ_EINT2-32));  //(IRQ_EINT4~IRQ_EINT11)
        }
    return SYSINTR_NOP;
    }
//*******************end of magcard driver***************************************************/

引用 6 楼 paul85 的回复:
这个和isr里面判断中断源有关.举个例子.
if(int10)
{}
else if(int11)
{}
这种代码,如果两个中断同时来了,INT11就丢了.

会不会有这种现象发生.要不同时来中断,应该都会有响应.
if(int10)
{}
if(int11)
{}
这样判断就不会丢.

#8


有道理,ISR响应N个中断后通知的方法不是 return sys_intr的方式,是设置了g_pMAGBuf->trans_flag |= BRUSH_BEGIN(所在的内存空间由ISR和IST共享);这个全局变量,IST端每隔100ms就去读这个变量,然后再等1.5ms处理_pMAGBuf->card_data_track3中的数。
引入DMA读取数据,还真不会,能否详细说明下方法?
引用 4 楼 domworldjohn 的回复:
我觉得读取电平确实应该放在ISR中,但是读取电平速度很快的,理论上不会影响ISR的效率。并且你不应该让ISR响应N个中断之后才通知ISR,而是响应一个ISR之后立刻通知IST处理。或者引入DMA来读取数据。

#9


引用 8 楼 haiou_arm 的回复:
有道理,ISR响应N个中断后通知的方法不是 return sys_intr的方式,是设置了g_pMAGBuf->trans_flag |= BRUSH_BEGIN(所在的内存空间由ISR和IST共享);这个全局变量,IST端每隔100ms就去读这个变量,然后再等1.5ms处理_pMAGBuf->card_data_track3中的数。
引入DMA读取数据,还真不会,能否详细说明下方法?

引……

要使用DMA需要你的外部接口支持DMA,如果支持,那么你只需要将外部接口的中断方式设置为DMA处理即可。这样,到外部中断来的时候,DMA自动处理,不需要经过CPU

#10


回楼上,明白了,谢谢!~这个作为优化方案,我后面做下。

我现在比较怀疑的是这个:
S3C6410有两个中断向量表VIC0、VIC1。共对应64个interrupt sources。
其中有五个分别是INT_EINT0、INT_EINT1、INT_EINT2、INT_EINT3、INT_EINT4。
以INT_EINT0、INT_EINT1举例如下:
INT_EINT0又分别对应IRQ_EINT0,IRQ_EINT1,IRQ_EINT2,IRQ_EINT3四个外部中断;
INT_EINT1对应IRQ_EINT4~IRQ_EINT11;

现在有两种情况:
     1、如果IRQ_EINT0和IRQ_EINT1同时都来了会丢一个吗?
     2、如果IRQ_EINT0和IRQ_EINT4同时都来了会丢一个吗?

我记得S3C2410的中断和ARM7核的单片机中断处理机制有个SRCPND的寄存器,两个中断同时都来了,SRCPND中两个中断位都会同时置位,按照优先级一个先处理,另一个等先处理的处理完了总会处理。对吧?总之不会丢

S3C6410也是这样吗?它也有EINT0PND寄存器,还一样吗?不知道我上面的理解对不对?

#11


引用 10 楼 haiou_arm 的回复:
回楼上,明白了,谢谢!~这个作为优化方案,我后面做下。

我现在比较怀疑的是这个:
S3C6410有两个中断向量表VIC0、VIC1。共对应64个interrupt sources。
其中有五个分别是INT_EINT0、INT_EINT1、INT_EINT2、INT_EINT3、INT_EINT4。
以INT_EINT0、INT_EINT1举例如下:
INT_EINT0又分别对应IRQ……


今天该结贴了,看来我这个理解是有问题的,我引用所存在的问题是对一级中断和二级中断的理解有误。
后来我做了这样一个实验:
1、一个开关同时对应两个中断,模拟两个终端同时产生;
2、得到的结果是:只能产生一个syetem_intr;
3、其实这个不难理解:仔细看OEMInterruptHandle这个函数就能明白;
4、因为磁卡肯定有两个终端同时来的情况,后来换成了别的思路解决了这个问题,才磁卡CS信号作为中断,然后扫描读取二、三磁道的值,读值过程中CPU是独占的,但因为这个时间不到1S,目前应用是能接受的。

    最终得出的结论是:WinCE当有两个外部中断同时产生时,只返回一个逻辑中断号,也就是我会丢掉一个!

#12


引用 11 楼 haiou_arm 的回复:
引用 10 楼 haiou_arm 的回复:
回楼上,明白了,谢谢!~这个作为优化方案,我后面做下。

我现在比较怀疑的是这个:
S3C6410有两个中断向量表VIC0、VIC1。共对应64个interrupt sources。
其中有五个分别是INT_EINT0、INT_EINT1、INT_EINT2、INT_EINT3、INT_EINT4。
以INT_EINT0、INT_EINT1……


我的理解是,两个中断同时来的时候,没有丢一个中断,而是先处理了一个中断,而再处理另外一个中断。

“我记得S3C2410的中断和ARM7核的单片机中断处理机制有个SRCPND的寄存器,两个中断同时都来了,SRCPND中两个中断位都会同时置位,按照优先级一个先处理,另一个等先处理的处理完了总会处理。对吧?总之不会丢”

你的这个理解是对的啊,正因为如此才不会把另外一个中断给丢了,

如果你的读卡数据的时间比较长的话,且多于两倍的ISR处理的时间的话,应该是可以一前一后读到两个卡的数据,不会丢失的。