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.
不时总有人问起DSP的中断嵌套问题,有必要说明白几个概念上的问题,同时今天做了一个小示例供参考,欢迎拍砖。
概念:
#1. 中断优先级的概念。没有高优先级可以打断低优先级中断的说法。优先级只针对于处于pending状态的中断,中断控制器取高优先级的中断执行。对于正在处理当中的中断,如果不做软件上的特殊处理(即示例代码),是不能被别的中断打断的,除了NMI中断。
#2. 为什么正在处理当中的中断不能被其它中断打断,因为中断控制在进入中断时,把全局中断(GIE)关了,当然别的中断进不来了。
#3. 不难理解为什么NMI可以响应了,因为NMI不受GIE控制。
好了,应用当中有需要对某个中断及时响应怎么办?也就是说某个中断一来,希望它及马上跳到中断服务程序,哪怕是在执行别的中断服务程序。方法如下:
#1. C674x DSP参考文档sprufe8b 5.6.2节 Nested Interrupts. C64x+参考文档spru732j 5.7.2 Nested Interrupts. 内容如下。
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
spru732j里还提供了一段示例如代码:
附件例子就是参照这个示例代码实现的。初步测试没看出有什么问题,也想不出能有什么问题。
#2. 如果用BIOS的话呢,在HWI里Masking Options里设置,下图红圈位置。
老版本的BIOS里,这地方没有BITMASK的输入框(上图是BIOS6_76的,已有了),根据下面贴子,还需要设disableMask and restoreMask instance configuration parameters,有兴趣自己去找怎么设吧。
https://e2e.ti.com/support/legacy_forums/embedded/tirtos/f/355/t/143228
附件的代码来源于L138 starterware C:\ti\OMAPL138_StarterWare_1_10_03_03\examples\lcdkOMAPL138\timer\timerCounter.c
将附件替换这个文件,用例子C:\ti\OMAPL138_StarterWare_1_10_03_03\build\c674x\cgt_ccs\omapl138\lcdkOMAPL138\timer编译即可验证一下中断嵌套了。
我是开了两个timer, 在timer 3 ISR里打开了嵌套,等timer 2的中断进来,执行完再回到timer 3 ISR,再退出。
/** * \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 ***********************************/
您好,您的例子中,明确知道其他中断会在 while(!flagIsrCnt);之后执行restore的操作,但是如果我不是明确知道会在什么地方打断,该如何实现嵌套呢?
这个while(!flagIsrCnt)可以换成任何代码,这只是个示例啊.
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);
}