0

First we set fuse bits:

avrdude -c usbasp -p atmega328p -U lfuse:w:0xFF:m -U hfuse:w:0xDF:m -U efuse:w:0x07:m # same for atmega168

In the following examples we use the following commands to compile and burn all the programs:

avr-gcc -Os -mmcu=atmega328p -c -o serial.o serial.c
avr-ld -o serial.elf serial.o
avr-objcopy -O ihex serial.elf serial.hex
avrdude -c usbasp -p atmega328p -U flash:w:serial.hex

Let us burn the following program:

#define F_CPU 16000000UL
#include <avr/io.h>
void main (void) {
  DDRB |= (1<<PB5);
  PORTB |= (1<<PB5);
  while (1);
}

It makes the led to be on constantly. And it stays so for infinite period of time.

Then we burn the following program:

#define F_CPU 16000000UL
#define BAUD 9600
#include <avr/io.h>
char data = 0;
void main(void) {
  // Initialize USART:
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE; // set the speed (Higher bit)
  UBRR0L = UBRRL_VALUE; // set the speed (Lower bit)
  UCSR0B |= (1<<RXEN0); // enable receiver
  UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00); // set mode (8N1)
  DDRB |= (1<<PB5); // enable output on pin PB5 (default led on arduino)
  while(1) {
    while(!(UCSR0A&(1<<RXC0))); // wait until a byte is received
    data = UDR0; // read it
    if (data) PORTB |= (1<<PB5); // set the led on
  }
}

Then we open a terminal (9600,8N1) and press several keys, until the led turns off. Now we burn the first program again and the led is constantly blinking. The reason for this is that watchdog times gets started when we press the keys in terminal. But why and when WDT gets started? How to make so that it will not start?

It should be noted also that we can disable the blinking only with complete poweroff/poweron - only after that the led lights constantly without blinking, as necessary.

This happens on atmega168 and atmega328p, 100% reproducible.

avr-gcc version 4.8.1 avrdude version 6.1

NOTE: bootloader is not used at all.

  • void main(void) { #include <util/setbaud.h> This caught my eye. It's quite unusual to do an include within the code? I'm not sure if it might cause issues. – Paul Nov 8 '15 at 16:43
  • Also, I'm not sure how watchdog is related to this question? You can disable it's fusebit? – Paul Nov 8 '15 at 16:44
  • and your if (data) PORTB |= (1<<PB5); will flip the LED on and off whenever data is set to something. You should reset the value? Even though the while(!( might block it from happening. – Paul Nov 8 '15 at 16:46
1

One thing that I found whilst experimenting with command line compilation is that for some strange reason no startup code was being linked with my code, so it all went completely screwy.

I finally tracked the problem down to a missing command line flag while linking.

First, you need to link with avr-gcc not avr-ld. Second, you need to pass the -mmcu=atmega328p flag to the link command so that it knows which startup code to link in.

This is my complete command line sequence for compiling a simple blink program:

avr-gcc -g -mmcu=atmega328p -ffunction-sections -fdata-sections   -c -o blink.o blink.c
avr-gcc -mmcu=atmega328p -Wl,--gc-sections -o blink.elf blink.o 
avr-objdump -S blink.elf > blink.dis
avr-objcopy -O ihex -R .eeprom blink.elf blink.hex

You notice I'm making function and data sections too, and then garbage collecting the unused ones - good practice since it can very much reduce the size of your finished program.

I am doing this through a Makefile, which looks like this:

PREFIX=avr-
CC=${PREFIX}gcc
CXX=${PREFIX}g++
LD=${PREFIX}ld
AS=${PREFIX}as
OBJCOPY=${PREFIX}objcopy
OBJDUMP=${PREFIX}objdump

BIN=blink
MCU=atmega328p
OBJS=blink.o

CFLAGS=-g -mmcu=${MCU} -ffunction-sections -fdata-sections
CXXFLAGS=-g -mmcu=${MCU} -ffunction-sections -fdata-sections -fno-exceptions
LDFLAGS=-mmcu=${MCU} -Wl,--gc-sections

${BIN}.hex: ${BIN}.elf
    ${OBJCOPY} -O ihex -R .eeprom $< $@

${BIN}.elf: ${OBJS}
    ${CC} ${LDFLAGS} -o $@ $? 
    ${OBJDUMP} -S $@ > ${BIN}.dis

install: ${BIN}.hex
    avrdude -c usbasp -p ${MCU} -U flash:w:${BIN}.hex -qq

clean:
    rm -f *.o *.elf *.hex

fuses:
    avrdude  -c usbasp -p ${MCU} -U lfuse:w:0xff:m -U hfuse:w:0xd6:m -U efuse:w:0x05:m -qq
| improve this answer | |
  • No, Like I said in my answer on EE, this has nothing to do with the Bootloader or the WDT. You seem to not understand fundamentally how this whole thing works... – Kurt E. Clothier Nov 10 '15 at 2:51
1

WDT settings will remain unchanged, even after a reset. So the timer will keep running and therefore keep resetting the device. Which causes the blinking. Power cycling will clear the WDT settings.

PS I didn't read the code, as uncommented register writes are pretty much unreadable.

| improve this answer | |
1

The problem code was reduced to this:

#define F_CPU 16000000UL
#include <avr/io.h>
char data;
void main(void) {
  UBRR0H = 0x00;
  UBRR0L = 0x67; // baud=9600
  UCSR0B = 0x10; // 00010000
  UCSR0C = 0x06; // 00000110
  DDRB |= (1<<PB5);
  PORTB |= (1<<PB5);
  while(1) {
    data = UDR0;
  }
}

This is the code which works:

#define F_CPU 16000000UL
#include <avr/io.h>
void main(void) {
  char data;
  UBRR0H = 0x00;
  UBRR0L = 0x67; // baud=9600
  UCSR0B = 0x10; // 00010000
  UCSR0C = 0x06; // 00000110
  DDRB |= (1<<PB5);
  PORTB |= (1<<PB5);
  while(1) {
    data = UDR0;
  }
}

But I don't know how to explain that char inside main makes the problem disappear...

EDIT Just for the record, here are two more examples. The first example works with both compilation methods. The second example works only with the second compilation method. The examples differ only with that in the first direct code is used, and in the second it is used via functions.

#define F_CPU 16000000UL
#define BAUD 9600

#include <avr/io.h>
void main(void) {
  char data;
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
  DDRB = (1<<PB5);
  while (1) {
    PORTB ^= (1<<PB5);
    while(!(UCSR0A&(1<<RXC0)));
    data = UDR0;
    UDR0 = data;
    while(!(UCSR0A&(1<<TXC0)));
  }
}
#define F_CPU 16000000UL
#define BAUD 9600

#include <avr/io.h>
void serialSetup(void) {
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
}
void serialSend(char data) {
  UDR0 = data;
  while(!(UCSR0A&(1<<TXC0)));
}
char serialGet(void) {
  while(!(UCSR0A&(1<<RXC0)));
  return UDR0;
}
void main(void) {
  char data;
  serialSetup();
  DDRB = (1<<PB5);
  while (1) {
    PORTB ^= (1<<PB5);
    data = serialGet();
    serialSend(data);
  }
}
| improve this answer | |
  • This may be related to a strange thing I was seeing when manually compiling that I just couldn't fathom - there seemed to be no crt0 being linked in, except if you had a global variable, which caused just the BSS portion of the crt to exist. If I added another function to the program suddenly that function became the entry point instead of main(). It was all messed up and completely brain melting. And yet I was calling the same compiler and command line options as compiling for the Arduino API. It made no sense at all. – Majenko Nov 9 '15 at 12:31
  • Actually I just solved my problem - and it will probably solve yours too. I'll post an answer with the detail. – Majenko Nov 9 '15 at 12:44
  • @Majenko: Yes, it solved the problem! – Igor Liferenko Nov 10 '15 at 1:52
  • @Majenko: But I did not understand the reason why it spontaneously starts to reset itself, and what your commands do to fix it. Could you please give some recommendations for further reading to understand what causes the problem and how it is cured? – Igor Liferenko Nov 10 '15 at 2:25
  • With the WDT, once it has started firing it's almost impossible to disable it. You can only disable it from "cold" so it never gets a chance to fire. Also without the proper startup code (crt0) it's anyone's guess what will actually happen with the program when it's run - variables won't be initialized, exception vectors won't be set up, etc etc. – Majenko Nov 10 '15 at 9:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.