RS-485 on Serial1 with SAMD51

Writing a test code for Modbus over RS-485 on an Itsybitsy M4 Express board. I am using the serial monitor to send Modbus read/write commands to the Itsy which will send the commands through the RS-485 interface. The Modbus code is based around the Modbus Master Slave for Arduino/examples/advanced_master. What I have not been able to find is where the Tx/Rx/Te pins are defined. I need to use PA17/PA16/PA19, the SERCOM1 pins (Arduino pins 0,1 and 9).
I presume Serial1 is the hardware serial port but it is not defined for the Itsy board.
The ModbusRTU.h file has -
#if defined(UBRR1H)
case 1:
port = &Serial1;

However, I cannot find where UBRR1H is defined either.
Any help appreciated.

That is a hardware UART register on AVR processors and is irrelevant to the M4. Check which processors that library supports.

If a hardware serial port is available, Adafruit predefines Serial1 for their boards. To check, compile and run this program with the correct board selected.


void setup() {
Serial.begin(115200);
while(!Serial) delay(1); //wait for connection
if (Serial1.begin(115200))  Serial.println("Serial1 defined");
}
void loop(){}.

But no need, as the existence of Serial1 is clearly stated and the pins are identified in the Getting Started guide.

Thanks, I was just looking at the stuff in the download page. I still need to define the Te pin as PA19 or is that already defined somewhere?
I am used to writing directly into the registers, not using predefined functions.
Any place I should look for what hardware is being used in the functions?
Eventially this program will be doing data acquisition and I can see arduino functions might be stepping on my program if I use the wrong hardware.

No. 'PA19' is again an AVR construct. SAMD51 is Arm-based.

Please post links to the Modbus library and RS485 adapter you plan to use.

Why did you choose the SAMD51?

The test Modbus code is from the Modbus-Master-Slave-for-Arduino/examples/advanced_master directory.
The RS-485 adapter for testing is one of the generic MAX485 based from China.
The PA16/17/19 pin names are from the Atmel data sheet for the SAMD5X uC.
I am using the SAMD51 because I need the speed and 32 bit processing. The ADC is a TI ADS127L01 24 bit running at 500Kb conversion.
The Itsy will be piggybacked on a motherboard that will have the amplifiers, ADC and WIN1500 WiFi. The RS-485 will be a SN75HVD3082E.
The VFD motor drive is an Invertec Optidrive which has an RS-485 interface as well as CAN and Fieldbuss.

It's much better to give a GitHub link than a bunch of words. Is it This One?

Hi @magno_grail

Here's a link to code that enables the Serial1 on the Adafruit Feather M4 on SERCOM5 with Te on D10:

The port pin-out for the Itsy Bitsy M4 is different from the Feather M4 with Serial1 allocated to SERCOM3. Tx and Rx remain on digital pins D1 and D0 respectively. The RS-485 Te output however is on D10 (PA20) (SERCOM3 pad 2). This means the code for the Itsy Bitsy M4 needs to be changed as follows:

// Convert Serial1 for RS485 operation on the Itsy Bitsy M4
void setup() {
  Serial1.begin(115200);                        // Initialise Serial1 (on SERCOM3)
  while (!Serial1);                             // Wait for the console to open
  SERCOM3->USART.CTRLA.bit.ENABLE = 0x0;        // Disable SERCOM3
  while (SERCOM3->USART.SYNCBUSY.bit.ENABLE);   // Wait for synchronization
  PORT->Group[g_APinDescription[10].ulPort].PINCFG[g_APinDescription[10].ulPin].bit.PMUXEN = 1;   // Enable the TE output on D10
  PORT->Group[g_APinDescription[10].ulPort].PMUX[g_APinDescription[10].ulPin >> 1].reg |= PORT_PMUX_PMUXE(3);
  SERCOM3->USART.CTRLA.bit.TXPO = 0x3;          // Set TXPO to 3 to activate the TE output
  SERCOM3->USART.CTRLC.bit.GTIME = 0x2;         // Set the RS485 guard time
  SERCOM3->USART.CTRLA.bit.ENABLE = 0x1;        // Enable SERCOM3
  while (SERCOM3->USART.SYNCBUSY.bit.ENABLE);   // Wait for synchronization
}

void loop() {
  Serial1.println("Test");                      // Send test message
  delay(1000);                                  // Wait for 1 second
}

The only difference from the Feather M4 code is that SERCOM5 has been changed to SERCOM3 and the port pin multiplexer (PMUX) switch has been set to PORT_PMUX_PMUXE(3). PMUX 'E' because PA '20' is an even number, and 3 being the port pin multiplex switch position for SERCOM3 pad 2.

Thanks Martin. I am not sure why the Te pin has to be on SERCOM3. The data sheet says all SERCOMs support RS485 and the Itsy is already using SERCOM1 for Tx and Rx then I should be able to use SERCOM1 pad2 for Te, yes? Page 854 of the data sheet.
SERCOM3 pad2 (pin33) is being used by the USB data on the Itsy board.
Is this:

PORT->Group[g_APinDescription[10].ulPort].PINCFG[g_APinDescription[10].ulPin].bit.PMUXEN = 1;

arduino code?
SERCOM5 on the Feather M4 has the Tx/Tx pins and SERCOM3 is the USB
SERCOM1 on the Itsy M4 has the Tx/Rx pins and SERCOM3 is the USB

Hi @magno_grail

The SAMD51's SERCOM (Serial Communication) peripherals are modules that can be configured for either Serial (USART), SPI or I2C operation. The microcontroller's native USB is a separate module detailed in section 38 of the MCU's datasheet and not associated with SERCOM peripherals in any way.

During intialisation, Adafruit's Itsy Bitsy M4 core code assigns the various SERCOM modules as follows:

SERCOM1 - SPI
SERCOM2 - I2C
SERCOM3 - Serial1

These are configured in the board's "variant.h" and "variant.cpp" files located on my Windows machine in the following directory:

C:\Users\Computer\AppData\Local\Arduino15\packages\adafruit\hardware\samd\1.7.16\variants\itsybitsy_m4

The remaining three SERCOM modules (0, 4 and 5) are free to use as you wish and can be configured as additional Serial, SPI or I2C ports.

At the bottom of the "variant.cpp" file Serial1 is assigned to SERCOM3:

Uart Serial1( &sercom3, PIN_SERIAL1_RX, PIN_SERIAL1_TX, PAD_SERIAL1_RX, PAD_SERIAL1_TX ) ;

By default this provides the standard Serial1 transmit and receive functionality on digital pins D1 and D0. However, to enable the hardware RS-485 transmit enable (Te) pin on SERCOM3's pad 2, it's necessary to configure the pin that's been assigned this pad, in this case it happens to be D10, as well as additionally setting TXPO bitfield in the SERCOM's CTRLA register.

If you run the example code provided (perhaps commenting out the while (!Serial1); line), the Te line on D10 automatically goes high every time the serial port transmits.

Hi Martin, Thanks. This is a bit confusing as Arduino redefines pins with their own names.
The schematic for the Itsy M4 shows the Tx/Rx pins (Arduino D0/D1) are on SERCOM1 and the USB is on SERCOM3.
When sending/receiving using the Serial Monitor, it is done by calling Serial, not Serial1. The SERIAL_PORT_MONITOR is defined as Serial at the end of the varinant.h file. Since the only connection to the PC is through the USB, I presumed Serial is connected to the native USB, not a SERCOM.
Is Arduino SERCOM3 not the same as SERCOM3 in the SAMD51 data sheet?
I had to dig in the dungeon to find the variant files.
Some defines make sense, PIN_LED_13 13u. On the schematic the LED D13 connects to PA22. But PIN_DOTSTAR_DATA 8u which connects to PB03 has no D8 associated with it.
It appears this might be easier to do in Microchip Studio where everything is defined in the data sheet.

No. The board's USB connector is wired to pins that could be used for SERCOM3 but are not. Those pins are internally connected to the processor's native USB port instead. You are failing to understand that on complex processor chips like SAMD51 there are far more available internal functions than there are available external pins. So, pins are multiplexed to serve multiple purposes ... BUT only one at a time.

Serial is an Arduino concept that allows common code across all members boards of the Arduino ecosystem to communicate with what you see as the Serial Monitor in the IDE. In the case of M4 Itsy, Serial is an instance of the Serial_ class. This class inherits from Stream (which in turn inherits from Print) and handles one instance (of potentially multiple) of the processor's native USB port(s).

On simpler Arduino's, Serial connects to an actual hardware UART that itself connects to an external UART <--> USB converter so you can plug it into your PC.

Hi @magno_grail

On the Arduino Uno, D0 and D1 and the USB share Serial. However, as @gfvalvo mentions, many modern microcontrollers contain their own native USB communications module that's separate from the UART serial ports.

On the Itsy Bitsy M4, "Serial" is the native USB port, while "Serial1" is independent and located on digital pins D1 and D0. If you have a +3.3V USB-to-Serial (FTDI) board, you could connect its Rx and Tx pins to D1 and D0 respectively and plug its USB into your computer to monitor Serial1 on the Arduino IDE's console, (with the board's native USB still attached to provide power).

The schematic is a good way of mapping between the Arduino pins and the microcontroller's port pin numbers. Adafruit also offer a handy pin-out diagram located here:

https://learn.adafruit.com/assets/130241

Regarding Serial1's SERCOM, if you look at the pin-out diagram you'll see that most of the pins offer the possibility of assignment to one of two SERCOM options with digital pins D0 and D1 offering either SERCOM1 and SERCOM3. This is also detailed in the multiplexing table in section 6 of the SAMD51's datasheet. Each pin is either GPIO or is connected to a peripheral determined by the position of the multiplex switch with positions: A to I (or 1 to 9).

Hi
you are probably better off using that library:
Modbus Master
With that library, you can use any Serial method and are not tied to fixed pins.

Yes, I realize the pins can be mapped to different functions. What I missed was in the light coloured annotation of the adafruit schematic also had that PA24/25 was the USB function.
Martin, you mention that SERCOM3 Pad 2 is mapped to D10 (PA20) but it is also mapped to D7 (PA18). Is there any reason to use one over the other?
I have to go through the multiplexer in the datasheet.
RIN - page not found. I have simple_master, PetitModbus-master and freemodbus-v1.5.0 also for reference. Thanks.

@magno_grail Yes you're right, you could use D7 as well. There's no reason to use one over the other.

Switching to D7 just requires modifying the pin configuration code:

PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1;   // Enable the TE output on D7
PORT->Group[g_APinDescription[7].ulPort].PMUX[g_APinDescription[7].ulPin >> 1].reg |= PORT_PMUX_PMUXE(3);