user13174: 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?

user46477: 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.

user13174: 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 write Serial.print("multi\nlines\n') instead of Serial.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


user4143: 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.

user48663: 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.


user10794: 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.

user21201: 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).

13174: <p>Interfacing an Arduino Uno (uploading etc.) with the Arduino IDE (using the Fedora package) works fine under Fedora 21.</p>

<p>But I rather want to use vim + make + vim-quickfix-mode etc.</p>

<p>How can I do that?</p>

<p>Preferably via the tools available from the Fedora repositories.</p>

<p>I assume that the IDE calls externals command line utilities for the uploading etc.</p>

<p>The equivalent to the IDE's serial monitor is probably connecting a terminal emulator (e.g. <code>screen</code>) to <code>/dev/ttyACM0</code>, right?</p>

<p>Perhaps there is a good example project one can look at the makefile?</p>
 46477: <p>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 <a href="https://github.com/pavelmc/amake" rel="nofollow noreferrer">amake</a> a tool to simplify the cli of the arduino, I use it with Geany but others are using it with vi, Atom, etc.</p>

<p>It's inspired and the now dead Ino and Arturo projects; please take 5 minutes to test it and please give feedback.</p>

<p>Example use:</p>

<pre><code>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]
</code></pre>

<p>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.</p>

<pre><code>amake -v
[to compile/verify your code]

amake -u
[to upload your code to an arduino connected via USB]
</code></pre>

<p>If you use some IDE macros you can craft the compile and upload commands easily, for example using Geany IDE it will became:</p>

<ul>
<li><strong>Compile/Verify:</strong> cd %d; amake -v uno %f</li>
<li><strong>Upload:</strong> cd %d; amake -u uno %f</li>
</ul>

<p>You can get more help running just "amake" or "amake -h" once installed.</p>

<p>Also, it can support <strong>EVERY</strong> board/lib/programmer you have installed/configured in your Arduino IDE, yes, modern board like the Adafuit Trinket M0 / Arduino M0 etc...</p>

<p>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.</p>

<p>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.</p>

<p>I'm looking for testers to grow up the number or board aliases and auto detection of the proper USB signatures.</p>

<p>Remember this is a private grown tool, now shared with the public, you know, just a programmer scratching it's itch...</p>

<p>Cheers.</p>
 13174: <p>A great way to compile for and flash an Arduino device from the command line and integrate with Vim is to use <a href="https://docs.platformio.org/en/latest/core/index.html" rel="nofollow noreferrer">PlatformIO Core (CLI)</a>.</p>
<p>Since it's written in Python it's easy to install even when it's not packaged for your Linux distribution. PlatformIO supports <a href="https://platformio.org/platforms" rel="nofollow noreferrer">many microcontroller devices</a>, 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.</p>
<h2>Example</h2>
<p>Getting started with PlatformIO and an Arduino Pro Mini 3.3v clone on Fedora 35:</p>
<pre><code>mkdir -p ~/local
cd ~/local
python -m venv platformio
source platformio/bin/activate
pip install platformio
</code></pre>
<p>This installs PlatformIO (CLI) in a virtual environment, i.e. its main command is then available from <code>~/local/platformio/bin/pio</code> and <code>pio</code> is found in your <code>PATH</code> when the virtual environment is activated.</p>
<p>Next, we need to find the right board ID for setting up a new project:</p>
<pre><code>pio boards arduino | less
</code></pre>
<p>That means search for <code>Pro.*Mini</code> in the listing. There are several versions of the Pro Mini, in our example the <code>pro8MHzatmega328</code> (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.</p>
<p>To set up a new project</p>
<pre><code>mkdir ~/project/some_new_project
cd ~/project/some_new_project
pio project init --board pro8MHzatmega328 --ide vim
</code></pre>
<p>Which prints:</p>
<pre><code>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.
</code></pre>
<p>For a first test one can copy a simple blink-led example using the usual <code>setup()</code>/<code>loop()</code> functions. It's possible to re-use an existing 'sketch' from the Arduino IDE, one just has to add <code>#include &lt;Arduino.h&gt;</code> at the top and place it under <code>src/some-name.cc</code> or <code>src/some-name.cpp</code>.</p>
<p>To compile everything:</p>
<pre><code>pio run
</code></pre>
<p>Which prints:</p>
<pre><code>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) &gt; 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 -&gt; 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 &quot;PlatformIO Home &gt; Project Inspect&quot;
RAM:   [          ]   0.4% (used 9 bytes from 2048 bytes)
Flash: [          ]   3.8% (used 1170 bytes from 30720 bytes)
========================= [SUCCESS] Took 0.51 seconds =========================
</code></pre>
<p>So for this example I created <code>src/sos-switch.cc</code> which is compiled to <code>.pio/build/.../sos-switch.cc.o</code>.</p>
<p>To upload (flash) the device:</p>
<pre><code>pio run --target upload
</code></pre>
<p>As always, a common pitfall are the permissions of the USB device. For example, on Fedora, my USB2TTL serial device registers as <code>/dev/ttyUSB0</code> with read-write permissions for just <code>root:dialout</code>. Thus, you have to add your user to the <code>dialout</code> group or adjust the permissions by other means.</p>
<h2>Vim Quickfix Mode</h2>
<p>For integrating with Vim's quickfix mode a simple makefile is sufficient, e.g.:</p>
<pre><code>
.PHONY: all
all: build


.PHONY: build
build:
    pio run

.PHONY: upload
upload:
    pio run --target upload
</code></pre>
<p>Thus, everything is built when <code>:make</code> is invoked in Vim, and there one can navigate the quickfix mode as usual.</p>
<h2>Serial Monitoring</h2>
<p>An easy way to monitor the serial interface is to use <a href="https://github.com/npat-efault/picocom" rel="nofollow noreferrer">picocom</a>, e.g.:</p>
<pre><code>picocom --baud 9600 --echo --imap lfcrlf --noreset /dev/ttyUSB0
</code></pre>
<p>where:</p>
<ul>
<li><code>--imap lfcrlf</code> maps newline to carriage return + newline such that we can just write <code>Serial.print(&quot;multi\nlines\n')</code> instead of <code>Serial.print(&quot;multi\r\nlines\r\n&quot;)</code> in our program</li>
<li><code>--noreset</code> tells picocom to <strong>not</strong> clear DTR - without it, when DTR is connected, the Anrdoid device is reset</li>
</ul>
<p>Of course, one has to terminate picocom when uploading.</p>
<hr />
<p>Alternatively, one can use the PlatformIO monitor command:</p>
<pre><code>pio device monitor
</code></pre>
<p>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 <code>pio run --target upload</code> is invoked.</p>
<h2>Closing Remarks</h2>
<ul>
<li>PlatformIO is <a href="https://bugzilla.redhat.com/show_bug.cgi?id=2021751" rel="nofollow noreferrer">currently packaged</a> for Fedora and thus might be directly available in Fedora 36 or so</li>
<li>the classic Arduino IDE was packaged for Fedora, but isn't available anymore in Fedora 35 because of the big Java package exodus</li>
<li>there is also a PlatoformIO plugin for VSCode which seems to be quite popular</li>
</ul>
 4143: <p>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: <a href="https://github.com/sudar/Arduino-Makefile" rel="nofollow">https://github.com/sudar/Arduino-Makefile</a></p>

<p>Compiling from the command line isn't trivial due to the way the Arduino IDE handles libraries.</p>

<blockquote>
  <p>The equivalent to the IDE's serial monitor is probably connecting a terminal emulator (e.g. screen) to /dev/ttyACM0, right?</p>
</blockquote>

<p>For the serial monitor I would recommend minicom. It is a fully functional terminal emulator (vt102) on the command line.</p>

<pre><code>minicom -D /dev/ttyACM0 -b 115200
</code></pre>

<p>... for example.</p>
 48663: <h1>Official CLI tool</h1>

<p>The arduino team is developing a <strong>cli</strong> client
<a href="https://github.com/arduino/arduino-cli" rel="noreferrer">https://github.com/arduino/arduino-cli</a></p>

<p><strong>Announcement</strong>: <a href="https://blog.arduino.cc/2018/08/24/announcing-the-arduino-command-line-interface-cli/" rel="noreferrer">https://blog.arduino.cc/2018/08/24/announcing-the-arduino-command-line-interface-cli/</a></p>

<p>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 <a href="https://arduino.stackexchange.com/a/24802/48663">Metamorphic's method</a> using <code>stty</code> <code>cat</code>, It works!)</p>

<p>The commands are very similar to <a href="https://arduino.stackexchange.com/a/24802/48663">Metamorphic's answer</a> since this tool is branching out of that one</p>

<p>Instructions in the <a href="https://github.com/arduino/Arduino-cli" rel="noreferrer">Github repo</a> and the man page:</p>

<pre><code>    $ arduino-cli Arduino Command Line Interface (arduino-cli).

    Usage:   arduino-cli [command]

    Examples: arduino &lt;command&gt; [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.
</code></pre>
 10794: <p>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.</p>

<pre><code>#
# 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
</code></pre>

<p>You would need to change <code>ARDUINO_DIR</code> 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.</p>

<p>The lines with the leading spaces above would need the <strong>tab</strong> character instead of spaces, as is normal for a Makefile.</p>
 21201: <p>I use the <a href="https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc" rel="noreferrer">command-line interface to the <code>arduino</code> command</a>.</p>

<p>I run it like this:</p>

<pre><code>arduino --upload sketch/sketch.ino --port /dev/ttyUSB*
</code></pre>

<p><a href="http://playground.arduino.cc/Learning/CommandLine" rel="noreferrer">There is a page</a> which describes other command-line tools, like <code>inotool</code>. That page also has an example <code>Makefile</code>. 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.</p>

<p>Running <code>arduino</code> as above is a bit slow, because it has to load Java I guess, but at least it works. There is also an <a href="https://github.com/arduino/arduino-builder" rel="noreferrer"><code>arduino-builder</code></a> 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 <code>arduino</code>. The README also mentions being able to reuse object files from a previous compile, so there is some make-like functionality.</p>

<hr>

<p>To view serial output <a href="https://arduino.stackexchange.com/questions/24741/how-do-i-read-from-dev-ttyacm0-in-linux-without-a-terminal-emulator">I use something like</a></p>

<pre><code>stty -F /dev/ttyUSB* 1000000 raw -clocal -echo
cat /dev/ttyUSB*
</code></pre>

<p>The number 1000000 should match the number you pass to <code>Serial.begin()</code> in your board code. You can also use <code>screen</code> 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 <code>/dev/ttyACM0</code> (rather than <code>/dev/ttyUSB0</code> for the Uno).</p>
