Software Serial library for MKR1000

Hi all,

Love the MKR1000 so far. I'm finding it quite a nice little board.

The roadblock I hit with my project was that the MKR1000 only has one serial port. As there was no official software serial library yet, I started to modify the NewSoftSerial library for the MKR1000. So far I have successfully been able to receive serial data up to 57600 baud, however the TX side does not seem to work. I feel like it's something simple I'm overlooking for the TX, so suggestions would be welcome.

Hopefully this helps someone until a more official library is worked out.

https://github.com/guywithaview/MKRSoftSerial

Cheers

Did you get any further ?

There isn't a software serial library, but fortunately you can configure the SAMD21's spare serial communciation (SERCOM) modules to obtain multiple hardware serial ports. The SAMD21 has 6 (0..5) flexible SERCOM modules that can be configured either as an I2C, SPI or Serial port. Looking at the MKR1000's "variant.cpp" file it looks as though 3 are currently in use, that's:

Sercom 0 - I2C
Sercom 1 - SPI
Sercom 5 - Serial1

That leaves Sercom 2, 3 and 4 that are free to be configured how you wish.

Here's an Adafruit article, (it's for their Adafruit Feather M0, but it uses the same SAMD21G18A processor): Creating a new Serial | Using ATSAMD21 SERCOM for more SPI, I2C and Serial ports | Adafruit Learning System

The article also tells you how to configure the SERCOM modules to add additional I2C and SPI ports.

The code to set-up MKR1000's Serial2 (using SERCOM3) on digital pins 0 (TX) and 1 (RX) should go something like this:

#include <Arduino.h>                              // required before wiring_private.h
#include <wiring_private.h>

// Serial2 pin and pad definitions (in Arduino files Variant.h & Variant.cpp)
#define PIN_SERIAL2_RX       (1ul)                // Pin description number for PIO_SERCOM on D1
#define PIN_SERIAL2_TX       (0ul)                // Pin description number for PIO_SERCOM on D0
#define PAD_SERIAL2_TX       (UART_TX_PAD_0)      // SERCOM pad 0 TX
#define PAD_SERIAL2_RX       (SERCOM_RX_PAD_1)    // SERCOM pad 1 RX

// Instantiate the Serial2 class
Uart Serial2(&sercom3, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);

void setup()
{
  Serial2.begin(115200);          // Begin Serial2 
  pinPeripheral(0, PIO_SERCOM);   // Assign pins 0 & 1 SERCOM functionality
  pinPeripheral(1, PIO_SERCOM);
}

void loop()
{
  if (Serial2.available())        // Check if incoming data is available
  {
    byte byteRead = Serial2.read();    // Read the most recent byte
    Serial2.write(byteRead);           // Echo the byte back out on the serial port
  }
}

void SERCOM3_Handler()    // Interrupt handler for SERCOM3
{
  Serial2.IrqHandler();
}

According to Adafruit you need to include "Arduino.h". I got the code to compile without it, so it's probably unnecessary, but as I don't own a MKR1000 can't confirm whether this include can be omitted.

Awesome, thanks! Far better than using software serial. I will try this out soon.

Tested and working! Thanks MartinL!

I created a test sketch with two extra serial ports if anyone needs to get started. This gives Serial (USB), Serial 1, Serial 2 and Serial 3.

Pretty cool that the MKR1000 can do this.

Awesome, will try!

Hello,
You can check also this tutorial we've created:

tkuehn:
Awesome, thanks! Far better than using software serial. I will try this out soon.

I would like to know why you got multiple Tx and Rx defined?

Hi abdallaziz92,

The definitions are for both the TX and RX pads and pins.

The SERCOM peripheral IO is generated on 4 internal pads. These pads can then be connected to physical pins of the device, by setting the TXPO (Transmit Data Pinout) and RXPO (Receive Data Pinout) bitfields in the SERCOM's CTRLA (Control A) register.

The defines just determine what pad is connected to what pin.

Hi,

I need a second hardware port on my MKRW1010 board, I have been looking at the various examples here but can't get them to work on this board. I've looked at the variant.cpp files and the MKR1000 and MKRW1010 seem the same as far as SERCOM3 is concerned.

Am I missing something?

Anyone got a second port running on a MKR W1010?

This is the code I'm suing from the tutorial, the only issue I could see is that the pins seem transposed here:

Uart mySerial (&sercom3, 0, 1, SERCOM_RX_PAD_1, UART_TX_PAD_0); // Create the new UART

I think it should be:

Uart mySerial (&sercom3, 1, 0, SERCOM_RX_PAD_1, UART_TX_PAD_0); // Create the new UART

But neither works, here's the full test code.

#include <Arduino.h>
#include "wiring_private.h"

Uart mySerial (&sercom3, 0, 1, SERCOM_RX_PAD_1, UART_TX_PAD_0); // Create the new UART instance assigning it to pin 0 and 1

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(115200);
  mySerial.begin(38400);

  pinMode(1,INPUT_PULLUP);
  pinMode(0,OUTPUT);

  pinPeripheral(0, PIO_SERCOM); //Assign RX function to pin 0
  pinPeripheral(1, PIO_SERCOM); //Assign TX function to pin 1

}

// the loop routine runs over and over again forever:
void loop() 
{
  // read the input on analog pin 0:

  mySerial.println("Hello From Serial 3");
  Serial.println("Hello From Serial");
  while (mySerial.available()) {
    Serial.print(mySerial.read());
  }
  delay(500);        // delay in between reads for stability
}

// Attach the interrupt handler to the SERCOM
void SERCOM3_Handler()
{
  mySerial.IrqHandler();
}

Update:

I have the sample code working on a MKR1000, so it has to be a difference between the two boards but can't see what that is yet..

Update2:

I now have this code working on the MKR-W1010 board. However, I need to move the TX pin from D0, so far I have had no luck using any alternative pins or a different SERCOM.

Hello,

Were you able to make it work. You said that you had to change the TX pin to 0, would you mind sharing the final code if you still have it. I will appreciate it very much.

Have a great day,

Santiago

Hi Santiago,

It should be possible to set up a second serial port on pins 0 (Tx) and 1 (Rx), on either the MKR1000 or MKR1010 with the following code:

#include <Arduino.h>                              // required before wiring_private.h
#include <wiring_private.h>

// Instantiate the Serial3 class
Uart Serial3(&sercom3, 1, 0, SERCOM_RX_PAD_1, UART_TX_PAD_0);

void setup()
{
  Serial3.begin(115200);          // Begin Serial3
  pinPeripheral(0, PIO_SERCOM);   // Assign pins 0 & 1 SERCOM functionality
  pinPeripheral(1, PIO_SERCOM);
}

void loop()
{
  if (Serial3.available())        // Check if incoming data is available
  {
    byte byteRead = Serial3.read();    // Read the most recent byte
    Serial3.write(byteRead);           // Echo the byte back out on the serial port
  }
}

void SERCOM3_Handler()    // Interrupt handler for SERCOM3
{
  Serial3.IrqHandler();
}

Thank you Martin. I will try this out.

I have a question, byte byteRead = Serial3.read(); will read the bytes coming from the serial port, what is Serial3.write(byteRead) for? Can you explain this to me in dummy language.

I appreciate your help,

have a good day,

Santiago