How I went from toggling a single GPIO pin to deploying intelligent, low-power firmware on the edge — and the lessons that shaped me along the way.
The first program I ever ran on a microcontroller did exactly one thing: it blinked an LED.
No operating system. No framework. No safety net. Just my code, a register, and a clock ticking a few million times a second. When that LED finally blinked at the rate I intended — not too fast, not stuck on — I felt something I hadn't felt writing software before. On a bare-metal system, nothing happens unless you make it happen. There's no runtime quietly cleaning up after you. That mix of total control and total responsibility is what pulled me into embedded systems, and it's the same thread that eventually led me to running machine learning models on the edge.
This is the story of that journey — from a single blinking pin to intelligent devices that sense, decide, and act on their own.
The Bare-Metal Beginning
Bare-metal firmware is where you learn what a computer actually is.
When you write to a memory-mapped register to toggle a GPIO, or configure a UART peripheral one bit at a time, there's no abstraction hiding the hardware from you. You read the datasheet. You read the reference manual. You get the clock configuration wrong, and nothing works — no error message, just silence. Then you fix it, and suddenly bytes are streaming out of a pin at exactly the baud rate you configured.
Most of my early growth happened writing low-level peripheral drivers — UART, SPI, I2C, GPIO, ADC — on ARM Cortex-M platforms. These are the unglamorous building blocks, but they teach you the discipline embedded work demands:
- Every byte and every milliwatt matters. On a resource-constrained MCU, you don't get to be careless with memory or power.
- Timing is a first-class citizen. An interrupt that fires 50 microseconds late can break the whole system.
- The hardware is always right. If your code and the oscilloscope disagree, the oscilloscope wins.
That last lesson stuck with me. I've spent long sessions with a J-Link debugger and a logic analyzer, watching real signals on real pins, learning that "it should work" means nothing until the waveform proves it.
One project that crystallized this for me was building a secure UART-based authentication protocol between an ESP32 and an nRF platform. It sounds simple — two chips talking over a serial line — but doing it securely meant thinking about device validation, data privacy, and what happens when a message arrives corrupted or out of order. Bare metal forces you to handle every one of those cases explicitly. There's no library that magically does it for you.
When One Loop Isn't Enough: Discovering RTOS
Bare-metal while(1) loops are beautiful until your device needs to do several things at once.
Read a sensor. Maintain a wireless connection. Respond to a button. Blink a status LED. Handle a timeout. Suddenly a single super-loop turns into a tangle of state machines fighting for attention, and adding one new feature risks breaking the timing of three others.
That's the wall that pushed me toward a real-time operating system. Working with Zephyr RTOS (and FreeRTOS) changed how I think about firmware architecture entirely. Instead of one giant loop, I could break the system into independent tasks, each with its own priority, and let a deterministic scheduler decide who runs when.
What RTOS taught me:
- Task design is system design. Deciding what becomes its own thread, and at what priority, is one of the most important architectural choices you make.
- Shared state is dangerous. Inter-task communication — queues, semaphores, mutexes — exists because two tasks touching the same variable at the wrong moment is a bug waiting to happen.
- Determinism beats raw speed. In mission-critical systems, a response that's always on time matters more than one that's sometimes fast and sometimes late.
Moving from bare-metal to RTOS felt like going from building a single machine to conducting an orchestra. The individual instruments were the same drivers I'd written before — but now they had to play together, in time.
Giving Devices a Voice:
Connectivity and IoT
A device that can sense and compute is useful. A device that can communicate is powerful.
The next chapter of my journey was connectivity — getting embedded devices to talk to the wider world reliably and, crucially, on a tiny power budget. This meant working with BLE for short-range links and NB-IoT on platforms like the nRF9160 for long-range, low-power industrial telemetry.
IoT firmware introduced a whole new class of problems that bare-metal work never had to worry about:
- The network is unreliable by default. Connections drop. Packets get lost. Your firmware has to recover gracefully instead of hanging forever.
- Power is the real constraint. A device that runs for two days on a battery is a prototype. One that runs for months is a product. Every radio transmission is a withdrawal from the power budget, so you learn to sleep aggressively and wake only when you must.
- Over-the-air updates aren't optional. Once a device is deployed in the field, you need a safe way to update its firmware without bricking it.
Building a low-power monitoring system on the nRF9160 with Zephyr taught me to think about the entire lifecycle of a device — not just "does it work on my desk," but "will it still be working, unattended, months from now."
Making the Edge Think: TinyML and Edge AI
Here's where the journey gets interesting.
For a long time, "smart" devices weren't actually smart — they just shipped raw data to a cloud server, and the intelligence lived somewhere else. That model has real costs: latency, bandwidth, privacy exposure, and a hard dependency on a network connection that might not be there.
Edge AI flips that around. Instead of sending data to the intelligence, you bring the intelligence to the data — running machine learning models directly on the microcontroller, right next to the sensor.
The challenge is brutal: how do you fit a neural network into a device with kilobytes of RAM? The answer is TinyML — quantized, heavily optimized models (often 8-bit integer) that run inference in milliseconds without a cloud round-trip. Tools like TensorFlow Lite and Edge Impulse make this possible, but the real engineering is in the tradeoffs: model size versus accuracy, inference speed versus power draw.
The project that made Edge AI click for me was a Smart Foot Weight Analytics system — a portable, ML-driven device using a high-density force-sensor array to detect postural imbalances and early indicators of musculoskeletal issues. Clinical-grade diagnostics usually require expensive, non-portable equipment. By extracting center-of-pressure trajectories and running classification on-device, the goal was to make early detection accessible and portable. That's the promise of the edge: intelligence where it's needed, not locked away in a data center.
I also got to explore the more experimental side of this during a hackathon, deploying conversational AI voice agents onto physical hardware — an ElevenLabs-powered agent running on a Raspberry Pi 4, bridging embedded hardware with cloud AI into a single interactive system. Different scale, same core idea: putting intelligence into the physical world.
What the Journey Taught Me
Looking back from bare metal to the edge, a few lessons hold across every layer:
- Fundamentals compound. Everything I learned wrestling with registers and timing on bare metal paid off when I moved to RTOS, then to IoT, then to Edge AI. You never leave the fundamentals behind — you build on them.
- The abstraction is a tool, not a truth. RTOS, HALs, and ML frameworks are powerful, but the hardware underneath never disappears. The best debugging still starts with "what is the silicon actually doing?"
- Constraints make you a better engineer. Limited memory, limited power, and real-time deadlines force clarity. There's nowhere to hide sloppy design on a microcontroller.
- Reliability is the real product. Anyone can make a device work once. Making it work every time, for months, unattended — that's the engineering that matters.
Where I'm Headed
The journey isn't finished. Right now I'm going deeper into Digital Signal Processing — FFT-based spectral analysis, digital filtering, and modulation schemes — with a growing fascination for SDR and SATCOM. There's a natural convergence happening between DSP, communication systems, and Edge AI, and I want to be building at that intersection: devices that don't just sense the world, but understand the signals in it.
From a single blinking LED to intelligent edge devices, the throughline has always been the same — the satisfaction of making silicon do exactly what you intend, reliably, in the real world.
I write about embedded systems, firmware, ARM Cortex-M, RTOS, IoT, TinyML, and DSP. If you're working on something in this space — or just want to talk shop — I'd love to connect.
Portfolio: shafqat-ashraf.vercel.app
LinkedIn: muhammad-shafqat-ashraf
GitHub: Shafqat-16
If you found this useful, drop a ❤️ or a comment — and let me know what part of the embedded stack you'd like me to write about next.
Top comments (0)