Arduino Mega 2560 Serial Communication Problem Atmel Studio

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

For couple of days I have  been trying to implement a serial communication between Arduino Mega and a terminal program.

The problem is that after uploading the code to the Arduino Mega through Atmel Studio, nothing is being sent to the terminal on the computer.

I am working on my own project where I will need serial communication that is why I am asking after I have been trying for days.

I have created a library for the serial communication.

Perhaps some comments on the code.

I defined all the information in #define statements. Firstly I had repeating numbers for different statements

For Example:

#define EVEN 0
#define NONE 0

but I thought that this could be the problem and changed them but with no success.

Then I thought perhaps it is in the

void UART_Init(int UART_num, char mode, int baud, char double_speed, char data_bits, char parity, char stop_bits, char UART_interrupt)

function that the parameters that I pass to the function should be in the same order as the if statements in the function body. But I do not think that the order matters.

Actually, even the

printf()

function does not work.

Then I tried to do some other implementation of serial but with no success.

I have seen some other functions like

void UART_Putchar(unsigned char data)
unsigned char UART_Getchar(void)

but I do not really understand what they are used for. I am not sure if I need them though.

There is nothing in Realterm.

 

Best Regards

 

Here is the code:

 

Library Code: UART.c:

#ifndef UARTInit
#define UARTInit

#include <stdio.h>
#include <avr/io.h>
#include <math.h>

#define EVEN 2
#define ODD 1
#define NONE 0
#define ASYNC 10
#define SYNC 11
#define ONINT 3

/*
	UART_Number: 0, 1, 2, 3
	Mode: ASYNC, SYNC
	Baud: Value
	Double Speed: 1, 0
	Data Bits: 6, 7, 8, 9
	Parity: EVEN, ODD
	Stop Bits: 1, 2
*/

unsigned char ReceiveUART(int UART_num)
{
	if(UART_num == 0)
	{
		while ( !(UCSR0A & (1 << RXC0)) ); //Wait for the RXC to not have 0
		return UDR0; //Get that data out there and back to the main program!
	}

	if(UART_num == 1)
	{
		while ( !(UCSR1A & (1 << RXC1)) ); //Wait for the RXC to not have 0
		return UDR1; //Get that data out there and back to the main program!
	}
}

void TransmitUART(unsigned char data, int UART_num)
{
	if(UART_num == 0)
	{
		//Wait until the Transmitter is ready
		while (! (UCSR0A & (1 << UDRE0)) );
		//Make the 9th bit 0 for the moment
		//I do not need it for now
		//UCSR0B &=~(1 << TXB80);
		//If the 9th bit of the data is a 1
		//if (data & 0x0100)
		//Set the TXB8 bit to 1
		//UCSR0B |= (1 << TXB80);
		//Get that data out here!
		UDR0 = data;
	}

	if(UART_num == 1)
	{
		//Wait until the Transmitter is ready
		while (! (UCSR1A & (1 << UDRE1)) );
		//Make the 9th bit 0 for the moment
		//I do not need it for now
		//UCSR1B &=~(1 << TXB81);
		//If the 9th bit of the data is a 1
		//if (data & 0x0100)
		//Set the TXB8 bit to 1
		//UCSR1B |= (1 << TXB81);
		//Get that data out here!
		UDR1 = data;
	}
}

void UART_Init(int UART_num, char mode, int baud, char double_speed, char data_bits, char parity, char stop_bits, char UART_interrupt)
{
	uint16_t UBBRValue = lrint((F_CPU) / (16L * baud) ) - 1;

	// UART0
	if(UART_num == 0)
	{
		// Asynchronous Or Synchronous Mode
		if(mode == ASYNC) UCSR0C = (1 << UMSEL00); //setting the UMSEL bit to 1 for synchronous mode
		if(mode == SYNC) UCSR0C &= ~(1 << UMSEL01); //setting the UMSEL bit to 0 for asynchronous mode

		// Normal Or Double Speed
		if(double_speed == 1) UCSR0A = (1 << U2X0); //setting the U2X bit to 1 for double speed asynchronous
		else
		{
			UCSR0A &= ~(1 << U2X0); //setting the U2X bit to 0 for normal asynchronous
		}

		// UBRR Value
		//UBBR0H &= ~(1 << URSEL0);
		UBRR0H = (unsigned char) (UBBRValue >> 8);
		UBRR0L = (unsigned char) UBBRValue;

		// Enable Transmitter And Receiver
		UCSR0B |= (1 << RXEN0) | (1 << TXEN0);

		// Enable Interrupt
		if(UART_interrupt == ONINT) UCSR0B |= (1 << RXCIE0);

		// Number Of Stop Bits
		if(stop_bits == 1) UCSR0C &= ~(1 << USBS0); //clears the USBS for 1 stop bit, only needed if the bit was already set
		if(stop_bits == 2) UCSR0C |= (1 << USBS0); //Sets 2 stop bits

		// Parity - EVEN Or ODD
		if(parity == NONE);
		if(parity == EVEN) UCSR0C |= (1 << UPM01); //Sets parity to EVEN
		if(parity == ODD)  UCSR0C |= (1 << UPM01) | (1 << UPM00); //Sets parity to ODD, or //UCSR0C |= (3 << UPM00); //Alternative way to set parity to ODD

		// Number Of Data Bits
		if(data_bits == 6) UCSR0C |= (1 << UCSZ00); //6-bit data length
		if(data_bits == 7) UCSR0C |= (1 << UCSZ01); //7-bit data length, or //UCSR0C |= (2 << UCSZ00); //Alternative code for 7-bit data length
		if(data_bits == 8) UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //8-bit data length, or //UCSR0C |= (3 << UCSZ00); //Alternative code for 8-bit data length
		if(data_bits == 9) UCSR0C |= (1 << UCSZ02) | (1 << UCSZ01) | (1 << UCSZ00); //9-bit data length, or //UCSR0C |= (7 << UCSZ00); //Alternative code for 8-bit data length
	}

	// UART1
	if(UART_num == 1)
	{
		// Asynchronous Or Synchronous Mode
		if(mode == ASYNC)UCSR1C = (1 << UMSEL10); //setting the UMSEL bit to 1 for synchronous mode
		if(mode == SYNC)UCSR1C &= ~(1 << UMSEL11); //setting the UMSEL bit to 0 for asynchronous mode

		// Normal Or Double Speed
		if(double_speed == 1) UCSR1A = (1 << U2X1); //setting the U2X bit to 1 for double speed asynchronous
		else
		{
			UCSR1A &= ~(1 << U2X1); //setting the U2X bit to 0 for normal asynchronous
		}

		// UBRR Value
		UBRR1H = (unsigned char) (UBBRValue >> 8);
		UBRR1L = (unsigned char) UBBRValue;

		// Enable Transmitter And Receiver
		UCSR1B = (1 << RXEN1) | (1 << TXEN1);

		// Enable Interrupt
		if(UART_interrupt == ONINT) UCSR1B |= (1 << RXCIE1);

		// Number Of Stop Bits
		if(stop_bits == 1) UCSR1C &= ~(1 << USBS1); //clears the USBS for 1 stop bit, only needed if the bit was already set
		if(stop_bits == 2) UCSR1C |= (1 << USBS1); //Sets 2 stop bits

		// Parity - EVEN Or ODD
		if(parity == EVEN) UCSR1C |= (1 << UPM11); //Sets parity to EVEN
		if(parity == ODD) UCSR1C |= (1 << UPM11) | (1 << UPM10); //Sets parity to ODD

		// Number Of Data Bits
		if(data_bits == 6) UCSR1C |= (1 << UCSZ10); //6-bit data length
		if(data_bits == 7) UCSR1C |= (1 << UCSZ11); //7-bit data length
		if(data_bits == 8) UCSR1C |= (1 << UCSZ11) | (1 << UCSZ10); //8-bit data length
		if(data_bits == 9) UCSR1C |= (1 << UCSZ12) | (1 << UCSZ11) | (1 << UCSZ10); //9-bit data length
	}
}
#endif

Main code: Main.c:

/*
 * Arduino Mega1.c
 *
 * Created: 19-Mar-20 17:38:46
 * Author : Konstantin
 */
#define F_CPU 16000000UL

#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <uart/UART.c>

volatile unsigned char ReceivedByte;
unsigned char data;

int main(void)
{
	DDRB |= 1 << PINB7;

    UART_Init(0, ASYNC, 19200, 0, 8, NONE, 1, ONINT);

	sei();

    while (1)
    {
		_delay_ms(500);
		TransmitUART(0, 'A');
		printf("Hi");
    }
}

ISR(USART0_RX_vect)
{
	ReceivedByte = UDR0;

	PORTB ^= PINB7;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define F_CPU 16000000UL

is in Mega1.c but:

	uint16_t UBBRValue = lrint((F_CPU) / (16L * baud) ) - 1;

is in UART.c.

 

How could the UART code possibly know the F_CPU value in this case? I'd suggest you have two options:

 

1) in AS7 use "Symbols" to define F_CPU so it is passed as -D in the compilation. That will be presented to ALL files in the project so UART.c will know as well as Mega1.c what the value is or,

 

2) Pass the F_CPU to the library code too. So:

  UART_Init(0, ASYNC, 19200, F_CPU, 0, 8, NONE, 1, ONINT);

then:

void UART_Init(int UART_num, char mode, int baud, uint32_t f_cpu, char double_speed, char data_bits, char parity, char stop_bits, char UART_interrupt)
{
	uint16_t UBBRValue = lrint(f_cpu / (16UL * baud) ) - 1;

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
in AS7 use "Symbols" to define F_CPU so it is passed as -D in the compilation.

 

@ KonstantinK - for illustrated instructions on how to do that, see:

 

https://www.avrfreaks.net/commen...

 

See also: https://www.avrfreaks.net/commen...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please note that setting up F_CPU in the code or in the symbols does not actually set the frequency of operation.

If the CKDIV8 fuse is programmed, the CPU will be running at one-eighth of its "normal" frequency.

 

This is usually "fixed" by changing the CLKPS bits within Clock Prescale Register using (for example) "clock_prescale_set(clock_div_1);"  early in the code.

(To use this instruction, include the power.h file, (i.e. "#include <avr/power.h>")

 

Edit: Changed "CLKPS bit" to "CLKPS bits"

David

Last Edited: Fri. Mar 20, 2020 - 03:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

@ clawson

@ awneil

 

Firstly, I tried the 2nd option that you suggested above - I pass the F_CPU to the library like:

UART_Init(0, ASYNC, 19200, F_CPU, 0, 8, NONE, 1, ONINT);

void UART_Init(int UART_num, char mode, int baud, uint32_t f_cpu, char double_speed, char data_bits, char parity, char stop_bits, char UART_interrupt)
{
	uint16_t UBBRValue = lrint(f_cpu / (16UL * baud) ) - 1;

But unfortunately no luck, still nothing on the terminal. I also tried to define the frequency in the library file but no luck again.

Then I found out that in the main file in the

TransmitUART(0, 'A');

function I swapped the order of the passed variables in the function.

This is the function declaration in the library.

void TransmitUART(unsigned char data, int UART_num)

I changed it to this

void TransmitUART(int UART_num, unsigned char data)

and still no success.

Afterwards I set the UBBRValue manually by writing

uint16_t UBBRValue = 51; // 19200 BaudRate; The value is taken from the datasheet

and again no success.

And I tried the 1st option as well but still no luck.

It seems that perhaps the UART is not set correctly, I am not sure.

What about these:

void UART_Putchar(unsigned char data)
unsigned char UART_Getchar(void)

Do I have to define them?

Any suggestions?

 

@ frog_jr

This is from the datasheet, apparently it says that the frequency by default is 1MHz. I tried to change it to 1MHz but again no luck, nothing is printed.

 

 

Last Edited: Fri. Mar 20, 2020 - 01:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

frog_jr wrote:
Please note that setting up F_CPU in the code or in the symbols does not actually set the frequency of operation
Wot he said!

 

Just putting:

#define F_CPU 16000000UL

in the code does not mean the AVR is running at 16MHz. It only means you think it is running at 16MHz. As #3 in my signature shows almost every time someone's AVR UART "does not work" it's ultimately traced back to the fact that the assumed speed in the UBRRH/L calculation is not the actual speed of the AVR

 

You said "Arduino Mega" so in theory this is a 2560 with a 16Mhz crystal and the CKSEL/CKDIV8 fuses set to enable it. So it *should* be 16MHz but if you have ever changed the fuses in any way there's a strong chance it may not be. One of the most error free ways to check is to set the CLKOUT use active then probe pin 9/PE7 with a scope and see if there is 16MHz there.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Serial comms with AVR megas is easy to do, but details are important.

You need a USB to ttl serial adapter for your PC, connect its TX pin to the AVR RXD pin, and the RX pin of the adapter to the AVR TXD pin, and GND to GND pin of the AVR.

 

Next the AVR needs an accurate clock source, a XTAL is cheap and provides this clock!

next make sure your AVR is running on this xtal, tell how you proved it is.

 

Next set the AVR TXD pin to be an output, the default format for the USART is 8N1.

 

Now test you can send by sending the letter “U”, this character is special because it has a repeating 0/1 pattern.

 

once the above works the rest is easy!

 

jim

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have said you are using an Arduino Mega.

I presume it contains a 16MHz crystal and that the fuses were set to utilize the crystal since the ATmega2560 is mounted to a board (and not in its factory default state).

If so, it probably also has the CKDIV8 fuse programmed so that it starts off at 2MHz.

Setting the CLKPS bits in the CLKPR can change the clock prescale value as I previously indicated...

If you don't use the clock_prescale_set function, then you MUST make sure that you write the CLKPS bits within 4 clock cycles of setting the CLKPCE bit as indicated in the datasheet section 10.13.2

David

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have an Arduino Mega, what happens when you test the USART using Arduino IDE, Arduino libraries, and Arduino serial code?

 

void setup() {

   Serial.begin(19200);

}

void loop() {

   delay(500);

   Serial0.write('x');

   if (Serial0.available() ) { Serial0.read();  PortB ^= (1 << PINB7); }

}

 

Life doesn't have to be complicated.  Arduino is supposed to make all this stuff easy so you can concentrate on the high-level application code, instead of low-level peripheral configuring.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@ clawson

It is an Arduino Mega that I have. On the chip it says "ATMEGA 2560 16U-TW and other numbers and letters".

I have not changed any settings to the fuses.

I am not sure it is important but just behind the USB Plug I have a crystal and it says "12.000".

 

@ ki0bk

I have the Arduino Mega as a board not a ATMEGA 2560 as a chip. I guess it has the TTL to USB converter integrated.

 

@ Simonetta

I tried your sketch but I had to do little modification.

Everything worked, it prints 'x' to the Serial Monitor, except that the LED which should be the built in one does not toggle.

This is the code I tried:

void setup()
{
   Serial.begin(19200);
   DDRB |= (1 << PINB7);
}

void loop()
{
   delay(500);

   Serial.write('x');

   if (Serial.available() ) { Serial.read();  PORTB ^= (1 << PINB7); }
}

 

Basically, within the Arduino IDE everything works with the serial.

I checked the

boards.txt

in the Arduino folder and the frequency of the Mega is indeed 16MHz.

I have not changed any setting in this file.

 

I am not sure one more thing, I have not declared the RX and TX pins as an Input and as an Output respectively

I am not sure if I have to.

I also read of some kind of pin redirecting, do I have to do something similar in this case?

What would you suggest to do now?

 

 

Last Edited: Sat. Mar 21, 2020 - 02:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I'm amazed that the sketch works, because I was using it as an example of the ease of writing Ard code.  The Mega LED is on D13.  Try:

   if (Serial.available() ) { 
        Serial.read();  
        If ( digitalRead(D13) == HIGH) digitalWrite(D13,LOW); 
        else digitalWrite(D13, HIGH); }

 The 12MHz crystal on Arduino boards is for the USB-to-Serial interface IC (CH340g).  You don't need to set the direction of the TX/RX pins when you use the Serial.h library.   In Arduino, you don't need to #include the Serial.h library.  The IDE includes this in your sketch.   The Mega operates at 16MHz.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@ Simonetta

It completely works, the LED is toggling when I send to the serial.

This is the code, I had to modify it a bit:

void setup()
{
  Serial.begin(19200);
  pinMode(13, OUTPUT);
}

void loop()
{
  if (Serial.available() ) {
        Serial.read();
        if ( digitalRead(13) == HIGH) digitalWrite(13,LOW);
        else digitalWrite(13, HIGH); }
}

EDIT:

 

Well, eventually it works. The problem was in this part of the code.

// Asynchronous Or Synchronous Mode
if(mode == ASYNC) UCSR0C = (1 << UMSEL00); //setting the UMSEL bit to 1 for synchronous mode
if(mode == SYNC) UCSR0C &= ~(1 << UMSEL01); //setting the UMSEL bit to 0 for asynchronous mode

I swapped ASYNC and SYNC, if you look the comments. I changed the modes and now everything is working fine.

I also tried this code

int main(void)
{
	// 0 Input; 1 Output;
	//DDRE = 0b00000010; // Define RX and TX as Input and Output respectively
	DDRB |= (1 << PINB7);
	PORTB |= (1 << PINB7);
	
	sei();
	
    UART_Init(F_CPU, 19200, 0, ASYNC, 0, 8, NONE, 1, ONINT);
	
    while(1) 
    {
		_delay_ms(500);
		TransmitUART(0, ReceiveUART(0));
		PORTB |= ~(1 << PINB7);
		_delay_ms(1000);
		PORTB |= (1 << PINB7);
		printf("Hi");
    }
}

but for some reason I have to press the send button on the terminal couple of times before I actually see the number I sent. The TXD indicator blinks every time I press the button while the RXD indicator blinks only when I see the number on the terminal.

The

printf()

function does not work as well. I do not why, perhaps you have any suggestion.

Apparently I do not have to define the RX and TX pins as Input and Output respectively, it is somehow done automatically.

The LED does not toggle at all. It stays always ON as I have defined its state in the

main(void)

 

Last Edited: Sat. Mar 21, 2020 - 09:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To use printf() you have to do the FDEV_SETUP_STREAM thing to direct stdout to an output function.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't really see the reasons for this "wizard" routine -- sure uses up a lot of stuff to do a few register assignments.  Immaterial on the '2560; wait till you look for the waste in a Mega48 app.

 

Anyway, consider how your code will work when called more than once with different parameters.  All that |=  (and no clear of registers, which you can't do because another routine also fusses with them) will end up with corned beef hash.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.