Adding More SERCOM Ports for SAMD Boards
Adding a UART
1.) Figure Out Which Pins to Use.
Let's start by checking out the SERCOM.h file in Arduino's SAMD21 core files. Specifically, we are looking at lines 73-86. You should see the code listed below. But what does it mean? There are 2 parts, the first part defines which pads you can use for an RX pad. It looks like you can use pads 0
, 1
, 2
, and 3
which is all of them. Next, it defines which pads you can use for TX. It looks like you can only use pads 0
and 2
. So, we'll need to keep that in mind when we select our pins.
language:c
typedef enum
{
SERCOM_RX_PAD_0 = 0,
SERCOM_RX_PAD_1,
SERCOM_RX_PAD_2,
SERCOM_RX_PAD_3
} SercomRXPad;
typedef enum
{
UART_TX_PAD_0 = 0x0ul, // Only for UART
UART_TX_PAD_2 = 0x1ul, // Only for UART
UART_TX_RTS_CTS_PAD_0_2_3 = 0x2ul, // Only for UART with TX on PAD0, RTS on PAD2 and CTS on PAD3
} SercomUartTXPad;
Since none of the boards I've come across use SERCOM 2 for anything, we're going to use it for our examples. Let's start with TX since those pins are limited compared to the RX. We'll need to find which pins are on 2:0 or 2:2. Looking at our charts, you can see those pins are labeled as MISO, D4, D2, and D1/TX. Since MISO and D1/TX are already being used, that means we can use D2 or D4. Let's use D2 and see if we can put our new serial port right next to the original one. That means that RX should be on D3. It looks like D3 is on 2:1 so that will work.
2.) Add Your Code.
Next, lets figure out what code we need. Let's take a look at the variant.cpp file again. Near the bottom, you'll see the following lines. This is what we are trying to duplicate in our code. The variant.h file defines all those macros, but their names give us a good idea of what should go there.
language:c
Uart Serial1( &sercom0, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ;
Uart Serial( &sercom5, PIN_SERIAL_RX, PIN_SERIAL_TX, PAD_SERIAL_RX, PAD_SERIAL_TX ) ;
void SERCOM0_Handler()
{
Serial1.IrqHandler();
}
void SERCOM5_Handler()
{
Serial.IrqHandler();
}
Let's start with the definition. Let's pick a name. "mySerial
" sounds good. We also know we are going to use SERCOM 2, that RX will be on D3, TX on D2, and that D3 uses pad 1, and D2 uses pad 2. So we'll add the following to our code.
language:c
Uart mySerial(&sercom2, 3, 2, SERCOM_RX_PAD_1, UART_TX_PAD_2);
void SERCOM2_Handler()
{
mySerial.IrqHandler();
}
3.) Update the Pin Definitions Based on the Pin Mux.
Next, we need to set up the mux. Right now, D2 and D3 are defined as general I/O pins. We want them to act as SERCOM pins. The first thing we need to do is to add the pin peripheral library. Then we use the pinPeripheral
commands to set up the pin definition.
language:c
#include "wiring_private.h" // pinPeripheral() function
pinPeripheral(2, PIO_SERCOM);
pinPeripheral(3, PIO_SERCOM_ALT);
You'll notice that one uses the argument PIO_SERCOM
and the other PIO_SERCOM_ALT
. If you look on the datasheet, you'll notice that pins can have a SERCOM port listed under SERCOM or SERCOM-ALT. For D2, we are using the SERCOM port in the SERCOM column. For D3, we are using the SERCOM port in the SERCOM-ALT column.
4.) Putting It All Together.
Step 4 is running the code, testing, and troubleshooting. For this example, we are going to grab a serial LCD screen and connect it to our new serial UART port. Make sure that you have soldered headers to the LCD if you have not already.
The next step is to test out the UART port with the code listed below. The code is pretty bare bones and shows you where all your new code should go. Copy and paste the code in your Arduino IDE. Select your board, COM port, and hit upload.
language:c
/*********************************************************************
* Sample code for setting up additional Serial ports on a SamD21 board
* In this example the Redboard Turbo is used with the 16x2 SerLCD display
* For more information on the SerLCD code check out the github repo
* https://github.com/sparkfun/OpenLCD
* https://www.sparkfun.com/products/14812
* https://www.sparkfun.com/products/14072
* By: Michelle Shorter - SparkFun Electronics
* License: This code is public domain but you buy me a burger
* if you use this and we meet someday (Beefware license).
*********************************************************************/
#include "wiring_private.h" // pinPeripheral() function
//D2-TX, D3-RX
Uart mySerial (&sercom2, 3, 2, SERCOM_RX_PAD_1, UART_TX_PAD_2);
void SERCOM2_Handler()
{
mySerial.IrqHandler();
}
int i = 0;
void setup() {
// put your setup code here, to run once:
mySerial.begin(9600);
pinPeripheral(2, PIO_SERCOM);
pinPeripheral(3, PIO_SERCOM_ALT);
mySerial.write('|');//Setting character
mySerial.write('-');//Clear display
mySerial.write('|');//Put LCD into setting mode
mySerial.write(158 + 0); //Set green backlight amount to 0%
mySerial.write('|');//Put LCD into setting mode
mySerial.write(188 + 0); //Set blue backlight amount to 0%
mySerial.write('|');//Put LCD into setting mode
mySerial.write(128 + 29); //Set white/red backlight amount to 51% (100%=+29)
mySerial.print("Welcome");
delay(1000);
}
void loop() {
// put your main code here, to run repeatedly:
mySerial.write('|');//Setting character
mySerial.write('-');//Clear display
mySerial.print("Counting ");
mySerial.print(i);
i++;
delay(1000);
}