Go Down

Topic: An alternative Serial Library for Arduino 1.0 (Read 23 times) previous topic - next topic

fat16lib

I have posted an early version of a new serial library http://code.google.com/p/beta-lib/downloads/list.  The file is SerialPortBeta20111230.zip.

Please try the SerialPort library and post any comments here.

The SerialPort library provides flexible control of RX and TX buffering.

I used a parametrized template so buffering is specified in the class constructor.
Code: [Select]
SerialPort<PortNumber, RxBufSize, TxBufSize>

In this example, a SerialPort object is created for port zero, with no buffering so it uses very little RAM.
Code: [Select]
#include <SerialPort.h>
SerialPort<0, 0, 0> NewSerial;

void setup() {
NewSerial.begin(9600);
NewSerial.write("Hello World\r\n");
}
void loop() {}

This example has a RX buffer with a capacity of 32 bytes and unbuffered output:
Code: [Select]
#include <SerialPort.h>
SerialPort<0, 32, 0> NewSerial;

void setup() {
NewSerial.begin(9600);
NewSerial.write("Hello World\r\n");
}
void loop() {}

Flash use varies depending on buffering options.  It is usually about the same as Arduino 1.0 HardwareSerial but may be more or less.  I will try to optimize flash usage in a later version.

I have attempted to maintain compatibility with the API for Serial.

flush() behaves like HardwareSerial::flush().  On 1.0 and above it waits for TX data to be sent and on Arduino 0023 and before it discards RX data.

I have also added separate flushRx() and flushTx() functions.

robtillaart


feature request based upon "mode com1:9600,N,8,1"
In words, please make it possible to define parity (None,Odd,Even), number of databits (4,5,6,7,8) / stopbits (0,1,2)

Is this possible?

usage:
Sometimes I have to communicate just nibbles (4bit) e.g. a single digit (0..9) or 4 boolean states. And then a byte has 50% overhead.
Some older devices (e.g. terminals) use 7 databits and multiple stopbits (even 1.5 was possible IIRC).

If time permits I'll dive into your code to see if it makes sense to me ;)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Code: [Select]

struct SerialRingBuffer {
  uint8_t* buf;   /**< Pointer to start of buffer. */
  uint16_t head;  /**< Index to next empty location. */
  uint16_t tail;  /**< Index to last entry if head != tail. */
  uint16_t size;  /**< Size of the buffer. Capacity is size -1. */
};


Think buffers larger than 255 bytes are very rare ==> uint8_t head, tail, size;  // saves a few bytes and might speed up indexing of the buffer access in the isr()'s

----

Code: [Select]
void flushRx() {
    if (RxBufSize) {
      rxbuf_->head = rxbuf_->tail;
    } else {
    // put correct code here/////////////////////////////////////////////////////////////
      usart_->udr;
      usart_->udr;
    }
  }


I think flushRX must allways make head and tail equal, whether there is a buffer or not. ==>

Code: [Select]
void flushRx() {
  rxbuf_->head = rxbuf_->tail;
  }


----

Code: [Select]
  void end() {
    // wait for transmission of outgoing data
    while (txbuf_->head != txbuf_->tail) {}
    usart_->ucsrb &= ~((1 << B_RXEN) | (1 << B_TXEN)
                     | (1 << B_RXCIE) | (1 << B_UDRIE));
    // clear any received data
    flushRx();  // <<<<<<<< prevent duplicate code?
  }


So far my 2 cents ...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

fat16lib

Adding options for parity, character size, and number of stop bits is a good idea.

Parity generation on transmit is easy. 

For receive parity errors it would be difficult to flag each character since I buffer 8-bits.  I could set a flag indicating a parity error occurred in some character and the user could check and clear it.  Is that adequate?

The avr USART is capable of character sizes of 5, 6, 7, 8, and 9 bits.  Nine data bits would be difficult since I use an 8-bit data type for ring buffers.

The USART allows one or two stop bits in a asynchronous mode.  I didn't know zero stop bits was allowed for asynchronous serial.  I thought there needed to be a stop bit to maintain correct framing.  The fact that the start bit has space value and the stop bit has mark value allows frame synchronization independent of the character data pattern.

I have had requests for buffers larger than 255 bytes for data logging at very high speeds.  Writing an SD can take as long as 200 milliseconds on rare occasions.  At high speeds this requires more than 255 bytes.  On a Mega over 2000 bytes of buffering is required insure no data loss at 115200 baud.

You can't access the ring buffer when there is no buffer.  It is possible that the ring buffer doesn't exist if BUFFERED_RX is zero.

Here is my new code for end() and flushRx()
Code: [Select]

void end() {
  // wait for transmission of outgoing data
  flushTx();
  usart_->ucsrb &= ~((1 << B_RXEN) | (1 << B_TXEN)
                     | (1 << B_RXCIE) | (1 << B_UDRIE));
  // clear any received data
  flushRx();
}

void flushRx() {
  if (RxBufSize) {
    rxbuf_->flush();
  } else {
    // empty USART fifo
    usart_->flush();
  }
}

void flushTx() {
  if (TxBufSize) {
    while (!txbuf_->empty()) {}
  }
}

// empty USART fifo
void SerialRegisters::flush() {
  uint8_t b;
  while (ucsra & (1 << B_RXC)) b = udr;
}


Don't spend too much time looking at the current implementation.  I am changing it to optimize flash usage.  By default templates generate inline code which can use extra flash.  I am making changes so read() and write() are not inline.

robtillaart

Quote
For receive parity errors it would be difficult to flag each character since I buffer 8-bits.  I could set a flag indicating a parity error occurred in some character and the user could check and clear it.  Is that adequate?

Any step forward is OK :)

Quote
The avr USART is capable of character sizes of 5, 6, 7, 8, and 9 bits.  Nine data bits would be difficult since I use an 8-bit data type for ring buffers.

Don't lnow of any device using 9 databits (never used it either) so don't care about that one. The 5,6,7 are still interesting.

The # stopbits support sounds good too! Do you have a link to a PDF describing the USART? 
Stopbits come from a time where devices needed time to process the incoming data (think mechanical teletypes), and to be sure to give them enough time. Zero stopbits came in when local buffering removed that need.

I am familiar with your (great!) highspeed SD work so now I understand your 16 bit int choice better (add this rationale in the readme file ?)

Quote
You can't access the ring buffer when there is no buffer.  It is possible that the ring buffer doesn't exist if BUFFERED_RX is zero.

You're right, I missed that in my quick review

New code looks better imho, well done!

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up