En un artículo previo utilicé Arduino-Makefile en debian para crear y
cargar programas arduino. Me pregunto… ¿ahora que estoy utilizando
OpenBSD (7.1, -current
) cambiará mucho como hacerlo?
TL;DR:
Instalar paquetes:
$ doas pkg_add arduino-makefile picocom
Agregar al usuario al grupo dialer
:
$ doas usermod -G dialer jmpc
Utilizar como Makefile
:
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
BOARD_TAG = mega
BOARD_SUB = atmega2560
MONITOR_PORT = /dev/ttyU0
AVRDUDE_CONF = /usr/local/share/examples/avrdude/avrdude.conf
USER_LIB_PATH = libraries
# ARDUINO_LIBS = <...> # no se están incluyendo librerías
include /usr/local/share/arduino-makefile/Arduino.mk
Conectarse a la placa a través del dispositivo /dev/ttyU0
.
Instalación
Comienzo revisando los paquetes disponibles para arduino:
$ pkg_info -Q arduino
arduino-1.8.10v0
arduino-adafruit-gfx-1.7.0
arduino-adafruit-ra8875-1.3.5
arduino-esp32-2.0.1
arduino-esp8266-3.0.2p0
arduino-makefile-1.6.0p2
makeesparduino-6.5.0p1
¡Suerte!, al parecer ya está empaquetado Arduino-Makefile. Se revisa la descripción de ambos paquetes:
$ pkg_info -d arduino arduino-makefile
Information for https://cdn.openbsd.org/pub/OpenBSD/snapshots/packages/amd64/arduino-1.8.10v0.tgz
Description:
Arduino is an open-source electronics prototyping platform based on
flexible, easy-to-use hardware and software. It's intended for artists,
designers, hobbyists, and anyone interested in creating interactive
objects or environments.
Arduino can sense the environment by receiving input from a variety of
sensors and can affect its surroundings by controlling lights, motors,
and other actuators. The microcontroller on the board is programmed
using the Arduino programming language (based on Wiring) and the Arduino
development environment (based on Processing). Arduino projects can be
stand-alone or they can communicate with software running on a computer
(e.g. Flash, Processing, MaxMSP).
This package contains the libraries, header files and tools to develop
Arduino sketches. It does not include the Arduino IDE frontend.
Maintainer: The OpenBSD ports mailing-list <ports@openbsd.org>
WWW: https://www.arduino.cc/
Information for https://cdn.openbsd.org/pub/OpenBSD/snapshots/packages/amd64/arduino-makefile-1.6.0p2.tgz
Description:
This is a very simple Makefile which knows how to build Arduino
sketches. It defines entire workflows for compiling code, flashing
it to Arduino and even communicating through Serial monitor. You
don't need to change anything in the Arduino sketches.
To use, create a Makefile and add:
include /usr/local/share/arduino-makefile/Arduino.mk
Then compile with `gmake` and upload with `gmake upload`.
Maintainer: The OpenBSD ports mailing-list <ports@openbsd.org>
WWW: https://github.com/sudar/Arduino-Makefile
Confirmamos que es lo que estamos buscando. También vemos en la descripción indicaciones de como usar Arduino-Makefile:
- hay que usar
/usr/local/share/arduino-makefile/Arduino.mk
en lugar de/usr/share/arduino/Arduino.mk
que se utiliza en debian - hay que usar el comando gmake - GNU make - en lugar de make - OpenBSD -.
Se revisan las dependencias de los paquetes:
@name arduino-1.8.10v0
@depend devel/avr/binutils:avr-binutils-*:avr-binutils-2.30
@depend devel/avr/gcc:avr-gcc-*:avr-gcc-8.5.0p0
@depend devel/avr/libc:avr-libc-*:avr-libc-2.0.0
@depend devel/avrdude:avrdude-*:avrdude-6.3
@name arduino-makefile-1.6.0p2
@depend devel/arduino:arduino-*:arduino-1.8.10v0
@depend devel/gmake:gmake-*:gmake-4.3
@depend devel/py-serial,python3:py3-serial-*:py3-serial-3.4p2
@depend devel/teensyloader:teensyloader-*:teensyloader-2.2
@depend lang/python/3.9,-main:python->=3.9,<3.10:python-3.9.12
Aquí vemos que arduino-makefile
depende de arduino
, así que vamos a instalar
directamente el primero:
$ doas pkg_add arduino-makefile
Hello World - Blink
Revisando el contenido de los paquetes, vemos ambos traen ejemplos, entre ellos el Hello World! del mundo arduino: Blink.
$ pkg_info -L arduino arduino-makefile | grep /Blink/
/usr/local/share/examples/arduino/01.Basics/Blink/Blink.ino
/usr/local/share/examples/arduino/01.Basics/Blink/Blink.txt
/usr/local/share/examples/arduino-makefile/Blink/Blink.ino
/usr/local/share/examples/arduino-makefile/Blink/Makefile
Revisando la diferencia en los archivos, aparte de los comentarios en un caso se
utiliza el valor del pin 13
y en otro la constante LED_BUILTIN
.
Si bien el archivo /usr/local/share/examples/arduino-makefile/Blink/Makefile
parecería que podría sernos útil, este incluye una ruta relativa a Arduino.mk
que no aplicaría a nuestro caso, ya que vamos a copiar solo el ejemplo y tampoco
aplicaría el valor de la variable BOARD_TAG
, ya que la placa que voy a estar
utilizando como ejemplo es la atmega2560
. Por lo anterior copio el ejemplo
del paquete arduino
y creo un Makefile
a partir del que tenía en el post
anterior con debian con los siguientes cambios:
- se ajusta la de
Arduino.mk
- se comenta
MONITOR_PORT
ya que/dev/ttyACM0
no existe en OpenBSD - se utiliza para
AVRDUDE_CONF
el valor/usr/local/share/examples/avrdude/avrdude.conf
obtenido al revisar los archivos del paquete avrdude (pkg_info -L avrdude
). Se comparó con el archivo /etc/avrdude.conf de debian constatando que son el mismo, solo que debian utiliza una versión más reciente.
$ cp -a /usr/local/share/examples/arduino/01.Basics/Blink .
$ cd Blink
$ cat > Makefile <<'END'
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
BOARD_TAG = mega
BOARD_SUB = atmega2560
# MONITOR_PORT = /dev/ttyACM0 # el dispositivo no existe en OpenBSD
AVRDUDE_CONF = /usr/local/share/examples/avrdude/avrdude.conf
USER_LIB_PATH = libraries
# ARDUINO_LIBS = <...> # no se están incluyendo librerías
include /usr/local/share/arduino-makefile/Arduino.mk
END
Como paso siguiente compilamos con gmake
y vemos que errores se obtienen:
$ gmake
-------------------------
Arduino.mk Configuration:
- [AUTODETECTED] CURRENT_OS = OPENBSD
- [USER] ARDUINO_DIR = /usr/local/share/arduino
- [COMPUTED] ARDMK_DIR = /usr/local/share/arduino-makefile (relative to Common.mk)
- [DEFAULT] ARDUINO_VERSION = 100
- [DEFAULT] ARCHITECTURE =
- [DEFAULT] ARDMK_VENDOR = arduino
- [DEFAULT] ARDUINO_SKETCHBOOK =
- [USER] AVR_TOOLS_DIR = /usr/local
- [COMPUTED] ARDUINO_LIB_PATH = /usr/local/share/arduino/libraries (from ARDUINO_DIR)
- [USER] ALTERNATE_CORE_PATH = /usr/local/share/arduino
- [COMPUTED] ARDUINO_VAR_PATH = /usr/local/share/arduino/variants (from ALTERNATE_CORE_PATH)
- [COMPUTED] BOARDS_TXT = /usr/local/share/arduino/boards.txt (from ALTERNATE_CORE_PATH)
- [USER] USER_LIB_PATH = libraries
- [DEFAULT] PRE_BUILD_HOOK = pre-build-hook.sh
- [USER] BOARD_SUB = atmega2560
- [USER] BOARD_TAG = mega
- [COMPUTED] CORE = arduino (from build.core)
- [COMPUTED] VARIANT = mega (from build.variant)
- [COMPUTED] OBJDIR = build-mega-atmega2560 (from BOARD_TAG)
- [COMPUTED] ARDUINO_CORE_PATH = /usr/local/share/arduino/cores/arduino (from ALTERNATE_CORE_PATH, BOARD_TAG and boards.txt)
- [ASSUMED] MONITOR_BAUDRATE = 9600
- [DEFAULT] OPTIMIZATION_LEVEL = s
- [DEFAULT] MCU_FLAG_NAME = mmcu
- [DEFAULT] CFLAGS_STD = -std=gnu11 -flto -fno-fat-lto-objects
- [DEFAULT] CXXFLAGS_STD = -std=gnu++11 -fno-threadsafe-statics -flto
- [COMPUTED] DEVICE_PATH = /dev/ttyU0 (from MONITOR_PORT)
- [DEFAULT] FORCE_MONITOR_PORT =
- [AUTODETECTED] Size utility: Basic (not AVR-aware)
- [COMPUTED] BOOTLOADER_PARENT = /usr/local/share/arduino/hardware/arduino//bootloaders (from ARDUINO_DIR)
- [COMPUTED] ARDMK_VERSION = 1.5
- [COMPUTED] CC_VERSION = 8.5.0 (avr-gcc)
-------------------------
...
/usr/local/bin/avr-size build-mega-atmega2560/Blink_.hex
text data bss dec hex filename
0 1536 0 1536 600 build-mega-atmega2560/Blink_.hex
De la salida anterior vemos que compiló sin problemas y nos da la pista que el
dispositivo a usar para conectar la placa y subir el programa es /dev/ttyU0
.
Comenzamos revisando el manual:
$ apropos tty
...
tty, cua(4) - general terminal interface
ucom(4) - USB tty support
...
$ man ucom
UCOM(4) Device Drivers Manual UCOM(4)
NAME
ucom – USB tty support
...
FILES
/dev/ttyU? tty devices
/dev/cuaU? call out devices (see tty(4))
Ahora revisando los permisos del dispositivo:
$ ls -lh /dev/ttyU*
crw-rw---- 1 root dialer 66, 0 Apr 17 03:19 /dev/ttyU0
crw-rw---- 1 root dialer 66, 1 Apr 17 03:19 /dev/ttyU1
crw-rw---- 1 root dialer 66, 2 Apr 17 03:19 /dev/ttyU2
crw-rw---- 1 root dialer 66, 3 Apr 17 03:19 /dev/ttyU3
Por lo que tenemos que agregarnos al grupo dialer
:
$ doas usermod -G dialer jmpc
y ahora tenemos que salir de la sesión y volver a entrar para que se cargue el grupo.
Confirmamos que tenemos permisos:
$ groups
jmpc ... dialer ...
Conectamos la placa a un puerto usb y corroboramos que el sistema la detectó:
$ dmesg
umodem0 at uhub0 port 2 configuration 1 interface 0 "Arduino (www.arduino.cc) product 0x0042" rev 1.10/0.01 addr 5
umodem0: data interface 1, has no CM over data, has break
umodem0: status change notification available
ucom0 at umodem0
Ahora intentamos hacer un upload:
$ gmake upload
...
mkdir -p build-mega-atmega2560
gmake reset
gmake[1]: Entering directory '/home/jmpc/tmp/Blink'
/usr/local/bin/ard-reset-arduino /dev/ttyU0
gmake[1]: Leaving directory '/home/jmpc/tmp/Blink'
gmake do_upload
gmake[1]: Entering directory '/home/jmpc/tmp/Blink'
/usr/local/bin/avrdude -q -V -p atmega2560 -C /usr/local/share/examples/avrdude/avrdude.conf -D -c wiring -b 115200 -P /dev/ttyU0 \
-U flash:w:build-mega-atmega2560/Blink_.hex:i
avrdude: AVR device initialized and ready to accept instructions
avrdude: Device signature = 0x1e9801 (probably m2560)
avrdude: reading input file "build-mega-atmega2560/Blink_.hex"
avrdude: writing flash (1536 bytes):
avrdude: 1536 bytes of flash written
avrdude: safemode: Fuses OK (E:FD, H:D8, L:FF)
avrdude done. Thank you.
gmake[1]: Leaving directory '/home/jmpc/tmp/Blink'
Y podemos comprobar que el programa se cargó en la placa y el led está parpadeando.
Leer puerto serie - ASCIITable
Previamente ya vimos que podíamos cargar sin problemas un programa y ejecutarlo.
Ahora se intentará leer información enviada por la placa por el puerto serie.
Nuevamente se partirá de un ejemplo existente, esta vez ASCIITable
:
$ cp -a /usr/local/share/examples/arduino/04.Communication/ASCIITable .
$ cd ASCIITable
$ cat > Makefile <<'END'
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
BOARD_TAG = mega
BOARD_SUB = atmega2560
MONITOR_PORT = /dev/ttyU0
AVRDUDE_CONF = /usr/local/share/examples/avrdude/avrdude.conf
USER_LIB_PATH = libraries
# ARDUINO_LIBS = <...> # no se están incluyendo librerías
include /usr/local/share/arduino-makefile/Arduino.mk
END
Esta vez se explicitó el valor de MONITOR_PORT
ya que sabemos a que
corresponde. El resto de los valores fueron los utilizados (y explicados)
previamente.
Se compila y carga el programa a la placa sin problemas:
$ gmake && gmake upload
...
avrdude: AVR device initialized and ready to accept instructions
avrdude: Device signature = 0x1e9801 (probably m2560)
avrdude: reading input file "build-mega-atmega2560/ASCIITable_.hex"
avrdude: writing flash (2308 bytes):
avrdude: 2308 bytes of flash written
avrdude: safemode: Fuses OK (E:FD, H:D8, L:FF)
avrdude done. Thank you.
gmake[1]: Leaving directory '/home/jmpc/tmp/ASCIITable'
Luego para conectarnos instalamos el programa picocom:
$ doas pkg_add picocom
y luego nos conectamos utilizando:
$ picocom -b 9600 /dev/ttyU0
picocom v3.1
port is : /dev/ttyU0
flowcontrol : none
baudrate is : 9600
parity is : none
databits are : 8
stopbits are : 1
escape is : C-a
local echo is : no
noinit is : no
noreset is : no
hangup is : no
nolock is : no
send_cmd is : sz -vv
receive_cmd is : rz -vv -E
imap is :
omap is :
emap is : crcrlf,delbs,
logfile is : none
initstring : none
exit_after is : not set
exit is : no
Type [C-a] [C-h] to see available commands
Terminal ready
ASCII Table ~ Character Map
!, dec: 33, hex: 21, oct: 41, bin: 100001
", dec: 34, hex: 22, oct: 42, bin: 100010
#, dec: 35, hex: 23, oct: 43, bin: 100011
...
~, dec: 126, hex: 7E, oct: 176, bin: 1111110
Notas:
- La velocidad se obtiene de revisar el código (
ASCIITable.ino
) y corroborar la velocidad a la que se incializa la conexión serial (Serial.begin(9600);
). - En OpenBSD también existe el programa [cu] disponible en el sistema base en lugar de picocom.
Escritura en puerto serie - PhysicalPixel
Al revisar la documentación de cu (que no se utilizó previamente ya que
tengo mayor experiencia utilizando picocom
) se indica de utilizar los
dispositivos /dev/cua??
y leer el manual de cua. En este se encuentra:
For hardware terminal ports, dial-out is supported through matching device nodes called calling units. For instance, the terminal called /dev/tty03 would have a matching calling unit called /dev/cua03.
De aquí que surja la duda de si se puede escribir en el puerto serie utilizando
el dispositivo /dev/ttyU0
(lo que sería lo esperable) o debe utilizarse el
/dev/cuaU0
(y no me imagino escribiendo en una terminal y recibiendo los datos
en otra). Si bien la duda parece venida de una lectura superficial del manual
probemoslo con el ejemplo PhysicalPixel
:
$ cp -a /usr/local/share/examples/arduino/04.Communication/PhysicalPixel .
$ cd PhysicalPixel/
$ cat > Makefile <<'END'
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
BOARD_TAG = mega
BOARD_SUB = atmega2560
MONITOR_PORT = /dev/ttyU0
AVRDUDE_CONF = /usr/local/share/examples/avrdude/avrdude.conf
USER_LIB_PATH = libraries
# ARDUINO_LIBS = <...> # no se están incluyendo librerías
include /usr/local/share/arduino-makefile/Arduino.mk
END
$ gmake
$ gmake upload
Luego nos conectamos a la placa e intentamos mandarle los carácteres L
y H
que apagan y prenden el led interno respectivamente:
$ picocom -b 9600 /dev/ttyU0
Y se corrobora que funciona como se esperaba.
Nota: en este ejemplo se incluye en el archivo layout.png
que puede llevar a
pensar que siempre hay que conectar un led a la placa. Como se indica en la
página del ejemplo:
Many Arduino boards have a built-in LED connected to pin 13; if your board has no built-in LED, attach an external LED to pin 13.
Conclusión
- No hubo mayores problemas para instalar los programas necesarios en OpenBSD ya que estos estaban empaquetados.
- Leyendo la descripción del paquete y teniendo un poco de intuición se pudieron compilar y subir (upload) los programas Blink, ASCIITable y PhysicalPixel de arduino sin problemas.
- Se tuvo suerte en que el parche haya agregado por defecto el valor de
MONITOR_PORT
, lo que permitió encontr la documentación sobre los puertos ucom. - Lo único no indicado en la documentación, pero trivial de solucionar era tener permisos para el dispositivo usb en el cual se conecta la placa.
- La página del manual de ucom y cu me confundió al mencionar el
caso de los
call-out
devices odial-out
respectivamente, pero luego de probar se pudo enviar sin problemas informacion mediante el dispositivo/dev/ttyU0
.
En resumen, ¡igual de fácil que en linux!
Apéndice - Cálculo de MONITOR_PORT
¿Como se calculó el MONITOR_PORT a /dev/ttyU0
?
Suponiendo que el dispositivo es específico de OpenBSD o los BSD en general, ya
que en linux es /dev/ttyACM0
, se busca en los parches del port y se
encuentra en patch-Common_mk:
+ ifndef MONITOR_PORT
+ MONITOR_PORT = /dev/ttyU0
+ endif
Apéndice - Uso de cu
Buscando en internet por el uso de arduino en OpenBSD encuentro los posts:
- Arduino Development on OpenBSD en el blog de Joshua Stein, quien agregó el port Arduino-Makefile a OpenBSD
- Run lisp on Arduino using OpenBSD en el blog de Peter Ljung.
En estos se indica el uso de cu
pero utilizan el dispositivo /dev/cuaU0
en
lugar de /dev/ttyU0
:
$ cu -l /dev/cuaU0 -s 9600
Volviendo a probar los programas Blink
, ASCIITable
y PhysicalPixel
utilizando /dev/cuaU0
en lugar de /dev/ttyU0
, los programas funcionaron
igual.