I have had lots of problems trying to get a piece of firmware to work which has worked fine earlier, and is working on a copy of the board I'm having problems with. I've narrowed in down to the following (at least to start with):
This piece of code works:
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
// LEDs - initial setting
DDRC |= 0x03; // LEDs on pins PC0 and PC1
PORTC &= ~(1<<0); // LED0 OFF
PORTC |= (1<<1); // LED1 ON
DDRD |= 0x30; // PD4..5 OUT
TCCR1A = 0xE2; //0b11100010 (Set OC1A + Clear OC1B on compare match, )
TCCR1B = 0x19; //0b00011001 (WGM13:10 = 0b1110 => Fast PWM Mode, TOP = ICR1, CS12:0 = 001 => Use IO clock, no prescaling)
OCR1A = 18;
OCR1B = 18; // 18 / 8000000 = 2.25 us (Output compare match value (OC1A->HIGH, OC1B->LOW)
ICR1 = 757; // 757 / 8000000 = 94.625us (TOP value for timer1)
// Loop blinks LED0..1 alternately
while(1)
{
PORTC = PORTC ^ 0x03;
_delay_ms(250);
}
}
It starts the timer and outputs the pulse with the specified timing, and enters the blinking LED loop.
However, this code fails:
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
void pulse_init(void)
{
DDRD |= 0x30; // PD4..5 OUT
TCCR1A = 0xE2; //0b11100010 (Set OC1A + Clear OC1B on compare match, )
TCCR1B = 0x19; //0b00011001 (WGM13:10 = 0b1110 => Fast PWM Mode, TOP = ICR1, CS12:0 = 001 => Use IO clock, no prescaling)
OCR1A = 18;
OCR1B = 18; // 18 / 8000000 = 2.25 us (Output compare match value (OC1A->HIGH, OC1B->LOW)
ICR1 = 757; // 757 / 8000000 = 94.625us (TOP value for timer1)
}
int main(void)
{
// LEDs - initial setting
DDRC |= 0x03; // LEDs on pins PC0 and PC1
PORTC &= ~(1<<0); // LED0 OFF
PORTC |= (1<<1); // LED1 ON
pulse_init();
// Loop blinks LED0..1 alternately
while(1)
{
PORTC = PORTC ^ 0x03;
_delay_ms(250);
}
}
…it's just the same statements as before, moved to the pulse_init() function. When I upload this code the timer is set up correctly and the output pulse is OK, but the program never starts blinking the LEDs on PC0..1.
Any ideas? It's not just this function, this is part of a bigger program with other initalization functions and it seems whenever the program enters a function separate from the main loop it fails to return to main. I am not so familiar with C and how it works on the function block level. I am using Atmel Studio 7 now with the following compiler options:
-x c -funsigned-char -funsigned-bitfields -DDEBUG -I"C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\include" -O1 -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -g2 -Wall -Wextra -pedantic -mmcu=atmega32 -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\gcc\dev\atmega32" -c -std=gnu99 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)"
but I had the same problems with avrdude. I also tried reading the full binary from the working board and writing it to the board I'm working on. It should communicate with PC over a USB-to-serial but it doesn't work. When I power up the board it spews a few kilobytes on nonsense to the serial (the same nonsense every time, though) and then freezes, i.e. doesn't send the regular "Waiting for command" message or reply to any commands.
The chip is Atmega32L8AU, 8MHz external crystal, LFUSE=0xFF
, HFUSE=0x99
.
Any ideas?
Edit: SOLVED – The firmware works after changing the AVR chip. Turns out to be a faulty memory area in the SRAM or possibly something wrong with the SRAM/GPR bus. This was suggested by in comments to Maximus' answer below.
Thank you for all your help!
Best Answer
Have you considered the warnings in your compiler (if any) ?
Your problem seems to me like there is an issue with function decleration, perhaps. Can you try to declare the function first on top of main and put function body at the bottom of main.c? Does the issue persists?
Also, have you tried debugger of atmel studio? If you haven't yet, please try and execute step by step. Observe the registers and see how they change.
One more question, can you do a simple error checking/tracking? For example,
You get the idea. If you do something like this, then you can observe the state of your program live (apart from the debugger).
Edit:
Added Atmega32/32L internal block diagram