assembly arduino embedded cortex-m isr

assembly - Cortex M0+(SAMD21) no se está ejecutando pendiente de interrupción



arduino embedded (1)

The String debugstring = ""; es la clave de que esto es en realidad C ++. Por lo tanto, debe declarar el controlador de IRQ como función C pura:

extern "C" { void EIC_Handler(void); } void EIC_Handler(void){ int_count++; EIC->INTFLAG.reg = 1 << 0; }

De lo contrario, la función es C ++ y no funciona como controlador de IRQ porque el enlazador no puede reconocerlo como tal.

Descubrí este problema cuando traté de poner el microcontrolador en modo de suspensión y luego despertarlo, como una aplicación impulsada por interrupciones. Noté que mi código no se reanudó desde la línea de código que estaba después de mi instrucción de ''suspensión''.

Cuando acciono manualmente una interrupción mientras paso por mi código con un depurador, toma varios pasos (a veces 2, a veces 50 dependiendo del código) antes de que salte al ISR.

Al intentar depurar este problema, escribí este código muy simple que muestra el problema:

#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(); }

Estoy depurando usando una interrupción externa que me disparo con un cable de puente para saber cuándo debería haberse disparado. Lo que estoy notando es que mientras depuro el código y lo paso, si activé la interrupción externa manualmente, entonces no salta directamente al ISR. La interrupción se convierte en ''pendiente'' en el NVIC, pero la entrada de excepción no se lleva a cabo hasta más adelante en el código.

He leído mucho sobre interrupciones y excepciones en la hoja de datos SAMD21, la Guía de usuario genérica Cortex M0 + y el manual de ARM Architecture. Supuestamente, la serie Cortex M tiene bajas interrupciones de latencia sin sobrecarga de instrucciones, por lo que parece que el código debería saltar al ISR relativamente rápido después de disparar una interrupción.

He leído varias veces la 2.3.6 de la Guía genérica Cortex M0 + y la B1.3.2 del manual ARM Architecture, que cubren la entrada de excepciones con bastante detalle. La hoja de datos SAMD21 no parece tener mucha información de bajo nivel.

Intenté aislar el problema e identificar cualquier patrón en el comportamiento del dispositivo y me di cuenta de algunas cosas.

Solo salta al ISR en líneas de código específicas. Por ejemplo, en el código anterior, si la interrupción externa se activa al inicio de ''loop ()'' saltará al ISR cuando llegue a la declaración String, independientemente de la cantidad de iteraciones en el ciclo ''for''. Si muevo la declaración de cadena por encima del bucle ''for'', saltará al ISR casi de inmediato (después de 2 o 3 pasos de depuración).

Intenté insertar retrasos, NOP e ISB que no afectan el tiempo que toma o lo hacen saltar al instante. Cuando establezco una interrupción pendiente en el software a través del registro ISPR en el NVIC, ocurre el mismo problema. He seguido la pista de la memoria FLASH básica en Atmel Studio y noté que la "pila" en la que se impulsa el "estado" actual del procesador tampoco cambia inmediatamente. Solo cambia cuando llego a la primera línea de código en el ISR.

Otras piezas de código que he notado actúan de forma similar a una declaración de cadena y hacen que el código salte al ISR es la función de transmisión final de la biblioteca Wire, algunas funciones en la biblioteca de tarjeta SD, la función de retardo Arduino.

¿Podría estar relacionado con el hecho de que estoy usando un depurador en primer lugar que interfiere / no funciona bien con interrupciones? Estoy bastante seguro de que el problema ocurrió antes de que obtuviera el depurador. Edición: leyendo el Manual de referencia técnica de Cortex M0 + y el manual de ARMv6 He encontrado un registro llamado DHCSR que permite que el depurador enmascare las interrupciones, pero no puedo encontrar la forma de acceder a estos registros.

Pregunta principal: además de PRIMASK y bits de registro de habilitación global / individual, ¿qué otra cosa podría estar impidiendo que se ejecute una interrupción pendiente?

Editar: omití una información importante, aunque estoy trabajando en Atmel Studio el proyecto usa el núcleo Arduino.

EDIT: he notado que después de activar manualmente una interrupción, queda pendiente en el registro NVIC-> ISPR durante mi próximo paso de depuración. Esto me lleva a creer que las interrupciones están siendo enmascaradas en alguna parte (he revisado PRIMASK, habilitación global y habilitación individual hasta ahora sin suerte).