Software for Linux-capable application processors: the layer between silicon and userspace — bootloaders, device trees, kernel drivers and the system integration that turns a board into a product.
What you will be able to do
- Write production C and navigate a large multi-file codebase
- Implement and debug I2C, UART, SPI and I2S links on real hardware
- Explain and control the full boot path — ROM, bootloader, kernel, root filesystem
- Describe new hardware to the kernel through the device tree and bring a board up
- Write, build and load kernel modules and character and platform drivers
- Build a complete image with Buildroot or Yocto and flash it to an SoC board
Syllabus
Modules 1 and 2 are the shared embedded foundation — the same C and protocol work that opens the RTOS programme. From Module 3 onwards this course is entirely Linux and application-processor territory.
Module 1 — C and Embedded C
Shared foundation
- Data types, operators, control flow, and what the compiler really emits for each
- Functions, scope and storage classes — auto, static, extern, register
- Arrays and strings, and the off-by-one mistakes that reach production
- Pointers in depth: arithmetic, pointer-to-pointer, function pointers, const correctness
- Structures, unions and bitfields for register maps; packing, padding and alignment
- Bit manipulation — masks, shifts, set/clear/toggle, read-modify-write hazards
- Dynamic memory: malloc and free, fragmentation, and why most firmware avoids the heap
- The build pipeline — preprocessor, compiler, assembler, linker — and multi-file projects with make
- Linker scripts and memory sections (.text, .data, .bss), and the startup code that runs before main()
- volatile, memory-mapped I/O, and the compiler reordering that bites you once
- Data structures that fit in a few kilobytes: ring buffers, linked lists, queues, state tables
- Debugging with gdb, reading a map file, and coding standards including MISRA-C awareness
Module 2 — Communication protocols — I2C, UART, SPI, I2S
Shared foundation
- UART — framing, baud rates, parity, flow control, and diagnosing corrupt bytes
- SPI — the four clock modes, chip select, daisy chaining, and full-duplex timing
- I2C — addressing, ACK/NACK, clock stretching, arbitration, pull-up sizing and bus recovery
- I2S — audio framing, word select, channel alignment and clock domains
- Choosing between them: distance, speed, pin cost and how many devices share the bus
- Bench work — capture each bus on a logic analyser, decode it, and find the fault when it goes quiet
Module 3 — Linux systems programming
- Kernel space and user space, and the system call boundary between them
- Processes — fork, exec, wait, process states and scheduling
- Signals, and why signal handlers are harder than they look
- File I/O, descriptors, blocking versus non-blocking, select, poll and epoll
- IPC — pipes, FIFOs, message queues, shared memory and semaphores
- POSIX threads — creation, mutexes, condition variables, and finding race conditions
- Virtual memory, mmap, and what the address space actually looks like
- Shell scripting and the cross toolchain you will live inside
Module 4 — Networking for connected devices
- TCP/IP layering, addressing, routing and what the kernel does on your behalf
- Socket programming — TCP and UDP, client and server, concurrent server designs
- Device protocols on top: HTTP and MQTT, and when each is the right answer
- Capturing and reading traffic when the link misbehaves
Module 5 — Boot flow and the bootloader
- The full path: ROM code, SPL, U-Boot, kernel, root filesystem — and each handover
- U-Boot — commands, environment, scripting, and booting from eMMC, SD or network
- Kernel command line, initramfs, and what breaks when the rootfs is not found
- Building a kernel: configuration, defconfigs, image formats
Module 6 — Device tree and board bring-up
- Device tree syntax — nodes, properties, phandles, and the compiled blob
- compatible strings and how a driver gets matched to hardware
- Pin control, clocks, regulators and GPIO described in the tree
- Overlays, and adapting a vendor tree to your own board
- Bringing a new peripheral up end to end, from schematic to working node
Module 7 — Kernel modules and device drivers
- The kernel build system, out-of-tree modules, insmod and rmmod
- Character drivers — file_operations, cdev, major and minor numbers
- The platform driver model, probe and remove, and resource acquisition
- sysfs, debugfs, procfs and ioctl as userspace interfaces
- Interrupt handling in the kernel — top and bottom halves, workqueues, threaded IRQs
- Kernel debugging — printk, dmesg, ftrace, and reading an oops or panic
Module 8 — Build systems and integration
- Cross toolchains and sysroots, and why host tools are not target tools
- Buildroot — configuration, packages and a minimal reproducible image
- Yocto — layers, recipes, bitbake, and when the complexity pays for itself
- Root filesystem layout, init systems and bringing services up at boot
- Flashing, updating in the field, and recovering a bricked board
Module 9 — Projects on SoC boards
- Raspberry Pi — the fastest path to a working driver and a measurable result
- NXP i.MX — a vendor BSP, its device tree, and its quirks
- Rockchip and Qualcomm — bringing up a peripheral on a production-class SoC
Capstone
Take one board from power-on to a working product: bootloader configured, device tree describing your hardware, a driver you wrote loaded by the kernel, and a userspace application using it — then defend the design under review.