Implementation of Serial.write()/w FreeRTOS Industruino (SAMD21G ARM Cortex-M0)

Hi All. I have an industrial robot which has a control system based on FreeRTOS. One task has the duty of talking Modbus RTU over one of the USARTs to an IO expander at a rather slow rate of 57600.. the problem is the way the board code handles writes to the USART.

SERCOM.cpp from https://github.com/Industruino/IndustruinoSAMD/blob/master/cores/industruino/SERCOM.cpp

int SERCOM::writeDataUART(uint8_t data)
{
  // Wait for data register to be empty
  while(!isDataRegisterEmptyUART());

  //Put data into DATA register
  sercom->USART.DATA.reg = (uint16_t)data;
  return 1;
}

This effectively blocks the transmitting task until the TX is complete, Makes no use of the SAMD21G's 16 byte FIFO buffer or the stream buffer for Serial.write() (at least I think it does). I end up having to wrap all my Serial.write() in a vTaskSuspendScheduler() to ensure the timing doesn't get screwed up. This wastes a massive load of processor cycles I could be using for other tasks. I don't like having some of the more critical threads blocking for sometimes more than 50ms.

Ideally I'd like to make use of the FIFO buffer offered in hardware, use an ISR to handle filling the hardware FIFO from a larger software one, meaning I don't need to wrap my modbus writes with a scheduler disable, as the ISR can easily keep the timing good on a 48MHz RISC core.

IIRC Serial.write() is supposed to be non-blocking?... What do you think? some of this core hardware level stuff is a bit beyond me. It strikes me that I could copy/paste some code from the Arduino Due implementation since the hardware is very similar?. I've had a look at the Due UART code and it looks quite different.

I don’t think that there is any “hardware fifo” on the samd21…

Yep there is, Page 480 in the datasheet

Huh. Interesting. There it is, even in my slightly older datasheet. I guess I was looking at the SAMC21 datasheet, assuming that the SERCOMs would all be the same (I should know better. There are other ways that SERCOMs differ between chips.) SAMC21 doesn't seem to have a FIFO. Nor does the (newer) SAMD51.

There is some doubt whether the SAMD21 FIFO actually exists as well. The "CTRLC" register used to control most of the FIFO functions (according to the "functional description" part of the datasheet) is not defined in the "registers summary" or "register description" area, nor is it defined in sercom.h or the .atdf file. No mention of "fifo" at all!

See also: https://community.atmel.com/forum/what-happended-ctrlc-register-sercom-module-samd21 (which didn't actually come up with a definitive answer, alas.)

The Arduino SAMD core has TX and RX buffers in the Uart class (which then calls SERCOM::writeDataUART()). The Industruino SAMD core was forked from the Arduio core just before the TX buffer was added. RX buffer was already there earlier.

Yeah, Industruino code hasn't been updated in 2 years. Unfortunately I'm stuck with it. Whole project was set out by the engineer before me, and has had massive scope creep since then. If it was just me I would have gone with a mainstream (and hence, supported) board like the Due.

Theres still a Festo PLC in that system I can use, but dear lord.. programming that thing is so, frustrating.

so I need to fix the behind the scenes code, which will include (I think) -Implement use of hardware FIFO -Implement software FIFO -Write ISR to handle serial events

so not being familiar with Arduino "behind the scenes" where is the correct place to implement each step?

where is the correct place to implement each step?

Most "board" packages implement small changes in the pin definition code, and leave the "core" firmware alone. You can check the history of "industuino" here: https://github.com/Industruino/IndustruinoSAMD/commits/master/cores/industruino and see that it didn't take many changes. (Unfortunately, it's difficult for a 3rd party board to say "use these files from me, and get the rest from the standard location.) That means that I'd start by checking whether you can replace the current sercom.cpp with a more modern one from https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/SERCOM.cpp (actually, it probably makes sense to try to replace the entire core.) I'm not sure how this plays with FreeRTOS; I would think that it would use entirely different sercom drivers...

Hi all I think we have a solution here.. somebody has written a vastly more up to date board file.

https://github.com/Industruino/IndustruinoSAMx

For some reason they haven't updated the board file for the Arduino IDE to use the newer code. New code has everything I need, TX and RX buffers, IRQ driven IO. Even uses the hardware FIFO.

This has certainly made my day :D

Has anyone confirmed how to use the sercom TX and RX FIFO on the samd21? I can see that the datasheet documents the FIFO registers. However, the critically important CTRLC register appears to be missing. Is there an undocumented register somewhere?