Serial communication between ATMega328P and ATMega 2560 glitch

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

Hello guys I am trying to connect the ATMega328P and ATMega 2560 MCUs using UART.  Both are arduino based boards.  Initial baud rate is 9600, 8bit, 1 stop bit, No parity.  I used 4  inputs from ATMega328P to drive 4 ATMega2560 outputs.  What I noticed is that when I activate this PINB3 input:

 

if(PINB&(1<<3))                               

                    {

                           while(!(UCSR0A&(1<<UDRE0)));            

                           {

                                 UDR0=0b11111110;

                           }                    

                    }

 

 

the OCR1A output (case 0b11111111) of the ATMEGA2560 is intermittently activated.

 

 

case 0b11111111:                       

                                 OCR1A=102;                        //enable PWM.  Inverted

                                 break;

 

 

So what I did is to change the baud rate from 9600 to 4800 and the intermittent failure was gone.  What could be the reason for this? Is there a limit to the number of data passing through the UART line?  I have the transmit and receive codes attached below. 

//This is the transmit code ATMega328P

#include <avr/io.h>
#define F_CPU 16000000
#include <util/delay.h>




void UART_Tx()
{
    UCSR0B=(1<<TXEN0);				    //enable Transmit
    UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);		//set to 8 bit/ No Parity/ 1 stop bit
    UBRR0L=207;	                            //set baud to 4800  = ((F_CPU/(16*Baud)-1).     
}	

int main(void)
{
    DDRD=0xFF;
	DDRB=0x00;
	DDRC=0x00;
	
	UART_Tx();								
	
	
    while (1) 
    {
		{
			if(PINB&(1<<0))					
			{
				while(!(UCSR0A&(1<<UDRE0)));		//wait for empty transmit
				{	
					UDR0=0b11110000;
				}
			
			}
			else
			{	
				while(!(UCSR0A&(1<<UDRE0)));			
				{	
					UDR0=0b00001111;
				}
			}
		}
		
		{
			if(PINB&(1<<2))					
			{
				while(!(UCSR0A&(1<<UDRE0)));		
				{
					UDR0=0b11111100;
				}
				
			}
			else
			{
				while(!(UCSR0A&(1<<UDRE0)));		
				{
					UDR0=0b00000011;
				}
			}
		}
		
		{
			if(PINB&(1<<3))					
			{
				while(!(UCSR0A&(1<<UDRE0)));		
				{
					UDR0=0b11111110;
				}
				
			}
			else
			{
				while(!(UCSR0A&(1<<UDRE0)));		
				{
					UDR0=0b00000001;
				}
			}
		}
		
		{
			if(PINB&(1<<1))					
			{
				while(!(UCSR0A&(1<<UDRE0)));		
				{
					UDR0=0b11111111;
				}
				
			}
			else
			{
				while(!(UCSR0A&(1<<UDRE0)));		
				{
					UDR0=0b00000000;
				}
			}
		}
		
		{
			if (PINC&(1<<4))
			{
				PORTD|=(1<<7);
			}
			else
			{
				PORTD&=~(1<<7);
			}	
		}
    }
}



//This is the receive code ATMega2560

#include <avr/io.h>
#define F_CPU 16000000
#include <util/delay.h>

void PWM_init()
{
	TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(1<<WGM10);
	TCCR1B=(1<<WGM12)|(1<<CS12)|(1<<CS10);
}

void UART_Rx()
{
	UCSR2B=(1<<RXEN2);					    //enable Receive
	UCSR2C=(1<<UCSZ21)|(1<<UCSZ20);			//set to 8 bit/ No Parity/ 1 stop bit
	UBRR2L=207;					           	//set baud to 4800  = ((F_CPU/(16*Baud)-1)
}	

int main(void)	
{
    DDRB=0xFF;						
	DDRA=0x00;						
	DDRH=0xFF;						
	DDRC=0xFF;
	DDRL=0xFF;
	UART_Rx();						
	PWM_init();
	
    while (1) 
    {
		{
			while(!(UCSR2A&(1<<RXC2)));			//wait for empty receive buffer  
			
			switch(UDR2)
			{
				case 0b11110000:			
					PORTB|=(1<<7);
					PORTB&=~(1<<6);
					break;
			
				case 0b00001111:
					PORTB|=(1<<6);
					PORTB&=~(1<<7);
					break;
				
				case 0b11111100:
					PORTC|=(1<<1);
					break;
				
				case 0b00000011:
					PORTC&=~(1<<1);
					break;
				
				case 0b11111110:
					PORTL|=(1<<2);
					break;
				
				case 0b00000001:
					PORTL&=~(1<<2);
					break;	
					
				case 0b11111111:				
					OCR1A=102;				//enable PWM.  Inverted
					break;
				
				case 0b00000000:					
					OCR1A=255;				//Disable PWM.  Inverted
					break;
			}
		 }
		 
		{
			if(PINA&(1<<0))						
			{
				PORTH|=(1<<4);					
			}
			else
			{
				PORTH&=~(1<<4);					 
			}
		}
	}
}


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

First up, let's simplify the code. Repeating the same thing over and over is asking for defects.

 

//This is the transmit code ATMega328P

#include <avr/io.h>
#define F_CPU 16000000
#include <util/delay.h>




void InitUART()
{
    UCSR0B=(1<<TXEN0);				    //enable Transmit
    UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);		//set to 8 bit/ No Parity/ 1 stop bit
    UBRR0L=207;	                            //set baud to 4800  = ((F_CPU/(16*Baud)-1).     
}	

void UART_Tx(uint8_t ch)
{
    while(!(UCSR0A&(1<<UDRE0)));
    UDR0 = ch;
}

int main(void)
{
    DDRD = 0xFF;
	DDRB = 0x00;
	DDRC = 0x00;
	PORTB = 0xff;    //enable pullups on PB0..7
	PORTC = 0xff;      //enable pullups on PC0..7
	
	InitUART();								
	
	
    while (1) 
    {
			if (PINB & (1<<0))					
			{
			    UART_Tx(0xf0);

			}
			else
			{	
			    UART_Tx(0x0f);
			}

			if (PINB & (1<<2))					
			{
			    UART_Tx(0xfc);
			}
			else
			{
			    UART_Tx(0x03);
			}

			if (PINB & (1<<3))					
			{
			    UART_Tx(0xfe);

			}
			else
			{
			    UART_Tx(0x01);
			}

			if (PINB & (1<<1))					
			{
			    UART_Tx(0xff);

			}
			else
			{
                UART_Tx(0x00);
			}

			if (PINC & (1<<4))
			{
				PORTD |= (1<<7);
			}
			else
			{
				PORTD &= ~(1<<7);
			}
    }
}

I cleaned up the code a bit. Simple code = simple problems. Less code = less problems!

 

As such - I couldn't see anything obvious in your transmit code that might be a problem - however, you've not told us about your hardware setup apart from being Arduino boards. How are your inputs wired? Pullup resistors? I'm guessing not - so I enabled them in the code. If your inputs were floating, that might explain the strange results you reported - changing the baud rate might introduce different timing to change how the problem presents itself.

 

You can use your PC sound card as an oscilloscope - it will show 9600 baud data easily. Google soundcard oscilloscope. This will allow you to see what is actually transmitted.

 

I left the receive code alone - you might want to write a UART_Rx() function to tidy it up a bit.

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

I would back up a little further. It seems you want to let the mega2560 know what the state of 4 pins may be on the 328p and relay that info via uart. I'm not sure the significance of the bit pattern, but with 4 pins there are 16 possible choices so simply give the mega2560 the value 0-15 and let it work out what is going on. Also if there is no change on the pins, there is no need to transmit again (it seems to me) so only transmit if there was a change. Now you have a simple 0-15 value you can work with (and only incoming as fast as you can change the pins on the mega328), and maybe only 0/1/2/4/8 are valid numbers where you want only a single pin active. You can do whatever you want on the mega2560 side and the 328p does not have to worry about all the special bit patterns or what the mega2560 is going to do with the info provided- you just told it what pins are high and your job is done.

 

https://godbolt.org/z/auTdVP

 

and you could add a little more code in case the mega is not listening while the change occurred-

https://godbolt.org/z/qqDE43

so whether the pins change or not, it sends the info every 500ms (and also sends the initial state if no pins active).

Last Edited: Mon. Jan 20, 2020 - 04:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How have you proved that you are running from the external 16MHz crystal?

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

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

Kartman wrote:

First up, let's simplify the code. Repeating the same thing over and over is asking for defects.

 

//This is the transmit code ATMega328P

#include <avr/io.h>
#define F_CPU 16000000
#include <util/delay.h>




void InitUART()
{
    UCSR0B=(1<<TXEN0);				    //enable Transmit
    UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);		//set to 8 bit/ No Parity/ 1 stop bit
    UBRR0L=207;	                            //set baud to 4800  = ((F_CPU/(16*Baud)-1).     
}	

void UART_Tx(uint8_t ch)
{
    while(!(UCSR0A&(1<<UDRE0)));
    UDR0 = ch;
}

int main(void)
{
    DDRD = 0xFF;
	DDRB = 0x00;
	DDRC = 0x00;
	PORTB = 0xff;    //enable pullups on PB0..7
	PORTC = 0xff;      //enable pullups on PC0..7
	
	InitUART();								
	
	
    while (1) 
    {
			if (PINB & (1<<0))					
			{
			    UART_Tx(0xf0);

			}
			else
			{	
			    UART_Tx(0x0f);
			}

			if (PINB & (1<<2))					
			{
			    UART_Tx(0xfc);
			}
			else
			{
			    UART_Tx(0x03);
			}

			if (PINB & (1<<3))					
			{
			    UART_Tx(0xfe);

			}
			else
			{
			    UART_Tx(0x01);
			}

			if (PINB & (1<<1))					
			{
			    UART_Tx(0xff);

			}
			else
			{
                UART_Tx(0x00);
			}

			if (PINC & (1<<4))
			{
				PORTD |= (1<<7);
			}
			else
			{
				PORTD &= ~(1<<7);
			}
    }
}

I cleaned up the code a bit. Simple code = simple problems. Less code = less problems!

 

As such - I couldn't see anything obvious in your transmit code that might be a problem - however, you've not told us about your hardware setup apart from being Arduino boards. How are your inputs wired? Pullup resistors? I'm guessing not - so I enabled them in the code. If your inputs were floating, that might explain the strange results you reported - changing the baud rate might introduce different timing to change how the problem presents itself.

 

You can use your PC sound card as an oscilloscope - it will show 9600 baud data easily. Google soundcard oscilloscope. This will allow you to see what is actually transmitted.

 

I left the receive code alone - you might want to write a UART_Rx() function to tidy it up a bit.

 

Thank you sir.  Somehow I did a cleanup as you mentioned and there were some unused lines of codes on the Atmel Studio which were not captured when I paste it here on this forum and I think those lines caused the intermittent operation.  Now everything works fine even at 9600 baud.

How to write this code in interrupt function?  

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

Brian Fairchild wrote:

How have you proved that you are running from the external 16MHz crystal?

 

Yes it is 16MHz.  I found out some unused lines which were not included when I paste the code in this forum and those lines need to be removed and everything works fine.  Thank you.

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

curtvm wrote:

I would back up a little further. It seems you want to let the mega2560 know what the state of 4 pins may be on the 328p and relay that info via uart. I'm not sure the significance of the bit pattern, but with 4 pins there are 16 possible choices so simply give the mega2560 the value 0-15 and let it work out what is going on. Also if there is no change on the pins, there is no need to transmit again (it seems to me) so only transmit if there was a change. Now you have a simple 0-15 value you can work with (and only incoming as fast as you can change the pins on the mega328), and maybe only 0/1/2/4/8 are valid numbers where you want only a single pin active. You can do whatever you want on the mega2560 side and the 328p does not have to worry about all the special bit patterns or what the mega2560 is going to do with the info provided- you just told it what pins are high and your job is done.

 

https://godbolt.org/z/auTdVP

 

and you could add a little more code in case the mega is not listening while the change occurred-

https://godbolt.org/z/qqDE43

so whether the pins change or not, it sends the info every 500ms (and also sends the initial state if no pins active).

 

Thank you sir for taking time to look at my problem.  Some cleanup did the job.  Let me study your shared codes :)

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

ryan2019 wrote:

Brian Fairchild wrote:

How have you proved that you are running from the external 16MHz crystal?

 

Yes it is 16MHz.  I found out some unused lines which were not included when I paste the code in this forum and those lines need to be removed and everything works fine.  Thank you.


Jus because there's a 16MHz crystal attached to the pins does NOT mean it's being use. That depends on the fuses.

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

ryan2019 wrote:
How to write this code in interrupt function?  

Why?   What do you hope to gain by using interrupts?

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

ki0bk wrote:

ryan2019 wrote:
How to write this code in interrupt function?  

Why?   What do you hope to gain by using interrupts?

Jim

 

 

I have never tried it before but it maybe useful if the polling fails.  Also I would like to learn it in case I would be needing it.  

Last Edited: Tue. Jan 21, 2020 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(though out of context for this thread)

IIRC, XMEGA application notes describe polling vs interrupts vs DMA.

AN_8319 AVR1510: XMEGA-A1 Xplained training - XMEGA USART

 

"Dare to be naïve." - Buckminster Fuller

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

Why did you start a new thread when you have brought this up here:

 

https://www.avrfreaks.net/forum/...

 

Grrrrr.

 

JIm

 

 

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user