Custom size Arduino serial buffers mod



Note: in this article I use the Arduino IDE 1.0.x version that was the default non beta IDE at the time when I wrote the post. Since the Arduino core may change in more recent IDE, you may need to adapt what is said here - the main method and idea remains the same.

Source code of the Arduino serial buffers


The Arduino boards come with handy serial buffers. The default buffers are defined in two files named HardwareSerial.cpp and HardwareSerial.h . On my Ubuntu machine with default installation, those files are located in /usr/share/arduino/hardware/arduino/cores/arduino. By default, the size of both RX (receive) and TX (transmitt) buffers is 64 bits on a 2kB RAM Arduino Uno board, as defined in HardwareSerial.cpp:

 
#if (RAMEND < 1000)
  #define SERIAL_BUFFER_SIZE 16
#else
  #define SERIAL_BUFFER_SIZE 64
#endif

The size of the buffers is chosen to allow 'reasonable' communcations without using too much of the scarce RAM available. However, some projects may require much bigger RX or TX buffers to enable proper communications (for example, if you need to receive packets of data that you cannot read on the fly and are bigger than the 64 bits RX limit).

Mod 1: modification of both RX and TX buffers to the same size


The simplest option is then to create a new board software in which the default size of the buffers is increased to fit you needs, as explained in this post. The first step to perform consists in modifying the size of the define statements (to get, for example, 128 bits RX and TX buffers):

 
#if (RAMEND < 1000)
  #define SERIAL_BUFFER_SIZE 16
#else
  #define SERIAL_BUFFER_SIZE 128
#endif

If you do not want to erase the default Uno configuration, this modified code should then be inserted in a complete copy of the default code /hardware/arduino/cores/arduino, that I will name /hardware/arduino/cores/arduino_128_serialbuf. The modified Uno board should finally be added in the bords lists of the IDE, located in hardware/arduino/boards.txt by adding a new entry:

 
##############################################################

uno256.name=Arduino Uno (128 Serial Buffer)
uno256.upload.protocol=arduino
uno256.upload.maximum_size=32256
uno256.upload.speed=115200
uno256.bootloader.low_fuses=0xff
uno256.bootloader.high_fuses=0xde
uno256.bootloader.extended_fuses=0x05
uno256.bootloader.path=optiboot
uno256.bootloader.file=optiboot_atmega328.hex
uno256.bootloader.unlock_bits=0x3F
uno256.bootloader.lock_bits=0x0F
uno256.build.mcu=atmega328p
uno256.build.f_cpu=16000000L
uno256.build.core=arduino_128_serialbuf
uno256.build.variant=standard

##############################################################

This new board will now be available from the board menu of the IDE. Both RX and TX buffers will be 128 bits.

Mod 2: modification of RX and TX buffers to different custom sizes


However, there are still some limits with this modification. In particular, in some cases, you want a quite big RX buffer (say 1024 bits) but you do not need a big TX buffer (say 32 bits is enough). If you use the Mod 1 approach, you will use all your RAM and your program will not run. So you need to be able to set separately the size of the RX and TX buffers.
This requires more work than the previous approach. In the original source code, the RX and TX buffers are defined by the same structure, while we want two different structures that contain arrays of different sizes. Here are the new definitions that I use in my implementation of HardwareSerial.cpp for custom size buffers:


// OLD definition, two buffers together
// #if (RAMEND < 1000)
//   #define SERIAL_BUFFER_SIZE 16
// #else
//   #define SERIAL_BUFFER_SIZE 64
// #endif
// OLD definition end
// NEW definition
// RX and TX buffers separately. Remember that SRAM is only 2KBytes on ATMega328
// or 8KBytes on ATMega2560
#define SERIAL_BUFFER_SIZE_RX 1024
#define SERIAL_BUFFER_SIZE_TX 32
// NEW definition end

, and:

 
// OLD definition, two buffers together
// struct ring_buffer
// {
//   unsigned char buffer[SERIAL_BUFFER_SIZE];
//   volatile unsigned int head;
//   volatile unsigned int tail;
//  static const int size = SERIAL_BUFFER_SIZE;
// };
// OLD definition end
// NEW definition
// define separate structures for rx and tx buffers with different sizes
struct ring_buffer_rx
{
  unsigned char buffer[SERIAL_BUFFER_SIZE_RX];
  volatile unsigned int head;
  volatile unsigned int tail;
//  static const int size = SERIAL_BUFFER_SIZE_RX;
};

struct ring_buffer_tx
{
  unsigned char buffer[SERIAL_BUFFER_SIZE_TX];
  volatile unsigned int head;
  volatile unsigned int tail;
//  static const int size =  SERIAL_BUFFER_SIZE_TX;
};
// NEW definition end

Other modifications are required in several places in both HardwareSerial.cpp and HardwareSerial.h to remain coherent with those new definitions. The new code should be placed in a copy of the Arduino default code in the same way as explained in Mod 1, and a new entry should also be added to the boards list. All the source code is available on my GitHub.

Edit: updated Arduino code on official GitHub



It seems that some version of the Arduino source code has been updated since the version I am using, and that the new code defines separately the RX and TX buffers. It is then possible to do exactly the same modification directly in the more recent source code. However, I am not sure of what code is included with which version of the Arduino IDE so the present mod may still be of practical interest.