I've been experiencing this weird behavior on an AVR ATmega328p.
What is happening is the following: I have written a firmware that makes use of USART, TIMER0 and interrupts. The firmware works as expected.
Here is the output from the USART when it behaves as expected:
USART
Timer0
Sched
IRQ
tick
tick
tick
But as soon as I add a call to a function (namely Uptime_Create()) to its main(), execution stops at the call of Uptime_Create(). I assume that because I have calls to USART_Puts() after each component is initialized.
This is my 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();
}
The complete source code is available at github (http://github.com/lazlo/). The main.c was taken from the "lzoOS-test-firmware" repository from the sched/ directory.
In order to build the main.c you will have to check out the "Drivers" and the "lzoOS" repository as well and place them in the same directory.
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
As soon as the call to Uptime_Create() is active again, the firmware stops execution (IMHO) after "Timer0" is printed out by USART_Puts().
I have already compiled a version with and without the call to Uptime_Create() and compared the assembly listing (.lss files). From what I can see only offsets differ (as Uptime.o is always linked to the firmware, no matter if the call is made or not).
What Uptime_Create() actually does is to initlaize a static struct (inside of Uptime.c) with zero.
Here is the code form 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;
}
Any suggestions welcome!
UPDATE: I made a little experiment where I only use the USART and Uptime code. It looks like this:
#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)
;
}
Turns out, the strinf "Uptime" is never printed. Again I looked at the assembly listing but wasn't able to make sense or see the problem that would make the controller halt. What happens in Uptime_Create() looks like this:
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>:
}
UPDATE: When I was asked to answer if Uptime_Create() ever actually returns (on the microcontroller) I wrote a new minimal firmware that only uses the USART and Uptime module. While running this firmware in Simulavr, I noticed, Uptime_Create() returns but USART_Puts() makes code execution stop/run an endless loop. Specifically it is BitIsSet() in USART_Putc() that checks if UDRE (USART Data Register Empty) bit is set. Weird enough, before I call Uptime_Create() I call USART_Puts(uart, "USART ready\r\n"); which works and I can see the output. But after calling Uptime_Create() the next call to USART_Puts() results in an endless loop because the UDRE in the UCSRA (USART control and status register) is never set.
Why this is, I can only guess. As i tried to set a data watchpoint using gdb in the simulator but as it seems the simulator does not support data watchpoints.
UPDATE: I found the reason: Uptime_Create() initializes "static UptimeStruct uptime" zero, which turns out to be at the same memory address as "static USARTStruct usart[0]". Which in turn results in setting the pointers in usart struct that point to the registers (UCSR[A..C] and so on) to zero.