Compilando desde la consola

El siguiente procedimiento sólo funciona en Linux.

El proyecto Molcajete nació de mi necesidad de compilar programas para Arduino desde una consola, ya que es la forma en que he compilado mis programas de C/C++ los últimos 25 años de mi vida. Y francamente no soporto ni los sketches ni el modelo de súper-loop de Arduino. Además, me gusta tener el control, ¿te has puesto ha pensar dónde está la función main(), la cual es el punto de entrada de todos los programas, incluyendo los basados en sketches? Pues resulta que también me gusta empezar desde la función main().

Sin embargo, no soy lo suficientemente bueno trabajando con archivos Makefile, pero por suerte hay gente que sí lo es. Y fue que encontré el proyecto Arduino-mk que mi sueño se hizo realidad. Luego, resulta que también son fanático del sistema operativo FreeRTOS y pensé, ¿podré integrar FreeRTOS y al mismo tiempo compilar desde la consola? La respuesta fue afirmativa y eme aquí intentando explicarte cómo se hace, esperando que la siguiente información mueva tu curiosidad y también te sea de utilidad.

Tabla de contenidos

¿Qué es y qué necesito?

Los programas multiarchivo en C/C++, como los escritos para Arduino, utilizan la herramienta make para automatizar el proceso de compilación. Este proceso se configura a partir de archivos Makefile’s. Cuando presionas el botón de Verificar/Compilar (ó Ctrl+r) en la IDE de Arduino, ésta se encarga de generar los Makefile’s correspondientes y llamar al compilador. Después, si todo fue bien, presionas el botón Subir (Ctrl+u) y tu programa se sube a tu tarjeta gracias al programa avrdude. Afortunadamente para muchos, todo este proceso es automático; pero habemos algunos que queremos más.

Como mencioné en la introducción, es posible sacar el proceso descrito hacia una consola, gracias al proyecto Arduino-mk. Éste lo podrías instalar por sí solo si así lo quisieras, pero el proyecto Molcajete ya lo incluye, por lo que nada más necesitas descargarlo para tu computadora (actualmente sólo está disponible para Linux y Windows) y descomprimirlo en el lugar de tu preferencia. En este mismo directorio encontrarás las instrucciones para compilar programas en la IDE o en la consola (README.pdf).

A diferencia del trabajo con sketches, aquí son necesarios unos pasos adicionales para instalar un par de cosas: una versión de Arduino y una versión de Arduino-mk. Hice lo posible porque no tuvieras que instalar nada más aparte del proyecto Molcajete, pero no lo logré. Por esta razón deberás instalar:

  • Arduino-core. En una consola (o con tu administrador de paquetes) escribe: sudo apt install arduino-core.
  • Arduino-mk. En la misma consola escribe: sudo apt install arduino-mk.

Por alguna razón los scripts de Arduino-mk requieren que Arduino-core esté instalado, aunque no se use, y no supe cómo evitarlo, así que hay que vivir con ello.

Proyectos de consola

Cada proyecto de consola que realices está formado de al menos dos archivos. Un main.cpp y un Makefile en el mismo directorio. En el archivo main.cpp escribirás la función main(), y el resto de funciones que necesites, aunque es recomendable que dividas tu proyecto en módulos. En el archivo Makefile indicarás, principalmente, la ruta donde descomprimiste al proyecto Molcajete.

main.cpp

Un archivo main.cpp típico se ve así:

// main.cpp

#include <Arduino.h>

#include <FreeRTOS.h>
#include <task.h>

void led_task( void* pvParameters )
{
    (void) pvParameters;

    pinMode( 13, OUTPUT );

    while( 1 )
    {
        digitalWrite( 13, HIGH );

        vTaskDelay( 500 / portTICK_PERIOD_MS );

        digitalWrite( 13, LOW );

        vTaskDelay( 500 / portTICK_PERIOD_MS );
    }
}

void taskAnalog( void* pvParameters )
{
    (void) pvParameters;

    Serial.begin( 115200 );

    while( 1 )
    {
        Serial.println( analogRead( A0 ) );

        vTaskDelay( 1000 / portTICK_PERIOD_MS );
    }
}

int main(void)
{
    cli();

    xTaskCreate( taskLed,
        (const portCHAR *)"LED",
        128,
        NULL,
        tskIDLE_PRIORITY,
        NULL );

    xTaskCreate( taskAnalog,
        (const portCHAR *) "ANLG",
        128,
        NULL,
        tskIDLE_PRIORITY,
        NULL );

    init();
    // inicializa al hardware de Arduino

    vTaskStartScheduler();
    // inicia las operaciones del sistema operativo FreeRTOS

    while( 1 )
    {
        // si hubiera algún error, el programa quedaría atrapado aquí
    }
}

En esta entrada podrás encontrar información detallada de qué son las tareas dinámicas, la función de creación xTaskCreate(), sus parámetros, cómo se inicia al sistema operativo, y cómo se configura tu proyecto en el archivo FreeRTOSConfig.h.

Las diferencias entre un programa basado en sketch y uno de consola son las siguientes (en órden de aparición, es decir de arriba-abajo, del programa anterior):

  • Debes incluir al archivo de encabezado Arduino.h con: #include <Arduino.h>.
  • Debes escribir la función main(), que como sabes es el punto de entrada de cualquier programa escrito en C/C++.
  • La primer instrucción, cli(), deshabilita las interrupciones para que puedas crear tus tareas y arrancar de forma correcta a FreeRTOS. No queremos que interrupciones pendientes
  • Luego puedes crear tus tareas, ya sean estáticas o dinámicas; este procedimiento no tiene nada que ver con su naturaleza.
  • Después debes llamar a la función de Arduino init(). Esta función inicializa el hardware que un programa para Arduino UNO y compatibles necesita. Si olvidas hacerlo tus programas no funcionarán.
  • Lo siguiente es iniciar al sistema operativo con la función de FreeRTOS vTaskStartScheduler().
  • Si el sistema operativo inició correctamente nunca deberías regresar a la función main(). Sin embargo, si algo saliera mal, entonces el programa quedaría atrapado dentro del ciclo infinito para que no se salga de control y que además puedas buscar la fuente de error.

Makefile

Como ya te decía, en este archivo debes indicarle al compilador dónde está la carpeta /arduino-1.8.13 (el nombre puede variar según la versión instalada):

ARDUINO_DIR = /tu/ruta/de/instalación/arduino-1.8.13

Algo que tal vez necesites cambiar es el puerto serial. En Linux, el cual es el sistema operativo que yo uso, nombra (casi siempre) a los adaptadores seriales como /dev/ttyUSB* (y veces los nombra como /dev/tty/ACM*):

ARDUINO_PORT = /dev/ttyUSB*

También puedes cambiar el baudrate del puerto serial, si así lo deseas. Yo uso 115200 BPS (bits por segundo), pero he visto que mucha gente usa 9600 BPS:

MONITOR_BAUDRATE = 115200

Y esos son todos los cambios que deberís hacerle a este archivo.

Compilando y subiendo el proyecto

Es momento de compilar. Pero antes de que lo hagas revisa que tu archivo de configuración FreeRTOSConfig.h esté correcto y actualizado. Visita esta entrada si aún no estás familiarizado con él.

Abre una consola en el directorio donde están tus archivo main.cpp y Makefile, y ejecuta la orden make:

$ make

(El símbolo $ indica el prompt del sistema y no debes escribirlo). Si todo fue correcto, obtendrás una salida parecida a la siguiente con el ejemplo que estamos trabajando:

Extracto del resultado de la compilación del proyecto.

Si obtuviste una salida parecida, entonces toca subir el programa a la tarjeta. Ejecuta la orden make upload:

$ make upload

(Si estás usando alguna de las tarjetas UB-1S328, UB-C328A, o UB-PLR328, entonces deberás presionar y soltar el botón de reset al mismo tiempo que le das ENTER a la instrucción anterior.)

Si todo fue correcto, obtendrás una salida parecida a la siguiente y tu tarjeta ya debería estar ejecutando el programa:

Extracto del resultado de subir el programa a una tarjeta UB-1S328, la cual es una versión minimalista pero compatible con Arduino UNO.

Si tu programa incluye instrucciones del tipo Serial.println(), entonces querrás ver la salida. Para ello tienes dos opciones:

  • Abre la IDE de Arduino e inicia el monitor serial que viene incluído (Ctrl-Shift-m), o
  • En la misma consola abre un monitor ejecutando la instrucción make monitor. Para salir presiona Ctrl-a, k y luego y.
Monitor mostrando lecturas del ADC.

¿Que sigue?

¡Felicidades! Ya compilaste tu primer proyecto de Arduino en la consola utilizando un sistema operativo de tiempo real. Pero si la consola no es lo tuyo, no te preocupes, podrás seguir utilizando los sketches. Utilizar a FreeRTOS, en consola o en sketch, evitará que uses variables globales cuando no son necesarias, y también dejarás de usar el súper-loop de Arduino (función loop()).

Espero que esta entrada haya sido de tu interés. Si fue así podrías suscribirte a mi blog, o escribirme a fjrg76 dot hotmail dot com, o compartir esta entrada con alguien que consideres que puede serle de ayuda.

Índice del curso


Si encuentras este blog interesante, entonces podrías considerar suscribirte a él y recibir información relevante sobre tecnología y sistemas embebidos, y de vez en cuando, uno que otro regalo.

Fco. Javier Rodríguez

Deja una respuesta