
Explore how embedded systems and embedded software drive operating systems, and learn to create your own through a practical hands-on approach that covers hardware and software step by step.
Discover how embedded systems combine cpu, memory, io, peripherals. Engage in hands-on hardware with PIC32 and Raspberry Pi boards, writing device drivers for LCDs and sensors, building an operating system.
Create a platform-independent development workspace with three folders: datasheets, os, and drivers, and set up a Mplab X project for a PIC32 device, then review hex output and datasheet specs.
Identify and map the 44-pin device pinout, including 3.3v power, ground, reset, and clock pins. Connect a 20 MHz crystal with load capacitors and configure programming pins and reset pull-up.
Master practical surface-mount soldering techniques for an SMD adapter and PIC microcontroller, using flux, solder paste, hot air rework, and hand thinning of pads for precise reflow.
Set up a cpu breakout on a breadboard with a 12 MHz crystal, decoupling capacitors, and an LED, then program the microcontroller with the MPLAB Pickit 4 to explore pins.
Explore simulators like MPLAB X and Proteus to develop and debug embedded software for PICs, run code without hardware, and visualize circuits, LEDs, and LCDs.
Introduce decoupling through a base support package and a unified system call interface to portable embedded software across MCUs. Explore tasks with priorities, preemption, and IPC, including periodic executions.
Explore multitasking in single cpu systems, detailing tasks, resources, and the scheduler’s role in ready, running, waiting, and blocked states, including preemption and priorities.
Explore shared resources in a primitive kernel prototype, learning how preemption, race conditions, and mutual exclusion affect LCD and TFT displays through system calls and BSP interactions.
Learn how a preemptive task switch saves each task's 32 registers and stack pointer to preserve its execution context on the stack, then restores it for seamless resumption.
Explore how kernels manage cpu time, perform context switching, and provide inter task communication, contrasting non-preemptive and preemptive scheduling with led-based visualizations and practical examples.
Learn to build a scheduler from scratch using a round-robin policy with a one-millisecond quantum, triggered by system ticks or interrupts, and selecting the next ready task while excluding the idle task.
Learn how critical sections prevent race conditions in embedded systems by using locking and disable interrupts to make code atomic, with writes to buffers and unsafe increments under round-robin scheduling.
Demonstrate how two tasks can deadlock over two lockable objects, each waiting for the other, and explore locking in critical sections, unlock procedures, and event signaling.
Explore how semaphores synchronize tasks, provide restricted zones, differentiate binary semaphore (mutex) from counting semaphores, and manage resource access with take and release operations.
Explore how the system tick, driven by a crystal-fed hardware timer and a prescaler, steers the scheduler; use PWM on timer two to produce 1 kHz and 2 kHz tones.
Explore ISA, API, ABI, and EAB concepts, and how binary compatibility and platform implementations enable same machine code across CPUs. Examine assembly language, instruction encoding, addressing modes, and CPU-memory interaction.
Select the right cpu for an embedded platform by evaluating a color-coded candidate table with performance and peripheral criteria, and choose the PIC32 microcontroller for prototyping.
Learn how the MIPS32 register file of 32 four-byte registers interacts with memory via load and store, with emphasis on word alignment and frame pointer, stack pointer, and return address.
Explore the MIPS32 memory layout, with text, static data, heap, and stack. See how registers and memory mapped io use fetch-decode-execute cycles to move data between memory and registers.
Explore the PIC32 microcontroller, a MIPS 32 platform with timers, UART, SPI, I2C, ADC and DMA, and learn assembly basics—from load/store to procedure calls and delay slots.
Explore the microchip embedded connectivity starter kit with harmony three to rapidly prototype adc-based joystick input, spi-driven tft output, and usb/uart interfaces, enhanced by an analog multiplexer.
Learn how interrupts disrupt program flow, how interrupt service routines run from interrupt vectors, and how priority, multi-vector mode, and flags control preemption and coordination in embedded systems.
Configure timer one and timer two with different frequencies using multi-vector mode and assembly ISRs, and study interrupt flags, vectors, and enabling global interrupts.
Assess interrupt latency in a preemptive kernel as time to start context saving after an IRQ; assess interrupt response as latency plus saving time, and recovery as restore and IRET.
Illustrate how the kernel manages interrupts, including timer tick interrupts for the scheduler, external hardware interrupts with edge polarity settings, and core software interrupts for cooperative multitasking.
Test interrupts by toggling red, green, and blue LEDs on pins 22–24 using timer one, core software, and external interrupts triggered by pin 43 on falling edge.
Build an essential board support package for target system, configuring stage one hardware (LEDs, micro SD, SPI-2, UART over USB via the MCP2221), and a boot loader with DFU upgrade.
Set up the system timer in the BSP to generate a 1 kHz system tick using timer1 with a prescaler, configuring interrupts, and initializing BSP for tick handling.
Set up the system tick interrupt within the stage one BSP, enabling timer1 interrupt and routing it to an ISR that clears the interrupt flag and returns from exception.
Wire three leds as digital outputs (red 19, blue 20, green 21), implement bsp leds macros for on/off/toggle, initialize them in bsp, and test with a system test function.
Flash an SOS in Morse code using the blue LED, sending three short, three long, and three short pulses, with a three-second delay in the main loop.
Explain UART basics for two-device serial communication, covering simplex, half duplex, full duplex, asynchronous transfer, baud rate, and the frame with start, data, parity, and stop bits, LSB first, 8N1.
Perform uart testing by sending capital a every two seconds, observe start and stop bits, eight lsb data bits, and echo uppercase received characters back through the serial console.
Learn how spi enables master–slave serial data transfer using MOSI, MISO, SDO, and SDI. Pull the chip select to enable a slave and configure modes by clock polarity and phase.
Demonstrates spi master-slave data exchange with Arduino, prints over uart via printf and scanf, and enables SD card access through a decoupled fat file system driver.
Define the base kernel infrastructure with BSP interrupt macros, create portable types and constants, and implement a preemptive policy with atomic, critical sections, and software interrupts.
Implement task states and priorities by defining an os task state enum and a task control block storing stack pointer, state, id, priority, time out, and idle task.
Learn how to implement per-task stack isolation using a two-dimensional task_stack array, initialize stacks with cpu stack init, and prepare for context switching by saving registers, gp, sr, and ipc.
Implement context switching in assembly for an embedded OS by saving and restoring CPU context, managing idle and highest-priority ready tasks, and driving the scheduler.
Learn task management in embedded systems by implementing OS task create, delete, and set running or waiting. Manage priority changes using TCB and stack initialization, with context switches.
Implement a simple preemptive scheduler that checks the highest priority ready task against the running task, waking tasks on time delays or events and preempting the running one.
Learn to initialize and start an embedded operating system by implementing os init and os start, creating and scheduling tasks, and handling the system tick interrupt.
Implement the time delay function in the kernel to suspend a task for milliseconds, using a critical section and timeout ticks until expiry, after which the task becomes ready.
Implement a simple event management concept with event control blocks and a fifo, where ECBs store flags, data, sources, and wait mode, linked to a TCB, for 16 event types.
Define data structures for event management and implement a circular buffer FIFO to store events. Cover the event control block, event flags, and basic FIFO operations.
Create and manage kernel events with OS event create, assign event types and sources, queue via FIFO, and wait on event sets using flags and modes to awaken tasks.
Implement mutexes to enforce mutual exclusion on shared resources, explain lock, unlock, and ownership mechanics, and introduce semaphores and priority inversion protection in an embedded systems OS development context.
Implement and test os semaphores by initializing size and available positions, then use wait, post, and query inside critical sections, triggering a semaphore available event to wake waiting tasks.
Explore the priority inversion problem and implement priority inheritance to avoid it in a mutex-based system, enabling high-priority tasks to proceed by elevating the mutex owner's priority.
Implement inter-task communication via a mailbox, a fifo queue of os messages with sender and data fields, supporting create, delete, push, pull, and blocking or non-blocking behavior.
In this course you will learn how to create an Embedded OS, really from the ground up.
You will be guided step by step in the creation of each and every technical software module composing an embedded operating system, as well as in the development of your own target device on the bench (optional: you can use a free simulator or a ready-to-use Starter Kit), starting with basic electronic components and an industry-standard processor.
You will learn how to create device drivers step-by-step for real hardware components like displays, SD card storage, Wi-Fi, Inertial Movement Units (IMU, i.e. accelerometer and gyroscope), USB communication, analog Joysticks, thermal camera modules and more.
By the end of this course you will master system-level programming in the assembly and C languages, as well as the technical processes governing the interaction between CPU and memory. Thanks to the numerous hands-on experiences and practical demonstrations, you will develop the ability of gaining full control on the machine by manipulating CPU registers, stack, instruction pointer, return addresses, and much more. At the end of the software development part, you will learn how to create a porting to another architecture, like x86.
Although the hardware development part is optional, if you have access to an electronics lab you will also develop the ability of prototyping your circuit, designing and assembling your own target PCB (Printed Circuit Board).