Serial communication - UCSR0A register - bit RXC0

Hello everybody,
I'm trying to make a serial communication between my PC and an arduino MEGA card.
If I use arduino instruction like serial.available and serial read... all is good.
My PC send a very simple message (juste '3'); and the arduino receive well! (I even send back the received message to my PC)

But if I Try to use C instructions and write/read register... I have big problems!

First:
The RXC0 bit in the register UCSR0A never rise!
To check it, I use the following instructions:

unsigned char USART_rx( void ) {
  while( ! (UCSR0A & (1<<RXC0)) );
  digitalWrite(LED_BUILTIN, LOW);
  return UDR0;
}

My program is only a loop wich call the function rx.

I'm sure that my PC send a mesage.
the TX LED switch on and off

But the digital LED never switch ON...

Any Idea?

Thanks.

digitalWrite(LED_BUILTIN, LOW);

well the builtin led is active HIGH on a Mega, that for starters,
but just the snippet is not really enough for me to where else you may have made mistakes.
Did you setup the registers correctly ?
I would use this to read the UART like this

ISR(USART_RX_vect) {
    unsigned char c  =  UDR;
    uart_write(c);
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

void uart_write(char data) {
  UDR = data;
  while((UCSRA & 1<<TXC)==0);
  UCSRA |= 1<<TXC;  
}

The registers will have to have their designator added for a Mega i guess.

So why didn't you post the complete sketch? My guess is that you use some methods of the Serial object which activates the Serial module of the Arduino IDE. That handles all these registers and registers interrupt handlers that actually read received characters into a buffer and clear all flags immediately after the hardware finished the reception of the last bit.

Thank you for your interest...
In fact, for the moment, I try a very simple code... I don't want to use interrupts.

There is all the code (I've found it on the web):

unsigned char message;

void USART_init( void ) {
//  int baudrate=12; // 4800 Bauds by default
  int baudrate=207; //4800 Bauds avec quartz 16Mhz
  /* Set baud rate */
  UBRR0L = (unsigned char)baudrate;
//  UBRR0H = (unsigned char)(baudrate>>8);
  
  /* Enable Receiver and Transmitter */
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  
  /* Set frame format: 8data, 1stop bit */
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
}


void USART_Flush( void ) {
  unsigned char dummy;
  while ( UCSR0A & (1<<RXC0) ) dummy = UDR0;
}

unsigned char USART_rx( void ) {
  while( ! (UCSR0A & (1<<RXC0)) );
  digitalWrite(LED_BUILTIN, LOW);
  return UDR0;
}

void USART_tx( unsigned char data ) {
  while( ! (UCSR0A & (1<<UDRE0)) );
  UDR0 = data;
}

void USART_putstring( const char *StringPtr ) {
  int cmp = 0;
  while ( strlen( StringPtr ) != cmp ) {
    USART_tx( StringPtr[cmp] );
    cmp++;
  }
}

void setup() 
  {

  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  }

 
int main(void)
{       
  USART_init(); // Call the USART initialization code
    
    while(1)
    {
    delay(1000);  
    digitalWrite(LED_BUILTIN, HIGH);
   
    message = USART_rx();
//    delay(50000L);
//      delay(1000);
//    USART_tx(message);
    }
}

I'm starting to understand what you mean pylon, because before using this code, I was trying to watch the bit RXC0 while I was using arduino commands... And that does not work!
The very BIG problem with Arduino is that it is impossible to know what does an instruction really do! But it will be an other dicussion.

This afternoon, my arduino Mega card died... I use now an Arduino UNO... But the problem is the same... I wonder if my baudrate configuration is OK...
I think that the clock speed of an Arduino card is 16Mhz... but I'm not really sur.
Ii you have any idea... Thanks!

No, that's the problem of almost every other IDE but not of Arduino. You have the source code of every piece used. You can know exactly what is happening, if you want to know that.

If the comment is still true (4800 baud should be set) that value is correct. But you should configure all USART register to correct values as you don't know what values the boot loader left there.

Hi Pylon,

You have the source code of every piece used

Please, can you tell me where can I find this source code?

If the comment is still true (4800 baud should be set) that value is correct

Wich value in my code should be correct: 12 or 207?
In fact, I have a lot of difficulties to find:

  • the clock speed of an ATMEGA 328 on an ARDUINO Uno card
  • the clock speed of an ATMEGA 2560 on an ARDUINO MEGA card

The 16Mhz quartz on the card is linked to the programer, and no the ATMEGA.

Thanks.

Which one are you looking for? Almost all pieces are inside the Arduino github account: https://github.com/arduino .

The one you use: 207.

Both use a 16MHz clock speed. It's not a quartz but a ceramic resonator.

That is the wrong approach. You should just let the UART trigger the RX interrupt, and read the byte from the register.

In the core libraries of the specific board.

You can access the value that has been set by the bootloader using the F_CPU macro.

This is my code for TX & RX for a 328P

#define BAUD 250000UL   // set this to the BAUD rate you want.
#define UB ((F_CPU / (8 * BAUD)) - 1)

void setup() {
  // UART TX and RX pins
  DDRD |=  (1<<PORTD1) | (1<<PORTD2) ;  // set TX pin and pin 4 to output
  DDRD &= ~(1<<PORTD0);  // set RX pin to input 

  UCSR0A = 0x02; // 1<<U2X | 0<<MPCM;
  UCSR0B = 0x98; // 1<<RXCIE | 0<<TXCIE | 0<<UDRIE | 1<<RXEN | 1<<TXEN | 0<<UCSZ2;  // enable TX & RX
  
  UCSR0C = 0x06; //0<<UMSEL0 | 0<<UPM1 | 0<<UPM0 | 0<<USBS | 1<<UCSZ1 | 1<<UCSZ0 | 0<<UCPOL;  // 8N1
  UBRR0H = (UB >> 8);  // set baud rate
  UBRR0L = (UB & 0xFF); // HL register
}

void loop() {
  /*const char * dat = "Hi There\n";
  uart_write_string(dat);
  delay(1000);*/
}

void uart_write(char data) {
  UDR0 = data;
  while((UCSR0A & 1<<TXC0)==0);
  UCSR0A |= 1<<TXC0;  
}

void uart_write_string(const char * data) {
  for(uint8_t count = 0; data[count] != 0; count++) {
    UDR0 = data[count];
    while((UCSR0A & 1<<TXC0) == 0);
    UCSR0A |= 1<<TXC0;
  }
}

ISR(USART_RX_vect) {
    unsigned char c  =  UDR0;
    uart_write(c);
    PORTD ^= (1<<PORTD2);
}

For low baudrates you may want to use the normal speed mode (rather than the double speed mode i selected)
check the datasheet for which register to set. The USART part starts at page 143

THANKS a lot Deva_Rishi!!!
Your code works on my Arduino!!
For the Baud rate, I've put:

#define BAUD 4800UL   // set this to the BAUD rate you want.

That is the speed for my application.

I'm trying to Understand what was wrong in my program above...

First... BIG BIG BIG mistake... My main fonction is called... main....arrrrrrgh

Of course It must be LOOP !!!
Like Pylon said, I have written in all registers concerned by the USART0 configuration to be sure of the value of each bit...
But it still doesn't work... I continue to compare the 2 programs...

To Pylon:
I've been to the Git page of ARDUINO...
But I don't find what I want.
For exemple, if I want to know what exactly does the ATMEGA when I use the instruction:
Serial.begin()
Serial.available()
Where can I find these informations?
Thank you very much for your help!

hardwareSerial.h & .cpp and related files (within the same folder)

As Deva_Rishi already pointed out, the source for that is HardwareSerial.cpp (and corresponding .h file). You can find that in the github account of Arduino or in your IDE directory:
hardware/arduino/avr/core/arduino/HardwareSerial.cpp

Wouahhhh!!!
Thanks a lots both of you!!!

All my problems are solved thanks to you!!

So, In my programm of the begining...
Pfffff... many things were wrong:

  • The name of the LOOP() (pfff it was main instead of LOOP() )
  • Pylon told me to write the good value in each registers concerned by the USART0, but I was doing it in a wrong way... You want to know my mistakes?
    I used mask like this: :frowning:
 UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);  
  UCSR0C = UCSR0C & (0<<UMSEL01);// asynchronous USART
  UCSR0C = UCSR0C & (0<<UMSEL00);// asynchronous USART
  UCSR0C = UCSR0C & (0<<UPM01);// disabled parity
  UCSR0C = UCSR0C & (0<<UPM00);// disabled parity
  UCSR0C = UCSR0C & (0<<USBS0);// 1bit STOP
  UCSR0C = UCSR0C & (0<<UCPOL0);// 0 for asynchonous USART

But when this is done, there is not only a zero put in the aimed bit... but zeros in each bit of the register!!! (I'm so stupid!)

I think the best way is to do like Deva_Rishi, and write the entire value in each register (UCSRnA; UCSRnB... Don't care if in the register some bits are read only - for these bits, put the default value).

  • And my function USART_rx() is a little stange... I've written it again.

Concerning the code of an arduino instruction...
Great, In the installed folder... I've found hardwareSerial.h and .cpp But I nead to spend many hours to understand what it does exactly!

A big Thank you for your help!!!

UCSR0C = 0x06; //0<<UMSEL0 | 0<<UPM1 | 0<<UPM0 | 0<<USBS | 1<<UCSZ1 | 1<<UCSZ0 | 0<<UCPOL; 

if you want to set a bit to zero you can use

UCSR0C = UCSR0C & ~ (1<<USBS0);// 1bit STOP

instead of writing & 0 what you do, you write & bitwise NOT of the whole byte. That inverts the bit you want cleared from 1 to 0 and all other bits from 0 to 1

same here, gave up on figuring out the exact details. Some functions make sense, some are just a bit beyond me.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.