打印

很奇怪的问题:关于at91sam9260 FIQ中断 的触发

[复制链接]
6210|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nicholasldf|  楼主 | 2010-4-30 19:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 nicholasldf 于 2010-4-30 19:35 编辑

现象为:我设置9260的FIQ为由PC13管脚的上升沿触发,但是实际上是下降沿和上升沿都会触发FIQ中断。

9260的外部中断触发只有4种情况:
Low level Sensitive、Negative edge triggered、High level Sensitive、Positive edge triggered
也就是低电平、下降沿、高电平、上升沿,,,所以上升沿和下降沿都会触发中断的情况是不可能同时实现的。
要么是下降沿,要么是上升沿,二选一。

FIQ的输入由有一个传感器控制,,,传感器从“被码盘挡住”到“未被码盘挡住”时FIQ输入上升沿,,,
传感器从“未被码盘挡住”到“被码盘挡住”时FIQ输入下升沿,,,其实FIQ输入波形就是类似于一个方波。

用示波器看了FIQ的输入波形很好,没有什么毛刺干扰之类的。

拿纸片手动去操作传感器:拿纸片挡住,再拿开,,手动的产生方波波形,,测试也是一样,,在下降沿产生了FIQ中断。

FIQ的初始化代码如下:
AT91C_BASE_PIOC->PIO_PDR = AT91C_PC13_FIQ; //设置PC13引脚为功能引脚,而不是IO口
AT91C_BASE_PIOC->PIO_ASR = AT91C_PC13_FIQ; //设置PC13为FIQ输入中断引脚
AIC_ClearIT(AT91C_ID_FIQ); //清空FIQ中断
//配置FIQ中断向量:最低优先级(对FIQ无用,对普通IRQ起作用),外部中断类型,上升沿触发,中断服务函数为IntVectReactDishPassOneCup
AIC_ConfigureIT(AT91C_ID_FIQ, AT91C_AIC_PRIOR_LOWEST | \
       AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE, IntVectReactDishPassOneCup);
//使能FIQ中断
AIC_EnableIT(AT91C_ID_FIQ);  

FIQ中断服务函数为:
void IntVectReactDishPassOneCup(void)
{
    DEBUG("CurPassing: %2d  CurrentCup: %2d\n\r", pReactDishModule->CurPassing, pReactDishModule->CurrentCup);
    pReactDishModule->CurPassing++;
    pReactDishModule->CurrentCup++;

    AIC_ClearIT(AT91C_ID_FIQ);
}

下面是uCOS官方移植代码中断处理部分:
void  BSP_IntSched(CPU_INT08U  int_type)
{
    CPU_FNCT_VOID   p_isr;
   
    if (int_type == BSP_INT_CTRL_TYPE_FIQ) {   
         p_isr = (CPU_FNCT_VOID)BSP_INT_AIC_FVR;                 /* Read the interrupt vector from the VIC             */        
         while (p_isr != (CPU_FNCT_VOID)0) {                     /* Make sure we don't have a NULL pointer             */
               (*p_isr)();
               BSP_INT_AIC_EOICR = DEF_BIT_NONE;                   /* End of handler                                     */   
               p_isr = (CPU_FNCT_VOID)BSP_INT_AIC_FVR;             /* Read the interrupt vector from the VIC             */
         }
         BSP_INT_AIC_EOICR = DEF_BIT_NONE;                       /* End of handler                                     */
    }

    if (int_type == BSP_INT_CTRL_TYPE_IRQ) {   
          p_isr = (CPU_FNCT_VOID)BSP_INT_AIC_IVR;                 /* Read the interrupt vector from the VIC             */        
          while (p_isr != (CPU_FNCT_VOID)0) {                     /* Make sure we don't have a NULL pointer             */
              (*p_isr)();
               BSP_INT_AIC_EOICR = DEF_BIT_NONE;                   /* End of handler                                     */   
               p_isr = (CPU_FNCT_VOID)BSP_INT_AIC_IVR;             /* Read the interrupt vector from the VIC             */
         }
          BSP_INT_AIC_EOICR = DEF_BIT_NONE;                       /* End of handler                                     */
    }
}

被调用到的三个中断API函数AIC_ClearIT,AIC_ConfigureIT,AIC_EnableIT是atmel提供的开发包at91lib_softpack_1.5的aic.c文件里面的函数:
void AIC_ConfigureIT(  unsigned int source,   unsigned int mode,   void (*handler)(void)   )
{
    // Disable the interrupt first
    AT91C_BASE_AIC->AIC_IDCR = 1 << source;
    // Configure mode and handler
    AT91C_BASE_AIC->AIC_SMR[source] = mode;
    AT91C_BASE_AIC->AIC_SVR[source] = (unsigned int) handler;
    // Clear interrupt
    AT91C_BASE_AIC->AIC_ICCR = 1 << source;
}

void AIC_EnableIT(unsigned int source)
{
    AT91C_BASE_AIC->AIC_IECR = 1 << source;
}
  
void AIC_ClearIT(unsigned int source)
{
    AT91C_BASE_AIC->AIC_ICCR = 1 << source;
}

相关帖子

沙发
dami| | 2010-5-3 20:40 | 只看该作者
本帖最后由 dami 于 2010-5-3 20:46 编辑

据我所知,GPIO的中断是上下降缘都产生(GPIO是一个口共用一个中断)输入变化中端,你可以用软件把不要的滤掉.
如果你用IRQ1..那三个中断就可以设置上下降缘.

使用特权

评论回复
板凳
dami| | 2010-5-3 20:49 | 只看该作者
如果你用IRQ0,IRQ1,IRQ2..那三个中断就可以设置上下降缘.

使用特权

评论回复
地板
nicholasldf|  楼主 | 2010-5-4 08:56 | 只看该作者
看看9260数据手册对内部中断和外部中断的描述:
        The internal interrupt sources wired on the interrupt outputs of the embedded peripherals can be programmed either in level-sensitive mode or in edge-triggered mode. The active level of the internal interrupts is not important for the user.
        The external interrupt sources can be programmed either in high level-sensitive or low level-sensitive modes, or in positive edge-triggered or negative edge-triggered modes.

        IRQ0,IRQ1,IRQ2,FIQ,,都属于外部中断,只有4种情况:Low level Sensitive、Negative edge triggered、High level Sensitive、Positive edge triggered,也就是低电平、下降沿、高电平、上升沿,,,上升沿和下降沿都会触发的外部中断9260是不可能同时实现的。
        只有普通IO口边沿跳变可以出发中断,,The PIO Controller can be programmed to generate an interrupt when it detects an input change on an I/O line.
        但是,,我这里的情况是把PC13是配置为FIQ快速中断输入,,而不是普通IO中断,,因此,,这个现象还是比较奇怪。。。

使用特权

评论回复
5
dami| | 2010-5-4 10:56 | 只看该作者
设置为快速中断是可以设置为边缘触发或电平触发,和IRQ0,1,2一样.边缘触发还可以设置是上升还是下降缘.

使用特权

评论回复
6
dami| | 2010-5-4 10:57 | 只看该作者
本帖最后由 dami 于 2010-5-4 21:49 编辑

有点象GPIO的中断触发.可能是设置中断触发方式时出了问题吧.你检查检查触发方式对不对.

使用特权

评论回复
7
dami| | 2010-5-4 10:58 | 只看该作者
你出现的现象有点象GPIO的中断.纠正一下.

使用特权

评论回复
8
nicholasldf|  楼主 | 2010-5-4 13:02 | 只看该作者
应该不会啊, PC13是分配了A功能啊,,,,9260有个寄存器可以供软件模拟硬件产生中断,,,我用软件模拟FIQ中断是正常的,,每设置一次,,就产生一次FIQ中断:
AIC Interrupt Set Command Register
Register Name: AIC_ISCR
Interrupt Set: 0 = No effect.  1 = Sets corresponding interrupt

我说的边沿触发是指:上升沿、下降沿都会触发,,,你的意思是指:IRQ0-IRQ2、FIQ可以设置为跳变触发吗?(也就是上升沿下降沿都能同时触发)

FIQ的初始化代码:
AT91C_BASE_PIOC->PIO_PDR = AT91C_PC13_FIQ; //设置PC13引脚为功能引脚,而不是IO口
AT91C_BASE_PIOC->PIO_ASR = AT91C_PC13_FIQ; //设置PC13为FIQ输入中断引脚

使用特权

评论回复
9
dami| | 2010-5-4 22:01 | 只看该作者
本帖最后由 dami 于 2010-5-4 22:04 编辑

IRQ0-IRQ2、FIQ,可以设置为边缘触发,电平触发,边缘触发有分上升,或下降,电平触发分高或低电平.
GPIO就不能设置,变化就产生中断.
如果是在LINUX里有:
IRQ.H,interrupt.h都有定义:
#define IRQF_TRIGGER_NONE        0x00000000
#define IRQF_TRIGGER_RISING        0x00000001
#define IRQF_TRIGGER_FALLING        0x00000002
#define IRQF_TRIGGER_HIGH        0x00000004
#define IRQF_TRIGGER_LOW        0x00000008
#define IRQF_TRIGGER_MASK        (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \
                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
用到request_irq里.
如果你没有设置有可能有问题哦.但看你的代码里好象是有UCOS的中断模式配置哦.你再仔细研究一下UCOS,看哪里不对.
给你看个连接:
http://linux.chinaunix.net/bbs/archiver/?tid-1121727.html

使用特权

评论回复
10
nicholasldf|  楼主 | 2010-5-5 09:54 | 只看该作者
谢谢!

我的头文件是这样定义触发类型的:没有错误
#define         AT91C_AIC_SRCTYPE_EXT_LOW_LEVEL        (0x0 <<  5) //add (AIC) External Sources Code Label Low-level Sensitive
#define         AT91C_AIC_SRCTYPE_EXT_NEGATIVE_EDGE    (0x1 <<  5) //add (AIC) External Sources Code Label Negative Edge triggered
#define         AT91C_AIC_SRCTYPE_EXT_HIGH_LEVEL       (0x2 <<  5) // (AIC) External Sources Code Label High-level Sensitive
#define         AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE    (0x3 <<  5) // (AIC) External Sources Code Label Positive Edge triggered

我用AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE初始化为上升沿触发:
AIC_ConfigureIT(AT91C_ID_FIQ,   AT91C_AIC_PRIOR_LOWEST | \
        AT91C_AIC_SRCTYPE_EXT_POSITIVE_EDGE,   IntVectReactDishPassOneCup);

看看中断模式寄存器,程序初始化没有问题。
AIC Source Mode Register:
31 30 29 28 27 26 25 24
– – – – – – – –
23 22 21 20 19 18 17 16
– – – – – – – –
15 14 13 12 11 10 9 8
– – – – – – – –
7      6 5       4 3    2 1 0
– SRCTYPE – – PRIOR

SRCTYPE         Internal Interrupt Sources                  External Interrupt Sources
0   0                High level Sensitive                             Low level Sensitive
0   1                Positive edge triggered                       Negative edge triggered
1   0                High level Sensitive                             High level Sensitive
1   1                Positive edge triggered                       Positive edge triggered

使用特权

评论回复
11
dami| | 2010-5-6 08:52 | 只看该作者
要不把PC13定义一下过滤毛刺,还有你没挡住时为高电平,最好定义下降缘触发.

使用特权

评论回复
12
nicholasldf|  楼主 | 2010-5-6 11:01 | 只看该作者
thanks dami!

dami:“要不把PC13定义一下过滤毛刺”
答:
应该不是毛刺,,因为是每次下降沿必发的。
我也是加了滤波的:AT91C_BASE_PIOC->PIO_IFER = AT91C_PC13_FIQ;//输入滤波
根据9260数据手册,只能滤掉1.5个时钟宽度的毛刺,MCK为100M时,也就是15nS左右。
此外,硬件好像也有滤波电容,示波器看的波形很好,所以不大可能是干扰。

dami:最好定义下降缘触发.
答:
产品的设计决定的,上升沿触发数据处理任务,,检测下降沿对我来说没有用,毫无意义的。^_^

我目前的解决方法有两种,实际使用了第(2)种:
(1)方法一: 下降沿中断直接pass,上升沿才任务有效,,并在1uS时间内检测有效次数,1uS可以检测200次,如果大于150次就认为是有效的FIQ中断。
(2)方法二:FIQ的输入波形周期为22mS左右(接近于方波),,也就是每隔22mS来一次上升沿触发FIQ,我现在是,在当前FIQ中断退出时,关闭FIQ中断,用定时器延时大概20mS左右
再使能FIQ中断检测下一个上升沿,,在这20mS内,下降沿已经过去,同时也免去了20mS内由于干扰可能引发的误触发,,稳定性肯定会好很多。

void IntVectReactDishPassOneCup(void) --- FIQ中断服务函数
{
        unsigned int i, j;                                                                                          

        //设置为上升沿触发中断,但是下降沿也会触发,暂时用软件的方法判断,
        //如果是下降沿则中断无效。此外,还可以用作上升沿滤波。
        //注:启用定时器,在当前码盘中断后,关闭码盘中断,定时器在指定时间(20mS)后
        //再打开码盘中断,这样就跳过了下降沿检测,还能滤去干扰防止码盘误检测
       
        //在1uS内检测码盘有效次数,以防干扰
        j = 0;
        for(i=0; i<200; i++){//1uS
                if(AT91C_PC13_FIQ == (AT91C_BASE_PIOC->PIO_PDSR & AT91C_PC13_FIQ)){
                        j++;
                }
        }

        if(j<150){
                //DEBUG("Invalid FIQ Int\n\r");
                return;
        }

        //检测到有效码盘则通知码盘处理任务
        OSSemPost(pReactDishModule->pPassOneCupSem);

        //每一次码盘中断后都要关闭FIQ中断,由定时器
        //在指定时间后再打开中断,以检测下一个码盘
        AIC_DisableIT(AT91C_ID_FIQ);
        AIC_ClearIT(AT91C_ID_FIQ);                       
}

/*
*********************************************************************************************************
*  TimerCallbackOpenFIQ : 定时器回调函数,用于经过指定时间(20mS)后打开码盘FIQ中断
*********************************************************************************************************
*/
void TimerCallbackOpenFIQ(OS_TMR *ptmr, void *p_arg)  ---  定时器回调函数
{
        AIC_ClearIT(AT91C_ID_FIQ);//清空FIQ中断
        AIC_EnableIT(AT91C_ID_FIQ);//打开反应盘码盘信号FIQ中断                          
}

虽然问题用上面的方法暂时解决,但还是想知道个究竟,呵呵,不高明白,,心里不舒服,万一可能迁出软件BUG,,

使用特权

评论回复
13
4027379| | 2013-5-22 14:51 | 只看该作者
我感觉是软件BUG

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

261

帖子

10

粉丝