Table of contents
The universal synchronous and asynchronous receiver and transmitter (USART) is an interface type using two pins where one is used for transmitting (TX) and one for receiving (RX) the serial data between two devices, e.g. chips or units. Unlike the I2C (Wire) or SPI busses the serial interface can only be used between two devices. Typically the communication speed is from 1200 Baud to 115200 Baud but both lower and faster is also possible.
The RFzero board comes with the possibility of 5 serial devices, of which one is dedicated to the GPS module and the remaining 4 may be used for external connections.
Communicating via the serial interface
Here is an example that used both the Serial5 and USB interfaces by communicating between the them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// RFzero include and object creation #include <RFzero.h> // MUST ALWAYS be included for RFzero void setup() { // Initialize USB SerialUSB.begin(9600); // Set the serial USB port to 9600 Baud and 8N1 (default) while (!SerialUSB); // Wait for the USB port to be ready // Initialize Serial1 Serial5.begin(9600); // Set the Serial5 port to 9600 Baud and 8N1 (default) } void loop() { if (SerialUSB.available()) // Is there any USB data available? { char ch = (char) SerialUSB.read(); // Read the USB data Serial5.print(ch); // Copy the data to Serial5 } if (Serial5.available()) // Is there any Serial5 data available? { char ch = (char) Serial5.read(); // Read the Serial5 data SerialUSB.print(ch); // Copy the data to the USB port } } |
The above examples are rather simple. But what if you don’t want to process the received data before a terminating character is received, e.g. an exclamation mark (!). The below code is an example of how to do this using a buffer to store the USB data temporarily.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// RFzero include and object creation #include <RFzero.h> // MUST ALWAYS be included for RFzero void ReceiveSerial5Data() { static char serialBuffer[100] = "\0"; // Initialize the buffer static int serialBufferCount = 0; // Empty buffer to first character is the 0 terminator bool resetBuffer = false; while (Serial5.available()) // Is there any Serial5 data available? { char ch = (char) Serial5.read(); // Read the Serial5 data // Check if buffer can overflow if (serialBufferCount < sizeof(serialBuffer) - 1) { // No overflow serialBuffer[serialBufferCount] = ch; // Add the new character to the end of the buffer serialBufferCount++; serialBuffer[serialBufferCount] = 0; // Set 0 terminating character } else resetBuffer = true; // Buffer overflow to reset buffer if (ch == '!') // Check if the character is a line feed { SerialUSB.print(serialBuffer); // Copy the data to Serial5 resetBuffer = true; // Buffer overflow to reset buffer } if (resetBuffer) { serialBuffer[0] = 0; serialBufferCount = 0; } } } void setup() { // Initialize USB SerialUSB.begin(9600); // Set the serial USB port to 9600 Baud and 8N1 (default) while (!SerialUSB); // Wait for the USB port to be ready // Initialize Serial1 Serial5.begin(9600); // Set the Serial5 port to 9600 Baud and 8N1 (default) } void loop() { if (SerialUSB.available()) // Is there any USB data available? { char ch = (char) SerialUSB.read(); // Read the USB data Serial5.print(ch); // Copy the data to Serial5 } ReceiveSerial5Data(); } |
The above example uses a buffers 100 bytes in size. If a larger amount of data is expected a ring buffer, with start and stop positions, that is large enough to hold the received data should be used instead.
The last example shows how to receive data with the help of an Interrupt Service Routine (ISR). Please note the name of the ISR SERCOM#_Handler() where # is the SERCOM number and the IRQ handler Serial#IrqHandler() where the # is the Serial number. For SERCOM5 and Serial5 they are the same but all the others are different! Please see the SERCOM table at the top of this page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
// RFzero include and object creation #include <RFzero.h> // MUST ALWAYS be included for RFzero // Serial5 receiver ISR handler void SERCOM5_Handler() { Serial5.IrqHandler(); // IRQ handler number is the same as Serial# ! ! ! static char serialBuffer[100] = "\0"; // Initialize the buffer static int serialBufferCount = 0; // Empty buffer to first character is the 0 terminator bool resetBuffer = false; while (Serial5.available()) // Is there any Serial5 data available? { char ch = (char) Serial5.read(); // Read the Serial5 data // Check if buffer can overflow if (serialBufferCount < sizeof(serialBuffer) - 1) { // No overflow serialBuffer[serialBufferCount] = ch; // Add the new character to the end of the buffer serialBufferCount++; serialBuffer[serialBufferCount] = 0; // Set 0 terminating character } else resetBuffer = true; // Buffer overflow to reset buffer if (ch == '!') // Check if the character is a line feed { SerialUSB.print(serialBuffer); // Copy the data to Serial5 resetBuffer = true; // Buffer overflow to reset buffer } if (resetBuffer) { serialBuffer[0] = 0; serialBufferCount = 0; } } } void setup() { // Initialize USB SerialUSB.begin(9600); // Set the serial USB port to 9600 Baud and 8N1 (default) while (!SerialUSB); // Wait for the USB port to be ready // Initialize Serial1 Serial5.begin(9600); // Set the Serial5 port to 9600 Baud and 8N1 (default) } void loop() { if (SerialUSB.available()) // Is there any USB data available? { char ch = (char) SerialUSB.read(); // Read the USB data Serial5.print(ch); // Copy the data to Serial5 } } |
Receiving USB data via an ISR is a complex task. Please see the USB generic example page how to do this in a different way using the Arduino standard function called yield().
Serial signal | RFzero pin | RFzero MCU pin | Arduino Zero/M0 pins |
---|---|---|---|
TX | A4 | PA6 | A4 |
RX | A5 | PA7 | A5 |
Don’t use serialEventRun()
You may see the use of the serialEventRun() function is many Arduino examples. However, we can’t recommend using it because it is part of loop() and thus may not get attention in slow loops and functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
void serialEventRun(void) { if (SerialUSB.available()) SerialUSBEvent(); if (SerialGPS.available()) SerialGPSEvent(); ... } void SerialUSBEvent() { char chUSB = SerialUSB.read(); ... } void SerialGPSEvent() { char chGPS = SerialGPS.read(); ... } |
Instead use one of the other ways described. Then you are in control.