当我试图让微控制器进入睡眠状态,然后唤醒它,作为一个中断驱动的应用程序时,我发现了这个问题。我注意到,我的代码没有从我的“睡眠”指令之后的代码行中恢复。
当我在使用调试器执行代码时手动触发中断时,在跳转到ISR之前,它会采取多个步骤(有时是2步,有时是50步,取决于代码)。
在尝试调试此问题时,我编写了一段非常简单的代码,其中显示了这个问题:
#include <Arduino.h>
// Setup and Loop declared in Arduino core
void configInterrupt(void);
volatile uint32_t debug = 0;
uint32_t int_count = 0;
void EIC_Handler(void){
int_count++;
EIC->INTFLAG.reg = 1 << 0;
}
void configInterrupt(void){
NVIC_DisableIRQ(EIC_IRQn);
NVIC_ClearPendingIRQ(EIC_IRQn);
NVIC_SetPriority(EIC_IRQn, 0);
NVIC_EnableIRQ(EIC_IRQn);
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EIC));
EIC->WAKEUP.reg |= (1 << 0);
EIC->CONFIG[0].reg |= 0x2; // falling edge
pinConfig(16,INPUT,UP); // pin 16 as input with pullup
PORT->Group[0].PINCFG[16].bit.PMUXEN = 1; // enable peripheral muxing
PORT->Group[0].PMUX[8].bit.PMUXE = 0x0; // function A (EIC) = 0x0
EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << 0);
EIC->CTRL.bit.ENABLE = 1;
}
void setup() {
configInterrupt();
}
void loop() {
for(int i = 0 ; i < 100 ; i++) debug++; // volatile so that the compiler doesn't touch
String debugstring = "";
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__DSB();
__WFI();
}
我正在使用外部中断进行调试,我用跳线触发自己,这样我就知道什么时候应该触发了。我注意到的是,当我调试代码并执行它时,如果手动触发外部中断,那么它不会立即跳转到ISR。中断在NVIC中变为“未决”,但异常项要到代码的后面才会执行。
我在SAMD21数据表、Cortex M0+通用用户指南和ARM体系结构手册中阅读了很多关于中断和异常的文章。据推测,Cortex M系列具有低延迟中断,没有指令开销,因此在触发中断后,代码应该相对较快地跳转到ISR。
我已经多次阅读过Cortex M0+泛型指南的2.3.6以及ARM体系结构手册的B1.3.2,这两本手册都详细介绍了异常条目。SAMD21数据表似乎没有太多低级别的信息。
我试图隔离这个问题并识别设备行为中的任何模式,我注意到了一些事情。
它只在特定的代码行跳到ISR。例如,在上面的代码中,如果外部中断是在' loop ()‘开头触发的,那么无论' For’循环中有多少次迭代,当它到达字符串声明时,它都会跳转到ISR。如果我将字符串声明移到“for”循环上方,那么它几乎会立即跳转到ISR (在2或3个调试步骤之后)。
我尝试过插入延迟,NOPs和ISB,这不会影响它花费多长时间或使它立即跳跃。当我在软件中设置一个挂起的中断时,通过国家核生化中心的ISPR寄存器,也会出现同样的问题。我跟踪了Atmel Studio中的基本闪存,并注意到处理器当前状态被推送到的“堆栈”也不会立即改变。只有当我到达ISR中的第一行代码时,它才会改变。
我注意到的其他代码片段类似于字符串声明,并导致代码跳转到ISR中,这是电线库的endTransmission函数,SD卡库中的一些函数,Arduino延迟函数。
这是否与我一开始就使用调试器而干扰/不使用中断的事实有关?不过,我相当肯定问题发生在调试器出炉之前。编辑:通过阅读Cortex M0+技术参考手册和ARMv6手册,我找到了一个名为DHCSR的寄存器,它允许调试器屏蔽中断,但我无法想出如何访问这些寄存器。
的主要问题:除了PRIMASK和全局/个人启用寄存器位之外,还有什么可以阻止挂起的中断被执行呢?
编辑:遗漏了一段重要的信息,尽管我在Atmel Studio工作,但这个项目使用Arduino核心。
编辑:我注意到,在我手动触发一个中断之后,在我的下一个调试步骤中,它就会被挂在N维也纳->ISPR寄存器中。这让我相信中断被掩盖了(我已经检查了PRIMASK,全局启用和个人启用到目前为止没有运气)。
发布于 2016-06-23 15:19:37
String debugstring = "";
是这个东西实际上是C++的线索。因此,必须将IRQ处理程序声明为纯C函数:
extern "C" {
void EIC_Handler(void);
}
void EIC_Handler(void){
int_count++;
EIC->INTFLAG.reg = 1 << 0;
}
否则,函数是C++,an不作为IRQ处理程序,因为链接器本身无法识别它。
https://stackoverflow.com/questions/37958762
复制相似问题