Skip to main content

VxWorks XR16L788 Driver: 16-Port UART on S3C2410

·627 words·3 mins
VxWorks Device Driver UART XR16L788 S3C2410 Embedded Systems Serial
Table of Contents

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
#

  1. write() triggers TX startup
  2. TX interrupt fires when FIFO is ready
  3. ISR invokes TX callback
  4. Data is pushed into FIFO
  5. Process repeats until buffer is empty

Receive Flow
#

  1. Incoming data fills RX FIFO
  2. Interrupt triggers at threshold
  3. ISR invokes RX callback
  4. 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.

Related

S3C2440 VxWorks NAND Boot Using Stepping Stone SRAM
·616 words·3 mins
S3C2440 VxWorks NAND Embedded Systems Bootloader ARM9 BSP
VxWorks Multi-Image Boot: Universal Startup Method
·643 words·4 mins
VxWorks Embedded Systems RTOS Bootrom Application-Loading BSP Startup-Script Multi-Image
Developing a Dual Serial Port Driver for VxWorks Using XR16L788
·672 words·4 mins
VxWorks Device Driver UART Embedded Systems Serial Communication