How can I force an Arduino Leonardo to reset with AVRDUDE?
Asked Answered
C

8

11

I want to compile and transfer an Arduino program by myself on a Leonardo board.

Everything works great with the Arduino official IDE. I have enabled verbose mode for compiling and bytecode transfer.

I can see each command line.
I want to understand each line.

Everything is good except last step: transfer with AVRDUDE. If I type exactly the same command, I get an error:

.avrdude: butterfly_recv(): programmer is not responding

This error is not present if I upload code with the Arduino IDE.

I can see a difference - the Arduino IDE displays this line before the AVRDUDE call:

Forcing reset using 1200 bps open/close on port /dev/cu.usbmodem1431

How can I make this reset by command line?

Calise answered 25/3, 2017 at 13:33 Comment(0)
M
0

Well, you pretty much wrote the answer yourself.

You need to open a serial connection at 1200 baud to the Arduino and then close the connection. The Arduino will then boot into SAM-BA, and reset itself, and is now ready for a new program.

Marianelamariani answered 25/3, 2017 at 20:32 Comment(2)
I do not understand how arduino will understand to reset just by openning/closing port ?Calise
Here is something for you to read then, arduino.cc/en/main/arduinoBoardLeonardo - See "Automatic (Software) Reset and Bootloader Initiation" sectionMarianelamariani
B
13

I had the same issue on macOS, and I came up with the following Bash script:

# Find the Arduino port
ARDUINO_UPLOAD_PORT="$(find /dev/cu.usbmodem* | head -n 1)"

# Reset the Arduino
stty -f "${ARDUINO_UPLOAD_PORT}" 1200

# Wait for it...
while :; do
  sleep 0.5
  [ -c "${ARDUINO_UPLOAD_PORT}" ] && break
done

# ...upload!
avrdude "${OPTIONS[@]}"

The while loop is the trick! It's going to proceed as soon as the Arduino port is back online.

This is part of a Makefile I wrote for the project Sesame.

Bensky answered 4/9, 2017 at 15:41 Comment(3)
Not sure if this is a typo or a MacOS thing. Under Linux stty has only an -F switch that seems to do what the above -f is supposed to do...Licit
Indeed, at one point in space and time they diverged, macOS tools are BSD and linux ones are GNU: Know Your Tools: Linux (GNU) vs. Mac (BSD) Command Line UtilitiesBensky
Ha! You are right, FreeBSD man page says -f, too: freebsd.org/cgi/man.cgi?query=stty Anyway, good to know and maybe it would be good to point it out in the answer.Licit
A
6

For uploading from Windows, I made a bat file wrapper for AVRDUDE.

It identifies the Leonardo COM port with WMI, resets this COM port to 1200 baud with the MODE command, identifies the bootloader COM port and invokes AVRDUDE.

The firmware is supposed to be placed in firmware.hex, but it can be changed to be supplied from the command line.

Code is in a GitHub repository, Arduino Leonardo Uploader

Or below:

@echo off
setlocal

for /f "tokens=1* delims==" %%I in ('wmic path win32_pnpentity get caption  /format:list ^| find "SparkFun Pro Micro"') do (
    call :resetCOM "%%~J"
)

:continue

:: wmic /format:list strips trailing spaces (at least for path win32_pnpentity)
for /f "tokens=1* delims==" %%I in ('wmic path win32_pnpentity get caption  /format:list ^| find "Arduino Leonardo bootloader"') do (
    call :setCOM "%%~J"
)

:: end main batch
goto :EOF

:resetCOM <WMIC_output_line>
:: sets _COM#=line
setlocal
set "str=%~1"
set "num=%str:*(COM=%"
set "num=%num:)=%"
set port=COM%num%
echo %port%
mode %port%: BAUD=1200 parity=N data=8 stop=1
goto :continue

:setCOM <WMIC_output_line>
:: sets _COM#=line
setlocal
set "str=%~1"
set "num=%str:*(COM=%"
set "num=%num:)=%"
set port=COM%num%
echo %port%
goto :flash

:flash
avrdude -v -C./avrdude.conf -patmega32u4 -cavr109 -P%port% -b57600 -D -V -Uflash:w:./firmware.hex:i
Amadou answered 29/6, 2017 at 10:54 Comment(1)
I need to upload my sketch on startup, I am using Arduino UNO, this solution fit me?Dasyure
H
5

I had the same problem. I've tried opening and closing the ACM0 port with a Python script at 1200 baud, as someone already mentioned. It didn't work for me. Then I have received half-advice to try toggling RTS/DTS and that will make autoreset. So in the end I found the solution (at least for me) on Linux Mint 18.2 (Sonya):

#! /usr/bin/python

import sys
import serial

com = serial.Serial(sys.argv[1], 1200)
com.dtr=False
com.close()


python ./reset.py "/dev/ttyACM0"

dmesg shows me:

[21850.047120] cdc_acm 1-1:1.0: ttyACM0: USB ACM device
[22093.700327] usb 1-1: USB disconnect, device number 53
[22094.034133] usb 1-1: new full-speed USB device number 54 using xhci_hcd
[22094.175377] usb 1-1: New USB device found, idVendor=2341, idProduct=0036
[22094.175381] usb 1-1: New USB device strings: Mfr=2, Product=1, SerialNumber=0
[22094.175384] usb 1-1: Product: Arduino Leonardo
[22094.175387] usb 1-1: Manufacturer: Arduino LLC
[22094.175964] cdc_acm 1-1:1.0: ttyACM0: USB ACM device
Hipbone answered 20/3, 2018 at 12:27 Comment(2)
For me, this (plus waiting 2 seconds) finally got my atmeg32u4 itsy bitsy programming. Whew!Tattoo
This also seems to be the way to go for the Arduino Nano Every board.Frieze
T
4

On Windows, in a command prompt, the same solution, slightly different batch file:

It determines the bootloader COM port as well. Note that just only the Leonardo to be flashed should be connected!

@echo off
echo Upgrade procedure starting.
if %1.==. goto error
set hexfile=%1
set comportA=NONE
set comportB=NONE
if not exist %hexfile% goto error
for /f "usebackq" %%B in (`wmic path Win32_SerialPort Where "Caption LIKE '%%Leonardo%%'" Get DeviceID ^| FIND "COM"`) do set comportA=%%B
if %comportA%==NONE goto nodevice
echo COM port for Arduino device is detected as %comportA%.
echo Reset Arduino into bootloader
mode %comportA%: baud=12 > nul
timeout 2 > nul
for /f "usebackq" %%B in (`wmic path Win32_SerialPort Where "Caption LIKE '%%Leonardo%%'" Get DeviceID ^| FIND "COM"`) do set comportB=%%B
if %comportB%==NONE goto nobldevice
echo COM port for Arduino bootloader device is detected as %comportB%.
echo.
echo Starting AVR Downloader/UploaDEr.....
avrdude -pm32u4 -cavr109 -D -P%comportB% -b57600 -Uflash:w:%hexfile%
goto upgradedone
:nodevice
echo No matching module found, you should connect the module you want to upgrade.
goto end
:nobldevice
echo Reset into bootloader failed, please try again...
goto end
:error
Echo Missing parameter or file, you should provide the full filename of an existing .hex file you want to use.
goto end
:upgradedone
echo.
echo Upgrade done!
:end
Temptation answered 8/2, 2018 at 23:10 Comment(0)
B
1

I use this for Nano-every: I think the essential elements are:

  1. configure appropriate com port at 1200 baud with DTR = ON
  2. Turn DTR off.
  3. Flash device with correct version of avrdude and avrdude.config. My version came with the installation of my Nano-every device. For other boards, it might be different. Lines 1, 2 reset the port and I think this is independent of the board, but change the port number!

c:\windows\system32\mode.com com6: baud=1200 dtr=on

c:\windows\system32\mode.com com6: dtr=off

C:\Users\Ludo\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude -CC:\Users\Ludo\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf -v -patmega4809 -cjtag2updi -PCOM6 -b115200 -e -D -Uflash:w:C:\Users\Ludo\AppData\Local\Temp\arduino_build_385557/sketch_dec11a.ino.hex:i -Ufuse2:w:0x01:m -Ufuse5:w:0xC9:m -Ufuse8:w:0x00:m {upload.extra_files}

Bosky answered 12/12, 2020 at 11:38 Comment(0)
K
1

Like Ludo answer:

I use this for Nano-every: I think the essential elements are:

https://mcmap.net/q/962627/-how-can-i-force-an-arduino-leonardo-to-reset-with-avrdude

Except on my machine (Windows10), following gives a kick:

c:\> mode.com COM4: baud=1200 dtr=ON  DATA=8
Default to even parity.

Status for device COM4:
-----------------------
    Baud:            1200
    Parity:          Even
    Data Bits:       8
    Stop Bits:       1
    Timeout:         ON
    XON/XOFF:        OFF
    CTS handshaking: OFF
    DSR handshaking: OFF
    DSR sensitivity: OFF
    DTR circuit:     ON
    RTS circuit:     OFF

then

avrdude -p atmega4809 -c jtag2updi -P COM4 -U flash:r:testDump -b115200 -v
...
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.28s

avrdude: Device signature = 0x1e9651 (probably m4809)
avrdude: reading flash memory:

Reading | ################################################## | 100% 7.59s

avrdude: writing output file "testDump"

avrdude: safemode: Fuses OK (E:FF, H:FF, L:FF)

avrdude done.  Thank you.

In my example I just wanted to take dump (pun intended) of flash to the file. Took me 1/2 day and half night but I am happy as a child. Thanks to OP and Ludo!

Kingpin answered 16/12, 2023 at 0:54 Comment(0)
M
0

Well, you pretty much wrote the answer yourself.

You need to open a serial connection at 1200 baud to the Arduino and then close the connection. The Arduino will then boot into SAM-BA, and reset itself, and is now ready for a new program.

Marianelamariani answered 25/3, 2017 at 20:32 Comment(2)
I do not understand how arduino will understand to reset just by openning/closing port ?Calise
Here is something for you to read then, arduino.cc/en/main/arduinoBoardLeonardo - See "Automatic (Software) Reset and Bootloader Initiation" sectionMarianelamariani
E
0

I had the same problem with arduino leonardo.

I want to share my solution for people wanting to solve this problem using Qt.

Here is solution ready to be copy and paste, also taking care of timeout:


#include <QtCore/QString>
#include <QtCore/QDebug>
#include <QtCore/QThread>
#include <QtCore/QElapsedTimer>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

bool forceResetComPort(const QString& portName)
{
    QSerialPort serial;
    serial.setPortName(portName);
    serial.setBaudRate(1200);

    qDebug() << "Forcing reset using 1200bps open/close on port ") << portName;
    if(!serial.open(QIODevice::ReadWrite))
        return false;

    // This seems optional
    serial.setDataTerminalReady(false);

    qDebug() << "Waiting for the new upload port...";

    QElapsedTimer timeoutWatcher;
    qint64 timeoutMs = 10000;
    bool isPortPresent = true;

    const auto fetchIsPortPresent = [&]() -> bool
    {
        const auto ports = QSerialPortInfo::availablePorts();
        for(const auto& info : ports)
        {
            if(info.portName() == serial.portName())
                return true;
        }
        return false;
    };

    timeoutWatcher.start();

    // Wait for port to disconnect
    while(isPortPresent && !timeoutWatcher.hasExpired(timeoutMs))
    {
        isPortPresent = fetchIsPortPresent();

        if(isPortPresent)
            QThread::msleep(1);
    }

    serial.close();

    // Wait for port to reconnect
    while(!isPortPresent && !timeoutWatcher.hasExpired(timeoutMs))
    {
        isPortPresent = fetchIsPortPresent();

        if(!isPortPresent)
            QThread::msleep(1);
    }
 
    return !timeoutWatcher.hasExpired(timeoutMs);
}

It is all about timing. I really needed to wait for the serial port to disconnect to close serial.

  • Closing too fast didn't have any effect.
  • Closing too slow, the usb serial was reconnecting but with a different port name. (For example /dev/ttyACM0 to /dev/ttyACM1).
  • It's important to wait for the port to reconnect in my case because I call avrdude in QProcess after.

Here is dmesg:

[ 8566.623621] cdc_acm 1-8:1.0: failed to set dtr/rts
[ 8566.979697] usb 1-8: new full-speed USB device number 21 using xhci_hcd
[ 8567.133193] usb 1-8: New USB device found, idVendor=2341, idProduct=0036, bcdDevice= 0.01
[ 8567.133197] usb 1-8: New USB device strings: Mfr=2, Product=1, SerialNumber=0
[ 8567.133199] usb 1-8: Product: Arduino Leonardo
[ 8567.133200] usb 1-8: Manufacturer: Arduino LLC
[ 8567.134820] cdc_acm 1-8:1.0: ttyACM0: USB ACM device
Entoblast answered 9/2, 2021 at 12:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.