Python in embedded systems means running Python on microcontrollers (using MicroPython or CircuitPython) or on embedded Linux boards (using standard Python) to read sensors, control hardware and connect devices to the cloud. It shines in prototyping, IoT and automation. C and C++ still lead for hard real-time, ultra-low-power and tightly memory-limited firmware.If you came up through the traditional route, embedded systems probably means C, register maps and a datasheet open in the next tab. Then someone shows you a microcontroller blinking an LED in three lines of Python, and the natural reaction is: “Wait, that actually runs on a chip?”
It does, and it is far more than a party trick. Here is the honest picture up front: Python will not replace C in production firmware, but it has earned a permanent place in the embedded toolbox. Whether you are an engineering student, a fresher or an experienced C developer, this guide shows you where, why and how.
Python in embedded systems is the use of the Python language to program, control, test or support embedded hardware, either directly on the device or alongside it on a PC.
That “alongside it” part matters. Most beginners see only one-third of the picture. Python appears in three places:
gpiozero, RPi.GPIO, OpenCV, NumPywest, PlatformIO, esptool and pyOCD are all Python-basedPro Tip: When someone says “Python can’t be used in embedded,” ask which of these three they mean. Usually they only mean the second one.
Python is gaining ground because it shortens the path from idea to working prototype, and modern microcontrollers are finally powerful enough to run it.
There are three main ways to run Python on embedded hardware: standard CPython on Linux boards, MicroPython on microcontrollers, and CircuitPython, a beginner-friendly fork of MicroPython.
| Flavor | Runs on | Typical hardware | Best for |
|---|---|---|---|
| CPython (standard Python) | Embedded Linux | Raspberry Pi, BeagleBone, Jetson | Gateways, vision, edge AI |
| MicroPython | Bare-metal microcontrollers | Pico, ESP32, STM32, nRF52 | Prototypes, IoT nodes, sensor logic |
| CircuitPython | Bare-metal microcontrollers | Adafruit boards, Pico, ESP32-S2/S3, nRF52840 | Beginners, learning, quick demos |
CIRCUITPY. Save code.py and it runs instantlymachine module. CircuitPython uses board, digitalio, busio and friendsOn a microcontroller, Python does not run like a normal PC program. The chip runs a small firmware that contains a Python interpreter, and that interpreter executes your script.
Think of the MicroPython firmware as a translator living inside the chip: you speak Python, it speaks to the hardware. (If you’re new to the hardware side, brush up on how a microcontroller works first.)
Your script (main.py)
|
MicroPython runtime (bytecode compiler + virtual machine + garbage collector)
|
Hardware drivers (machine module: Pin, ADC, I2C, SPI, UART...)
|
Microcontroller peripherals (GPIO, ADC, timers, communication blocks)boot.py runs (optional early setup)main.py runs (your application). CircuitPython looks for code.py instead.mpy files and “frozen” modules (built into the firmware) save RAM and startup timemachine Module ExplainedIn MicroPython, the machine module is the bridge between your Python code and the chip’s peripherals, and each object maps to a core embedded concept you already know from C.
| MicroPython object | What it controls | Embedded concept |
|---|---|---|
Pin | LEDs, buttons, digital signals | GPIO |
ADC | Analog sensors | Analog-to-digital conversion |
PWM | Dimming, servo and motor speed | Pulse width modulation |
I2C / SoftI2C | Sensors, OLED displays, RTC chips | I2C protocol |
SPI | SD cards, fast displays, RFID readers | SPI protocol |
UART | GPS, GSM and Bluetooth modules | Serial communication |
Timer | Periodic tasks | Hardware timers and interrupts |
WDT | Auto-recovery from hangs | Watchdog timer |
Pin(25) means GPIO25, not physical pin 25Remember: Python hides syntax, not physics. You still need pull-up resistors, debouncing and a datasheet.
| Board family | Chip | Why choose it | Python support |
|---|---|---|---|
| Raspberry Pi Pico, Pico W, Pico 2 | RP2040 / RP2350 | Beginner-friendly, dual-core, programmable I/O (PIO) | MicroPython, CircuitPython |
| ESP32, ESP32-S3, ESP32-C3 | Espressif | Built-in Wi-Fi and Bluetooth for IoT | MicroPython; CircuitPython on S2/S3/C3 variants |
| STM32 boards (Nucleo, Pyboard) | STM32 | Industrial-grade MCUs, rich peripherals | MicroPython; selected boards on CircuitPython |
| nRF52840 boards | Nordic | Bluetooth Low Energy, low power | CircuitPython, MicroPython |
| Raspberry Pi 4/5, BeagleBone | Linux SBCs | Full OS, camera, networking, AI | Standard Python (CPython) |
.uf2 firmware for your board from micropython.org.uf2 file onto the drive. The board reboots by itselfprint("Hello, embedded world") and press Enteresptool instead of drag-and-dropmpremote (the official tool) handles the REPL and file copying. VS Code with the MicroPico extension is another good optionThese examples target a Raspberry Pi Pico. Pin numbers differ on other boards, so check your pinout first.
from machine import Pin
import time
led = Pin(25, Pin.OUT) # onboard LED on Pico (use Pin("LED", Pin.OUT) on Pico W)
while True:
led.toggle()
time.sleep(0.5)from machine import ADC
import time
sensor = ADC(4) # internal temperature sensor on RP2040
factor = 3.3 / 65535 # scale the 16-bit reading to volts
while True:
voltage = sensor.read_u16() * factor
temp_c = 27 - (voltage - 0.706) / 0.001721
print("Temperature: {:.1f} C".format(temp_c))
time.sleep(1)read_u16() returns a value from 0 to 65535, even though the Pico’s ADC is 12-bit. MicroPython scales it for youfrom machine import Pin
import time
led = Pin(25, Pin.OUT)
button = Pin(14, Pin.IN, Pin.PULL_UP)
last_press = 0
def on_press(pin):
global last_press
now = time.ticks_ms()
if time.ticks_diff(now, last_press) > 200: # ignore bounces within 200 ms
led.toggle()
last_press = now
button.irq(trigger=Pin.IRQ_FALLING, handler=on_press)
while True:
time.sleep_ms(100) # main loop stays free for other workPULL_UP means the pin reads HIGH until the button (wired to GND) pulls it LOWmicropython.alloc_emergency_exception_buf(100) early so errors inside interrupts show a readable messageimport asyncio
from machine import Pin
led = Pin(25, Pin.OUT)
async def blink(delay_ms):
while True:
led.toggle()
await asyncio.sleep_ms(delay_ms)
async def monitor():
while True:
print("Checking sensors...")
await asyncio.sleep(2)
async def main():
asyncio.create_task(blink(500))
await monitor()
asyncio.run(main())uasyncioimport serial # pip install pyserial
with serial.Serial("COM3", 115200, timeout=1) as port:
while True:
line = port.readline().decode(errors="ignore").strip()
if line:
print(line)/dev/ttyACM0 or /dev/ttyUSB0 on Linux instead of COM3C and C++ are faster, smaller and more predictable than Python on a microcontroller, while Python is quicker to write, easier to read and better for prototyping.
| Factor | Python (MicroPython) | C / C++ |
|---|---|---|
| Execution speed | Slower (interpreted bytecode) | Fastest (compiled machine code) |
| Memory use | Higher (runtime, heap, garbage collector) | Minimal and fully controllable |
| Real-time determinism | Weaker (GC pauses, interpreter overhead) | Strong (bare-metal or RTOS) |
| Development speed | Very fast (REPL, no compile step) | Slower (compile, flash, debug cycle) |
| Hardware control | Good through libraries, limited cycle-level control | Complete (registers, DMA, interrupts) |
| Power efficiency | Fine for periodic tasks | Best for coin-cell and battery designs |
| Learning curve | Gentle | Steeper (pointers, memory, registers) |
| Safety-critical use | Rare | Standard (MISRA C, ISO 26262, IEC 62304) |
| Best for | Prototypes, IoT, tooling, learning | Production firmware, drivers, hard real-time |
Python is used in embedded systems for IoT devices, prototyping, test automation, edge AI, robotics and data logging, mostly where timing is flexible and development speed matters.
pymodbus and pushing data to dashboardsPython struggles in embedded systems when you need hard real-time timing, tiny memory footprints, maximum battery life or safety certification.
MemoryError on small chipsYou can cut Python’s overhead on a microcontroller by controlling memory allocation, using pre-compiled code and handing timing-critical work to hardware.
bytearray and memoryview instead of creating new objects inside loopsgc.collect() at moments you choose and watch gc.mem_free()const(): from micropython import const for fixed values@micropython.native and @micropython.viper often give a big speedup (viper needs typed code).mpy: saves RAM and startup timetime.sleep() callsmachine.WDT recovers the device from hangstry/except and recover with a retry or resettime.ticks_ms() and time.ticks_diff() for timing instead of time.time()machine.deepsleep() for battery projectstime.sleep() callsMemoryError until the device crashes in the fieldThe smoothest path is Python basics first, hardware fundamentals second, MicroPython projects third, and embedded C last to complement it.
| Project | Hardware | You will practice |
|---|---|---|
| Temperature and humidity logger | ESP32 + BME280 | I2C, JSON, MQTT |
| Smart plant monitor | Pico + soil moisture sensor + OLED | ADC, I2C display |
| Door-open alert | ESP32 + reed switch | Interrupts, Wi-Fi notifications |
| RFID attendance system | Pico or ESP32 + MFRC522 | SPI, data storage |
| BLE beacon scanner | ESP32 or nRF52840 | Bluetooth Low Energy |
Python will not replace C, but it is becoming a permanent part of the embedded toolbox.
For the bigger career picture, read about the scope of embedded systems in the future.
Python has quietly moved from “hobby language” to a practical part of embedded development. Whether you are prototyping a sensor node, automating a test bench or building an IoT gateway, it lets you move faster, and C is still there when you need every cycle.
Pick a board, run the blink example, then push on to sensors and Wi-Fi. That is how real skill gets built.
Yes. Python runs on embedded Linux boards as standard Python and on microcontrollers as MicroPython or CircuitPython. It is also widely used on the PC side for testing, logging and tooling.
It is good for prototyping, IoT, automation and learning, where development speed matters more than microsecond timing. For hard real-time, ultra-low-power or safety-critical firmware, C and C++ remain the better choice.
MicroPython is a lean implementation of Python 3 built for microcontrollers. It includes the core language, a subset of the standard library and hardware modules like machine. Standard Python needs an operating system and far more memory.
For soft real-time tasks, such as sensor polling or display updates, yes. For hard real-time, where a missed deadline is a failure, use C/C++ with an RTOS or hardware peripherals.
Popular choices include Raspberry Pi Pico (RP2040/RP2350), the ESP32 family, STM32 boards and Nordic nRF52840. Check the official MicroPython and CircuitPython board lists for your exact board.
Indian Institute of Embedded Systems – IIES