I'm working with an Atmega328p, running off the internal 8MHz oscillator, divided by 8 to produce a 1MHz clock. I set the fuses according to the calculator here. Confirming this with avrdude:
avrdude -p m328p -c usbasp
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: safemode: Fuses OK (E:FF, H:D9, L:62)
The timing seems to be correct – blinking an led on and off every 1000 ms takes ca. 1 second, as expected.
I am confused when it comes to setting up serial communication to my computer. No matter what I try, the connection is set to 1200. The program I'm using is:
#include <avr/io.h>
#include <util/delay.h>
#include <USART.h>
int main(void) {
DDRB |= 0b0000001;
initUSART();
while (1) {
printString("\n\r==== Looping ====\n\r");
PORTB = 0b00000001;
_delay_ms(750);
PORTB = 0b00000000;
_delay_ms(250);
}
return (0);
}
Where USART is from Elliott Willams' book. It includes the following:
#include <avr/io.h>
#include "USART.h"
#include <util/setbaud.h>
void initUSART(void) { /* requires BAUD */
UBRR0H = UBRRH_VALUE; /* defined in setbaud.h */
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}
// more code follows, not included here
My Makefile generates the following commands:
avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -DF_CPU=1000000UL -DBAUD=9600UL -I. -I../../AVR-Programming-Library -mmcu=atmega328p -c -o blinkLED.o blinkLED.c
avr-gcc -Wl,-Map,blinkLED.map -Wl,--gc-sections -mmcu=atmega328p blinkLED.o ../../AVR-Programming-Library/USART.o -o blinkLED.elf
avr-objcopy -j .text -j .data -O ihex blinkLED.elf blinkLED.hex
avrdude -c usbasp -p atmega328p -P /dev/ttyACM0 -U flash:w:blinkLED.hex
Baud is set in the Makefile, in this case to 9600UL. If I set it to 19200UL, everything works the same. In either case, everything behaves as it should, but when I connect to the serial line from my computer (via screen /dev/ttyUSB0
), the output is garbled unless I specify BAUD = 1200. (i.e., screen /dev/ttyUSB0 1200
).
I've been struggling through a bunch of webpages, the Williams book, and the atmega datasheet, but I'm still not getting this. Is the baud rate fixed for this chip? If not, how do I set it to a rate higher than 1200?
At this point I actually need to set it any higher, but I'd like to understand how this is supposed to work, and what I'm getting wrong.
Update
Note that I have explicitly set BAUD and F_CPU with the avr-gcc flags: -DF_CPU=1000000UL -DBAUD=9600UL
. Even if I set these macros in the code (as #define BAUD 9600UL
and #define F_CPU 1000000UL
as the first lines in the file, I'm still stuck with BAUD of 1200.
Update 2
I have isolated the problem to the setbaud.h file. If I set the baud rate 'by hand', that is, using the following code in place of the call to initUSART();
above, it works as expected – the BAUD is correctly set to 9600. This sets the prescaler to 12 (0b00001100) and enables USE_2X. So my problem must be that I'm using setbaud.h
improperly, but I can't see how.
UBRR0H = 0;
UBRR0L = 0b00001100;
UCSR0A |= (1 << U2X0);
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
Best Answer
As the comments suggest, you have to define BAUD in the setbaud.h file. Here it says you have to define F_CPU before including setbaud.h file. (That's because setbaud.h uses some macros to calculate UBR0 values based on your required baud rate and operating CPU speed)