He estado experimentando este extraño comportamiento en un AVR ATmega328p.
Lo que está sucediendo es lo siguiente: He escrito un firmware que hace uso de USART, TIMER0 e interrupciones. El firmware funciona como se esperaba.
Aquí está la salida del USART cuando se comporta como se espera:
USART
Timer0
Sched
IRQ
tick
tick
tick
Pero tan pronto como agrego una llamada a una función (es decir, Uptime_Create ()) a su main (), la ejecución se detiene en la llamada de Uptime_Create (). Supongo que porque tengo llamadas a USART_Puts () después de que se inicializa cada componente.
Este es mi main.c
/* Written for Rainbowduino (ATmega328p at 16MHz) */
#include "USART.h"
#include "Timer.h"
#include "Sched.h"
#include "Uptime.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
static USART uart;
static void uart_init(const uint32_t baud)
{
uart = USART_Create(&UCSR0A, &UCSR0B, &UCSR0C, &UBRR0L, &UBRR0H, &UDR0);
USART_SetBaudRate(uart, 38400, F_CPU);
USART_Enable(uart, 1);
USART_Puts(uart, "USART\r\n");
}
static void timer_init(void)
{
Timer t0;
t0 = Timer_Create(0, &TCCR0A, &TCCR0B,
&TCNT0, 0,
&OCR0A, 0,
&OCR0B, 0,
0, 0,
&TIMSK0, &TIFR0);
Timer_SetOverflowInterrupt(t0, 1);
Timer_SetClockSource(t0, 3); /* 64 */
USART_Puts(uart, "Timer0\r\n");
}
static void testTask(void)
{
#if 0
char utstr[9];
Uptime_Tick();
Uptime_ToStr(utstr);
USART_Puts(uart, utstr);
#endif
USART_Puts(uart, " tick\r\n");
}
static void sched_init(void)
{
Sched_Create();
Sched_AddTask(testTask, 1000, 0);
USART_Puts(uart, "Sched\r\n");
}
int main(void)
{
uart_init(38400);
timer_init();
//Uptime_Create();
sched_init();
sei();
USART_Puts(uart, "IRQ\r\n");
while (1)
Sched_Dispatch();
}
ISR(TIMER0_OVF_vect)
{
Sched_Update();
}
El código fuente completo está disponible en github ( enlace ). La main.c se tomó del repositorio "lzoOS-test-firmware" del sched / directory.
Para construir main.c, también deberá revisar los "Controladores" y el repositorio "lzoOS" y colocarlos en el mismo directorio.
mkdir tmp
cd tmp
git clone https://github.com/lazlo/Drivers.git
git clone https://github.com/lazlo/lzoOS.git
git clone https://github.com/lazlo/lzoOS-test-firmware.git
cd lzoOS-test-firmware/sched
make
Tan pronto como la llamada a Uptime_Create () vuelva a estar activa, el firmware detiene la ejecución (IMHO) después de que USART_Puts () imprima "Timer0".
Ya compilé una versión con y sin la llamada a Uptime_Create () y comparé la lista de ensamblajes (archivos .lss). Por lo que puedo ver, solo las compensaciones difieren (ya que Uptime.o siempre está vinculado al firmware, no importa si la llamada se realiza o no).
Lo que realmente hace Uptime_Create () es iniciar una estructura estática (dentro de Uptime.c) con cero.
Aquí está el código de Uptime.c
typedef struct UptimeStruct
{
uint8_t seconds;
uint8_t minutes;
uint8_t hours;
} UptimeStruct;
static UptimeStruct uptime;
void Uptime_Create(void)
{
uptime.seconds = 0;
uptime.minutes = 0;
uptime.hours = 0;
}
Cualquier sugerencia es bienvenida!
ACTUALIZACIÓN: Hice un pequeño experimento en el que solo uso el código USART y Uptime. Se parece a esto:
#include "USART.h"
#include "Uptime.h"
#include <avr/io.h>
int main(void)
{
USART u;
u = USART_Create(&UCSR0A, &UCSR0B, &UCSR0C, &UBRR0L, &UBRR0H, &UDR0);
USART_SetBaudRate(u, 38400, F_CPU);
USART_Enable(u, 1);
USART_Puts(u, "USART\r\n");
Uptime_Create();
USART_Puts(u, "Uptime\r\n");
while (1)
;
}
Resulta que el strinf "Uptime" nunca se imprime. Nuevamente miré la lista de ensamblajes pero no pude tener sentido o ver el problema que haría que el controlador se detuviera. Lo que sucede en Uptime_Create () tiene este aspecto:
00000384 <Uptime_Create>:
static UptimeStruct uptime;
void Uptime_Create(void)
{
uptime.seconds = 0;
384: 10 92 18 01 sts 0x0118, r1
uptime.minutes = 0;
388: 10 92 19 01 sts 0x0119, r1
uptime.hours = 0;
38c: 10 92 1a 01 sts 0x011A, r1
390: 08 95 ret
00000392 <Uptime_Destroy>:
}
ACTUALIZACIÓN : cuando me pidieron que respondiera si Uptime_Create () alguna vez regresa (en el microcontrolador) escribí un nuevo firmware mínimo que solo usa el módulo USART y Uptime. Mientras ejecutaba este firmware en Simulavr, noté que Uptime_Create () regresa pero USART_Puts () hace que la ejecución del código se detenga / ejecute un ciclo sin fin. Específicamente, es BitIsSet () en USART_Putc () el que comprueba si el bit UDRE (Registro de datos USART vacío) está establecido. Lo suficientemente extraño, antes de llamar a Uptime_Create () llamo a USART_Puts (uart, "USART ready \ r \ n"); Que funciona y puedo ver la salida. Pero después de llamar a Uptime_Create (), la próxima llamada a USART_Puts () da como resultado un bucle sin fin porque nunca se establece el UDRE en UCSRA (registro de estado y control USART).
Por qué esto es, sólo puedo adivinar. Como intenté establecer un punto de observación de datos usando gdb en el simulador, pero como parece, el simulador no admite puntos de observación de datos.
ACTUALIZACIÓN : encontré la razón: Uptime_Create () inicializa "UptimeStruct uptime estático" cero, que resulta estar en la misma dirección de memoria que "USARTStruct static usart [0]". Lo que a su vez resulta en establecer los punteros en la estructura de usart que apuntan a los registros (UCSR [A..C] y así sucesivamente) a cero.