Faster Serial

Hello everyone. I can't manage to get reliable SoftwareSerial (Arduino 1.0) communication to happen between two Arduino Unos if I use over a 9600 baud rate. Bytes get mixed up above that speed. Has anyone managed to get a fast and reliable HARDWARE serial baud rate between two MCUs? What do we do if we need a serial baud rate of say, 250,000 baud?

Thanks,
Greg

Hello everyone. I can't manage to get reliable SoftwareSerial (Arduino 1.0) communication to happen between two Arduino Unos if I use over a 9600 baud rate.

With what connected to what? Running what code?

Has anyone managed to get a fast and reliable HARDWARE serial baud rate between two MCUs?

If you are trying to get hardware serial going, why are you using SoftwareSerial?

What do we do if we need a serial baud rate of say, 250,000 baud?

Get a different microcontroller that supports that speed. The fastest supported speed on the Arduino is 115200.

What are you trying to send between the boards that requires that speed?

Hi Paul,

I presume you are referring to the Arduino IDE, not the Atmel microprocessor, right?

Per the Atmel spec sheet, the 328P appears to support 1,000,000 baud connections in hardware with a 0% error rate while running at a 16MHz system clock. (see page 201 in http://www.atmel.com/dyn/resources/prod_documents/doc8025.pdf, the relevant datasheet). Is there a particular reason that the IDE does not offer more speeds for users to choose amongst? Consider that the error rate appears to be lower at 250,000 baud than at 56,700 baud...

Or is there a way to modify a preference somewhere within the Arduino IDE to expand the range of baud settings? I couldn't find any references to allowable baud speeds in the preferences.txt file... just the last one used.

I am sure there is a very good reason why some of the baud rates that Atmel lists as superior in performance to the ones used by the IDE are not used. I just don't know know enough about the subject... but if you happen to have that info handy, I'd appreciate being enlightened. Many thanks!

I guess I'll try again... I need to find a way to interface one arduino (master) with multiple arduino devices (slaves) via TTL serial at a decent baud rate with a low error rate. I was thinking SoftwareSerial might be a solution as you can have multiple serial outs but I'm not finding good speeds with low error.

Can HardwareSerial be hacked in order to let me use a higher baud rate than 115,200? Even if not is there a solution for some sort of TTL serial switch IC where I can switch between sending commands to multiple devices over one hardware serial UART?

Thanks!

gcotten:
I guess I'll try again... I need to find a way to interface one arduino (master) with multiple arduino devices (slaves) via TTL serial at a decent baud rate with a low error rate. I was thinking SoftwareSerial might be a solution as you can have multiple serial outs but I'm not finding good speeds with low error.

Can HardwareSerial be hacked in order to let me use a higher baud rate than 115,200? Even if not is there a solution for some sort of TTL serial switch IC where I can switch between sending commands to multiple devices over one hardware serial UART?

Thanks!

Is there a reason why you can't use SPI or I2C? It would seem your need for a such a bus is justified (now, there might be distance issues)...

Am I missing something here as far as connections go?
Master sends to all slaves, only selected slave (software address - "Hey, that's me!") responds...

With TTL connections between parts, lines are low between data bytes so any high from a slave becomes a high out of the OR gate.
(unless I have it backwards, then use a 4 input AND gate instead, and any low becomes a low of the AND gate).
So the slave have to play nice or data get garbled.

At 115,200, you only got 86uS to read the data from the serial port, decide what to do with, etc, before the next byte comes in.
That's 138 clock cycles, not a lot of instructions to be doing stuff.

You don't want to be wasting time sending out 2 address lines to be switching some kind of mux chip. That would imlpy your slaves are out of control and sending stuff willy nilly, and then you lose even more time getting ones attention to send you proper stuff.
Or letting them ramble, and lose some time figuring where the state a data sequences is.

cr0sh:
Is there a reason why you can't use SPI or I2C? It would seem your need for a such a bus is justified (now, there might be distance issues)...

I can't use i2c due to distance being too short (I need at least 10 meters) and SPI is already in use for interfacing with some flash memory...

CrossRoads:
Am I missing something here as far as connections go?
Master sends to all slaves, only selected slave (software address - "Hey, that's me!") responds...

With TTL connections between parts, lines are low between data bytes so any high from a slave becomes a high out of the OR gate.
(unless I have it backwards, then use a 4 input AND gate instead, and any low becomes a low of the AND gate).
So the slave have to play nice or data get garbled.

At 115,200, you only got 86uS to read the data from the serial port, decide what to do with, etc, before the next byte comes in.
That's 138 clock cycles, not a lot of instructions to be doing stuff.

You don't want to be wasting time sending out 2 address lines to be switching some kind of mux chip. That would imlpy your slaves are out of control and sending stuff willy nilly, and then you lose even more time getting ones attention to send you proper stuff.
Or letting them ramble, and lose some time figuring where the state a data sequences is.

Would it be OK if I split the TX line 6 ways (serial is going to 6 devices)? I am a little worried about line loss over 10 meters+. Do people use distribution amplifiers for this kind of stuff?

I'm not constantly sending out a stream of bytes to all the serial devices - only every 2ms each device is sent 4 bytes of data to be processed and integrated into a closed-loop PID. I would like the baud rate to be as high as possible (has anyone gone above 115200 on HardwareSerial??) so that the PID can be as tight as possible.

Sure, buffer it & send to as many as you want.
Can use RS232 , RS422 drivers & recievers even if you wanted.
MAX232, MAX3488 or equivalent type parts.

Hi Crossroads!

In my particular application, I have a 328P talking to a 1284P, hardware serial, sending short data packets (a couple of bytes) every second. Basically, the 328P acts as a DAQ, manipulating the results, and sending summaries to the 1284P which samples other data meanwhile before writing it to micro-SD and/or transmitting via NRF+. Speeding up the serial bus increases the number of samples/s the 328P is able to collect. Using a serial bus between the Atmels is convenient for debugging purposes and EasyTransfer makes getting the data from one Atmel to the other one almost trivial. I just found out that someone implemented EasyTransfer via I2C, that certainly sounds interesting!

The fastest supported speed on the Arduino is 115200. ...

Note that the Arduino can send faster but the IDE is the limiting factor here. Switch to a (real) terminal program like putty.exe or ...

More see - Fast communication to PC with low Arduino footprint - #12 by robtillaart - Networking, Protocols, and Devices - Arduino Forum -

Thank you, Rob. That link contains good info and seems to confirm my interpretation of the Atmel 328P datasheet. I wonder if you would have any luck with a 1Mbit/s transfer rate since Atmel seems to indicate this as one of their 'legal' serial speeds. I plan on trying it out tonight...

FWIW, and that is probably purely academic, the Atmels are communicating fine via serial at 1Mbit/s. XD

The resultant improvement is fairly marginal in impact (~60 additional samples/second, IIRC, for the 328P or about 1.5%) but I'll take the free additional samples... even if there is some impact on usability thanks to the IDE not supporting that speed. Cheers!

Glad to hear that. You might look into RS485 for cabling the longer cable runs. Since you are writing to an SD card (an inherently slow operation) I would have thought that really high speed transfers wouldn't really be required. As for SPI, you can deselect the SD card and address another device. My timings indicate you can transfer around 333,333 bytes per second using SPI, but I'm not sure about the long cable runs. Using I2C you should be able to look at around 40,000 bytes per second.

FWIW, and that is probably purely academic, the Atmels are communicating fine via serial at 1Mbit/s.

Which version of the IDE are you using? With 1.0, outgoing serial data is buffered, so the Serial.write() function is no longer blocking. I would think that generating the data to send would take longer than actually moving the data to the buffer, so I'd think that moving the data out of the buffer 8 times as fast would have nearly no impact.

Prior to 1.0, serial output was blocking, so moving it out faster would have a small effect on samples per second.

One reason I am dedicating one of the Atmels solely to sampling (i.e. ADC) is that can sample and process exactly what I want how I want to and can then send it on to the second Atmel. It allows the Atmel to reach high sampling rates and hence good resolution. At 16MHz clock speed and a 128 ADC pre-scaler, the 328p is capturing about 4.5kSps per channel or 9kSps total. I plan on using a different ceramic resonator on that unit, up the main clock speed to 20MHz and then get about 6kSps for each channel yet stay safely below the maximum ADC sampling rate (158 vs 200kHz).

The other Atmel takes the data, adds other data (such as temperature and humidity, as well as external sensors) and then assembles a data string. The data string is prefaced by a excel-format time stamp that is based on the output of a DS3231 real time clock. Some additional work is done, then the whole enchilada is sent to the SD card as well as a NRF module. By putting the I/O on the second chip, I avoided all sorts of performance issues re: all things sampling, and the Atmel 328P is a lot easier to program and calibrate than standard-issue power measurement chips like the ADE7753, at least for me. It may not have the same performance but the price point is about the same and it is a lot easier to troubleshoot.

The 1284P that I am using to do all the other work has way more RAM to accomodate the data string (char operations are still a bit of challenge for me). The program on the 1284p is only 23k but I managed to hang a previously-used 328p consistently thanks to the use of string operations. The data string wasn't even that long... and some day I will figure out how to assemble the data properly using char array operations, which appear to use a lot less memory.

As for the IDE, I am currently using the brewtroller-version of the 022 IDE in order to get good support for the 1284p (thank you, BrewTroller project!). Has Arduino 1.0 added support for 1284s? I wouldn't think so based on my brief review of the change-log but I haven't tried it out yet.

No 1284 support yet - but wouldn't be hard to copy & manipulate one of the
pins_arduino.h files
in the
Arduino-1.0\hardware\arduino\variants\
folders to add a 1284.

They seem to have complicated the format a bit!

Hi CrossRoads!

Thanks for the reply. I will try to take a look at those files and see if I can decipher them. Are there any guides posted as to how to configure the pins file to reflect the wishes of the Arduino team? I'd rather not muck around and blow a fuse or two on the chip - unlike your DIP units, my TQFPs take a bit more time and effort to replace! Cheers and happy new year.

Not that I know of.
I've got this file for my Bobuino's, figure line up the parts that match, fill in the new stuff from there.

I had this in pins_arduino.c, looks like they've pulled these into pins_arduino.h files instead

// ATMEL ATMEGA1284P / BOBUINO
//
//                    +---\/---+
//  INT0 (D 4)  PB0  1|        |40  PA0 (AI 0 / D14)
//  INT1 (D 5)  PB1  2|        |39  PA1 (AI 1 / D15)
//  INT2 (D 6)  PB2  3|        |38  PA2 (AI 2 / D16)
//   PWM (D 7)  PB3  4|        |37  PA3 (AI 3 / D17)
//   PWM (D 10) PB4  5|        |36  PA4 (AI 4 / D18)
//  MOSI (D 11) PB5  6|        |35  PA5 (AI 5 / D19)
//  MISO (D 12) PB6  7|        |34  PA6 (AI 6 / D21)
//   SCK (D 13) PB7  8|        |33  PA7 (AI 7 / D22)
//              RST  9|        |32  AREF
//              VCC 10|        |31  GND 
//              GND 11|        |30  AVCC
//            XTAL2 12|        |29  PC7 (D 29)
//            XTAL1 13|        |28  PC6 (D 28)
//  RX0 (D 0)   PD0 14|        |27  PC5 (D 27) TDI
//  TX0 (D 1)   PD1 15|        |26  PC4 (D 26) TDO
//  RX1 (D 2)   PD2 16|        |25  PC3 (D 25) TMS
//  TX1 (D 3)   PD3 17|        |24  PC2 (D 24) TCK
//  PWM (D 30)  PD4 18|        |23  PC1 (D 23) SDA
//  PWM (D 8 )  PD5 19|        |22  PC0 (D 22) SCL
//  PWM (D 9)   PD6 20|        |21  PD7 (D 31) PWM
//                   +--------+
//

#if defined(__AVR_ATmega1284P__) 
// add this if use these other chips
//|| defined(__AVR_ATmega644P__)|| defined(__AVR_ATmega324P__)

// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint16_t PROGMEM port_to_mode_PGM[] =
{
	NOT_A_PORT,
	&DDRA,
	&DDRB,
	&DDRC,
	&DDRD,
};

const uint16_t PROGMEM port_to_output_PGM[] =
{
	NOT_A_PORT,
	&PORTA,
	&PORTB,
	&PORTC,
	&PORTD,
};

const uint16_t PROGMEM port_to_input_PGM[] =
{
	NOT_A_PORT,
	&PINA,
	&PINB,
	&PINC,
	&PIND,
};

// these these 3 arrays must match up, & define the ordering of the Digital assignments
// first the ports to be used:
const uint8_t PROGMEM digital_pin_to_port_PGM[] =  
{
	PD, /* 0  PD0 */
	PD, /* 1  PD1 */
	PD, /* 2  PD2  */
	PD, /* 3  PD3  */
	PB, /* 4  PB0  */
	PB, /* 5  PB1  */
	PB, /* 6  PB2  */
	PB, /* 7  PB3  */

	PD, /* 8  PD5  */
	PD, /* 9  PD6  */
	PB, /* 10 PB4  */
	PB, /* 11 PB5  */
	PB, /* 12 PB6  */
	PB, /* 13 PB7  */
	PA, /* 14 PA0  */
	PA, /* 15 PA1  */

	PA, /* 16 PA2  */
	PA, /* 17 PA3  */
	PA, /* 18 PA4  */
	PA, /* 19 PA5  */
	PA, /* 20 PA6  */
	PA, /* 21 PA7  */
   	PC, /* 22 PC0  */
	PC, /* 23 PC1  */

	PC, /* 24 PC2  */
	PC, /* 25 PC3  */
	PC, /* 26 PC4  */
	PC, /* 27 PC5  */
	PC, /* 28 PC6  */
	PC, /* 29 PC7  */
	PD, /* 30 PD4  */
	PD  /* 31 PD7  */

};
// then the pins for the particular ports:
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
{
	_BV(0), /*D0: 0, port D */
	_BV(1), /*D1: 1, port D */
	_BV(2), /*D2: 2, port D */
	_BV(3), /*D3: 3, port D */
	_BV(0), /*D4: 0, port B */
	_BV(1), /*D5: 1, port B */
	_BV(2), /*D6: 2, port B */
	_BV(3), /*D7: 3, port B */

	_BV(5), /*D8: 5, port D */
	_BV(6), /*D9: 6, port D */
	_BV(4), /*D10: 4, port B */
	_BV(5), /*D11: 5, port B */
	_BV(6), /*D12: 6, port B */
	_BV(7), /*D13: 7, port B */
	_BV(0), /*D14: 0, port A */
	_BV(1), /*D15: 1, port A */

	_BV(2), /*D16, 2, port A */
	_BV(3), /*D17: 3, port A */
	_BV(4), /*D18: 4, port A */
	_BV(5), /*D19: 5, port A */
	_BV(6), /*D20: 6, port A */
	_BV(7), /*D21: 7, port A */
	_BV(0), /*D22: 0, port C */
	_BV(1), /*D23: 1, port C */

	_BV(2), /*D24, 2, port C */
	_BV(3), /*D25: 3, port C */
	_BV(4), /*D26: 4, port C */
	_BV(5), /*D27: 5, port C */
	_BV(6), /*D28: 6, port C */
	_BV(7), /*D29: 7, port C */
	_BV(4), /*D30: 4, port D */
	_BV(7)  /*D31: 7, port D */

};
// then whether the pins have Timer capability:
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
{
	NOT_ON_TIMER,	/* 0  - PD0 */
	NOT_ON_TIMER, 	/* 1  - PD1 */
	NOT_ON_TIMER, 	/* 2  - PD2 */
	NOT_ON_TIMER,               /* 3  - PD3 */  
	NOT_ON_TIMER,	/* 4  - PB0 */ 
	NOT_ON_TIMER, 	/* 5  - PB1 */
	NOT_ON_TIMER, 	/* 6  - PB2 */
	TIMER0A,		/* 7  - PB3 */ // PWM

	TIMER1A,	 	/* 8  - PD5 */ // PWM
	TIMER2B, 		/* 9  - PD6 */ // PWM
	TIMER0B,	 	/* 10 - PB4 */ // PWM
	NOT_ON_TIMER, 	/* 11 - PB5 */
	NOT_ON_TIMER,               /* 12 - PB6 */ 
	NOT_ON_TIMER,               /* 13 - PB7 */ 
	NOT_ON_TIMER,               /* 14 - PA0 */ 
	NOT_ON_TIMER,               /* 15 - PA1 */ 

	NOT_ON_TIMER, 	/* 16 - PA2 */
	NOT_ON_TIMER,	/* 17 - PA3 */
	NOT_ON_TIMER,	/* 18 - PA4 */
	NOT_ON_TIMER,	/* 19 - PA5 */
	NOT_ON_TIMER,	/* 20 - PA6 */
	NOT_ON_TIMER,	/* 21 - PA7 */
	NOT_ON_TIMER,	/* 22 - PC0 */
	NOT_ON_TIMER,	/* 23 - PC1 */

	NOT_ON_TIMER,	/* 24 - PC2 */
	NOT_ON_TIMER,	/* 25 - PC3 */
	NOT_ON_TIMER,	/* 26 - PC4 */
	NOT_ON_TIMER,	/* 27 - PC5 */
	NOT_ON_TIMER,	/* 28 - PC6 */
	NOT_ON_TIMER,	/* 29 - PC7 */
	TIMER1B,		/* 30 - PD4 */ // PWM
	TIMER2A		/* 31 - PD7 */ // PWM

};


#endif

Hi CrossRoads,

Many thanks! If I manage to get through writing two sets of recommendations, throwing out the trash, fixing a busted door frame, and so on, I'll try to attack it to tonight and I'll post whatever I have. The 1284P is such a great chip since not everyone needs a bazillion I/O's and the smaller size factor than its larger cousins makes it much easier to accomodate the chip on a PCB. Thanks again.