Estoy trabajando en la creación de un flujo de programa basado en interrupciones utilizando el módulo PIC24FV32KA302 de Microchip. Sin embargo, tengo algunos problemas con los reinicios intermitentes (al parecer).
Actualmente estoy usando el simulador MPLAB X, tratando de averiguar dónde está ocurriendo el problema. Originalmente estaba usando un PICKit3 en hardware real, pero me encontré con algunos problemas en los que, después de algunos ciclos a través del bucle principal, el depurador se detenía y arrojaba un error "PC en 0x0", que es una dirección sin una instrucción válida. No creo que estos problemas estén relacionados, pero realmente no puedo eliminar la posibilidad.
En esencia, el flujo de mi programa es el siguiente:
main()
{
init();
print_an_init_message();
while(1)
{
check_some_flags();
if(flags_are_set)
{
do_something_about_them();
}
}
}
Durante la simulación, el programa imprime repetidamente el mensaje de inicio. Capta un punto de interrupción en el bucle while (1), por lo que debe estar ingresando. Además, si continúo desde ese punto de interrupción, volverá a él (no se restablecerá). Si salgo de ese punto de interrupción, el depurador falla.
Entonces, traté de imprimir valores del registro RSON (que se supone que se establece durante cualquier condición de reinicio) en el mensaje de inicio. Ninguno de los valores está establecido. Si agrego un retraso simple (XC16 incorporado __delay_ms()) al ciclo while, se llama a la interrupción _AddressError. La instrucción desde la cual se origina el error de dirección siempre es una instrucción ULNK de una de las funciones utilizadas en do_something_about_them() (que representa múltiples indicadores y funciones, parece posible que sea cualquiera de las funciones, pero con mayor frecuencia es la primero o último).
También vale la pena señalar que si pongo un punto de interrupción en la última línea de main (devuelve -1), nunca se alcanza, pero el simulador imprime continuamente el mensaje de inicio.
¿Es probable que esto sea un problema con el simulador o con mi programa? ¿Podría esto estar relacionado con el problema de mi PC 0x0 cuando se ejecuta en hardware real, o es probable que sean diferentes?
Si alguien quiere un código real para ayudar, puedo proporcionarlo; simplemente no lo proporcioné de inmediato porque siento que ofuscaría mi problema real, que no creo que esté causado por mi código C.
¡Gracias de antemano!
Después de un poco de depuración, logré que el error PC 0x0 desapareciera. Todavía estoy tratando de aterrizar en el error de dirección ISR. Esto ahora es programar hardware real con PICKit3.
Creo que el código que está causando el problema es una cola con la que estoy lidiando.
typedef struct uint16_queue_tag {
uint16_t *contents;
int front;
int back;
int maxSize;
int cnt;
} uint16_queue;
bool uint16_InitQueue(uint16_queue *queueP, uint8_t queueSize)
{
uint16_t newContents[queueSize];
queueP->contents = &newContents[0];
queueP->maxSize = queueSize;
queueP->cnt = 0;
queueP->front = -1;
queueP->back = -1;
return true;
}
bool uint16_IsQueueEmpty(uint16_queue *queueP)
{
return (bool) (queueP->cnt == 0);
}
bool uint16_IsQueueFull(uint16_queue *queueP)
{
return (bool) (queueP->cnt == queueP->maxSize);
}
bool uint16_ClearQueue(uint16_queue *queueP)
{
queueP->front = -1;
queueP->back = -1;
queueP->cnt = 0;
return true;
}
bool uint16_PushQueue(uint16_queue *queueP, uint16_t element)
{
if (uint16_IsQueueFull(queueP))
{
return false; // We can't push to the queue, its full
}
else
{
queueP->back++;
queueP->contents[(queueP->back % queueP->maxSize)] = element;
queueP->cnt++;
return true;
}
}
uint16_t uint16_PullQueue(uint16_queue *queueP)
{
if (uint16_IsQueueEmpty(queueP))
{
return NULL;
}
else
{
queueP->front++;
queueP->cnt--;
return queueP->contents[(queueP->front % queueP->maxSize)];
}
}
Parece que todo funciona bien para algunas iteraciones, pero en algún momento se uint16_PushQueue(&queue_obj, value)
rompe el código. Después de inicializar la cola, todo lo que hago es verificar si está llena, empujar y tirar. Extrañamente, parece que el valor del puntero de contenido es diferente: después de que se rompe, el puntero apunta al mismo valor que "frente", que definitivamente no es el mismo valor en el que comenzó. Además, MPLAB informa que el elemento en el lugar al que apunta es 0.0 (que definitivamente no es un flotante).
Así que supongo que esto es solo una especie de estupidez en la asignación del puntero, lo que también explica todo el problema de la dirección: de alguna manera me estoy moviendo hacia donde apunta el puntero de contenido.
La forma en que inicializa su cola no está bien:
bool uint16_InitQueue(uint16_queue *queueP, uint8_t queueSize)
{
uint16_t newContents[queueSize];
queueP->contents = &newContents[0];
queueP->maxSize = queueSize;
queueP->cnt = 0;
queueP->front = -1;
queueP->back = -1;
return true;
}
La newContents
matriz de longitud variable se inicializará en la uint16_InitQueue
pila de . Una vez que la función regrese, queueP->contents
apuntará a la pila y cualquier intento de modificar su contenido corromperá la pila y podría provocar un bloqueo.
Parece que todo funciona bien para algunas iteraciones, pero en algún momento un uint16_PushQueue(&queue_obj, value) rompe el código. Después de inicializar la cola, todo lo que hago es verificar si está llena, empujar y tirar.
Esto tiene mucho sentido, ya que hacer a uint16_PushQueue
corromperá la pila.
La matriz debe asignarse dinámicamente (no es una buena práctica para sistemas integrados sin un sistema operativo) o asignarse globalmente. Al programar un sistema integrado, generalmente establece un tamaño máximo para la cola (o cualquier otro contenedor) en el momento de la compilación.
Algunas sutilezas:
bool uint16_IsQueueEmpty(uint16_queue *queueP)
{
return (bool) (queueP->cnt == 0);
}
El elenco es totalmente inútil. Puedes hacer: return (queueP->cnt == 0)
en su lugar.
Cuanto menos código, mejor.
Suena como uno de los dos posibles problemas. O el código está golpeando un puntero nulo o alguna interrupción está habilitada que no tiene un controlador. En cualquier caso, el código intenta saltar a ninguna parte y ese error podría establecerse.
Para verificar que este es el problema, cree cuatro interrupciones para las trampas integradas. Mire las cuatro interrupciones principales en la sección de interrupciones de la hoja de datos.
Depure el código como lo hacía antes y verifique si cae en la trampa de error de Dirección. Esto confirmaría el problema.
Parece que podría tener un problema con el temporizador de vigilancia. Asegúrese de que el mecanismo de vigilancia esté de hecho desactivado o que esté restableciendo correctamente el temporizador del mecanismo de vigilancia. A veces, el temporizador de vigilancia está habilitado como opción predeterminada. Así que creo que el programa es el problema aquí. Y el problema que está experimentando en el hardware es que la misma PC en 0x0 significa literalmente que el contador del programa vuelve a cero, en otras palabras, el hardware se ha reiniciado.
Conocido