Software Serial on Giga

Hello,
I want to talk to a Sensor over a RS422 interface and it works with the hardware serial ports. However, since I'm using a GIGA, I would like to have the M4 core reading the sensor and the M7 handeling other stuff (saving to sd, communication via ethernet/wifi etc.). From what I read the M4 is not able do commuincate with the hardware serial port I wanted to make use of the software serial. But apperently the standard softwareserial.h is not available for this board.. Does anyone know another possibility?

#include <SoftwareSerial.h>

#define rxPin 6
#define txPin 8
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

void setup()  {
    // Define pin modes for TX and RX
    pinMode(rxPin, INPUT);
    pinMode(txPin, OUTPUT);
    
    // Set the baud rate for the SoftwareSerial object
    mySerial.begin(9600);
}

void loop() {
    if (mySerial.available() > 0) {
        mySerial.read();
    }
}

I'm not a Giga user; I only know that it exists.

It can indirectly as far as I understand it. Have you tried the RPC Serial example.

And in some way you should be able to use the UART in the M4 core as it's in the list of supported periperals: https://docs.arduino.cc/tutorials/giga-r1-wifi/giga-dual-core/#m4-support. But there is possibly no library for that.

Hi @henatu . The M7 is very powerful. Unless you have a really, really strong need to use the M4 I'd just use the M7.

You are right, it is working. I let myself mislead from a different thread that I found here:

My solution:

An Arduino Mega (with Voltage regulator) (Rx0 and Tx0) is sending something to the serial1 interface of the GIGA (Rx0 and Tx0). The connection is like this: Mega Rx0 -> Giga Tx0; Mega Tx0 -> Giga Rx0.

Code of the mega:

void setup() {
  Serial.begin(19200);
}

void loop() {
  Serial.print("Hello World!");
  Serial.println(random());
  delay(500);
}

For the M7 Core, the code is:

#include "RPC.h"

//M7 sketch

void setup() {
  
  // Start Serial (USB) to communicate with the PC
  Serial.begin(19200);
    while (!Serial) {
    ; // Wait for USB connection
  }
  Serial.println("M7 of Giga: Ready to forward M4 data.");
  RPC.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
  if (RPC.available()) {
    char incomingByte = RPC.read();  // Read byte from RPC
    Serial.write(incomingByte);  // Forward the byte to Serial (USB)
  }
}

And for the M4 core the code is:

#include "RPC.h"

//M4 sketch

void setup() {
  RPC.begin();
  Serial1.begin(19200);
  while (!Serial1) {
    ; // Wait for Serial connection
  }
  RPC.println("M4 of Giga: Ready to forward Serial1 data.");
}

void loop() {
    if (Serial1.available()) {
    char incomingByte = Serial1.read();  // Read byte from Serial1
    RPC.write(incomingByte);  // Forward the byte to RPC
  }
}

So, as the documentation is saying: the uart is working (at least for me for serial1).

Thank you, but the problem is with the timing. While doing the ethernet/wifi connection and saving/loading to an SD card the sensor reading would be halted. In order to have no interrupt in the measurement cycle, the M4 would be able to continue communicating with the sensor and the M7 is reading it when it is not busy doing the other stuff.

Regarding the software serial: I still would like to use it on the giga, since I would like to address as many sensors as possible over UART... If anyone knows a solution or help it is very welcome!

You might get disappointed when using SoftwareSerial for that. The normal SoftwareSerial implementations don't allow you to simultaneously receive data. So multiple sensors that simply pump data can't be used, only those that deliver on request.

There are a few possible solutions.

  1. You can use I2C/SPI UARTs; I do not know if they exist as breakout-boards so you might have to design yourself or use other microcontroller boards to act like that.
  2. Use multiplexers; this might work if the sensors deliver data on request.

You will have to write a SoftwareSerial yourself :wink:

Thank you, I will look into multiplexers. The sensor don't need to be accessed simultaniously. Just sending a command every few seconds to each of them and recieving the response would be sufficient.

I will also look into writing the software serial function, we will see how this turns out...

Other solutions: Use a Teensy 4.x :wink:
Teensy 4.1 has 8 UARTS, plus we can generate several more using FlexIO
And for some other pins we can use SoftwareSerial if necessary.

The reason I mention this, is because Paul of PJRC has recently updated his implementation for SoftwareSerial for Teensy boards to be able to do bitbang support on other pins.
I believe the implementation is setup to be able to sort of do Recv in background.
In particular I believe it sets an interrupt on the RX pin to trigger on the start bit, at which point it probably stays in the interrupt until all the bits are received, which is not great, but...

The code is semi-specific to the Teensy, but is up at:
PaulStoffregen/SoftwareSerial: SoftwareSerial library used on Teensy (github.com)

Again a lot of it is specific to the Teensy, but I am not sure how much. For example, here is the begin method.

void SoftwareSerial::begin(unsigned long speed)
{
	if (port) {
		port->begin(speed);
	} else {
		rx_head = 0;
		rx_tail = 0;
		cycles_per_bit = (uint32_t)(F_CPU + speed / 2) / speed;
		microseconds_per_bit = (float)cycles_per_bit / (float)(F_CPU / 1000000);
		// TODO: latency estimate could be better tuned to each board
		const float latency = 900.0f / (float)(F_CPU / 1000000);
		microseconds_start = microseconds_per_bit * 1.5f - latency;
		ARM_DEMCR |= ARM_DEMCR_TRCENA;
		ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
		pinMode(txpin, OUTPUT);
		digitalWrite(txpin, HIGH);
		pinMode(rxpin, INPUT_PULLUP);
		delayMicroseconds(5); // allow time for pullup -> logic high
		attachInterrupt(digitalPinToInterrupt(rxpin), start_bit_falling_edge, FALLING);
		active_object = this;
		//Serial.printf("begin bitbang, rxpin=%u, txpin=%u\n", rxpin, txpin);
	}
}

It is using the ARM instruction counter for timing, which works on the Teensy boards which
some are M0(LC) some are M3/4(T3.x) and some are M7(T4.x). Does this work on the GIGA processor? I don't know. I have not tried it on my GIGA.

But hopefully you can find some useful stuff in this implementation.

Good luck

I was going to pitch a Teensy, but I thought I'd wait for the master :wink:

Quick FYI - I have been playing around with porting parts of the Teensy version of the SoftwareSerial that Paul did for the Teensy boards. For now I stripped out some of the functionality, like if your RX and TX pins align with actual hardware RX and TX pins on the teensy it would convert to simply be a forwarder to HardwareSerial...

For the TX side, I use the ARM Cycle count for timing.

On the RX side, unlike software Serial on AVR boards which does it by polling, this code (like the teensy board) does it using interrupts. It uses the Pin change interrupt (attachInterrupt) on falling edge to detect the start of a new byte. It turns that interrupt off and starts up a timer interrupt, the timer interrupt changes the interval between the first tick and the subsequent ones, in order to adjust the sampling to be near the center of each bits pulse. More if anyone is interested.

I have mostly played with it on the M7 (main core), yesterday I did some testing and changes to code to allow it to be run on the M4. It needs a lot more testing and tuning, which may or may not happen.

If anyone is interested, I pushed it up to my github project:
KurtE/Arduino_GIGA-stuff: This is my GIGA test sketches and other like stuff for Arduino GIGA boards (github.com)