latest

Introducción a MicroPython. Parte 1

MicroPython es una reimplementación de Python 3 optimizada para correr en microcontroladores y sistemas embebidos. Para este curso de Introducción a MicroPython para desarrollos IoT asumimos que tenéis un nivel básico de programación en Python 3 y entendéis su sintaxis (no se requiere nada más).

- Sí, pero... ¿Qué diantres es un sistema embebido? y ¿un microcontrolador? y ¿Por qué nos interesa tanto programarlos usando MicroPython?..., ¿"I-o-T" qué?

-Umm, está bien, vamos a empezar con esto...

¿Qué es un sistema embebido?

Pues es un sistema electrónico que está pensado para realizar determinadas funciones específicas en servicio de un sistema electrónico mayor del que forma parte, generalmente en formato de tarjeta o placa de circuito impreso (Printed Circuit Board, PCB en inglés). El Arduino Mega de la figura siguiente es un buen ejemplo de sistema embebido basado en un microcontrolador, concretamente el ATmega2560 de 8-bits de Atmel (ahora Microchip Technology), al que se añaden otros Circuitos Integrados (CI o simplemente chips) que agregan funcionalidades adicionales inicialmente no integradas en el microcontrolador.

¿Qué es un Microcontrolador (μC)?

Es un circuito integrado programable, capaz de ejecutar instrucciones previamente grabadas en su memoria de programa (no volátil). Su arquitectura está compuesta de varios bloques funcionales que podéis ver, de manera conceptual, en la siguiente figura. Desde interfaces de comunicación de datos serial/secuencial para los protocolos UART, SPI o I2C, que nos permitirán comunicarnos con otros dispositivos, memorias externas y/o sensores; uno o varios osciladores con diferentes frecuencias; la Unidad Central de Proceso (CPU) que es la encargada de interpretar las instrucciones de nuestros programas, conversores Analógico-Digitales; la memoria volátil que permite el acceso aleatorio (RAM), puertos de Entrada/Salida (E/S) para otros periféricos, etc.

y ¿Qué diferencias hay entre un Microcontrolador y un Microprocesador?

Principalmente, la capacidad de funcionalidad autónoma del μC frente al microprocesador. Me explico:

Para utilizar un microprocesador (como el que contiene nuestro PC) en una aplicación real requerimos múltiple hardware adicional (físicamente separado): un disco duro, módulos de memoria principal externos, una placa base, buses de transmisión de datos empleando cables, un procesador gráfico, una interfaz de red, una fuente de alimentación, etc. El diagrama mostrado a continuación, extraído de este manual, ilustra bien lo que se acaba de decir. Un microprocesador sin el resto componentes hardware no sirve de mucho.

Arquitectura básica de un ordenador 

El chip del μC pretende ser autocontenido, de manera que integre todo lo necesario para ejecutar programas ocupando un espacio ínfimo, al tiempo que se reducen los costes de producción y se facilita su fabricación en masa. Naturalemente, en términos de nivel de cómputo, el microprocesador es más potente, de modo que el propósito funcional de uno y otro es diferente.

A un microcontrolador sólo tendremos necesidad de conectarle una fuente de alimentación o batería, un regulador de voltaje y un oscilador externo. Además, usando sus pines de E/S podremos añadir sensores analógicos y digitales, mecanismos de actuación (pequeñas pantallas, LEDs, servomotores, etc), módulos externos SPI de memoria FLASH para incrementar la capacidad de persistencia, etc; todos gobernados por el μC.

Pero, y ¿Por qué no integramos directamente todos los componentes de un sistema embebido específico en un único circuito integrado o chip?

Básicamente depende del grado de integración que se requiera y el coste que se pueda asumir por unidad de dispositivo integrado. La realidad es que la mayoría de los proyectos de sistemas embebidos fijan sus objetivos en diseños específicos, usando componentes electrónicos concretos para su solución, lo que no suele permitir la integración de todo el sistema en un solo chip, como sí ocurriría con el μC. Como digo, depende también del volumen de producción esperado para cierto dispositivo...

En la práctica, los sistemas embebidos suelen ser diseñados expresamente pensando en optimizar uno o varios procesos específicos que suponen la mayor parte de su rutina cotidiana de funcionamiento.

No obstante, la categorización entre sistemas embebidos y microcontroladores no es tan rígida y existe un punto intermedio. Una alternativa de diseño y fabricación, cuando no es rentable la completa integración del sistema embebido en un único chip, es lo que se conoce como Sistema en Paquete o SiP (System in Package). Un SiP comprende un conjunto de chips ensamblados —no integrados— formando un solo encapsulado/paquete (de ahí el término). Generalmente, uno de los chip ensamblados en el conjunto del SiP es un microcontrolador, pero también encontramos conversores A/D, multiplexores, filtros RC, osciladores, transceptores inalámbricos de diferente tipo, etc.

Podemos aseverar que la fabricación de dispositivos integrados será más y más rentable (por unidad) que la de sistemas SiP,  dado que si crece el volumen de producción, el rendimiento de fabricación unitario para un integrado aumenta.

Los Espressif ESP32-WROOM-32 que vamos a programar con MicroPython en este curso son un buen ejemplo de SiP. En la imagen inferior podéis ver un Espressif ESP32-WROOM-32, una vez se extrae el protector metálico que protege los chips ensamblados. En el centro de la figura de la derecha destaca el circuito integrado ESP32‑D0WDQ6 (que utiliza un encapsulado QFN de 6x6 mm). Dicho chip, es un microcontrolador de bajo coste y bajo consumo de tipo System on Chip (SoC). Con esta denominación se hace referencia a los μC con cierto poder de cómputo, arquitecturas de 32 y 64 bits, memoria RAM integrada >100KB y que suelen integrar también transceptores de comunicación inalámbrica como Wi-Fi, BLE, LTE, LoRa, etc; así como otros módulos funcionales (RFID, GPS, ...).

Espressif ESP32-WROOM-32 (Ejemplo de SiF) 

En particular, el ESP32‑D0WDQ6 integra transceptores Wi-Fi:802.11 b/g/n y Bluetooth: ver. 4.2, un microprocesador TensilicaXtensa LX6 de doble núcleo con 32-bit de tamaño de palabra que puede llegar a los 240MHz, 520KB de RAM y multitud de interfaces y características para conectar dispositivos periféricos: un conversor ADC (Analog-to-Digital Converter) de 12-bit de precisión con hasta 18 canales, 2 conversores DAC de 8-bit, 3 puertos UART, 4 interfaces SPI, 2 interfaces I2C, 2 interfaces I2S, pines de entrada con soporte capacitativo, soporte PWM (Pulse With Modulation) para pines de salida, etc. A modo de resumen, el diagrama mostrado a continuación ilustra todos los bloques funcionales de un ESP32.

Diagramas de bloques funcionales del Espressif ESP32 

Me habéis soltado un rollo de SoCs, SiPs, μCs, U-S-A... ah, bueno! esto último no, pero ¿Por qué quiero programar microcontroladores y sistemas embebidos?

Pues está estrechamente relacionado con el origen y evolución del Internet de la Cosas (IoT).

A diario estamos viviendo un proceso "casi mágico" en el que los objetos cotidianos en nuestras vidas dejan de ser objetos estáticos e inertes y se convierten en objetos con cierta capacidad de autonomía y comunicación.

Autonomía, entendida como la capacidad de elegir cómo actuar ante determinadas situaciones; y comunicación, tanto entre los propios dispositivos (m2m: Machine-to-Machine), como comunicación hombre-dispositivo (h2m: Human-to-Machine).

En este proceso, se establecen determinados comportamientos para dispositivos en el marco del Internet de las Cosas que, de algún modo, los "dota de vida", gracias a la incorporación de sistemas embebidos y μCs, así como de sensores y actuadores que, en su conjunto, convierten a los objetos cotidianos en dispositivos programables.

Vale sí, suena molón eso de "dotar de vida a objetos", "un proceso mágico", aunque se os "va la pinza", pero... ¿Por qué con MicroPython?

Porque MicroPython es una reimplementación de Python 3 y, la verdad, Python mola mucho.

Python se aprende fácil, su uso ya está muy extendido (todos o casi todos seguramente habéis programado en Python alguna vez). Desde nuestro punto de vista, es un lenguaje eficaz, que permite "hacer lo que se pretende en cada momento con código simple y conciso".

En este curso NO os vamos a enseñar a programar en Python 3, no obstante, sólo se requiere un nivel básico de conocimiento de sus sintaxis para poder seguir las distintas implementaciones que se van a llevar a cabo.

Además, otro factor importante en la elección de MicroPython es la cada vez mayor comunidad que se ha decidido a emplearlo para programar sus sistemas embebidos. Sólo hay que echar un ojo a páginas como hackaday o hackster para darse cuenta de ello. Encontramos robots, drones, dispositivos y plataformas sensorizadas de todo tipo para su uso en domótica, agronomía (smart farming), medidores de polución y otros dispositivos equipados con sensores para ciudades inteligentes (smart cities), sistemas embebidos para diferentes procesos de automatización, pequeños juegos hardware, ..., hasta incluso contadores Geiger gobernados por MicroPython.

Salvo contadas excepciones, todas las características del lenguaje Python a nivel de sintaxis están disponibles en MicroPython. Dicho de otra manera,  la forma de programar que conoces de Python es también aplicable en MicroPython. Principalmente tenemos:

  • Orientación a Objetos al estilo de Python 3.
  • Los mismos tipos de datos básicos predefinidos (enteros, numeros en coma flotante, cadenas unicode, booleanos) y estructuras de datos (listas, diccionarios, tuplas y conjuntos).
  • El mismo soporte de manejo de excepciones que en Python 3.
  • Funciones que pueden ser tratadas como variables (funciones de primera clase).
  • Soporte para ejecución de tareas asíncronas no-bloqueantes con las palabras claves async y await (incluidos en Python 3.5), permitiendo la multitarea cooperativa con precisión de milisegundos (OJO! que la concurrencia no es lo mismo que el paralelismo).

Si bien, internamente las diferencias entre las implementaciones de Python 3 y MicroPython son enormes. MicroPython ha sido diseñado para funcionar en sistemas con recursos muy limitados contando con, al menos, 16KB de RAM, lo que resulta increíblemente poco. A diferencia de la versión estándar de Python, MicroPython corre directamente sobre el hardware del  μC / sistema embebido teniendo control directo sobre éste, sin un sistema operativo de por medio.  

Dadas las restricciones a nivel de hardware que imponen los sistemas sobre los que va a correr MicroPython, el firmware adaptado para ellos no puede incluir la librería estándar de Python por completo, como comentaremos, esto va a depender de cada dispositivo de manera específica. De forma que un dispositivo concreto, por ejemplo el Espressif ESP32 que vamos a programar en este curso, tendrá un subconjunto de paquetes y módulos de la librería estándar de Python 3 (CPython), junto con otros no disponibles en dicha librería pero que sean de utilidad, e.j.,  el módulo machineque permite manejar los pines GPIOs (General-Purpose Input / Output) del sistema embebido, entre otras funciones. Los módulos estándar se reimplementarán en busca de la mayor eficiencia en estos sistemas embebidos, reduciendo algunas de sus características, como aquellas que se consideran redundantes o de utilización poco habitual.

En la documentación de MicroPython podemos encontrar un listado de módulos constituidos por clases, constantes, funciones... que bien:

  • Son módulos portados de CPython (concretamente de la versión 3.4 y módulos seleccionados de Python 3.5) que han sido ligeramente reducidos pero que implementan un subconjunto bastante amplio de la funcionalidad del módulo original.
  • Son módulos portados de CPython (concretamente de la versión 3.4 y módulos seleccionados de Python 3.5) que han sido drásticamente miniaturizados, implementando un subconjunto minimalista de la funcionalidad del módulo estándar en CPython (conservando su funcionalidad principal). Este tipo de módulo conserva el nombre de su homónimo en CPython pero antecediendo el prefijo "u" (micro) que lo distingue como su versión minimalista.
  • Módulos implementados en exclusiva para MicroPython que extienden las librerías estándar de Python con nuevas funciones útiles para el sistema embebido.
  • Módulos específicos de un port de MicroPython particular para una placa / sistema embebido concreto y, por lo tanto, no portables. El soporte para la comunicación WiFi en los ESPs es un ejemplo de este tipo de módulos.

El usuario tiene la posibilidad de extender un port de MicroPython con nuevos paquetes y módulos. En línea con esto, el projecto micropython-lib proporciona una librería estándar de MicroPython no monolítica, dividida en módulos o paquete disponibles como paquetes de distribución separados (publicados en PyPI). Dichos paquetes pueden integrarse en el port de MicroPython usando el gestor de paquetes upip.

Y hasta aquí esta primera sesión introductoria a MicroPython. Con lo que hemos comentado aquí ya os podéis hacer una idea de la potencia y el alcance que va a logra MicroPython en los próximos años. Para aquellos desarrolladores de sistemas embebidos acostumbrados a trabajar con C, puede que MicroPython no sea tan rápido ni maneje los recursos limitados de un μC de manera tan eficiente como lo hace C, sin embargo, la facilidad de uso y la productividad que se puede lograr alcanzar con MicroPython, especialmente en las fases iniciales de prototipado, pueden llegar a eclipsar en ocasiones al desarrollo de sistemas embebidos en C.

Continuaremos hablando de los sistemas embebidos y μCs más comunes que pueden programarse con MicroPython en la siguiente parte de este curso de Introducción a MicroPython para desarrollos IoT.

Author image
Iván González is postdoctoral researcher at the Castilla-La Mancha University.
Ciudad Real (Spain)