DEI.
Fab Academy · Week 4 · Lab Rwanda

Embedded Programming

Writing firmware that runs on microcontrollers to control hardware, reading sensors, processing data, and driving outputs like LEDs and motors under tight memory and power constraints.

Introduction

What is Embedded Programming?

Embedded programming is the process of writing firmware that runs on a microcontroller or microprocessor to control hardware components and perform specific tasks. It enables the system to read inputs from sensors, process data, and control outputs such as motors, LEDs, and displays, operating continuously with limited memory and power resources.

During Week 4 of Fab Academy, we dived deep into microcontrollers, explored different programming languages, and wrapped up with a series of assignments.

Group Assignment
Toolchain Comparison
  • Demonstrate and compare the toolchains and development workflows for available embedded architectures. Read it on our group assignment page.
Individual Assignment
Build & Program
  • Browse through the datasheet for a microcontroller
  • Write and test a program using a microcontroller with input/output devices and wired or wireless communication
  • Extra credit: Assemble the physical system
  • Extra credit: Try different languages and/or development environments
Group Assignment

Comparing Toolchains and Workflows

As a lab we compared the toolchains and development workflows for the embedded architectures we had on hand. The full write up lives on our group assignment page. Here is what I took from it and how it shaped the path I chose for my own work.

We looked at three ways to write and flash firmware for an ESP32: the Arduino IDE, ESP-IDF, and PlatformIO. They all end up talking to the same chip, but they feel very different to use and they trade ease of use against control.

Arduino IDESimplest to start. One window, one Verify button, one Upload button. It hides the build system and gives you the Arduino core (pinMode, digitalWrite, Serial). Huge library ecosystem. Best for learning and quick prototypes. Less control over the lower layers and the board config can feel hidden.
ESP-IDFEspressif's own framework. You work in C with FreeRTOS, menuconfig, and CMake. Full control of every peripheral and memory setting. This is what production ESP32 firmware usually ships on. Steeper to learn and slower to get a first blink running.
PlatformIOA build system and package manager that runs inside VS Code. It can target both the Arduino core and ESP-IDF, manages libraries per project, and keeps the board config in one platformio.ini file. More setup than the Arduino IDE but far more repeatable across machines and boards.

The pattern is clear. The Arduino IDE trades control for speed, ESP-IDF trades speed for control, and PlatformIO sits in the middle with proper project files and dependency tracking. Because my goal this week was to interact and communicate fast, I started in the Arduino IDE and the Wokwi simulator, which both use the Arduino core. As ORDER, my final project, grows I plan to move into PlatformIO so the build stays the same on every machine in the lab.

Microcontroller

ESP32

The ESP32 is a powerful and versatile microcontroller with built-in WiFi and Bluetooth, making it ideal for IoT projects. It features multiple GPIO pins, analog and digital inputs, and supports I2C, SPI, and UART communication, all while staying energy-efficient.

I opened the Espressif datasheet and read through it before writing any code, because it is the device I am building ORDER around. The button at the right opens the same PDF I used. The numbers that mattered to me were the operating voltage of 3.3V (so a 5V signal can damage a pin), the 12-bit ADC for reading analog sensors, the GPIO count, and the three serial buses I would lean on later. I pulled the key figures into the table below.

ESP32 microcontroller board
ESP32 Development Board
ESP32 board variants compared
The ESP32 family: the original ESP32, the S2, the S3 and the C3
CoreTensilica Xtensa Dual-Core 32-bit LX6
Voltage3.3V
Clock SpeedUp to 240 MHz
Flash MemoryTypically 4MB
SRAM520 KB
GPIO PinsUp to 36 configurable
ADC12-bit ADC (analog inputs)
DAC2x 8-bit outputs
WiFi802.11 b/g/n, station, soft-AP, P2P
Bluetoothv4.2 BR/EDR and BLE
PowerUltra-low power sleep modes
ESP32

A dual-core, WiFi + Bluetooth capable microcontroller built for the Internet of Things. Low power, high performance, and easy to prototype with.

Communication Protocols
UART

Serial comms, sensors, GPS, modems

SPI

High-speed, displays, SD cards

I2C

Multi-device via two wires (SDA & SCL)

CAN

Automotive/industrial variants

PWM

Motors, LEDs, servos

ADC / DAC

Analog read and output

GPIO

Switches, LEDs, relays

↓ View ESP32 Datasheet (PDF)
From the datasheet

What I pulled from the datasheet for programming

I read through the ESP32 datasheet and pulled out the parts that actually change how I write code and wire pins. This is my quick reference for the rest of the embedded weeks.

The numbers that matter

ItemValue
CoreXtensa dual core LX6, up to 240 MHz
Memory520 KB SRAM, 448 KB ROM, 16 KB RTC SRAM
RadiosWiFi 802.11 b/g/n (up to 150 Mbps), Bluetooth 4.2 and BLE
Working voltage2.3 to 3.6 V, use 3.3 V, supply 500 mA or more
GPIOs34 programmable pins
ADC12 bit, up to 18 channels
DACtwo 8 bit, true analog out
Touch10 capacitive touch pins
Buses4 SPI, 2 I2C, 2 I2S, 3 UART, CAN (TWAI), 16 channel LED PWM
Deep sleepabout 10 microamps

GPIO rules I have to respect

Analog and touch pins

Default pins for talking to things

BusTypical ESP32 pins
UART0 (USB serial and flashing)TX on GPIO1, RX on GPIO3
I2C (Arduino default)SDA on GPIO21, SCL on GPIO22
SPI (VSPI)MOSI 23, MISO 19, SCK 18, CS 5

The pins above are the common defaults. The ESP32 has a GPIO matrix, so most buses can be moved to other pins in code, as long as I avoid the flash pins and the input only pins.

How flashing actually works

GPIO0 decides the boot mode at reset. Held low it enters download mode so a new program can be written over UART, released high it just runs the program already in flash. That is exactly what the BOOT button does, and the EN pin (CHIP_PU) is the reset. So the flashing dance is: hold BOOT, tap EN, upload, release BOOT.

Getting Started · Wokwi

ESP32 Blink LED

Using Wokwi, a browser-based circuit simulator, to prototype the classic blink LED without any physical hardware. Follow along step by step:

01

Sign up on Wokwi, then click Create New Project

Create new project in Wokwi
Wokwi, Create New Project screen
02

Select ESP32 as the target microcontroller board

Choosing ESP32 in Wokwi
Selecting the ESP32 board
03

Started testing with the built-in LED, but LED_BUILTIN is a reserved keyword and caused a conflict

LED_BUILTIN keyword issue
Attempting to use the LED_BUILTIN keyword
04

Defined a custom pin variable to replace the reserved keyword and resolved the conflict

Updated code with custom pin name
Updated code with a custom pin definition
05

Drew the full circuit schematic inside the Wokwi workspace

Circuit schematic in Wokwi
Circuit schematic, drawing phase
06

Added a protection resistor, even though ESP32 pin current is limited, this is best practice for circuit safety

Complete Wokwi blink circuit
Complete circuit with protection resistor
07

Full Working Demonstration, the LED blinks as programmed

ESP32 wired to a red LED on GPIO12 in Wokwi
The ESP32 wired to the red LED on GPIO12 in Wokwi
ESP32 Blink, live simulation demo
08

The full code I used. You can copy it and paste it straight into the Arduino IDE or Wokwi. I gave my LED pin its own name so it does not clash with the reserved keyword.

blink.inocopy
// ESP32 blink, my own pin name so LED_BUILTIN does not clash
int ledPin = 2;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  digitalWrite(ledPin, HIGH);
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(1000);
}
My ESP32
My ESP32
Input & Output Interaction

Arduino with Tinkercad

Arduino is a beginner-friendly microcontroller with great input/output support, though it lacks built-in wireless connectivity. Inputs, push buttons, temperature sensors, light sensors, soil moisture sensors, let it sense the environment. Outputs, LEDs, motors, relays, buzzers, displays, let it respond and act.

By processing input data through programmed logic and generating appropriate outputs, Arduino can automate systems for robotics, home automation, and smart agriculture. For this section we used Tinkercad, a browser-based simulator by Autodesk.

Components Used
Arduino Uno Battery Resistor LED Push Button
01

Opened Tinkercad and started with a fresh circuit workspace

Tinkercad workspace
Getting started with Tinkercad
02

Searched for and added the Arduino board to the workspace

Adding Arduino to Tinkercad
Searching and adding the Arduino board
03

Added remaining components, resistor, battery, LED, and push button

Adding components in Tinkercad
Adding resistor, battery, LED, and button
04

Wired all components together following the circuit diagram

Connecting components
Components being connected
05

Circuit fully connected and verified

Fully connected circuit
Fully connected circuit
06

Labelled the circuit for clarity before writing code

Labelled circuit in Tinkercad
Labelled and annotated circuit
Complete Tinkercad circuit, Arduino UNO with LED, button and 9V battery
The complete Tinkercad circuit, Arduino UNO with an LED, a button and a 9V battery
07

Writing the Code, programmed the button input and LED output logic in C++

Writing the Arduino code in Tinkercad
08

Simulation, ran the simulation and adjusted the resistor value because the LED brightness was too low

Final simulation with corrected resistor value
Takeaways

Conclusion

I studied a great deal this week and interacted extensively with inputs and outputs using beginner-friendly microcontrollers. I worked with low-level languages like C++, and I am now building my Python skills to use Thonny IDE as confidently as I use the Arduino IDE.

Communicate

Talking Back Over Serial

Blinking an LED is the board interacting with the world through a local output. The next step the assignment asks for is to communicate, so the board sends data off the chip and not only flips a pin. The simplest path is the serial port over the USB cable. I started the serial line at 115200 baud and printed a counter once a second, so I could watch the board talk in the Serial Monitor while the same loop kept the LED blinking. This is wired communication.

This is the same sketch as the blink, with the serial calls added. Copy it into the Arduino IDE or Wokwi, then open the Serial Monitor at 115200 baud to see the messages.

blink_serial.inocopy
// ESP32 interact and communicate
// the LED is the local output, Serial is the wired link back to my computer
int ledPin = 2;
int blinkCount = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  Serial.println("ESP32 is awake and listening");
}

void loop() {
  digitalWrite(ledPin, HIGH);
  delay(1000);
  digitalWrite(ledPin, LOW);
  delay(1000);

  blinkCount = blinkCount + 1;
  Serial.print("Blink number ");
  Serial.println(blinkCount);
}

Serial over USB is the wired link. The reason I picked the ESP32 in the first place is that it also carries the wireless path I need for ORDER. The same chip does WiFi (802.11 b/g/n) and Bluetooth Low Energy, so later weeks the board will send orders over WiFi instead of a cable. The serial print I run here is the first rung of that ladder. I prove the board can talk on the wire now, then move the same idea onto WiFi and BLE when the project needs it.

Wokwi simulation running with the Serial Monitor printing LED ON and LED OFF
The simulation running: the Serial Monitor prints LED ON and LED OFF in step with the blink
Source Files