Skip to main content

The Complete VxWorks Programming Guide (2025 Edition)

·1804 words·9 mins
VxWorks RTOS Programming Guide Real-Time Operating Systems Wind River VxBus Networking
Table of Contents

VxWorks is one of the most widely used real-time operating systems (RTOS) in mission-critical domains such as aerospace, defense, automotive, robotics, and industrial control. Trusted for its determinism, safety certifications, and security, VxWorks has continued to evolve, offering developers modern tools, container support, and a flexible programming model.

This guide provides a comprehensive 2025 edition of VxWorks programming, with hands-on code examples and developer best practices.

Why VxWorks in 2025?
#

  • Deterministic Scheduling: Hard real-time guarantees with microsecond response.
  • Cross-platform Support: Runs on ARM, x86, PowerPC, MIPS, RISC-V.
  • Certified Safety: DO-178C (avionics), ISO 26262 (automotive), IEC 61508 (industrial).
  • Modern Features: Containerization, security hardening, AI/ML edge integration.

If your application requires predictability and safety, VxWorks remains a top choice.

1. VxWorks Architecture
#

At its core, VxWorks provides:

  • Kernel: Preemptive, priority-based scheduler.
  • Tasks: Lightweight threads with individual stack/priority.
  • VxBus I/O System: Unified device driver framework.
  • Networking Stack: Dual-stack IPv4/IPv6 with TSN support.
  • File Systems: NFS, HRFS, dosFS, ROMFS.
  • Security: Memory protection, stack guards, secure boot.

2. Development Environment Setup
#

Tools
#

  • Wind River Workbench IDE or CLI toolchain (wr-cc / gcc).
  • Target: Real hardware (ARM, PPC, x86, RISC-V) or QEMU simulation.
  • Connection: Serial, JTAG, or Ethernet with target server.

Workflow
#

  1. Build a VxWorks Image Project (VIP) with required kernel components.
  2. Write application modules or drivers.
  3. Deploy to target hardware.
  4. Debug using Workbench, Kernel Shell, or WDB Agent.

3. Task Management in VxWorks
#

Tasks are lightweight threads scheduled by priority.

Creating a Task
#

#include <taskLib.h>
#include <stdio.h>

void helloTask(void) {
    while (1) {
        printf("Hello from VxWorks task!\n");
        taskDelay(sysClkRateGet()); // 1 second delay
    }
}

int main(void) {
    taskSpawn("tHello", 100, 0, 8192, (FUNCPTR) helloTask,
              0,0,0,0,0,0,0,0,0,0);
    return 0;
}

Managing Tasks
#

TASK_ID tid = taskSpawn("tWorker", 90, 0, 8192, (FUNCPTR) workerTask,
                        0,0,0,0,0,0,0,0,0,0);

taskSuspend(tid);   // Pause task
taskResume(tid);    // Resume task
taskDelete(tid);    // Terminate task

4. Inter-Task Communication (IPC)
#

4.1 Semaphores
#

Used for synchronization and mutual exclusion.

#include <semLib.h>

SEM_ID sem;

void producer(void) {
    while (1) {
        printf("Producing data...\n");
        semGive(sem);
        taskDelay(60);
    }
}

void consumer(void) {
    while (1) {
        semTake(sem, WAIT_FOREVER);
        printf("Consumed data!\n");
    }
}

int main(void) {
    sem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
    taskSpawn("tProd", 100, 0, 8192, (FUNCPTR) producer,0,0,0,0,0,0,0,0,0,0);
    taskSpawn("tCons", 101, 0, 8192, (FUNCPTR) consumer,0,0,0,0,0,0,0,0,0,0);
    return 0;
}

4.2 Message Queues
#

For task-to-task communication.

#include <msgQLib.h>

MSG_Q_ID msgQ;
char buf[64];

void sender(void) {
    msgQSend(msgQ, "Hello IPC", 10, WAIT_FOREVER, MSG_PRI_NORMAL);
}

void receiver(void) {
    msgQReceive(msgQ, buf, sizeof(buf), WAIT_FOREVER);
    printf("Received: %s\n", buf);
}

int main(void) {
    msgQ = msgQCreate(10, 64, MSG_Q_PRIORITY);
    taskSpawn("tSender", 90, 0, 8192, (FUNCPTR) sender,0,0,0,0,0,0,0,0,0,0);
    taskSpawn("tReceiver", 91, 0, 8192, (FUNCPTR) receiver,0,0,0,0,0,0,0,0,0,0);
    return 0;
}

5. Device Drivers with VxBus
#

VxBus is the unified driver framework in VxWorks.

Skeleton Driver
#

#include <hwif/vxBus.h>
#include <hwif/vxBusCore.h>

LOCAL STATUS i2cProbe(VXB_DEV_ID dev) {
    return OK; // Device found
}

LOCAL STATUS i2cAttach(VXB_DEV_ID dev) {
    printf("I2C device attached!\n");
    return OK;
}

LOCAL VXB_DRV_METHOD i2cMethods[] = {
    { VXB_DEVMETHOD_CALL(vxbDevProbe),  i2cProbe },
    { VXB_DEVMETHOD_CALL(vxbDevAttach), i2cAttach },
    VXB_DEVMETHOD_END
};

VXB_DRV vxI2cDrv = {
    { NULL },
    "vxI2c",
    "Custom I2C Driver",
    VXB_BUSID_PLB,
    0, 0,
    i2cMethods,
    NULL
};

You register the driver in your BSP or project configuration so it loads at boot.

6. Networking in VxWorks
#

The VxWorks networking stack is full-featured, supporting IPv4/IPv6, TSN (Time-Sensitive Networking), IPSec, TLS, SNMP, and more.

6.1 Simple TCP Client
#

#include <sockLib.h>
#include <inetLib.h>

int tcpClient(void) {
    int sock;
    struct sockaddr_in server;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    server.sin_family = AF_INET;
    server.sin_port = htons(8080);
    inet_aton("192.168.1.10", &server.sin_addr);

    if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == OK) {
        write(sock, "Hello from VxWorks", 18);
    }
    close(sock);
    return 0;
}

6.2 Simple TCP Server
#

int tcpServer(void) {
    int sock, newSock;
    struct sockaddr_in server, client;
    char buf[64];

    sock = socket(AF_INET, SOCK_STREAM, 0);
    server.sin_family = AF_INET;
    server.sin_port = htons(8080);
    server.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sock, (struct sockaddr *)&server, sizeof(server));
    listen(sock, 5);

    while (1) {
        int addrlen = sizeof(client);
        newSock = accept(sock, (struct sockaddr *)&client, &addrlen);
        read(newSock, buf, sizeof(buf));
        printf("Received: %s\n", buf);
        close(newSock);
    }
    return 0;
}

6.3 UDP Client
#

UDP is lightweight and perfect for real-time telemetry.

int udpClient(void) {
    int sock;
    struct sockaddr_in server;
    char msg[] = "Telemetry packet";

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    server.sin_family = AF_INET;
    server.sin_port = htons(9000);
    inet_aton("192.168.1.20", &server.sin_addr);

    sendto(sock, msg, sizeof(msg), 0,
           (struct sockaddr *)&server, sizeof(server));
    close(sock);
    return 0;
}

6.4 UDP Server
#

int udpServer(void) {
    int sock;
    struct sockaddr_in server, client;
    char buf[128];

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    server.sin_family = AF_INET;
    server.sin_port = htons(9000);
    server.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sock, (struct sockaddr *)&server, sizeof(server));

    while (1) {
        int addrlen = sizeof(client);
        int n = recvfrom(sock, buf, sizeof(buf), 0,
                         (struct sockaddr *)&client, &addrlen);
        buf[n] = '\0';
        printf("Received UDP: %s\n", buf);
    }
    return 0;
}

6.5 Multicast Receiver
#

Multicast is common in avionics (ARINC 664) and industrial automation.

#include <ipcom_sock.h>   // required for multicast options

int udpMulticastRecv(void) {
    int sock;
    struct sockaddr_in addr;
    struct ip_mreq mreq;
    char buf[256];

    sock = socket(AF_INET, SOCK_DGRAM, 0);

    /* Allow multiple receivers */
    int reuse = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));

    addr.sin_family = AF_INET;
    addr.sin_port = htons(5000);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sock, (struct sockaddr *)&addr, sizeof(addr));

    /* Join multicast group 239.255.0.1 */
    mreq.imr_multiaddr.s_addr = inet_addr("239.255.0.1");
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));

    while (1) {
        int n = recvfrom(sock, buf, sizeof(buf), 0, NULL, 0);
        buf[n] = '\0';
        printf("Multicast received: %s\n", buf);
    }
    return 0;
}

6.6 Multicast Sender
#

int udpMulticastSend(void) {
    int sock;
    struct sockaddr_in addr;
    char msg[] = "Multicast data packet";

    sock = socket(AF_INET, SOCK_DGRAM, 0);

    addr.sin_family = AF_INET;
    addr.sin_port = htons(5000);
    addr.sin_addr.s_addr = inet_addr("239.255.0.1");

    sendto(sock, msg, sizeof(msg), 0,
           (struct sockaddr *)&addr, sizeof(addr));

    close(sock);
    return 0;
}

Networking Best Practices
#

  • Use UDP for low-latency telemetry, but handle packet loss.
  • Use TCP for reliable connections (e.g., command/control).
  • Use Multicast for one-to-many data distribution.
  • Always check for timeouts to avoid blocking indefinitely.
  • In safety-critical apps, validate all received packets.

7. Memory Management
#

VxWorks supports flat memory model with optional MMU protection.

Create a Private Heap
#

#include <memPartLib.h>

PART_ID myHeap;

void memDemo(void) {
    void *pool = malloc(1024 * 1024);
    myHeap = memPartCreate(pool, 1024 * 1024);

    void *ptr = memPartAlloc(myHeap, 256);
    printf("Allocated 256 bytes at %p\n", ptr);

    memPartFree(myHeap, ptr);
}

Stack Checking
#

#include <taskLib.h>

void monitor(void) {
    taskStackAllotCheck(0); // check current task stack usage
}

8. Debugging and Profiling
#

Kernel Shell
#

-> i
  NAME        ENTRY       TID    PRI  STATUS
  tHello      helloTask   0x3c8  100  READY

System Viewer
#

Captures context switches, ISR events, and task states for real-time profiling.

WDB Agent
#

Allows remote debugging via Workbench.

9. Best Practices
#

  • Use priority inheritance semaphores to avoid priority inversion.
  • Keep interrupt service routines (ISRs) short, defer work to tasks.
  • Always enable stack overflow protection.
  • Separate application logic from BSP/device tree configuration.
  • Test with fuzzers and fault injection to validate robustness.

10. Future of VxWorks Development
#

  • RISC-V support expanding in safety-critical domains.
  • Containerization for modern DevOps workflows.
  • Cybersecurity hardening with stronger encryption and runtime checks.
  • AI/ML at the edge, leveraging GPU/DSP integration.

11. Device Tree Configuration in VxWorks 7
#

Starting with VxWorks 7, the RTOS uses Flattened Device Tree (FDT) to describe hardware in a standardized, portable way.
The BSP parses the .dts file at boot, and VxBus drivers attach automatically to matching nodes.

Example: Adding an I2C Controller
#

device-tree.dts

&i2c0 {
    status = "okay";
    clock-frequency = <100000>;   /* 100 kHz */
    myTempSensor@48 {
        compatible = "myvendor,temp-sensor";
        reg = <0x48>;
    };
};
  • i2c0 → Refers to an existing I2C controller in SoC.
  • myTempSensor@48 → Device node with address 0x48.
  • compatible → Matches against your VxBus driver.

Writing a Matching Driver
#

LOCAL STATUS tempProbe(VXB_DEV_ID dev) {
    VXB_DEV_ID parent = vxbDevParent(dev);
    if (vxbResourceAlloc(dev) != OK)
        return ERROR;
    return OK;
}

LOCAL STATUS tempAttach(VXB_DEV_ID dev) {
    printf("Temp sensor attached: %s\n", vxbDevNameGet(dev));
    return OK;
}

LOCAL VXB_DRV_METHOD tempMethods[] = {
    { VXB_DEVMETHOD_CALL(vxbDevProbe),  tempProbe },
    { VXB_DEVMETHOD_CALL(vxbDevAttach), tempAttach },
    VXB_DEVMETHOD_END
};

VXB_DRV tempDrv = {
    { NULL },
    "tempSensor",
    "Custom Temp Sensor Driver",
    VXB_BUSID_I2C,
    0, 0,
    tempMethods,
    NULL
};

Now, when the system boots, the sensor node will be probed and attached automatically.

12. MMU Attributes and Memory Mapping
#

VxWorks supports MMU-based memory protection on ARM, PPC, and x86. You can configure cache, access permissions, and bufferability per memory region.

Example: Setting MMU Attributes
#

#include <vmLib.h>
#include <private/vmLibP.h>

void mmuSetup(void) {
    VM_CONTEXT_ID ctx = vmCurrentGet();

    /* Define a non-cacheable memory region for an MMIO device */
    void *physAddr = (void *)0x40000000;  // device base
    size_t size = 0x1000;

    vmRegionAdd(ctx, physAddr, size,
                VM_STATE_MASK_CACHEABLE | VM_STATE_MASK_WRITABLE,
                VM_STATE_CACHEABLE_NOT | VM_STATE_WRITABLE);

    printf("MMU region added at %p, size %x\n", physAddr, (int)size);
}
  • VM_STATE_CACHEABLE_NOT → Disables caching for MMIO.
  • VM_STATE_WRITABLE → Enables write access.

Common Attribute Configurations
#

Usage Cache Bufferable Access
Flash/ROM ON NO Read-only
RAM ON YES Read/Write
MMIO (devices) OFF NO Read/Write
Shared buffers ON YES RW (atomic)

13. Interrupt Handling in VxWorks 7
#

In embedded systems, interrupts are crucial for handling hardware events with minimal latency.
VxWorks allows you to register Interrupt Service Routines (ISRs) that run at interrupt context, and deferred service routines (DSRs) that run in task context.

Registering an ISR
#

#include <intLib.h>
#include <stdio.h>

LOCAL int irqCount = 0;

/* Simple ISR */
LOCAL void myIsr(void *arg) {
    irqCount++;
    printf("ISR fired, count = %d\n", irqCount);
}

void irqSetup(void) {
    int irqLine = 32; // Example IRQ line
    if (intConnect((VOIDFUNCPTR *)INUM_TO_IVEC(irqLine), myIsr, 0) == OK) {
        intEnable(irqLine);
        printf("ISR registered on IRQ %d\n", irqLine);
    }
}
  • intConnect() → Attaches ISR to an interrupt vector.
  • intEnable() → Enables the hardware interrupt line.

Best Practice: Keep ISRs Short
#

ISRs should be minimal, deferring heavy work to a task. Use semaphores or message queues to hand off work.

#include <semLib.h>

SEM_ID isrSem;

LOCAL void myIsr(void *arg) {
    semGive(isrSem);   // Signal task
}

void irqTask(void) {
    while (1) {
        semTake(isrSem, WAIT_FOREVER);
        printf("Interrupt handled in task context\n");
    }
}

void irqDemo(void) {
    int irqLine = 40;
    isrSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);

    intConnect((VOIDFUNCPTR *)INUM_TO_IVEC(irqLine), myIsr, 0);
    intEnable(irqLine);

    taskSpawn("tIrqTask", 100, 0, 8192, (FUNCPTR) irqTask,
              0,0,0,0,0,0,0,0,0,0);
}

Here:

  • ISR signals via semGive().
  • Worker task does actual processing.
  • Keeps interrupt latency low.

Handling Shared Interrupts
#

If multiple devices share an IRQ, your ISR must check the device’s status register before servicing:

LOCAL void sharedIsr(void *arg) {
    if (deviceStatus() & DEVICE_IRQ) {
        clearDeviceIrq();
        semGive(isrSem);
    }
}

Common Pitfalls
#

  • ❌ Doing printf() in ISR (slow, non-deterministic).
  • ❌ Allocating memory in ISR.
  • ❌ Holding ISRs for long loops.
  • ✅ Always defer work to tasks.

Conclusion
#

This 2025 edition of the VxWorks Programming Guide covered the entire spectrum of VxWorks programming essentials:

  • Task management and IPC
  • Device tree configuration
  • Driver development (VxBus)
  • Networking
  • Memory management and MMU attributes
  • Debugging and profiling
  • Interrupt handling (ISR + deferred tasks)

Together, these skills empower developers to build safe, reliable, real-time applications on VxWorks 7 and beyond.

With its proven reliability and forward-looking features, VxWorks continues to dominate mission-critical embedded systems.

If you’re building the next autonomous car, medical device, or satellite system, VxWorks programming expertise is an invaluable skill.

Related

Writing an I²C Driver in VxWorks 7: Complete Example
·679 words·4 mins
VxWorks 7 I²C Driver Device Driver RTOS Embedded Systems Wind River VxBus Device Tree
VxBus Driver Development: A Complete Guide for VxWorks Developers
·1223 words·6 mins
VxWorks VxBus Device Driver Embedded Systems RTOS Driver Development
Memory Management in VxWorks Explained
·803 words·4 mins
VxWorks RTOS Memory Management Embedded Systems Real-Time MMU RTP