Last Updated: 

Mastering MicroPython on Microcontrollers (MCU)

Microcontrollers (MCUs) are at the heart of countless embedded systems, enabling the control of various devices with limited resources. MicroPython, a lean and efficient implementation of the Python 3 programming language that includes a small subset of the Python standard library, brings the power and simplicity of Python to MCUs. This blog post aims to provide a comprehensive guide to using MicroPython on MCUs, covering fundamental concepts, usage methods, common practices, and best practices.

Table of Contents#

  1. Fundamental Concepts
  2. Getting Started: Usage Methods
  3. Common Practices
  4. Best Practices
  5. Conclusion
  6. References

Fundamental Concepts#

What is MicroPython?#

MicroPython is a lightweight implementation of the Python programming language optimized for microcontrollers and constrained environments. It provides a high-level programming interface, allowing developers to write code quickly and efficiently without having to deal with low-level details like memory management in most cases.

What are Microcontrollers?#

Microcontrollers are integrated circuits that contain a processor core, memory, and input/output peripherals on a single chip. They are designed for embedded systems, where they can perform specific tasks with limited power and resources. Examples of popular MCUs compatible with MicroPython include the ESP32, Raspberry Pi Pico, and Micro:bit.

Why Use MicroPython on MCUs?#

  • Ease of Use: Python is a beginner-friendly language with a simple syntax, which reduces the learning curve for new developers.
  • Rapid Development: You can write and test code much faster compared to traditional low-level languages like C or assembly.
  • Libraries and Modules: MicroPython comes with a set of built-in libraries for interacting with hardware peripherals, such as GPIO, I2C, and SPI.

Getting Started: Usage Methods#

Step 1: Choose an MCU#

Select an MCU that supports MicroPython. For example, the Raspberry Pi Pico is a popular choice due to its low cost and easy-to-use hardware.

Step 2: Install MicroPython Firmware#

  1. Download the MicroPython firmware for your chosen MCU from the official MicroPython website.
  2. Put the MCU into bootloader mode. For the Raspberry Pi Pico, you need to hold down the BOOTSEL button while plugging it into your computer.
  3. Drag and drop the downloaded firmware file onto the mass storage device that appears.

Step 3: Set Up a Development Environment#

You can use a serial terminal program like PuTTY (for Windows) or Minicom (for Linux) to interact with the MicroPython REPL (Read - Evaluate - Print Loop). Another popular option is Thonny, an integrated development environment (IDE) specifically designed for MicroPython.

Step 4: Write and Run Your First Program#

Here is a simple example to blink an LED on the Raspberry Pi Pico:

import machine
import time
 
# Define the GPIO pin connected to the LED
led = machine.Pin(25, machine.Pin.OUT)
 
while True:
    led.on()
    time.sleep(1)
    led.off()
    time.sleep(1)

To run this code:

  1. Open Thonny and connect to your MCU.
  2. Copy and paste the code into the Thonny editor.
  3. Click the "Run" button to upload and execute the code on the MCU.

Common Practices#

Reading and Writing GPIO Pins#

import machine
 
# Set up a GPIO pin as an input
button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)
 
# Set up a GPIO pin as an output
led = machine.Pin(25, machine.Pin.OUT)
 
while True:
    if button.value() == 0:
        led.on()
    else:
        led.off()

Using I2C Communication#

import machine
 
# Initialize I2C
i2c = machine.I2C(0, scl=machine.Pin(1), sda=machine.Pin(0))
 
# Scan for I2C devices
devices = i2c.scan()
if devices:
    for device in devices:
        print(f"Found device at address: 0x{device:02x}")

PWM (Pulse Width Modulation)#

import machine
import time
 
# Initialize PWM on a GPIO pin
pwm = machine.PWM(machine.Pin(25))
pwm.freq(1000)  # Set the frequency to 1000 Hz
 
while True:
    for duty in range(0, 65536, 100):
        pwm.duty_u16(duty)
        time.sleep(0.01)
    for duty in range(65535, -1, -100):
        pwm.duty_u16(duty)
        time.sleep(0.01)

Best Practices#

Memory Management#

  • Avoid Global Variables: Global variables consume more memory than local variables. Use local variables whenever possible.
  • Delete Unused Objects: Explicitly delete objects that are no longer needed using the del keyword to free up memory.
# Example of deleting an unused object
my_list = [1, 2, 3]
# Do something with my_list
del my_list

Error Handling#

  • Use Try - Except Blocks: Wrap your code in try - except blocks to handle errors gracefully. This prevents your program from crashing in case of unexpected events.
try:
    # Code that might raise an error
    result = 1 / 0
except ZeroDivisionError:
    print("Error: Division by zero")

Code Organization#

  • Modularize Your Code: Break your code into smaller functions and modules. This makes your code easier to read, test, and maintain.
def blink_led():
    import machine
    import time
    led = machine.Pin(25, machine.Pin.OUT)
    while True:
        led.on()
        time.sleep(1)
        led.off()
        time.sleep(1)
 
 
if __name__ == "__main__":
    blink_led()

Conclusion#

MicroPython on MCUs offers a powerful and accessible way to develop embedded systems. With its high-level programming interface, rapid development capabilities, and support for various hardware peripherals, it is a great choice for both beginners and experienced developers. By understanding the fundamental concepts, following the usage methods, adopting common practices, and implementing best practices, you can efficiently use MicroPython to build innovative embedded projects.

References#