2016-06-21 1 views
2

Я не уверен, что мне не хватает чего-то очевидного здесь, но у кого-то еще возникли проблемы с Cortex M0 + (или любым из диапазона Cortex M), возвращающимся с ISR в несколько случайную позицию в режиме потока после пробуждения из спящего режима (например, не возвращаясь к строке ниже инструкции WFI). Кажется, он проснулся в середине кода, например, в середине цикла for или в середине функции. Я использую ATSAMD218A микроконтроллер и использует отладчик в Atmel Studio, 7. Я пытался изолировать проблему и заметил следующее:Cortex M0 + возвращается в неправильное положение в режиме потока после прерывания сна

  • Это происходит только тогда, когда устройство усыпить, когда устройство прерывается, когда он бодрствует, ISR всегда возвращается в нужное место.
  • ISR всегда возвращается к тому же (некорректному) положению в коде, если я прокомментирую эту функцию или фрагмент кода, тогда он начнет возвращаться в другую неправильную позицию.
  • Я неудачно вставил задержки и NOP, чтобы попытаться определить если он связан с синхронизацией или связан с синхронизацией, но он все равно всегда возвращается в ту же (неправильную) позицию
  • Я попытался реализовать прерывания, используя как прямой доступ к регистру, так и используя библиотеку Arduino Interrupts.
  • Это происходит как в режиме ожидания, так и в режиме ожидания.
  • При просмотре инструкций по сборке во время отладки, перед выходом ISR выдается инструкция «bx lr», регистр ссылок. Регистр ссылок содержит значение, называемое EXC_RETURN, которое указывает на поведение возврата, которое в моем случае равно 0xFFFFFFF9 (возврат в режим потока). Однако я не могу найти фактический адрес памяти, который он возвращает в любом месте. Адрес памяти не входит ни в один из основных регистров R0-R15.

Я читал Справочное руководство по архитектуре ARMv6, а также Руководство пользователя Cortex M0 + Generic. Не совсем уверен, что происходит, и любые предложения по отладке будут высоко оценены. Кто-нибудь лучше понимает обработку исключений из серии Cortex M и может указать мне в правильном направлении, чтобы найти адрес памяти, в который возвращается поток, после ISR. Я мог бы предоставить код, если вы хотите, но даже простой фрагмент кода, который ничего не делает, кроме как считать в цикле, спать, а затем просыпаться, вызывает проблемы.

EDIT Я добавил соответствующий код ниже. Это самая удаленная версия (* striped), которая все еще вызывает проблемы. Я не включил функции кода RTC (использует библиотеку DS3231RTC), поскольку я уверен, что они не имеют никакого эффекта. Если вы думаете, что я должен загрузить больше, дайте мне знать.

void configInterrupt(void){ 
    NVIC_DisableIRQ(EIC_IRQn); 
    NVIC_ClearPendingIRQ(EIC_IRQn); 
    NVIC_SetPriority(EIC_IRQn, 0); 
    NVIC_EnableIRQ(EIC_IRQn); 

    // Enable GCLK for IEC (External Interrupt Controller) 
    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);      // custom 'pinMode' function 
    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 EIC_Handler(void){ 
    RTC_FLAG = 1;   // my debug breakpoint is here, at this point the stack has already been pushed and I can see the PC value that will be popped off 
    int_count++; 
    EIC->INTFLAG.reg = 1 << 0; 
} 

void setup() { 
    configInterrupt();     
    configureRTC(); 
    RTC_FLAG = 1; 
} 

void loop() { 
    if (RTC_FLAG == 1) { 
    RTC_FLAG = 0; 
    setNextAlarm(); 
    } 

    for (int i = 0 ; i <= WINDOW-1 ; i++) { 
     String data = ""; 

     rawVal = 0;  // data gets read from sensor here (stripped) 
     data += String(rawVal); 
     data += ","; 

     distance = 0; // distance calculated from rawVal here (stripped) 
     data += String(distance); 
     data += ","; 

     mean = 0;  // mean calculated in a function here (stripped) 
     data += String(mean); 
     data += ","; 

     data += String(int_count); // ISR returns here 
     // Data gets written to file here (stripped) 
} 

    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; 
    __DSB(); 
    __WFI(); 
} 
+0

Можете ли вы опубликовать код, который вы использовали, и те моменты, которые, по вашему мнению, терпят неудачу? –

+1

_ «Однако я не могу найти фактический адрес памяти, который он возвращает в любом месте» _ - См. B1.5.6 «Поведение элемента исключений» в ARM ARMv6-M; он находится в стеке. Как выглядит код ISR? – Notlikethat

+0

Я сомневаюсь, что это ручная вещь, вероятно, вещь чипа, нужно прочитать руководство для устройства с особым упором на все, что он говорит о том, когда он ложится спать.Что сохранилось, а что нет, если есть рекомендация о том, как и где спать, и т. Д. –

ответ

0

Я бы попробовать реализовать тот же фрагмент кода, используя структуру Atmel ASF, смотрите в регистрах наборов API и в каком порядке. Они также обычно ссылаются на ошибки и выполняют работу.

Загрузите пример проекции с малой мощностью, он переключится между режимами питания и просыпается на кнопке xplained board. Если это может прыгать между режимами на вашей доске, вы знаете, что это не та часть. Возможно, вам придется переместить будильный контакт на что-то в соответствии с вашим оборудованием.

Смежные вопросы