Skip to content

Serial Ports

The runtime exposes its serial ports through the SysCom system library. Numbering starts at 1, as the CODESYS standard requires.

PortPeripheralPinsAvailable to the application
COM1USB-CDCmicro-USBNo — this is the CODESYS gateway (login, download, online)
COM2UART0GP12 TX / GP13 RX, direction on GP18Yes
COM3UART1GP4 TX / GP5 RXYes

Both application ports are interrupt-driven. Opening a port configures its pins automatically — you do not need to touch them.

The format is currently fixed at 8N1 — 8 data bits, no parity, 1 stop bit: only the baud rate is selectable, and the parity and stop-bit fields of the settings are not applied.

COM2 and the boot log. COM2’s peripheral, UART0, is also where the runtime’s boot log goes out (GP0). When your application opens COM2, the runtime detaches the log from UART0: COM2 carries only your application’s data, and the boot log on GP0 stops from the moment COM2 is opened until the next reboot. If you need that log while the application runs, use COM3, which has no such tenant.

COM2 does have one thing COM3 doesn’t: GP18 is driven as a direction (DE) pin — high while transmitting, low otherwise — for RS‑485 transceivers. COM3 has no direction pin.

Add the SysCom library to your project (Library Manager → Add Library → SysCom), then:

PROGRAM PLC_PRG
VAR
hCom : RTS_IEC_HANDLE := RTS_INVALID_HANDLE;
settings : SysCom.SysComSettings;
result : SysTypes.RTS_IEC_RESULT;
txFrame : ARRAY[0..5] OF BYTE := [16#02, 16#06, 16#01, 16#00, 16#00, 16#05];
rxBuf : ARRAY[0..63] OF BYTE;
nRead : UDINT;
nWritten : UDINT;
xOpened : BOOL;
END_VAR
IF NOT xOpened THEN
settings.sPort := SysCom.PORTS.SYS_COM3; // COM3 = UART1, GP4/GP5
settings.ulBaudrate := SysCom.BAUDRATE.SYS_BR_115200;
settings.byParity := SysCom.PARITY.SYS_NOPARITY;
settings.byStopBits := SysCom.STOPBIT.SYS_ONESTOPBIT;
settings.ulTimeout := 0;
settings.ulBufferSize := 0;
hCom := SysCom.SysComOpen2(ADR(settings), 0, ADR(result));
xOpened := (hCom <> RTS_INVALID_HANDLE);
END_IF

Behind those enums are plain numbers: settings.sPort := 3 and settings.ulBaudrate := 115200 work just as well if your CODESYS version names the enums differently.

// Send 6 bytes. SysComWrite blocks until they are out of the UART.
nWritten := SysCom.SysComWrite(hCom, ADR(txFrame), SIZEOF(txFrame), 0, ADR(result));
// Read whatever has arrived so far. Timeout 0 returns immediately with
// the bytes already in the buffer — which is what you want inside a PLC cycle.
nRead := SysCom.SysComRead(hCom, ADR(rxBuf), SIZEOF(rxBuf), 0, ADR(result));
IF nRead > 0 THEN
// process rxBuf[0..nRead-1]
END_IF

SysComRead returns the number of bytes actually copied, and sets the result to ERR_OK only when it could fill the whole requested size — a shorter read reports ERR_TIMEOUT and is perfectly normal.

result := SysCom.SysComClose(hCom);
hCom := RTS_INVALID_HANDLE;

A port can only be opened once: a second SysComOpen2 on an already-open port returns an invalid handle.