He estado escribiendo un pequeño programa para mi Freescale Kinetis KE04Z que se ejecuta en la memoria RAM para programar el flash del dispositivo. He estado usando SWD para colocar el programa en RAM y ejecutarlo. Todo iba bien (parpadeando los LED como prueba, etc.) hasta que intenté iniciar el temporizador de interrupción periódica (módulo PIT) para confirmar la velocidad del microcontrolador al destellar un LED con cierta sincronización específica (el manual del controlador de flash dice que si la velocidad es incorrecta entonces podría destruir el flash). No tengo un osciloscopio disponible en este momento, de lo contrario simplemente descartaría el PIT, escribiría el registro de activación de pin de gpio (PTOR) una y otra vez, y mediría el período de la onda cuadrada resultante.
Tengo en mi sección de inicio el siguiente ensamblaje que mueve el VTOR a mi tabla de vectores de interrupción:
ldr r0, =0xE000ED08
ldr r1, =__interrupt_vector_table
str r1,[r0]
__interrupt_vector_table
apunta al comienzo de la sección de RAM donde he colocado mi tabla de vectores de interrupción (0x1fffff00 para el registro). El código se puede encontrar aquí . La lista de códigos de inicio y la tabla de interrupciones es aquí .
En mi método principal tengo lo siguiente:
SIM->SCGC |= SIM_SCGC_PIT_MASK; //turn on PIT clock
PIT->MCR = 0; //activate PIT
PIT->CHANNEL[0].LDVAL = 1.2e6; //100mS tick
PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK; //enable the timer
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK; //enable the interrupt
NVIC->ISER[0] = 1 << 22; //enable interrupt in NVIC
__enable_irq(); //cpsie i
Fue en este punto donde comencé a tener problemas. Una vez que el PIT se activara, se produciría un bloqueo de acuerdo con el registro SIM_SRSID cuando lo leí a través de SWD. Tengo un par de pensamientos sobre por qué esto podría suceder:
- El ISR se ejecuta, pero nunca regresa, lo que hace que el WDT se apague y se inicie un reinicio, lo que hace que el VTOR se reinicie a 0x0. Dado que el dispositivo no está programado, el vector de reinicio es 0xffffffff, lo que provoca un bloqueo.
- El ISR ejecuta, rompe los registros y evita que el método principal reinicie correctamente el WDT, causando la misma situación que la anterior.
- La interrupción se desactiva, pero por alguna razón, el NVIC no puede ejecutar mi ISR e inicia un HardFault. Mi código de error solo se bloquea para siempre, lo que eventualmente causará que el WDT se apague y así sucesivamente.
- Mi tabla de interrupciones escrita a mano está desactivada por una y una de las ISR predeterminadas se está ejecutando y causando un tiempo de espera de WDT (o no estoy habilitando la ISR correcta y está ocurriendo lo mismo). La cuestión es que nunca he podido mostrar que mi código ISR predeterminado se estaba ejecutando en lugar de mi controlador IRQ real. He realizado algunas pruebas utilizando las ubicaciones de memoria de escritura para valores específicos y luego las leo después del restablecimiento y el código para establecer esos valores nunca se ha ejecutado.
Estoy bastante seguro de que tiene que ver con mi ISR o la interrupción en general porque una vez que comento la línea de código que establece PIT_TCTRL0.TIE, el programa funciona bien y no se bloquea.
Mi ISR es muy simple en este momento:
void PIT_CH0_IRQHandler(void)
{
PIT->CHANNEL[0].TFLG = 0x1; //reset flags
}
Que compila a:
2000001c <PIT_CH0_IRQHandler>:
2000001c: 2201 movs r2, #1
2000001e: 4b01 ldr r3, [pc, #4] ; (20000024 <PIT_CH0_IRQHandler+0x8>)
20000020: 611a str r2, [r3, #16]
20000022: 4770 bx lr
20000024: 400370fc strdmi r7, [r3], -ip
Sinceramente, no sé si esto es correcto. No hay ahorro de contexto o cualquier otra cosa que haya visto en otros ISR, pero nunca he visto en detalle los ISR ARM Cortext M0 +, por lo que sé, el NVIC se encarga de guardar el contexto.
Mi pregunta es:
- ¿El código ISR, el código NVIC o el código de reubicación de VTOR es el problema aquí?
- ¿O tal vez la ubicación del VTOR en una ubicación en la RAM sea algo malo y no funciona correctamente?
Esta es la primera vez que escribo un programa que se ejecuta en RAM y también la primera vez que reubico el VTOR, por lo que no tengo mucha experiencia en estos asuntos. He hecho un montón de código de interrupción para un K20 antes, pero el VTOR siempre estaba en 0x0. Si he omitido algo o necesito proporcionar información adicional, simplemente avíseme.