VxWorks UART Programming: Serial Port Configuration and I/O
UART (Universal Asynchronous Receiver/Transmitter) remains a fundamental interface for debugging, control, and device communication in embedded systems. While the programming model is broadly consistent across operating systems, VxWorks exposes UART functionality through its I/O system and ioctl interface.
This guide provides a practical walkthrough of configuring serial ports, performing read/write operations, and implementing a complete UART task in VxWorks.
🛠️ Serial Port Configuration #
Opening the Serial Device #
Serial ports in VxWorks are exposed as device files:
fd = open("/tyCo/0", O_RDWR, 0);
/tyCo/0: First serial deviceO_RDWR: Enables both read and write access
Device naming may vary depending on BSP and hardware configuration.
Configuring Mode and Buffers #
Basic configuration is performed using ioctl():
ioctl(fd, FIOSETOPTIONS, OPT_RAW);
ioctl(fd, FIOFLUSH, 0);
OPT_RAW: Disables line processing (raw data mode)FIOFLUSH: Clears input/output buffers
Common ioctl Commands #
| Command | Purpose |
|---|---|
FIOBAUDRATE |
Set baud rate |
FIOGETOPTIONS |
Retrieve current options |
FIOSETOPTIONS |
Apply device options |
FIOREAD |
Query unread bytes |
FIOWRITE |
Query pending output |
FIOFLUSH |
Clear buffers |
FIOCANCEL |
Cancel I/O operations |
Setting Line Parameters #
Hardware-level configuration is applied using:
ioctl(fd, SIO_HW_OPTS_SET, CS8 | PARENB | CLOCAL | CREAD);
Key flags:
CS8: 8 data bitsPARENB: Enable parityPARODD: Odd parity (optional)CLOCAL: Ignore modem controlCREAD: Enable receiver
🔄 UART Read and Write Operations #
Once configured, UART communication uses standard POSIX-style APIs:
int read(int fd, char *buffer, size_t maxbytes);
int write(int fd, char *buffer, size_t nbytes);
Parameters #
fd: File descriptor fromopen()buffer: Data buffermaxbytes/nbytes: Transfer size
These APIs integrate seamlessly with the VxWorks I/O system.
💻 Complete UART Example #
The following example demonstrates a UART task that periodically sends data while coordinating access via shared memory and semaphores.
#include "vxWorks.h"
#include "stdio.h"
#include "ioLib.h"
#include "taskLib.h"
#include "sioLib.h"
#include "sdLib.h"
#include "semLib.h"
#include "msgQLib.h"
#define DEV_NAME "/tyCo/2"
#define MAX_BUF_SIZE 20
#define SHARE_DATA_LENGTH 20
typedef struct unix_clock_struct
{
UINT32 sec;
UINT32 msec;
UINT8 quality;
} UNIX_CLOCK_STRUCT;
char *comdata;
SEM_ID mutexComdata;
int set_serial(int fd);
void taskUart(void)
{
int ret;
int fd = open(DEV_NAME, O_RDWR, 0);
UNIX_CLOCK_STRUCT w_buff;
if (fd < 0)
printf("open failed.\n");
if (set_serial(fd) < 0)
printf("serial config failed.\n");
while (1)
{
semTake(mutexComdata, WAIT_FOREVER);
ioctl(fd, FIOFLUSH, 0);
bzero(&w_buff, sizeof(w_buff));
memcpy(&w_buff, comdata, sizeof(w_buff));
if (write(fd, &w_buff.sec, sizeof(w_buff.sec)) < 0)
printf("write failed.\n");
else
printf("write success: %d\n", w_buff.sec);
semGive(mutexComdata);
taskDelay(sysClkRateGet() * 2);
}
}
int set_serial(int fd)
{
if (fd < 0)
return -1;
if (ioctl(fd, FIOBAUDRATE, 9600) < 0)
return -1;
if (ioctl(fd, SIO_HW_OPTS_SET, CREAD | CS8 | CLOCAL) < 0)
return -1;
return 0;
}
🔍 Key Implementation Insights #
Synchronization #
- Use semaphores (
semTake,semGive) to protect shared data - Prevent concurrent access to UART resources
Buffer Management #
- Clear buffers before transmission (
FIOFLUSH) - Avoid stale or partial data reads
Task-Based Design #
- Run UART logic in a dedicated task
- Control execution rate using
taskDelay()
⚠️ Common Pitfalls #
Incorrect Device Name #
/tyCo/xmapping depends on BSP configuration- Verify using system device listing
Misconfigured Line Settings #
- Incorrect parity or data bits can corrupt communication
- Ensure both ends match configuration
Blocking Behavior #
read()may block if no data is available- Consider non-blocking modes or timeouts
✅ Best Practices #
- Always validate file descriptors and return values
- Use raw mode for binary communication
- Encapsulate configuration into reusable functions
- Separate UART logic from application logic
- Log errors for easier debugging in production systems
📌 Conclusion #
UART programming in VxWorks builds on a familiar POSIX-style model while leveraging powerful configuration via ioctl. By combining proper device setup, robust synchronization, and task-based design, developers can implement reliable serial communication for debugging, control, and data exchange.
This foundation can be extended to support interrupt-driven drivers, DMA-based transfers, or higher-level communication protocols in more advanced embedded systems.
Reference: VxWorks UART Programming: Serial Port Configuration and I/O