VxWorks XR16L788 Driver: 16-Port UART on S3C2410
Expanding serial interfaces in embedded systems often exceeds the capability of on-chip UARTs. This guide presents a production-grade VxWorks driver for dual XR16L788 UART devices, enabling 16 independent serial ports on an S3C2410 platform.
The implementation follows the VxWorks character device model, uses interrupt-driven FIFO handling, and supports scalable multi-channel operation suitable for industrial applications.
🔍 VxWorks Serial Driver Model #
In VxWorks, serial interfaces are implemented as character devices, providing byte-stream access via a unified I/O subsystem.
Key Characteristics #
- Device abstraction via standard APIs
- Integration with SIO (Serial I/O) framework
- Support for both:
- Interrupt-driven mode
- Polled mode
Each UART channel is exposed as a device node (e.g., /tyXR0) using:
ttyDevCreate()
🛠️ Hardware Architecture #
The system integrates:
- CPU: S3C2410 (ARM9)
- UART Chips: 2 × XR16L788
- Channels: 8 UARTs per chip → 16 total
XR16L788 Features #
- 64-byte TX/RX FIFOs
- Programmable baud rate
- Interrupt-driven operation
Interconnection #
- Shared address/data bus
- Dedicated chip-select logic
- Interrupt lines routed to CPU
⚙️ Driver Architecture #
The driver uses a two-level structure:
Device Structure #
typedef struct XR16L788_DEV {
int devNum;
int devRegBase;
int oscFreq;
int intNum;
int intMask;
char *devNamePrefix;
void *pChanArray;
} XR16L788_DEV;
Channel Structure #
typedef struct XR16L788_CHAN {
SIO_CHAN sio;
STATUS (*getTxChar)();
STATUS (*putRcvChar)();
void *getTxArg;
void *putRcvArg;
int chNum;
int chRegBase;
int baudRate;
int options;
int mode;
XR_CH_REG *pXrChReg;
struct XR16L788_DEV *pXrDev;
} XR16L788_CHAN;
This separation enables:
- Clean device/channel abstraction
- Scalable multi-chip support
- Modular initialization
🚀 Initialization Flow #
The driver uses a two-phase initialization model.
🔧 Phase 1: Hardware and Channel Setup #
void sysSerialHwInit_16788(void) {
xr16788Init();
for (devNum = 0; devNum < MAX_XR16788_DEVS; devNum++) {
pDev = &xr16788Dev[devNum];
pDev->pChanArray = &xr16788Chan[devNum];
if (ERROR == xrInitDev(pDev)) continue;
for (chanNum = 0; chanNum < MAX_XR16788_CHANS; chanNum++) {
pChan = &xr16788Chan[devNum][chanNum];
pChan->chNum = chanNum;
pChan->pXrDev = pDev;
pChan->baudRate = 19200;
pChan->chRegBase = pDev->devRegBase + 0x10 * chanNum;
pChan->mode = SIO_MODE_INT;
pChan->options = CLOCK | CREAD | CS8;
pChan->getTxChar = xrDummyCallback;
pChan->putRcvChar = xrDummyCallback;
xrInitChan(pChan);
}
}
}
Responsibilities #
- Initialize hardware registers
- Configure channel parameters
- Set default callbacks
🔁 Phase 2: Interrupts and Device Creation #
void sysSerialHwInit2_16788(void) {
for (devNum = 0; devNum < MAX_XR16788_DEVS; devNum++) {
pDev = &xr16788Dev[devNum];
intConnect(INUM_TO_Ivec(pDev->intNum), xr16l788_Interrupt, (int)pDev);
intEnable(pDev->intNum);
}
for (devNum = 0; devNum < MAX_XR16788_DEVS; devNum++) {
pDev = &xr16788Dev[devNum];
for (chanNum = 0; chanNum < MAX_XR16788_CHANS; chanNum++) {
sprintf(tyName, "%s%d", pDev->devNamePrefix, chanNum);
if (OK != ttyDevCreate(
tyName,
sysXRSerialChanGet(devNum, chanNum),
512,
512)) {
printf("ttyDevCreate(%s) failed.\n", tyName);
}
}
}
}
Responsibilities #
- Install interrupt service routines
- Enable hardware interrupts
- Create VxWorks device nodes
🔄 FIFO-Based Interrupt Handling #
The XR16L788 operates using FIFO-driven interrupts for both transmission and reception.
Transmit Flow #
write()triggers TX startup- TX interrupt fires when FIFO is ready
- ISR invokes TX callback
- Data is pushed into FIFO
- Process repeats until buffer is empty
Receive Flow #
- Incoming data fills RX FIFO
- Interrupt triggers at threshold
- ISR invokes RX callback
- Data is drained into system buffers
Key Advantages #
- Reduced CPU overhead
- High throughput
- Deterministic latency
📊 Validation Results #
Test setup:
- 4 external systems generating traffic
- All 16 ports active
- 19200 baud, continuous load
Observed Performance #
- Stable bidirectional communication
- No data loss or corruption
- Consistent real-time response
📈 Design Benefits #
| Feature | Benefit |
|---|---|
| 16 ports | High-density serial expansion |
| Interrupt-driven FIFO | Efficient data handling |
| Two-phase init | Clean system integration |
| Modular design | Easy reuse and scaling |
✅ Conclusion #
This XR16L788 driver provides a scalable and reliable solution for multi-port serial communication in VxWorks environments. By combining structured device abstraction, phased initialization, and efficient interrupt handling, it delivers high-performance operation suitable for industrial systems.
The design can be readily adapted to other ARM platforms and serves as a solid reference for multi-UART driver development in embedded systems.