Interfacing an Arduino Uno (uploading etc.) with the Arduino IDE (using the Fedora package) works fine under Fedora 21.
But I rather want to use vim + make + vim-quickfix-mode etc.
How can I do that?
Preferably via the tools available from the Fedora repositories.
I assume that the IDE calls externals command line utilities for the uploading etc.
The equivalent to the IDE's serial monitor is probably connecting a terminal emulator (e.g. screen
) to /dev/ttyACM0
, right?
Perhaps there is a good example project one can look at the makefile?
6 Answers 6
I use the command-line interface to the arduino
command.
I run it like this:
arduino --upload sketch/sketch.ino --port /dev/ttyUSB*
There is a page which describes other command-line tools, like inotool
. That page also has an example Makefile
. These alternatives seem enticing, but apparently, as of this writing, none of them work. I'm assuming this is due to some recent changes in Arduino IDE distribution files which they depend on.
Running arduino
as above is a bit slow, because it has to load Java I guess, but at least it works. There is also an arduino-builder
command that comes with the Arduino IDE distribution. As of this writing, it was not sufficiently well-documented for me to be able to figure out how to use it. For instance there are no example command lines in the README or in any of the tutorials I came across, and I couldn't figure out how to use it to upload code to the board. However, presumably it is able to give us a faster compile than arduino
. The README also mentions being able to reuse object files from a previous compile, so there is some make-like functionality.
To view serial output I use something like
stty -F /dev/ttyUSB* 1000000 raw -clocal -echo
cat /dev/ttyUSB*
The number 1000000 should match the number you pass to Serial.begin()
in your board code. You can also use screen
if you have a board program which is appropriately interactive, or you can use whatever utility to write directly to the device. By the way, my Due shows up as /dev/ttyACM0
(rather than /dev/ttyUSB0
for the Uno).
-
1Make sure you have a single
*.ino
file in the directory, as it does not seem to necessarily upload the one mentioned by the--upload
parameter.Chris Stryczynski– Chris Stryczynski2019年04月19日 12:39:22 +00:00Commented Apr 19, 2019 at 12:39 -
No X11 DISPLAY variable was set, but this program performed an operation which requires it. For meJackie– Jackie2020年04月11日 02:51:54 +00:00Commented Apr 11, 2020 at 2:51
I would suggest Googling for Makefile projects. I did one a while back for the Blink program, by basically seeing what got generated by the IDE and replicating that in a more general way.
#
# Simple Arduino Makefile
#
# Author: Nick Gammon
# Date: 18th March 2015
# where you installed the Arduino app
ARDUINO_DIR = C:/Documents and Settings/Nick/Desktop/arduino-1.0.6/
# various programs
CC = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-gcc"
CPP = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-g++"
AR = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-ar"
OBJ_COPY = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-objcopy"
MAIN_SKETCH = Blink.cpp
# compile flags for g++ and gcc
# may need to change these
F_CPU = 16000000
MCU = atmega328p
# compile flags
GENERAL_FLAGS = -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=$(MCU) -DF_CPU=$(F_CPU)L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=106
CPP_FLAGS = $(GENERAL_FLAGS) -fno-exceptions
CC_FLAGS = $(GENERAL_FLAGS)
# location of include files
INCLUDE_FILES = "-I$(ARDUINO_DIR)hardware/arduino/cores/arduino" "-I$(ARDUINO_DIR)hardware/arduino/variants/standard"
# library sources
LIBRARY_DIR = "$(ARDUINO_DIR)hardware/arduino/cores/arduino/"
build:
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(MAIN_SKETCH) -o $(MAIN_SKETCH).o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)avr-libc/malloc.c -o malloc.c.o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)avr-libc/realloc.c -o realloc.c.o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)WInterrupts.c -o WInterrupts.c.o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring.c -o wiring.c.o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_analog.c -o wiring_analog.c.o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_digital.c -o wiring_digital.c.o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_pulse.c -o wiring_pulse.c.o
$(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_shift.c -o wiring_shift.c.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)CDC.cpp -o CDC.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)HardwareSerial.cpp -o HardwareSerial.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)HID.cpp -o HID.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)IPAddress.cpp -o IPAddress.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)main.cpp -o main.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)new.cpp -o new.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)Print.cpp -o Print.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)Stream.cpp -o Stream.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)Tone.cpp -o Tone.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)USBCore.cpp -o USBCore.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)WMath.cpp -o WMath.cpp.o
$(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)WString.cpp -o WString.cpp.o
rm core.a
$(AR) rcs core.a malloc.c.o
$(AR) rcs core.a realloc.c.o
$(AR) rcs core.a WInterrupts.c.o
$(AR) rcs core.a wiring.c.o
$(AR) rcs core.a wiring_analog.c.o
$(AR) rcs core.a wiring_digital.c.o
$(AR) rcs core.a wiring_pulse.c.o
$(AR) rcs core.a wiring_shift.c.o
$(AR) rcs core.a CDC.cpp.o
$(AR) rcs core.a HardwareSerial.cpp.o
$(AR) rcs core.a HID.cpp.o
$(AR) rcs core.a IPAddress.cpp.o
$(AR) rcs core.a main.cpp.o
$(AR) rcs core.a new.cpp.o
$(AR) rcs core.a Print.cpp.o
$(AR) rcs core.a Stream.cpp.o
$(AR) rcs core.a Tone.cpp.o
$(AR) rcs core.a USBCore.cpp.o
$(AR) rcs core.a WMath.cpp.o
$(AR) rcs core.a WString.cpp.o
$(CC) -Os -Wl,--gc-sections -mmcu=$(MCU) -o $(MAIN_SKETCH).elf $(MAIN_SKETCH).o core.a -lm
$(OBJ_COPY) -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 $(MAIN_SKETCH).elf $(MAIN_SKETCH).eep
$(OBJ_COPY) -O ihex -R .eeprom $(MAIN_SKETCH).elf $(MAIN_SKETCH).hex
You would need to change ARDUINO_DIR
at least, to reflect where you installed the IDE. If you use other things like the Wire library you would need to expand it somewhat to compile additional libraries. Again, you can use what the IDE generates itself to guide your changes.
The lines with the leading spaces above would need the tab character instead of spaces, as is normal for a Makefile.
-
2An upload section in the make file would also be useful, to upload the compiled sketch to the arduino (using avr-dude).Gerben– Gerben2015年09月08日 09:04:24 +00:00Commented Sep 8, 2015 at 9:04
-
That would definitely be useful. However as, so far, the IDE has met my needs for compiling and uploading, I am not strongly motivated to work out how to do it. :)2015年09月08日 09:46:54 +00:00Commented Sep 8, 2015 at 9:46
-
Take a look at Metamorphic answer for an easier solutionVictor Lamoine– Victor Lamoine2017年09月30日 21:48:14 +00:00Commented Sep 30, 2017 at 21:48
-
Someone suggested editing out the statement "I would suggest Googling for Makefile projects." on the grounds that people probably reached this page from Google anyway. However I think it is still a helpful suggestion, especially in direct response to the posted question. My answer gave one suggested way of achieving the result, a Google search may supply others.2021年04月01日 05:05:12 +00:00Commented Apr 1, 2021 at 5:05
What you need is a Makefile. There are a few Makefile projects around for Arduino. Googling for "Arduino Makefile" returns many results including what looks like a good one on Github: https://github.com/sudar/Arduino-Makefile
Compiling from the command line isn't trivial due to the way the Arduino IDE handles libraries.
The equivalent to the IDE's serial monitor is probably connecting a terminal emulator (e.g. screen) to /dev/ttyACM0, right?
For the serial monitor I would recommend minicom. It is a fully functional terminal emulator (vt102) on the command line.
minicom -D /dev/ttyACM0 -b 115200
... for example.
-
2This Makefile is essentially a maintained version of the accepted answer. There is also a template project on GitHub that shows you how to set it up: github.com/ladislas/Bare-Arduino-ProjectStefan van der Walt– Stefan van der Walt2019年10月14日 20:14:01 +00:00Commented Oct 14, 2019 at 20:14
Official CLI tool
The arduino team is developing a cli client https://github.com/arduino/arduino-cli
Announcement: https://blog.arduino.cc/2018/08/24/announcing-the-arduino-command-line-interface-cli/
You can do almost everything with this, from downloading boards and libraries, to compile and upload scripts. What's missing is the monitoring part (you can use Metamorphic's method using stty
cat
, It works!)
The commands are very similar to Metamorphic's answer since this tool is branching out of that one
Instructions in the Github repo and the man page:
$ arduino-cli Arduino Command Line Interface (arduino-cli).
Usage: arduino-cli [command]
Examples: arduino <command> [flags...]
Available Commands:
board Arduino board commands.
compile Compiles Arduino sketches.
config Arduino Configuration Commands.
core Arduino Core operations.
help Help about any command
lib Arduino commands about libraries.
sketch Arduino CLI Sketch Commands.
upload Upload Arduino sketches.
version Shows version number of Arduino CLI.
If you want a fully compatible solution for your arduino project (yes, you can share your project with other people that use just plain Arduino IDE) you need to check amake a tool to simplify the cli of the arduino, I use it with Geany but others are using it with vi, Atom, etc.
It's inspired and the now dead Ino and Arturo projects; please take 5 minutes to test it and please give feedback.
Example use:
cd ~/Arduino/Blink/
[move to your arduino project folder]
amake -v uno Blink.ino
[to compile/verify your code]
amake -u uno Blink.ino /dev/ttyUSB0
[to upload your code to an arduino connected via USB]
It has some smart glue in there, it can remember the board and file, and even autodetect the usb of the board; so after a successfull "amake -v" command you can do this on the command line and it will work.
amake -v
[to compile/verify your code]
amake -u
[to upload your code to an arduino connected via USB]
If you use some IDE macros you can craft the compile and upload commands easily, for example using Geany IDE it will became:
- Compile/Verify: cd %d; amake -v uno %f
- Upload: cd %d; amake -u uno %f
You can get more help running just "amake" or "amake -h" once installed.
Also, it can support EVERY board/lib/programmer you have installed/configured in your Arduino IDE, yes, modern board like the Adafuit Trinket M0 / Arduino M0 etc...
Just fire your Arduino IDE, go to the board manager, install support and that's all, jut follow some simple instructions and your are set.
The board you have is not supported? not a problem, detect the fqbn (read the README.md file) and pass it along as the board name.
I'm looking for testers to grow up the number or board aliases and auto detection of the proper USB signatures.
Remember this is a private grown tool, now shared with the public, you know, just a programmer scratching it's itch...
Cheers.
A great way to compile for and flash an Arduino device from the command line and integrate with Vim is to use PlatformIO Core (CLI).
Since it's written in Python it's easy to install even when it's not packaged for your Linux distribution. PlatformIO supports many microcontroller devices, not just Arduino ones. Thus, you don't have to switch your development environment when you target another platform. PlatformIO takes care of downloading the right toolchain (compiler etc.) for your target.
Example
Getting started with PlatformIO and an Arduino Pro Mini 3.3v clone on Fedora 35:
mkdir -p ~/local
cd ~/local
python -m venv platformio
source platformio/bin/activate
pip install platformio
This installs PlatformIO (CLI) in a virtual environment, i.e. its main command is then available from ~/local/platformio/bin/pio
and pio
is found in your PATH
when the virtual environment is activated.
Next, we need to find the right board ID for setting up a new project:
pio boards arduino | less
That means search for Pro.*Mini
in the listing. There are several versions of the Pro Mini, in our example the pro8MHzatmega328
(3.3 V, 8 MHz, ATmega328, 30 kb flash, 2 kB RAM) is the right one as can be validated by looking at the board markings as well as its voltage regulator, and CPU markings.
To set up a new project
mkdir ~/project/some_new_project
cd ~/project/some_new_project
pio project init --board pro8MHzatmega328 --ide vim
Which prints:
The current working directory /home/juser/project/arduino/pro-mini will be used for the project.
The next files/directories have been created in /home/juser/arduino/pro-mini
include - Put project header files here
lib - Put here project specific (private) libraries
src - Put project source files here
platformio.ini - Project Configuration File
Platform Manager: Installing atmelavr
Downloading [####################################] 100%
Unpacking [####################################] 100%
Platform Manager: atmelavr @ 3.4.0 has been installed!
Tool Manager: Installing platformio/toolchain-atmelavr @ ~1.70300.0
Downloading [####################################] 100%
Unpacking [####################################] 100%
Tool Manager: toolchain-atmelavr @ 1.70300.191015 has been installed!
The platform 'atmelavr' has been successfully installed!
The rest of the packages will be installed later depending on your build environment.
Project has been successfully initialized including configuration files for `vim` IDE.
For a first test one can copy a simple blink-led example using the usual setup()
/loop()
functions. It's possible to re-use an existing 'sketch' from the Arduino IDE, one just has to add #include <Arduino.h>
at the top and place it under src/some-name.cc
or src/some-name.cpp
.
To compile everything:
pio run
Which prints:
Processing pro8MHzatmega328 (platform: atmelavr; board: pro8MHzatmega328; framework: arduino)
--------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/pro8MHzatmega328.html
PLATFORM: Atmel AVR (3.4.0) > Arduino Pro or Pro Mini ATmega328 (3.3V, 8 MHz)
HARDWARE: ATMEGA328P 8MHz, 2KB RAM, 30KB Flash
DEBUG: Current (avr-stub) On-board (avr-stub, simavr)
PACKAGES:
- framework-arduino-avr 5.1.0
- toolchain-atmelavr 1.70300.191015 (7.3.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 5 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio/build/pro8MHzatmega328/src/sos-switch.cc.o
Linking .pio/build/pro8MHzatmega328/firmware.elf
Checking size .pio/build/pro8MHzatmega328/firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM: [ ] 0.4% (used 9 bytes from 2048 bytes)
Flash: [ ] 3.8% (used 1170 bytes from 30720 bytes)
========================= [SUCCESS] Took 0.51 seconds =========================
So for this example I created src/sos-switch.cc
which is compiled to .pio/build/.../sos-switch.cc.o
.
To upload (flash) the device:
pio run --target upload
As always, a common pitfall are the permissions of the USB device. For example, on Fedora, my USB2TTL serial device registers as /dev/ttyUSB0
with read-write permissions for just root:dialout
. Thus, you have to add your user to the dialout
group or adjust the permissions by other means.
Vim Quickfix Mode
For integrating with Vim's quickfix mode a simple makefile is sufficient, e.g.:
.PHONY: all
all: build
.PHONY: build
build:
pio run
.PHONY: upload
upload:
pio run --target upload
Thus, everything is built when :make
is invoked in Vim, and there one can navigate the quickfix mode as usual.
Serial Monitoring
An easy way to monitor the serial interface is to use picocom, e.g.:
picocom --baud 9600 --echo --imap lfcrlf --noreset /dev/ttyUSB0
where:
--imap lfcrlf
maps newline to carriage return + newline such that we can just writeSerial.print("multi\nlines\n')
instead ofSerial.print("multi\r\nlines\r\n")
in our program--noreset
tells picocom to not clear DTR - without it, when DTR is connected, the Anrdoid device is reset
Of course, one has to terminate picocom when uploading.
Alternatively, one can use the PlatformIO monitor command:
pio device monitor
In contrast to picocom, it doesn't require explicit mapping or DTR handling. However, as with picocom, it must be terminated when uploading/flashing. That means PlatformIO doesn't automatically suspends monitoring when pio run --target upload
is invoked.
Closing Remarks
- PlatformIO is currently packaged for Fedora and thus might be directly available in Fedora 36 or so
- the classic Arduino IDE was packaged for Fedora, but isn't available anymore in Fedora 35 because of the big Java package exodus
- there is also a PlatoformIO plugin for VSCode which seems to be quite popular
-
1Nice answer. Re "
--imap lfcrlf
": This is not needed if you useSerial.println()
, which is the "Arduino way" of printing a new line.Edgar Bonet– Edgar Bonet2022年01月01日 21:05:40 +00:00Commented Jan 1, 2022 at 21:05 -
@EdgarBonet yes,
Serial.println()
writes\r\n
, thus we don't need the mapping if it's used exclusively. However, both the classic Arduino IDE and the PlatformIO monitor implicitly map\n
to\r\n
such that you get away with single\n
. If you transmit\r\n
you might end up with\r\r\n
, which doesn't hurt. Even if your program usesSerial.println()
you still might use\n
in multi-line strings. Updated my answer to illustrate this point. However, for an end-user facing console, it makes sense to stick to\r\n
and detect oversights by not having such a mapping.maxschlepzig– maxschlepzig2022年01月02日 11:38:53 +00:00Commented Jan 2, 2022 at 11:38
arduino-cli
tool is extremely good. You can make a very simple 2 lineMakefile
in no time.