Code not uploading to Teensy32 from Python

rmojica

Member
Hi all,

I've been experimenting with Paul's workaround to use arduino-cli with my Teensy 3.2 to automate my workflow. While it's been working great from all existing shells on my computer, the same cannot be said when calling arduino-cli from within Python. Instead of the usual behavior (compile then upload), the code gets compiled but fails to upload to the Teensy. The Teensy just hangs, with the Loader displaying that "Arduino is attempting to put Teensy into Program Mode", and the command line returns the following error:
Code:
[INDENT]
Unable to open COM4 for reboot request
  Windows Error Info: Access is denied.
  more ideas... [url]https://forum.pjrc.com/threads/40632?p=126667&viewfull=1#post126667[/url]
Teensy did not respond to a USB-based request to enter program mode.
Please press the PROGRAM MODE BUTTON on your Teensy to upload your sketch.[/INDENT]

I am using the following line to compile and upload:
Code:
/path/to/arduino-cli.exe compile --upload /path/to/treadmillEncoder.ino -p COM4 -b teensy:avr:teensy31
I have tried using os.system() and subprocess.run()/subprocess.call(), all with the same result. I also tried to offload arduino-cli itself off of Python, instead writing a batch script for it. When the script is called from the command line, it works as expected. When it is called from within Python, I get the same error.

Has anyone experience a similar problem?

- Raul
 
Looks like the INO being uploaded is meant to replace the PYTHON program currently running on the Teensy?

Once the Python HEX has been uploaded it presents as a Python device with its unique USB interface and not a Teensy Arduino Serial USB programmed to respond with the normal Upload response included in the PJRC Teensy CORES.

That would explain the indicated error: Teensy did not respond to a USB-based request to enter program mode.

The provided text shows: Please press the PROGRAM MODE BUTTON on your Teensy to upload your sketch.

If the Teensy program Button were to be pressed the upload should proceed as expected on the next attempt.
 
Thanks for the quick reply! The INO prints to serial, which is read from Python using pyserial, so my Python program does not run directly on the Teensy. Even if I reboot the Teensy and start a fresh instance of Python, and run the code below, the same error crops up.
Code:
subprocess.run('/path/to/arduino-cli.exe compile --upload /path/to/treadmillEncoder.ino -p COM4 -b teensy:avr:teensy31')
Does Python still attempt to access the COM port first, even though it's supposed to just run a shell script? Is there any workaround to evade this interaction?
 
I believe your subprocess command needs to be like this:

Code:
subprocess.run(['/path/to/arduino-cli.exe', 'compile', '--upload', '/path/to/treadmillEncoder.ino', '-p', 'COM4', '-b', 'teensy:avr:teensy31'])
i.e. you need a list containing the command and each argument separately. At least in the latest Python 3.x.

That's not to say it will fix your issue, but I run teensy_command_cli from a Python script on Raspberry Pi OS using the above method and it works fine. I don't run arduino-cli on the RPi because it takes too long to compile, so I compile on my PC, transfer the hex file and have Python upload the hex.

Also your command says teensy31 but your title suggest a Teensy 3.2. Not sure if that's just a typo along the way or if you have a mismatch somewhere.
 
Opps - misread the setup. The T_3.2 is just running a normal sketch, and python as used to execute the upload commands fails where the same device using a script can complete the upload.

Perhaps the problem is "INO prints to serial, which is read from Python using pyserial"

Perhaps that pyserial connection is active preventing the upload command from accessing the COM4 port as it is consumed with that pyserial connection? If the pyserial connection is dropped that should allow the upload to complete.
 
Given the similarity of T_3.1 and T_3.2 sometimes one name is used to cover both.

Though on github it suggests there is a name for both devices:
Code:
...
--mcu=TEENSY31          Teensy 3.1
--mcu=TEENSY32          Teensy 3.2

And indicates:
Code:
Usage and Command Line Options
A typical usage from the command line may look like this:

teensy_loader_cli --mcu=mk20dx256 -w blink_slow_Teensy32.hex
 
Unfortunately, using subprocess.run() with the arguments in a list yields the same result. I am using arduino-cli instead of teensy_loader_cli, but perhaps I should experiment with the latter.
As for the command, teensy31 and 32 are bundled together in arduino-cli (see attached image) arduino-cli board list.png
 
i.e. you need a list containing the command and each argument separately. At least in the latest Python 3.x.
Unfortunately, using subprocess.run() with the arguments in a list yields the same result. I am using arduino-cli instead of teensy_loader_cli, but perhaps I should experiment with the latter.
Also your command says teensy31 but your title suggest a Teensy 3.2.
As for the command, teensy31 and 32 are bundled together in arduino-cli View attachment 27984
If the pyserial connection is dropped that should allow the upload to complete.
I will dig in to this, but the error persists even when not using pyserial. Disconnecting, manually rebooting and re-compiling and uploading to the board using only subprocess.run() in a fresh Python shell still yields the error. The problem may be some odd interaction between Python and the serial port, even when Python itself shouldn't be accessing that port.
Though on github it suggests there is a name for both devices:
(See above) The new arduino-cli teensy workaround bundles 3.1 and 3.2. While this could be the problem, compiling and uploading straight from any CLI or shell on Windows is indeed successful. I am starting to think this is more of a Python problem than the teensy support for arduino-cli. The error is also present on different computers, and with different Teensy 3.2 boards.
 
My success is limited to using Python 3.x on a Raspberry Pi, so I can't offer much more in the way of suggestions. I will however set up a test on my computer later using ardiuno-cli from Python to see if I can replicate your issue. Sounds Python related, but may be a combination of Python/Windows together. What Python version are you using?
 
As suspected, it was indeed a Python problem. Essentially, I was programmatically finding whichever port the teensy was connected to, and establishing a serial connection within Python. While the serial read was indeed occurring after the upload, my script to find the teensy port returned a serial connection (serial.Serial()) instead of a string. Altering the behavior of my find_teensy() function so that it returns a script in the form f'COM{n}' as well as changing the order of my calls and adding a small pause (time.sleep(1)) between compilation/uploading and my serial connection solved the issue.
I am very ashamed of this mistake, but very grateful to you both for helping out and ruling out any arduino-cli/teensy issues.
 
Back
Top