Go Down

Topic: Arduino Zero - SoftwareSerial library (Read 15151 times) previous topic - next topic

rob_regent

I need to use the softwareSerial library, and isn't available for the arduino zero. Does anyone know of an alternative that is compatible with the Zero?

ogradyg

I'm looking for the same.

Any solution or suggestions?

david_prentice

Why do you want a Software UART ?

Not only are there  6 SERCOM channels,   you can re-arrange quite a few of the hardware pins.

Explain what you want to do.   It is easy to bit-bash an Serial TX.    Doing RX in software is fiddly.

David.

MartinL

#3
Oct 19, 2015, 06:07 pm Last Edit: Oct 19, 2015, 06:16 pm by MartinL
There are 6 Serial Communication (Sercom) channels on the SAMD21, each capable of operating as either a USART, I2C or SPI port.

Serial1 (on Sercom0) is obviously on digital pins 0 (Rx) and 1 (Tx).

Sercom 1 and 2 used to be free, but I believe that the Zero's latest "variant.cpp" file has now been modified to allow Serial2 and 3 to be used. So you should just be able to call on Serial2.begin() or Serial3.begin() in your sketch.

Serial2 (on Sercom1) should be on digital pins 12 (Rx) and 10 (Tx).

Serial3 (on Sercom2) should be on digital pins 5 (Rx) and 2 (Tx) on the Zero, or 5 (Rx) and 4 (Tx) on the M0 Pro.

If "variant.cpp" file hasn't been modified, the thread here shows you how to get the extra serial ports working.

Sercom 3 and 4 are reserved for Arduino's I2C Wire and SPI libraries. Sercom5 is reserved for serial communication with the EDBG debugging chip.


royce

As I look at variants.cpp on github, (today) I only see Serial1 and Serial declared. Is that the right place or the only place to look?

MartinL

#5
Oct 20, 2015, 10:11 am Last Edit: Oct 20, 2015, 10:15 am by MartinL
Yes, "variant.cpp"/"variant.h" are the places to look.

If it's not there, it's possible to get Serial2 working on D12 (Rx) and D10 (Tx) without modification to the "variant" files, using the following code in your Arduino sketch. This code example simply echos back characters sent from the Arduino IDE console:

Code: [Select]
// Serial2 pin and pad definitions (in Arduino files Variant.h & Variant.cpp)
#define PIN_SERIAL2_RX       (34ul)               // Pin description number for PIO_SERCOM on D12
#define PIN_SERIAL2_TX       (36ul)               // Pin description number for PIO_SERCOM on D10
#define PAD_SERIAL2_TX       (UART_TX_PAD_2)      // SERCOM pad 2
#define PAD_SERIAL2_RX       (SERCOM_RX_PAD_3)    // SERCOM pad 3

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

void setup()
{
  Serial2.begin(115200);          // Begin Serial2
}

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 SERCOM1_Handler()    // Interrupt handler for SERCOM1
{
  Serial2.IrqHandler();
}

Implementing Serial3 however, requires a modification to the "variant.cpp" file. Just dd the two following lines to the end of the "g_APinDescription" array in the file ..Computer\AppData\Roaming\Arduino15\packages\arduino\hardware\samd\1.6.1\variants\arduino_zero\variant.cpp:

Code: [Select]
// 44..45 - SERCOM2
  { PORTA, 14, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SERCOM2/PAD[2]
  { PORTA, 15, PIO_SERCOM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // SERCOM2/PAD[3]

Then to get Serial3 working on D5 (Rx) and D2 (Tx) on the Zero (or D5 (Rx) and D4 (Tx) on the M0 Pro), use the following code:

Code: [Select]
// Serial3 pin and pad definitions (in Arduino files Variant.h & modified Variant.cpp)
#define PIN_SERIAL3_RX       (45ul)               // Pin description number for PIO_SERCOM on D5
#define PIN_SERIAL3_TX       (44ul)               // Pin description number for PIO_SERCOM on D2
#define PAD_SERIAL3_TX       (UART_TX_PAD_2)      // SERCOM pad 2
#define PAD_SERIAL3_RX       (SERCOM_RX_PAD_3)    // SERCOM pad 3

// Instantiate the Serial3 class
Uart Serial3(&sercom2, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);

void setup()
{
  Serial3.begin(115200);          // Begin Serial3
}

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 SERCOM2_Handler()    // Interrupt handler for SERCOM2
{
  Serial3.IrqHandler();
}

Or alternatively, just replace your "variant.cpp" and "variant.h" files (in the directory specified above) with these modified ones (attached). This allows you to call on Serial2 and Serial3 in your Arduino sketch directly without any additional code:


pjrc

A problem we've encountered with Teensy 3.x involves 3rd party libraries with dependency on SoftwareSerial.

No matter how many real hardware serial ports you have (Teensy has 3 available), you can't use *any* of them if your project depends on some library that requires a pointer or a C++ reference to an object of type "SoftwareSerial".

Ideally, libraries should use Stream pointers or references, so they could be used interchangeably with HardwareSerial, SoftwareSerial and EthernetClient or other non-serial data streams.  Some libraries do, but many do not.  Some libraries don't even provide a function or constructor to set the stream, so you have to edit the library code.  Some libraries have overloaded functions to take HardwareSerial or SoftwareSerial, but not any other Stream-based objects.  Some *only* work with SoftwareSerial and have no provision to use a real serial port!

A lesser problem involves libraries that could take a HardwareSerial or Stream inherited object, in their constructor or begin function or whatever way they're configured, but they only provide examples using SoftwareSerial.  Usually such code is only ever tested with Arduino Uno.  Even if it could work, the lack of any examples or documentation, with all apparent paths showing it only works with SoftwareSerial on Uno, is a real stumbling block for beginners.

For Teensy, a "solution" I implemented involves a dummy SoftwareSerial library.  It only works if you configure for two pins which are one of the real hardware serial ports.  Internally, it just calls the hardware serial functions.  That's a tiny amount of extra overhead, but of course far more efficient than bit bashing serial.  Because it's actually defined as the SoftwareSerial object, you can use software that has a hard-coded dependency on SoftwareSerial.  I've never tested it on any other boards, but if you grab the code, it'll probably work on Zero with only a little fiddling to change the pin numbers and hardware serial port names.

wyojustin

Thank you MartinL.  Your solution worked out first try for me.  I'm back up an running because you took the time to post this simple solution.

Justin

glovisol

Hi MartinL

Or alternatively, just replace your "variant.cpp" and "variant.h" files (in the directory specified above) with these modified ones (attached). This allows you to call on Serial2 and Serial3 in your Arduino sketch directly without any additional code:

Which directory? Please explain.

MartinL

#9
Mar 21, 2016, 09:36 am Last Edit: Mar 21, 2016, 09:37 am by MartinL
Hi glovisol,

The currently Arduino core code sets up the Zero to create two serial ports. Serial1 on digtial pins 0 and 1, as well as Serial that connects to the programming port (via the Atmel EDBG chip). However, it's possible to create additional hardware serial ports by configuring the spare serial communication or Sercom modules on the SAMD21. The Sercom modules are flexible in that they can be configured to be an I2C, SPI port or a USART.

The "variant.cpp" and "variant.h" files define the Zero's pin allocation and amongst other thinks sets up Serial1 and Serial. It's possible to edit these files to include the configuration for Serial2 and Serial3, thereby removing the configuration code from your sketch. In hindsight though, it's probably best to leave most of it in your sketch as the variant files are overwritten everytime you update the core to the latest version (1.6.4). Serial3 does require a small change appended to the pin definitions in "variant.cpp" though.

Variant.cpp can be currently found in the following directory (at least on my Windows machine): C:\Users\Computer\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.4\variants\arduino_zero\variant.cpp.

glovisol

Hi MartinL

Thank you for the detailed info. I take it you are using Windows XP. I have a very similar path on the XP machines, but up to now it has been impossible for me to find the variant files in Windows 7, but I will try again tomorrow. I forgot how to open up Documents & settings which is locked up, but will recall...

In XP it is (as always better):

C:\Documents and Settings\Administrator\Impostazioni Locali\Dati Applicazioni\Arduino 15\packages\arduino\hardware\samd\1.6.4\variants\arduino_zero\variant.cpp.

and

C:\Documents and Settings\Administrator\Impostazioni Locali\Dati Applicazioni\Arduino 15\packages\arduino\hardware\samd\1.6.4\variants\arduino_zero\variant.h

Kind regards,

glovisol

ChrisChris

So i tried the example from adafruit to output tx on 10 and rx on 11, this works fine, now when i try to switch to pins 6TX and 7RX with sercom3 enable, pad2 tx, pad3 for rx, i am not getting anything output from tx. not sure why not.

#include <Arduino.h>   // required before wiring_private.h
#include "wiring_private.h" // pinPeripheral() function

Uart Serial2 (&sercom3, 7, 6, SERCOM_RX_PAD_3, UART_TX_PAD_2);
void SERCOM3_Handler()
{
  Serial2.IrqHandler();
}

void setup() {
 

  Serial2.begin(115200);
   // Assign pins 10 & 11 SERCOM functionality
  pinPeripheral(6, PIO_SERCOM);
  pinPeripheral(7, PIO_SERCOM);
}

void loop() {
 
  Serial2.println
   ("going");
    delay(100);
}

MartinL

#12
Apr 27, 2016, 09:59 am Last Edit: Apr 27, 2016, 10:26 am by MartinL
Hi ChrisChris,

Try changing the PIO_SERCOM to PIO_SERCOM_ALT.

Sercom3 for these pins is on the alternative sercom peripherial channel.

ChrisChris

Excellent!!!! That Works, Hoping that it would i already have a printed board with those pins dedicated as uart, thank god I actually put them on the correct pad for tx and rx.

Urs_Effi

Hi MartinL
Thanks for your tipps.
I work with Arduino Zero and the Adafruit shield "Adafruit Ultimate GPS+Logging Shield".

https://learn.adafruit.com/adafruit-ultimate-gps-logger-shield/overview

Using RX:D12 and TX:D10 and setting th switch to "Soft Serial" works fine

// Serial2 pin and pad definitions (in Arduino files Variant.h & Variant.cpp)
#define PIN_SERIAL2_RX       (34ul)               // Pin description number for PIO_SERCOM on D12
#define PIN_SERIAL2_TX       (36ul)               // Pin description number for PIO_SERCOM on D10
#define PAD_SERIAL2_TX       (UART_TX_PAD_2)      // SERCOM pad 2
#define PAD_SERIAL2_RX       (SERCOM_RX_PAD_3)    // SERCOM pad 3

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

I strongly asume, setting the switch on this shield to "Soft Serial" will connect D7 from Arduino Zero directly to RX of the shield and D8 to TX. Unfortunately I didn't find a schematics to verify my assumption, but it looks like on the surface of the shield. Do you have a link to the schematics?

As consequence I would like to alter your approche to use D7 and D8, because otherwise D7 and D8 are no longer usable for the Arduino Zero due to possbple electrical shurtcuts.

I could not find out what (number ul) to use. Pleas give me a tipp.

Thank you

Best regards
  Urs





Go Up