En esta entrada continuamos con la entrada anterior del blog donde veíamos el hardware necesario para crear un dispositivo LoRa, veremos como instalar las herramientas software necesarias para usar la placa con las librerías de Arduino y configuraremos el microcontrolador para usarlo con el resto de componentes del esquema.
Toda la información para poner a funcionar la placa la encontramos en este repositorio, en él nos explica como añadir el microcontrolador al entorno de Arduino. Por lo que lo primero si no lo tenemos ya es descargar e instalar el entorno de Arduino del siguiente enlace. Siempre que instalemos un entorno de programación es aconsejable hacerlo en el idioma inglés, debido a que cuando nos de errores será más fácil buscar el error en inglés que en cualquier otro idioma.
Una vez instalado el entorno de Arduino lo abrimos, siguiendo los pasos del repositorio anterior nos vamos a File>Preferences y en “Additional Boards Managers URLs” introducimos la dirección: https://mcudude.github.io/MegaCoreX/package_MCUdude_MegaCoreX_index.json
A continuación en la imagen inferior nos vamos a Tools>Board>Boards Manager e instalamos MegaCoreX en el entorno de Arduino.
Una vez instalada la placa la seleccionamos en el entorno de Arduino yendo a Tools>Board como se ve en la imagen inferior, configuramos los FUSES del microcontrolador de la siguiente forma.
- BOD: BOD disabled.
- Bootloader: No bootloader.
- Clock: 5 MHz (la frecuencia máxima del reloj es función del nivel mínimo de tensión al que alimentemos el microcontrolador, con la batería de 2xAAA debemos seleccionar 5MHz).
- EEPROM: EEPROM not retained.
- Pinout: 28 pin standard.
- Reset pin: Reset (el pin de Reset se puede usar como una entrada/salida o como pin de reset, ya que lo usamos conectado al timer para esta función lo configuramos como tal).
Escribimos el siguiente programa en el entorno de Arduino que hará parpadear el LED de la placa una vez por segundo.
Para descargar el código en la placa no tenemos que quemar un Bootloader en la placa ya que estamos usando un programador. Cuando tengamos el programa listo nos vamos a Sketch>”Upload Using Programmer” para subirlo a la placa, debemos iniciar el entorno de Arduino con el programador conectado para que nos de opción de seleccionar el puerto de este en el menú de Tools.
Una vez que le damos a subir el programa, si todo está bien configurado, el LED de la placa empezará a parpadear una vez por segundo y los FUSES de configuración del microcontrolador se quedarán grabados en este.
Si has hecho todo lo anterior y tienes experiencia en programación, puedes haber visto lo suficiente para quizás pensar que el entorno de Arduino no es una herramienta adecuada para desarrollar código, aunque si es simple y adecuada para la gente con menos experiencia siendo este su objetivo principal.
Para escribir el código de estas entradas del blog vamos a irnos a un entorno de desarrollo más completo como es PlatformIO. Para instalar PlatformIO comenzamos instalando Visual Studio Code.
Una vez instalado Visual Studio Code pulsamos en el botón de Extensions (flecha roja en la imagen inferior).
Y buscamos PlatformIO IDE y lo instalamos.
Una vez que lo instalamos accedemos a PlatformIO pulsando su botón (flecha roja con un 1 en la imagen inferior).
Para crear un nuevo proyecto pulsamos en Open (flecha roja con un 2) y en New Project (flecha roja con un 3), se nos abre la ventana de la imagen inferior donde damos nombre al proyecto, seleccionamos el ATmega4808 en Board y en el Framework Arduino.
Creado el nuevo proyecto lo primero que vemos en PlatformIO es el archivo platformio.ini, este es un fichero donde se configura el entorno del proyecto y el hardware del microcontrolador (los FUSES, paso que hicimos en Arduino).
Antes de editar el archivo platformio.ini vamos a instalar pymcuprog que necesitaremos para subir el programa que hagamos a nuestra placa usando el programador. Lo hacemos como nos explica Ricardo (la persona que lleva los talleres de Arduino en la Asociación Maker de Alicante) aquí, para instalarlo pulsamos en la flecha roja de la imagen inferior para abrir el monitor serie y escribir pip install pymcuprog.
Una vez instalado pymcuprog nos vamos a platformio.ini y añadimos las siguientes líneas (enlace al repositorio con el código de esta entrada). En este enlace encontramos las opciones de configuración para nuestro microcontrolador que podemos añadir a platformio.ini.
En la última línea de la imagen superior vemos “COM5”, este es el puerto del ordenador al que está conectado nuestro programador, en el Admninistrador de dispositivos de Windows encontramos donde está el programador en: Puertos (COM y LPT) como USB-SERIAL CH430. Por lo que aquí cada uno tendrá que poner el puerto que utilice su ordenador, aunque también se puede configurar PlatformIO para que lo detecte de manera automática.
En el archivo platformio.ini se puede añadir la configuración de los FUSES para grabarlos en el microcontrolador sin tener que recurrir al paso anterior en el entorno de Arduino, no he mirado como se hace debido a que para grabar (y comprobar) los FUSES suelo usar un programador de Atmel desde el IDE de desarrollo de Atmel (es el que suelo usar para trabajar con sus microcontroladores). En este taller de la asociación es la primera vez que he usado PlatformIO y muy pocas veces antes había utilizado Arduino, por lo que no estoy familiarizado con ninguno de los dos.
Dicho lo anterior en el explorador del proyecto de PlatformIO vamos a src>main.cpp, escribimos un código de prueba que encienda y apague el LED de la placa una vez por segundo.
Ponemos el interruptor del programador en modo UPDI, seleccionamos su opción de 3V (nunca podemos poner la de 5V con esta placa o se dañará la radio) y si la placa no tiene una batería conectada activamos el interruptor de alimentar la placa desde el programador. Pulsamos el botón de la imagen superior con la flecha roja, si todo está bien configurado el programa se subirá y LED de la placa LoRa empezará a parpadear una vez por segundo.
Configurados los FUSES de la placa en Arduino, probado el programador e instalado el entorno de programación PlatformIO, vamos a comenzar a crear el código necesario para poder utilizar el microcontrolador con los componentes electrónicos a los que lo hemos conectado en el esquema.
El código que vamos a usar para esta entrada lo podemos encontrar aquí, necesitaremos descargar y añadir al proyecto librerías. Vamos a añadir la librería necesaria para poner a dormir al microrcontrolador, para ello pulsamos en los botones en el orden de las flechas numeradas de la imagen inferior.
Necesitamos la librería Rocket Scream LowPowerAVRZero, pulsamos sobre ella (flecha roja con el número 4 de la imagen superior) y le damos al botón de Add to Project en la imagen inferior.
Se nos abre una ventana donde seleccionamos el proyecto donde queremos añadir la librería (seleccionamos el que hemos creado) y pulsamos añadir. Una vez añadida si nos vamos al archivo platformio.ini veremos que se ha añadido la línea: lib_deps = rocketscream/Rocket Scream LowPowerAVRZero@^1.0.0 que se corresponde con la librería añadida.
En la imagen inferior en el explorador del proyecto rojo vemos los ficheros de código que vamos a crear para esta prueba de la placa.
El código de esta entrada del blog lo podemos encontrar en este enlace y cada línea está explicada en los comentarios del código, paso a hablar de los aspectos más importantes de cada archivo.
Fichero platformio.ini: enlace.
Este fichero ya lo hemos visto, después de instalar la librería veremos que se ha añadio una línea con la librería. Faltaría configurar este fichero para programar los FUSES del microcontrolador sin tener que recurrir al entorno de Arduino para ello.
Ficheros pines.h: enlace y pines.cpp: enlace.
En estos ficheros asignamos un nombre a los pines del microcontrolador que conectamos a otros componentes en el esquema de la placa, cuando tengamos que usar el pin conectado al LED será más fácil de recordar y legible en el código si llamamos a este pin LED en lugar de PA0.
Para definir un pin podemos usar dos notaciones: la del nombre del pin del microcontrolador o la de Arduino, en la imagen inferior vemos el nombre que Arduino asigna a cada pin.
En la imagen superior en azul vemos como Arduino llama a cada pin del microcontrolador. Podemos usar #define RFM95_RST PIN_PD6 o #define LED RFMP5_RST A6. PIN_D6 y A6 tienen ambos asignado el valor de 18 en las librerías de Arduino, por lo que es igual usar una notación u otra.
En la serigrafía de la placa está la notación de Arduino, pero supongo que si hay una revisión de la placa cambiará a la de los pines del microcontrolador, ya que esta es más práctica e identifica directamente a que pìn del microcontrolador está referida.
En pines.cpp hacemos una función que configura los pines del microcontrolador que se vayan a usar en el programa, también configura el hardware de los pines que no estén conectados a nada para que consuman menos corriente utilizando la librería que hemos instalado.
Ficheros adc.h: enlace y adc.cpp: enlace.
En estos ficheros vamos a incluir una función para leer la tensión de la batería conectada al microcontrolador. Para leer el valor de tensión de la batería no vamos a usar ningún pin del microcontrolador si no que lo vamos a hacer con el método que se explica en esta nota de aplicación de Microchip/Atmel.
Lo que hacemos es conectar la referencia de tensión del módulo ADC del microcontrolador a la tensión de alimentación del microcontrolador, es decir a la tensión de la batería ya que conectamos la alimentación de la placa directamente a la batería sin usar ningún regulador. Como entrada del ADC usamos una referencia de tensión interna conocida, por lo que leyendo el valor del ADC podemos comparar ambas tensiones y calcular el valor de la tensión desconocida que alimenta al microcontrolador.
En PlatformIO (y en Arduino) podemos programar usando las abstracción del hardware del microcontrolador que nos proporcionan las librerías de Arduino, o programar sin usar estas librerías de Arduino manipulando directamente los registro del microcontrolador. Para crear esta función del ADC se ha hecho de esta última forma, ya que no hay una librería de Arduino (o no la he encontrado) ya hecha para la tarea. Microchip tiene esta nota de aplicación que podemos considerar seguir y nos indica el nombre de los registros, máscaras, referencia a bits, etc.. en sus librerías para programar el microcontrolador a nivel de registro.
Leer la batería de esta forma nos evita tener que usar componentes adicionales en la placa, si no lo hacemos así tendríamos que usar un divisor resistivo, un MOSFET para activarlo y desactivalor y no incrementar el consumo de corriente debido a este divisor cuando el microcontrolador duerme, y dos pines del microcontrolador para la tarea. Las ventajas de usar este método para conocer la carga de la batería son notables.
Si usamos el ADC para leer otros sensores en nuestra placa conectados a los pines analógicos, tendrémos que estar conmutando la tensión de referencia del ADC cada vez que queramos hacer una lectura de la batería o del pin analógico.
Fichero main.cpp: enlace.
Como su nombre indica este es el fichero principal que debe tener todo programa y en él se encuentra el setup() y el loop() del entorno de Arduino, donde reside el objeto del programa.
En main.cpp hemos hecho un programa que manda el valor de tensión de la batería por el puerto serie del microcontrolador conectado al programador, para comuicarnos con el microcontrolador y poder visualizar ese valor abriremos un monitor serie en PlatformIO. El microcontrolador se despertará cada vez que reciba un pulso del timer, mandará el valor de la batería y se volverá a dormir.
setup() se ejecuta una vez cuando se inicia el programa y en él llamamos a las funciones que configuran los pines del microcontrolador y el ADC. También en esta línea de código indicamos que función va a atender a la interrupción del timer.
Con la línea de código anterior lo que programamos es que cuando el microcontrolador reciba un pulso de flanco de subida en el pin done está conectado el timer, este se despierta o interrumpe lo que esté haciendo para llamar y ejecutar la función isr_timer. A este tipo de funciones se les denominan ISR (Interrupt Service Routine) y por lo general queremos que el código que escribimos dentro de ellas se ejecute lo más rápido posible, ya que hasta que el microcontrolador no termina de ejecutar una ISR no puede ejecutar otras interrupciones que puedan ocurrir de igual o menor prioridad.
El pulso de DONE con el que le respondemos al timer nunca lo generaremos dentro de la ISR del timer, debido a que si el programa se queda colgado en algún bucle el código de la ISR se seguirá ejecutando, ya que interrumpe el programa para ir a esta. Si metemos el pulso de DONE dentro de la ISR del timer perdemos la función de watchdog que tiene el timer.
A nivel de hardware el pin en el que el microcontrolador recibe el pulso del timer tiene que ser asícrono, ya que necesitamos que se despierte por flanco sin ningún reloj del microcontrolador funcionando. Si el pin del microcontrolador donde conectamos el pulso del timer no es asíncrono, la interrupción la tendríamos que configurar como CHANGE en lugar de RISING, lo que provocaría que entrasemos dos veces en la ISR por cada pulso recibido.
loop() es el bucle principal de Arduino que se ejecuta de manera continua, el código que encontramos en él es el siguiente:
Al inicio de loop() mandamos el pulso DONE al timer si ha ocurrido una interrupción, leemos el valor de tensión de la batería y lo mandamos por el puerto serie para visualizarlo en el entorno de PlatformIO. Cuando se ejeculta la instrucción LowPower.powerDown(); el microcontrolador para su reloj y se pone a dormir, cuando recibe el pulso del timer se despierta, ejecuta isr_timer y el programa continua justo después de las instrucción LowPower.powerDown();.
Compilamos el programa y si no tenemos errores conectamos el programador a nuestra placa, ponemos su interruptor en modo UPDI y pulsamos descargar el programa al microcontrolador. Una vez programado cambiamos el interruptor del programador de modo UPDI a modo UART, en PlatformIO pulsamos en el botón de la imagen inferior para abrir un monitor serie donde poder visualizar los mensajes que nos manda la placa.
Si todo está bien la placa nos mandará el valor de la tensión a la que está conectada una vez por minuto (configuración de la resistencia del timer).
Si comentamos la línea de Serial.print que está justo después de la instrucción de poner el microcontrolador a dormir, podemos ver cuanto tarda el microcontrolador en despertarse y generar el pulso DONE usando las librerías de Arduino
Power Profiler Kit II.
Para saber si el microcontrolador se está poniendo a dormir correctamente debemos observar el consumo de corriente de la placa. Para ello lo mejor es usar un “power profiler”, una herramienta que nos permite observar el consumo de corriente de la placa a lo largo del tiempo, y que cuando trabajamos con este tipo de dispositivos es totalmente necesario tener.
La mejor opción de bajo coste diría que es el Power Profiler Kit 2 de Nordic, nos permite alimentar a la placa a tensión que confiuremos entre 0.8V y 5V y observar su consumo de corriente, tomando 100k muestras por segundo.
En la imagen superior vemos el power profiler conectado al ordenador para alimentar a nuestra placa y medir su consumo, en la pantalla del ordenador nos mostraría lo siguiente cuando la placa ejecuta el programa que hemos subido.
La imagen superior muestra la pantalla del Power Profiler Kit II, en ella podemos ver el consumo del microcontrolador a lo largo del tiempo. Su ventana nos permite ver hasta el último minuto capturado y nos permite hacer zoom en la zona que nos interese, pudiendo medir tiempo como se muestra en la imagen. Captura en la que vemos los cerca de 500 ms que permance el microcontrolador despierto en nuestro programa antes de volverse a dormir.
Para ser un equipo de bajo coste la frecuencia de muestreo y precisión de las medidas es más que suficiente para muchos desarrollos, si hacemos zoom a la zona en la que el microcontrolador está durmiendo vemos lo siguiente.
Nos muestra un consumo de 0.27 uA. Esto es así ya que para tomar esta medida hemos desconectado el módulo de la radio (que no estamos usando en el programa) de la alimentación positiva de la batería, obteniendo un consumo de la placa bastante inferior al de 1 uA que veíamos en la entrada anterior.
Desconectando de la alimentación positiva de la placa el módulo de la radio que no estamos usando en el programa medimos con el multímetro que la placa consume tan solo 0.17 uA (microcontrolador + TPL5010 + resto de componentes), lo que coincide con el datasheet del microcontrolador que nos indica un consumo tipico de 0.1 uA @ 25ºC cuando está durmiendo.
Para terminar esta entrada solo comentar que para desconectar un componente de la alimentación no basta solo con apagar (mediante un MOSFET por ejemplo) su línea de alimentación positiva, si no que tenemos que pensar en todas las pistas que van al componte y que pueden tener un nivel de tensión positivo en este caso.
En la imagen superior vemos que la radio toma su alimentación positiva (Vcc) por el pin 13, si solo desconectasemos Vcc de este pin pero dejamos por ejemplo el pin 5 conectado a Vcc a través de R1, el integrado consumiría corriente (en este caso cientos de uA debido a R1 de 10k).
Esto es así porque aunque el pin 5 del RFM95W no sea un pin de alimentación (en este caso es un pin de entrada del interfaz SPI) este lleva diodos de protección ESD internos en el circuito integrado de la radio, que van conectados desde el pin 5 a Vcc y GND del integrado.
Los diodos de protección ESD son comunes en muchos circuitos integrados, y en estos diseños de bajo consumo es habitual apagar partes del circuito y solo encenderlas cuando las vamos a usar. Por lo que siempre tenemos que considerar apagar no solo las alimentaciones de esas partes, si no ver las líneas de señales que se puedan comunicar con los componentes de las partes que apagamos y ver si es necesario añadir algún tipo de buffer por ejemplo, que deje esas líneas en alta impedancia cuando alguna de las partes está sin alimentación.
No me extiendo más. Hemos visto en esta entrada como instalar el entorno de programación y configurar el microcontrolador para usarlo con la placa, en la siguiente entrada usaremos la librería LMIC de MCCI-Catena para conectar la radio a distintas redes LoRaWAN.
Si has leído hasta aquí espero que haya sido útil :).