Pages: [1] 2   Go Down
Author Topic: Mega 2560 Serial Problem at 300 baud, but not at any other baud  (Read 2465 times)
0 Members and 1 Guest are viewing this topic.
London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi There,

I'm trying to communicate via serial with an atomic clock receiver, which speaks slowly - at 300 baud. The clock receiver needs an ascii 'o' CR sent to it to make it spit out a string.

 I'm testing using a Mega connected to my mac AND to a laptop running hyper terminal. I've slightly modified Tom Igoe's Mega Multiple Serial Test example:

Code:
void setup() {
  // initialize both serial ports:
  Serial.begin(9600);
  Serial1.begin(300);
}

void loop() {
  // read from port 1, send to port 0:
  if (Serial1.available()) {
   
    int inByte = Serial1.read();
    Serial.print("recieved: ");
    Serial.println(inByte, DEC);
  }
 
  if (Serial.available()) {
    // read from port 0, send to port 1:
    int inByte = Serial.read();
    Serial.print("sending '");
    Serial.print(inByte, DEC);
    Serial.println("' to clock");
   
    Serial1.println(inByte);
  }
  delay(100);
}

If I change Serial1 to 1200 baud (or any other it seems) the sketch works fine, i can send data from one machine to another, via the mega, with both serial connections running at different speeds. However, if i set the baud rate of Serial1 to 300, i get 'wrong baud rate' nonsense (at least, thats what it looks like...).

So is the calculation that sets the baud rate bad? Could i set the baud rate with the UBRR after the Serial1.begin() call?  Have i missed something obvious :-) ?

cheers!

-h


Logged

Offline Offline
God Member
*****
Karma: 32
Posts: 507
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I once had a similar problem with a Uno not working at 300 baud, but I tried it just now and it is working again. Are you using the latest Arduino software? Maybe something was fixed.

The way I got round the problem at the time was to try changing the rates to slightly different numbers around 300, with the reasoning that if there was a bit-rate discrepancy it might compensate for it. I can't remember which exact speed worked, it was something like Serial.begin(297); try experimenting.
Logged


London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the swift reply! That's a good tip, I'll try that out and report back... Might have to wait until Monday now though :-)
Logged

London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, so i've tried several baudrates and still no dice. In fact i wrote some code to test it, and watched the output in hyperterminal (staring at hyperterminal - the most fun i've had in ages!)

Code:
int baudrate = 1198;
int maxBaud = 1200;
int testNum = 0;

void setup() {
  // initialize both serial ports:
  Serial.begin(9600);
  Serial.print("starting serial test at ");
  Serial.print(baudrate);
  Serial.println(" baud");
}

void baudTest(int rate) {
   Serial1.begin(rate);
   Serial.print("test #");
   Serial.print(testNum++);
   Serial.print(" at ");
   Serial.print(rate);
   Serial.println(" baud");
   Serial.println("");
   
   Serial1.println("a");
   delay(500);
   Serial1.println("a");
   delay(500);
   Serial1.println("a");
   delay(500);
   Serial1.println("a");
   delay(500);
   
   Serial1.end();
   
   delay(1000);
   
}

void loop() {
 
  if (baudrate < maxBaud) {
      baudTest(baudrate++);
  } else {
   Serial.println();
     Serial.println("test complete!");
     Serial.println();
  }
 
 
  // read from port 1, send to port 0:
  if (Serial1.available()) {
   
    int inByte = Serial1.read();
    Serial.print("recieved: ");
    Serial.println(inByte, DEC);
  }
 
  if (Serial.available()) {
    // read from port 0, send to port 1:
    int inByte = Serial.read();
    Serial.print("sending '");
    Serial.print(inByte, DEC);
    Serial.println("' to clock");
   
    Serial1.println(inByte);
  }
  delay(100);
}

Still no luck, so i'm at a loss. I suppose i can try to get another board to talk 300 baud serial. Since the clock i need to read doesn't have flow control, i'm stuck.

Any more ideas?
Logged

London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello Again,

I'm still stuck on this - I'd really appreciate some help!

I've now tried 300 baud communication on a Mega2560, a Duemilanove and a Nano - none of which work. I just get serial gobbledy-gook...

To reiterate, i'm opening a HW serial connection at 300 baud with
Code:
Serial.begin(300)
and then sending ascii chars up the serial cable to my computer, which has the serial monitor open, with the baudrate set to 300 - and it doesn't work. 1200 and higher works fine, 300 renders crap. I would use a higher baud rate, but the device i want to eventually talk to uses 300 so i'm stuck!

Is this some sort of error with my PC? Can anyone else test serial comms at 300 baud for me? Also if no-one can suggest how to get it to work, can anyone suggest a chip with a UART on it that i could talk to over i2C or something?

cheers!

-h
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17262
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe a little experiment could 'half split' the problem to being either with the 8U2 usb serial converter chip or the mega2560 hardware or sketch code.

Wire a jumper from the reset pin to a ground pin, that will hold the 2560 processor in reset mode. Jumper pins 0 and 1 together. Now plug the board into the PC, open the arduino IDE, select proper comm port number and board type. Now open the serial monitor and send data. Whatever you type should be 'looped back' to the serial monitors receive window. Try various baudrate selections in the serial monitor to see if 300 baud fails and other work fine. Let us know the results of this little test.

I've tried this with both my Seeeduino mega board (avr1280 based) and a rs-232 serial board based on a 328 chip, both work fine at 300 baud.

Lefty
« Last Edit: April 11, 2011, 01:23:31 pm by retrolefty » Logged

London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Cheers Lefty!

That works as expected, jumpers on the reset and gnd + tx and rx works as a loop-back at all the baud rates i tested... Also, it works across all the boards i've got.

So what next? I guess that proves that the computer's (virtual) serial port is behaving as expected  - in a separate test, i can get my 300baud serial clock to communicate with the computer too, so that's that.

Any other ideas? Really appreciate your help!

-h
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17262
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Any other ideas? Really appreciate your help!

Well the next step is to run as simple a sketch as possible that demonstrates the symptom. So load:


Code:
void setup() {
  // initialize serial port at desired speed:
  Serial.begin(300);
  
}

void loop() {
  // read from port 0, send to port 0:
  if (Serial.available() > 0) {
    int inByte = Serial.read();
    Serial.print(inByte, BYTE);
    
  }
}

Load and run that (no wire jumpers this time) and use the serial monitor at various baud rate (remember to change the sketch baudrate first) to see if you have the same problem at just 300 baud.

I ran it on both my Seeeduino mega board and RS-232 AVR328 board, and guess what?

All baud rates work fine EXCEPT 300 baud that garbles the data:

sent: abcdefghijklmnopqrstuvwxyz
receive: }bcfefgníîïlíîï|qrsvuvw~yzíŽ

That tells me that there is a serial library problem such that there is a problem properly setting up the baudrate divider for 300 baud support.

That's about as far as I can take it. Perhaps one of our software gods can look at the library and see what the problem may be. Perhaps there is an existing bug report for 300baud problems?

Lefty
« Last Edit: April 11, 2011, 03:15:03 pm by retrolefty » Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8472
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
sent: abcdefghijklmnopqrstuvwxyz
receive: }bcfefgníîïlíîï|qrsvuvw~yzíŽ
It's close though, so not a maths overflow problem that causes the serial to run at 1000x the expected speed.

It looks like this it worth raising as a bug.

Meanwhile how about using software serial as a work around?

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great - i cherish the honour of discovering bugs. I'll file it. Thanks so much for looking into the problem chaps.

In the meantime, i don't think i can use a software serial library - the clock i'm trying to talk to uses 7-E-2 instead of the more standard 8-N-1. I see that i can change the data format by altering UCSRnC with HW serial, but i don't see how to do that with SW serial. So that's a new problem :-)

cheers

-h
 
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 199
Posts: 12768
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


It's a bug.  The threshold to trigger the symptom is 488 baud.  The problem is the person who coded HardwareSerial::begin assumed the divisor register is 16 bits when it's actually 12 bits.

In HardwareSerial.cpp, change HardwareSerial::begin to this...

Quote
void HardwareSerial::begin(long baud)
{
  uint16_t baud_setting;
  bool use_u2x = true;

#if F_CPU == 16000000UL
  // hardcoded exception for compatibility with the bootloader shipped
  // with the Duemilanove and previous boards and the firmware on the 8U2
  // on the Uno and Mega 2560.
  if (baud == 57600) {
    use_u2x = false;
  }
#endif
 
try_again:

  if (use_u2x) {
    *_ucsra = 1 << _u2x;
    baud_setting = (F_CPU / 4 / baud - 1) / 2;
  } else {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  if ( (baud_setting > 4095) && use_u2x )
  {
    use_u2x = false;
    goto try_again;
  }


  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);
}
« Last Edit: April 12, 2011, 09:00:24 pm by Coding Badly » Logged

London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That works great, thanks for the input... but it only works great on the first serial port of a Mega2560.

Here's the sketch i'm using to test:

Code:
void setup() {
  Serial.begin(300);
  Serial1.begin(300);
}

void loop() {
  // read from port 0, send to port 0:
  if (Serial.available() > 0) {
    int inByte = Serial.read();
    Serial.print(inByte, BYTE);
  }
 
  // read from port 1, send to port 1:
  if (Serial1.available() > 0) {
    int inByte = Serial1.read();
    Serial1.print(inByte, BYTE);
  }
 
}

Serial:
sent: abcdefghijklmnopqrstuvwxyz
received: abcdefghijklmnopqrstuvwxyz

Serial1:
sent: abcdefghijklmnopqrstuvwxyz
received: ybcfefgnijklmnoxqrsvuvw~yz.

I've looked over HardwareSerial.cpp and can't see anything obvious - but my proper C is pretty dire admittedly. Any further ideas/solutions?
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 199
Posts: 12768
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


What do you have connected to Serial1?

Please run the following and reply with the results...

Code:
void setup( void )
{
  Serial.begin(300);
  Serial1.begin(300);
}

void loop( void )
{
  Serial.println();
  Serial.print( "#0 UCSR0A: " );
  Serial.println( UCSR0A & (1<<U2X0), HEX );
  Serial.print( "#0 UBRR0:  " );
  Serial.println( UBRR0, DEC );
  Serial.print( "#1 UCSR1A: " );
  Serial.println( UCSR1A & (1<<U2X1), HEX );
  Serial.print( "#1 UBRR1:  " );
  Serial.println( UBRR0, DEC );
  delay( 1000 );
}
Logged

London, UK
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've got a MAX 232 with a USB to Serial Adapter, which i'm looking at with a terminal emulator...

I ran your sketch, here's the output

#0 UCSR0A: 2
#0 UBRR0:  2570
#1 UCSR1A: 2
#1 UBRR1:  2570


(edit)

So, the UBRR0 & UBRR1 registers are where the baud rate is set for each port, so i'm guessing that we're checking that they're set correctly?

I changed your the test's setup() function to look like this:
Code:
void setup( void )
{
  Serial.begin(300);
  Serial1.begin(1200);
}

..and the output was this:

#0 UCSR0A: 2
#0 UBRR0:  2570
#1 UCSR1A: 2
#1 UBRR1:  2570


now, i might be showing my naivety, but shouldn't UBRRn be set differently if they baudrates are set differently? It looks to me like HardwareSerial sets both ports to whatever UBRR0 is set to...
« Last Edit: April 13, 2011, 01:48:07 pm by henryholland » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 199
Posts: 12768
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Yikes!  Give this a try...

Quote
void setup( void )
{
  Serial.begin(300);
  Serial1.begin(1200);
}

void loop( void )
{
  Serial.println();

  Serial.print( "#0 UCSR0A: " );
  Serial.println( UCSR0A & (1<<U2X0), HEX );
  Serial.print( "#0 UBRR0:  " );
  Serial.println( UBRR0, DEC );

  Serial.print( "#1 UCSR1A: " );
  Serial.println( UCSR1A & (1<<U2X1), HEX );
  Serial.print( "#1 UBRR1:  " );
  Serial.println( UBRR1, DEC );

  delay( 1000 );
}
Logged

Pages: [1] 2   Go Up
Jump to: