This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C6748 裸机 中断嵌套问题

外部触发一个GPIO中断,在这个IO中断函数中调用了一个I2C写函数,但是这个I2C写函数是使用中断方式进行的,结果实现不了。

不用操作系统,请问 C6748可以进行可屏蔽中断之间的嵌套吗? 如果可以的话,怎么实现?如果不可以,请问有没有I2C查询方式的写函数?

  • 这个问题没找到解决办法?求解答

  • 可以进行中断嵌套的

    需要在中断处理函数里把系统的总中断再打开。

  • 被这个问题困扰了一段时间了?

    谁知道有什么解决办法

  • 我在IO中断函数里调用stareware 库里的    IntGlobalEnable();// 使能 DSP 全局中断

    来打开总中断,IIC每写一个字节都需要进一次中断的。

    这样只用一次IntGlobalEnable() 可以吗? 另外需要考虑优先级的问题吗?

  • 我试了下,嵌套的中断进不去,不知道是哪里的配置会出问题??

  • 一般来说中断处理函数进入之前会把全局中断关掉,需要你在中断处理函数里显示的打开,才能重入。

    需要测试一下,单独的能否分别进入中断?

    在这基础上,观察一下中断相关的寄存器,全局的中断寄存器和I2C相关的中断寄存器,和单独的情况对比一下

  • 我单步调试了下,确实会在中断处理函数进入之前会把全局中断关掉。单独的都可以正确执行中断处理函数。我已经在IO中断处理中我已经将全局中断又打开了,全局中断标志使能位已经置1了,我观察了一下I2C相关的寄存器和单独的情况一样,就是进不去I2C的中断处理函数。

    可能是我没搞明白,怎样算显示的打开?有没有可屏蔽中断嵌套的例程可以参考一下?

    实在搞不清楚自己哪里错了

  • 如果全局中断打开了,应该是可以进去的。

    你可以简化一下,看看两个GPIO中断能不能重入?

  • 参考文档sprufe8b。(嵌套中断实现还是有点麻烦的,最好权衡一下是改一下程序结构,还是要实现中断嵌套)

    5.6.2 Nested Interrupts
    Generally, when the CPU enters an interrupt service routine, interrupts are disabled. However, when the
    interrupt service routine is for one of the maskable interrupts (INT4-INT15), an NMI can interrupt
    processing of the maskable interrupt. In other words, an NMI can interrupt a maskable interrupt, but
    neither an NMI nor a maskable interrupt can interrupt an NMI.
    Also, there may be times when you want to allow an interrupt service routine to be interrupted by another
    (particularly higher priority) interrupt. Even though the processor by default does not allow interrupt service
    routines to be interrupted unless the source is an NMI, it is possible to nest interrupts under software
    control. To allow nested interrupts, the interrupt service routine must perform the following initial steps in
    addition to its normal work of saving any registers (including control registers) that it modifies:
    1. The contents of IRP (or NRP) must be saved
    2. The contents of the PGIE bit must be saved
    3. The contents of ITSR must be saved
    4. The GIE bit must be set to 1

    Prior to returning from the interrupt service routine, the code must restore the registers saved above as
    follows:
    1. The GIE bit must be first cleared to 0
    2. The PGIE bit saved value must be restored
    3. The contents of ITSR must be restored
    4. The IRP (or NRP) saved value must be restored
    Although steps 2, 3, and 4 above may be performed in any order, it is important that the GIE bit is cleared
    first. This means that the GIE and PGIE bits must be restored with separate writes to CSR. If these bits
    are not restored separately, then it is possible that the PGIE bit is overwritten by nested interrupt
    processing just as interrupts are being disabled.
    NOTE: When coding nested interrupts for the CPU, the ITSR should be saved and restored to
    prevent corruption by the nested interrupt.

  • 您好,如果我不是明确知道会在什么地方打断,我该怎么样进行Prior to 这4个步骤的操作呢?
  • victor sun1 说:
    如果我不是明确知道会在什么地方打断,

    不明白你为什么会这么问,谁能知道会在什么地方打断。上面的操作跟知不知道这个没有一丝关系。

  • /**
    * \file timerCounter.c
    *
    * \brief Sample application for timer.
    */

    /*
    * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the
    * distribution.
    *
    * Neither the name of Texas Instruments Incorporated nor the names of
    * its contributors may be used to endorse or promote products derived
    * from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */

    #define SOC_TMR_0_REGS (0x01C20000)
    #define SOC_TMR_1_REGS (0x01C21000)

    #include "stdio.h"
    #include "c6x.h"
    #include "uart.h"
    #include "hw_uart.h"
    #include "interrupt.h"
    #include "soc_OMAPL138.h"
    #include "hw_syscfg0_OMAPL138.h"
    #include "timer.h"
    #include "lcdkOMAPL138.h"
    #include "uartStdio.h"

    #ifndef _TMS320C6X
    #include "cpu.h"
    #endif

    /******************************************************************************
    ** INTERNAL MACRO DEFINITIONS
    *******************************************************************************/
    #define STR_LEN (13)
    #define TMR_PERIOD_LSB32 (0x07FFFFFF)
    #define TMR_PERIOD_MSB32 (0x0)

    /******************************************************************************
    ** INTERNAL FUNCTION PROTOTYPES
    *******************************************************************************/
    static void TimerIsr(void);
    static void TimerSetUp64Bit(void);
    static void Timer3SetUp64Bit(void);
    static void TimerIntrSetUp(void);

    /******************************************************************************
    ** INTERNAL VARIABLE DEFINITIONS
    *******************************************************************************/
    static unsigned char cntArr[9] = {'8', '7', '6', '5', '4', '3', '2', '1', '0'};
    static volatile unsigned int secCnt = 0;
    static volatile unsigned int flagIsrCnt = 0;

    /******************************************************************************
    ** FUNCTION DEFINITIONS
    *******************************************************************************/
    int main(void)
    {
    /* Set up the UART2 peripheral */
    UARTStdioInit();

    /* Set up the Timer2 peripheral */
    TimerSetUp64Bit();
    Timer3SetUp64Bit();

    /* Set up the AINTC to generate Timer2 interrupts */
    TimerIntrSetUp();

    /* Enable the timer interrupt */
    TimerIntEnable(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
    TimerIntEnable(SOC_TMR_3_REGS, TMR_INT_TMR12_NON_CAPT_MODE); // Add by Tony

    #ifndef _TMS320C6X
    /* Switch to non privileged mode; This is done for demonstration purpose */
    CPUSwitchToUserMode();
    #endif

    /* Send the first String */
    UARTPuts("Tencounter: 9", -1);

    /* Start the timer. Characters from cntArr will be sent from the ISR */
    TimerEnable(SOC_TMR_2_REGS, TMR_TIMER12, TMR_ENABLE_CONT);
    TimerEnable(SOC_TMR_3_REGS, TMR_TIMER12, TMR_ENABLE_CONT); // add by Tony

    /* make sure all the characters from cntArray from ISR */
    while(secCnt < 9)
    {
    /* Replace previous number each time the timer interrupt occurs */
    if(flagIsrCnt)
    {
    UARTPutc('\b');
    UARTPutc(cntArr[secCnt]);
    secCnt++;
    flagIsrCnt = 0;
    }
    }

    /* Disable the timer. No more timer interrupts */
    // TimerDisable(SOC_TMR_2_REGS, TMR_TIMER12);

    /* Halt the program */
    while(1);
    }

    /*
    ** Timer Interrupt Service Routine
    */
    static void TimerIsr(void)
    {
    /* Disable the timer interrupt */
    // TimerIntDisable(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);

    #ifdef _TMS320C6X
    /* Clear interrupt status in DSPINTC */
    // IntEventClear(SYS_INT_T64P2_TINTALL);
    #else
    /* Clear the interrupt status in AINTC */
    IntSystemStatusClear(SYS_INT_TIMR2_ALL);
    #endif
    TimerIntStatusClear(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
    printf("timer 2.\n");

    /* Signal application to print a new character */
    flagIsrCnt = 1;

    /* Enable the timer interrupt */
    // TimerIntEnable(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
    }


    // add by Tony for nested interrupt example
    static void Timer3Isr(void)
    {

    unsigned int old_csr;
    unsigned int old_irp;
    /* Disable the timer interrupt */
    TimerIntDisable(SOC_TMR_3_REGS, TMR_INT_TMR12_NON_CAPT_MODE);

    #ifdef _TMS320C6X
    /* Clear interrupt status in DSPINTC */
    // IntEventClear(SYS_INT_T64P2_TINTALL); // not necessary to clear.
    #else
    /* Clear the interrupt status in AINTC */
    IntSystemStatusClear(SYS_INT_TIMR2_ALL);
    #endif
    TimerIntStatusClear(SOC_TMR_3_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
    printf("Save INT context for nest.\n");
    /*Protect context for interrupt nest */
    old_irp=IRP;
    old_csr = CSR;
    CSR = (old_csr | 1);

    while(!flagIsrCnt); //wait timer 2 interrupt.

    /* Signal application to print a new character */
    flagIsrCnt = 0;
    CSR = old_csr;
    IRP = old_irp;
    printf("Restored INT context.\n");

    /* Enable the timer interrupt */
    TimerIntEnable(SOC_TMR_3_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
    }

    /*
    ** Setup the timer for 64 bit mode
    */
    static void TimerSetUp64Bit(void)
    {
    /* Configuration of Timer */
    TimerConfigure(SOC_TMR_2_REGS, TMR_CFG_64BIT_CLK_INT);

    /* Set the 64 bit timer period */
    TimerPeriodSet(SOC_TMR_2_REGS, TMR_TIMER12, TMR_PERIOD_LSB32);
    TimerPeriodSet(SOC_TMR_2_REGS, TMR_TIMER34, TMR_PERIOD_MSB32);
    }

    // Add by Tony to configure timer 3 for nested interrupt.
    static void Timer3SetUp64Bit(void)
    {
    /* Configuration of Timer */
    TimerConfigure(SOC_TMR_3_REGS, TMR_CFG_64BIT_CLK_INT);

    /* Set the 64 bit timer period */
    TimerPeriodSet(SOC_TMR_3_REGS, TMR_TIMER12, 0x05FFFFFF);
    TimerPeriodSet(SOC_TMR_3_REGS, TMR_TIMER34, TMR_PERIOD_MSB32);
    }


    /*
    ** Set up the ARM Interrupt Controller for generating timer interrupt
    */
    static void TimerIntrSetUp(void)
    {
    #ifdef _TMS320C6X
    /* Initialize the DSPINTC */
    IntDSPINTCInit();

    /* Register the Timer ISR */
    IntRegister(C674X_MASK_INT4, TimerIsr);
    IntRegister(C674X_MASK_INT5, Timer3Isr); // Add by Tony for nested interrupt example.

    /* Map Timer interrupts to DSP maskable interrupt */
    IntEventMap(C674X_MASK_INT4, SYS_INT_T64P2_TINTALL);
    IntEventMap(C674X_MASK_INT5, 86); // Add by Tony for nested interrupt example.

    /* Enable DSP interrupt in DSPINTC */
    IntEnable(C674X_MASK_INT4);
    IntEnable(C674X_MASK_INT5); // Add by Tony for nested interrupt example.

    /* Enable DSP interrupts */
    IntGlobalEnable();
    #else
    /* Initialize AINTC and register timer interrupt */
    IntAINTCInit();

    /* Register the Timer ISR */
    IntRegister(SYS_INT_TIMR2_ALL, TimerIsr);

    /* Set the channel number for Timer interrupt, it will map to IRQ */
    IntChannelSet(SYS_INT_TIMR2_ALL, 2);

    /* Enable IRQ for ARM (in CPSR)*/
    IntMasterIRQEnable();

    /* Enable AINTC interrupts in GER */
    IntGlobalEnable();

    /* Enable IRQ in AINTC */
    IntIRQEnable();

    /* Enable timer interrupts in AINTC */
    IntSystemEnable(SYS_INT_TIMR2_ALL);
    #endif
    }
    /***************************** End Of File ***********************************/

    这个也是TI的技术支持提供的程序,while(!flagIsrCnt); //wait timer 2 interrupt.这边感觉是“蓄谋已久等待”另外一个中断来打断他,然后立刻进行restore操作,我就是想问,如果中断服务程序A,被打断了,去执行B,等B执行完了,如何再回到A呢?

  • 您好,这样说吧,就是CSR = old_csr;IRP = old_irp;这两句话,需要在被打断的中断服务子程序的什么位置填上呢?恳求您的回答
  • victor sun1 说:
    while(!flagIsrCnt); //wait timer 2 interrupt.这边感觉是“蓄谋已久等待”另外一个中断来打断他,然后立刻进行restore操作,我就是想问,如果中断服务程序A,被打断了,去执行B,等B执行完了,如何再回到A呢?

    这个例子仅仅是为了验证中断嵌套功能,所以在这个ISR里死等,以验证在一个ISR里能响应另一个嵌套的中断,并能正常返回。

    这仅仅是个例子,你自己的代码的话,这里方该干嘛干嘛。

  • victor sun1 说:
    就是CSR = old_csr;IRP = old_irp;这两句话,需要在被打断的中断服务子程序的什么位置填上呢?

    你不是看了这个贴子吗? 感觉你进入一个误区了。

    实现情况时,在进入ISR A后,通过配置使能“高优先级B”的中断,放到GIE后,这里这个“高优先级中断B“如果来了就可以响应了,但是至于这个中断B是否每次都会在进入这个ISR A时来,是不确定的,这本来是随机的。所以这时ISR A该干嘛干嘛,处理完后,再恢复就好了。

    如果这时中断B来了,那就跟正常响应中断一样进入B,退出B ISR后,回到 A ISR继续往下运行。

    理一理吧,已经够清楚了, 所有人都是看的这同一段说明。

  • 您好,也就是说在有可能被打断的ISR A中,进入后就将IRP CSR等保存起来,在中断的末尾将之前保存的恢复一下。如果有其他可屏蔽中断来打断ISR A的话,最后也会在ISR A的某尾将其恢复,如果在ISR A执行结束了,仍然没有任何可屏蔽中断来打断ISR A,ISR A 进行恢复操作也不受影响。是这样的吧?
  • 是的。

    只是

    victor sun1 说:
    如果有其他可屏蔽中断来打断ISR A的话,
    这句话我没太懂。

    总之,是因为进入ISR后,全局中断自动关闭了。所以如果想要让别的中断可以打断当前中断,那么就必需把全局中断打开,又由于中断的返回地址是由IRP保存的,所以IRP里的返回地址也要另做保存,这时如果“高优先级“的中断来了,则跟正常响应中断一样,进入相应的ISR,处理完后,通过IRP返回到前一个中断内的代码继续往下运行,在退出中断前,恢复IRP的返回地址,以及中断使能情况。 当然在前面的中断配置完了,没有来”高优先级“的中断,那么处理完后,同样恢复前面保存的上下文,再退出ISR就好了。

    嵌套配置是为了当有”优先级“中断来时,可以响应,如果没来,继续往下运行,退出,什么也不影响。

  • 忘了说了,那个附件.c文件是跟starterware来使用的,所以ISR前没有加interrupt关键字。因为starterware里的中断注册桩子函数已经加了interrupt关键字。
  • 您好,我想请问下,c6748能否实现组合中断优先级嵌套?场景就是,中断1属于组合事件0,中断2属于组合事件0,中断1与中断2做优先级嵌套,我使用startware里的dispatch,我想知道,能否将这两个中断做成优先级嵌套,谢谢。
  • 你好像把interrupt event和CPU interrupt ID搞混了 组合事件依然是event,最终是跟某个CPU中断号(4:15)挂起来,嵌套是指的CPU中断级的,不是event级的。

  • 我能理解您的意思,您的意思是嵌套实际是相对于中断线而言,我理解的不知对不对,但我有个需求就是想把同一个组合里的event做优先级嵌套,不知能否实现呢,谢谢您

  • 不能.

    为什么一定要这么做呢? 中断线不够用了? 否则通过中断线做就好了.

  • 哈哈哈,项目需求吧,目前也还没定下来,只是先预研着,那我目前还有个问题,我举例子说吧,如gpiob0_6使用单独的线4,组合事件0使用线5,gpiob6_0使用线6,然后在屏蔽参数上我使用的是bitmask,这样我认为可以实现优先级的嵌套,然后我设置当线5来中断时候,可以打断线4且不可以打断线6,线4不可以打断5和6,6都可以打断,这样优先级就是4小于5,5小于6,但我实际测试,发现4还是可以打断5,我不知道是我哪里设置出了问题,您能给点指点吗?谢谢啦
  • bit mask搞错了呗, "1"代表相应的中断来了也不会打断当前中断.
  • 感谢您的回答,代码逻辑,和其他的是一样的,创建组合事件时,屏蔽选成bitmask,这个值写成除了0以外的其他值,都会被其他的单独的线打断,尽管设置的值和线没关联,也会被打断,我想问下,组合的线和其他的线,在设置时是否有什么区别呢?谢谢您
  • 从这个框图来看,没有区别. combiner仅仅是为了同时支持更多的中断事件, 弥补中断线不足.

  • 谢谢您的解惑,我会仔细检查我的代码,谢谢您,