Unexpected Atmega16 response over UART
Brief problem summary
I have flashed an Atmega16 with code that should result in the Atmega16 sending back whatever character I send to it via a terminal. I get a response, but it is rarely ever the character I sent. I can see correct output by changing the baud rate but I don't understand why the correct baud rate works.
More detail
I am trying to learn more about firmware programming in my own time because I quite enjoy it. Thus far in the firmware programming I have done at uni, we have been given skeleton code files that do a lot of the peripheral interfacing and set up for us, but I would like to learn this myself. I've got a few questions about what i'm doing here sprinkled throughout the post but I will itemise them at the end. If you pick up on any misunderstandings or potential gaps in my knowledge, I would greatly appreciate any input you might have.
The code
The code I have flashed onto my Atmega16 is taken almost line for line from the 'Using the USART in AVR-GCC' tutorial found on this page. All I have added is the #define for F_CPU. The original code did not have a #define for F_CPU so my code would not compile in AtmelStudio 7. Could anyone explain why the author would not have defined F_CPU in their original file? I'm guessing they may have been using some other tool or compiler than Atmel Studio 7 but I can't say for certain.
#include <avr/io.h>
#define F_CPU 7372800 //this was chosen because the tutorial states this is the frequency we want to operate at
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)
int main ( void )
{
char ReceivedByte ;
UCSRB = (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
UCSRC = (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
UBRRH = ( BAUD_PRESCALE >> 8); // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8- bits of the baud rate value into the low byte of theUBRR register
for (;;) // Loop forever
{
while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}
}
The hardware setup
- MCU: Atmega16;
- Toolchain: Atmel Studio 7, flashing with AVR dragon;
- Power supply: 5V rail taken from a university provided development board (which is taken from computer USB). 100nF ceramic disc capacitor used for bypassing on the breadboard power lines
- USB to serial converter: This one. TXD on the USB to serial converter connected to RXD Atmega (Pin 15). RXD on the converter connected to RXD on Atmega (Pin 14).
Terminal software: PuTTY (with baudrate of 9600).
Evidence of the incorrect responses
To reiterate, the Atmega should return what was sent to it i.e. OUTPUT should be the exact same as INPUT.
PuTTY output
\begin{array} \hline \text{INPUT} & \text{OUTPUT} \\ \hline \text{f} & \text{&}\\ \hline \text{f} & \text{6}\\ \hline \text{z} & \text{>}\\ \hline \text{d} & \text{0}\\ \hline \text{space} & \text{0}\\ \hline \text{x} & \text{8}\\ \hline \end{array}
Oscilloscope Captures
I have used my Picoscope with serial decoding to check that the Atmega is receiving the correct input, which it appears to be. For instance, when I press the 'f' key, it is correctly received. The output is still a '6' (or an ampersand '&' on occasion).
A fix I stumbled upon that I do not understand
If I change the baudrate to 2500in PuTTY, everything is displayed correctly. I chose this value at random and I don't know why it works (it leads me to believe I have made an error somewhere to do with the baudrate but I don't see where given I copied the tutorial almost exactly... I thought).
Questions
- What have I done wrong/what's happening here?
- Why does the original tutorial not #define F_CPU?
- Why does setting the baud rate to 2500 fix the issue? (I suspect this will be answered if question 1 is answered)