Skip to main content

UART

UART (Universal Asynchronous Receiver/Transmitter) is a serial data port that transfers data between two devices over two wires:

  • TXD (Transmit Data) — output on one side connects to RXD on the other.
  • RXD (Receive Data) — input on one side connects to TXD on the other.

"Asynchronous" means there's no shared clock line. Both sides agree on a fixed baud rate (bits per second) and a start bit at the beginning of each character keeps them aligned.

Some UART controllers also have RTS and CTS pins for hardware flow control — active only when Handshaking is set to RequestToSend.

tip

Cross the wires. TXD on one device goes to RXD on the other, and vice versa. Wiring TX-to-TX won't work.

tip

UART ports are sometimes called COM ports, especially on PCs.

Two APIs

TinyCLR offers two serial APIs that coexist on the same hardware. Both namespaces ship in a single NuGet package — install one and you have both.

  • System.IO.Ports API — the standard full-.NET SerialPort class. Use this for new code and for portability with desktop .NET applications.
  • TinyCLR API — the original GHIElectronics.TinyCLR.Devices.Uart namespace. Keeps v2 code working without changes, and exposes embedded-specific extensions like RS-485 Driver Enable, pin polarity inversion, and TX/RX swap.

NuGet packages:

  • GHIElectronics.TinyCLR.Devices.Uart — contains both the System.IO.Ports (full .NET) and GHIElectronics.TinyCLR.Devices.Uart (TinyCLR) namespaces.
  • GHIElectronics.TinyCLR.Pins — pin name constants for SITCore boards. The UART pin constants (SC20100.UartPort.Uart7, etc.) work as the port name when using System.IO.Ports.SerialPort.
note

Unlike GPIO, SPI, I²C, and PWM, UART isn't part of Microsoft's System.Device.* IoT APIs. The serial API in standard .NET lives in System.IO.Ports, which TinyCLR also implements.

Loopback test

The easiest way to test UART hardware is a loopback test — connect the TXD pin directly to the RXD pin so everything you send is received back. The examples below send ABCDEF and print what comes back.

using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Threading;
using GHIElectronics.TinyCLR.Pins;

var txBuffer = new byte[] { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }; // A B C D E F
var rxBuffer = new byte[txBuffer.Length];

var serial = new SerialPort(FEZBit.UartPort.Uart6, 115200, Parity.None, 8, StopBits.One);
serial.Handshake = Handshake.None;
serial.Open();

serial.Write(txBuffer, 0, txBuffer.Length);

while (true){
if (serial.BytesToRead > 0){
var bytesReceived = serial.Read(rxBuffer, 0, serial.BytesToRead);
Debug.WriteLine(Encoding.UTF8.GetString(rxBuffer, 0, bytesReceived));
}
Thread.Sleep(20);
}

Settings

The standard settings (baud rate, data bits, parity, stop bits, handshaking) are available in both APIs. TinyCLR adds embedded-specific extensions through the UartSetting class:

SettingStandard SerialPortTinyCLR UartSettingPurpose
Baud rateBaudRateBaudRateBits per second
Data bitsDataBitsDataBitsUsually 8
ParityParityParityNone disables parity
Stop bitsStopBitsStopBitsMarker for end of each byte
HandshakingHandshakeHandshakingNone or RequestToSend
RS-485 Driver EnableEnableDePinReuses the RTS pin as DE
Invert DE polarityInvertDePolarityFor RS-485 transceivers expecting inverted DE
Invert TX polarityInvertTxPolarityFor hardware that inverts the transmit signal
Invert RX polarityInvertRxPolarityFor hardware that inverts the receive signal
Invert data onlyInvertBinaryDataInverts data without inverting start/stop bits
Swap TX and RXSwapTxRxPinCorrects board-layout mistakes

RS-485 driver enable

RS-485 transceivers usually need a DE (Driver Enable) pin to switch between transmit and receive. On SITCore, the DE pin is the same physical pin as RTS. Set EnableDePin = true on the UartSetting, with InvertDePolarity if your transceiver expects the inverted level.

note

RS-485 DE control is a TinyCLR API extension — not part of the standard System.IO.Ports.SerialPort.

RS-232

UART uses the processor's logic levels — 0V to 3.3V on SITCore. The older RS-232 standard uses −12V to +12V swings for reliable communication over longer cables and is what most PC serial ports use when present.

warning

A SITCore UART can't be connected directly to an RS-232 port. You need a voltage level shifter (a MAX3232 or similar chip). Connecting without one can damage the SITCore.

Break generation

A break is an extended low signal on the TXD line that some protocols (such as DMX for stage lighting) use to mark the start of a new data frame.

note

The previous transmission must finish before starting a new transmission that includes a break. Custom break duration is a TinyCLR API extension.

using System;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.Uart;
using GHIElectronics.TinyCLR.Pins;

GpioPin dmxEnablePin = GpioController.GetDefault().OpenPin(FEZBit.GpioPin.P0);
dmxEnablePin.SetDriveMode(GpioPinDriveMode.Output);
dmxEnablePin.Write(GpioPinValue.High);

var uart = UartController.FromName(FEZBit.UartPort.Uart6);

uart.SetActiveSettings(new UartSetting{
DataBits = 8,
StopBits = UartStopBitCount.Two,
BaudRate = 250000,
});

uart.Enable();

var txBuffer = new byte[] { 0, 127, 255, 255, 255 };

while (uart.BytesToWrite > 0) Thread.Sleep(0); // Wait for any previous transmission to finish.

// Send a 100 µs break, then transmit the data.
uart.Write(txBuffer, 0, txBuffer.Length, TimeSpan.FromTicks(1000));

Event handlers

Both APIs expose event-driven reception so you don't have to poll BytesToRead.

using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Threading;
using GHIElectronics.TinyCLR.Pins;

var serial = new SerialPort(FEZBit.UartPort.Uart6, 115200, Parity.None, 8, StopBits.One);
serial.Handshake = Handshake.None;
serial.Open();

serial.DataReceived += Serial_DataReceived;
serial.ErrorReceived += (s, e) => Debug.WriteLine("Error: " + e.EventType);
serial.PinChanged += (s, e) => Debug.WriteLine("Pin changed: " + e.EventType); // CTS, DSR, etc.

serial.Write(new byte[] { 0x41, 0x42 }, 0, 2);

Thread.Sleep(Timeout.Infinite);

void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e){
var port = (SerialPort)sender;
var rxBuffer = new byte[port.BytesToRead];
var bytesReceived = port.Read(rxBuffer, 0, rxBuffer.Length);
Debug.WriteLine(Encoding.UTF8.GetString(rxBuffer, 0, bytesReceived));
}

API reference

NamespaceDescription
GHIElectronics.TinyCLR.Devices.UartTinyCLR UART controller and stream classes
System.IO.Ports.NET standard serial port API (included in the same NuGet)