I'm trying to make a Python function in the TCLab package to flash firmware to an Arduino Leonardo (32u4). I can compile the TCLab ino (firmware) and deploy with the Arduino IDE or with the Python avryp package. The Python avr_helpers package looks like a possible solution but is only supported with the older Python 2.7. Forum posts such as this one, how can I upload a hex file to an arduino uno?, and others suggest avrdude to upload a hex file. However, I need a Python solution that can be used on any platform (MacOS, Windows, Linux, etc) without a requirement to install packages (avrdude, Arduino IDE, etc).

I have the hex file from a successful Arduino build. Here is an unsuccessful attempt to load the hex file with serial communication:

import serial
import time
import os

# open and close COM8 to activate bootloader
ser = serial.Serial('COM8',baudrate=1200)
print(ser.isOpen()); ser.close()

# load hex file on COM9
filesize = os.path.getsize('tclab_v2.ino.hex')
fid = open('tclab_v2.ino.hex','rb')
offset = 0; MTU = 20
ser2 = serial.Serial('COM9',115200)
while (offset < filesize):
    fid.seek(offset, 0)
    offset = offset + MTU

The script is able to activate the bootloader on another port and connect. If I transfer all at once with ser2.write(fid.read()), it semi-bricks the Arduino and I recover it by hitting the reset button just before the Arduino IDE installs the firmware. I use a Maximum Transfer Unit (MTU) of 20 but I couldn't verify if there is one for the Leonardo. I can write a Python function to identify the ports and have used COM8 and COM9 here just to simply the test. Although the TCLab firmware is preloaded for Python, sometimes users change the firmware to use MATLAB, Octave, or Java and then want to switch back to Python. I'd like to make that as easy as possible without adding more steps or more instructions to the troubleshooting FAQ. Can I update the firmware like the MATLAB Arduino Support Package that detects a new device and transfers the firmware automatically with user confirmation?

  • use baud rate of 9600 ... that should remove the possibility that 115200 is not supported – jsotola Jun 16 '20 at 14:25
  • Thanks for the suggestion. I just tried baudrate of 9600 with ser2 = serial.Serial('COM9',9600) but it has the same result. – John Hedengren Jun 16 '20 at 14:31
  • 1
    The Leonardo uses the AVR109 protocol, not STK500. – Majenko Jun 16 '20 at 14:41
  • 1
  • 3
    the point is, there is some negotiation described in the protocol specification. you can't simply dump the hex to com port – Juraj Jun 16 '20 at 14:44

This isn't the exact answer but it helps.

Uploading without avrdude is complicated and generally slow. The best solution to not using the IDE is to open and close a port then use the avrdude command that the ide usually uses.

from serial import Serial
from time import sleep
from subprocess import run

while input('Press enter to upload ') == '':
    run(["C:\\Progra~2\\Arduino\\hardware\\tools\\avr/bin/avrdude", "-CC:\\Progra~2\\Arduino\\hardware\\tools\\avr/etc/avrdude.conf", "-v", "-patmega32u4", "-cavr109", "-PCOM6", "-b57600", "-D", "-Uflash:w:C:\\Users\\USER\\Desktop\\Python\\tclab_v2/tclab_v2.ino.hex:i"])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.