Using Pymcuprog for upload

I am currently using PyUPDI for code uploads to my AVR 4809s. Having communicated with the Pyupdi author, it’s recommended to use Pymcuprog instead (it’s a supported resource). So I looked at pymcuprog and also found this,
I have installed pymcuprog using pip install pymcuprog.

I can’t work out what my PIO.ini should look like.

Any help with that much appreciated

If you have the pymcuprog command globally available you can try, based on this and this, adding

upload_protocol = custom
upload_speed = 115200
upload_port = /some/serial/port
upload_flags =
  -t
  uart
  -d
  $BOARD_MCU
  -u
  $UPLOAD_PORT
  -c
  $UPLOAD_SPEED
upload_command = pymcuprog write $UPLOAD_FLAGS -f $SOURCE

to the platformio.ini.

It might be of an advantage, if these flags don’t work, to try and figure out the stand-alone flash command first. After the PIO project has been built and say a .pio\atmega4809\firmware.hex has been generated, it can be tried on the command-line standalone to do

pymcuprog write -d atmega4809 -t uart -u COM35 -f .pio\ATmega4809\firmware.hex

and see what that does.

thanks I copied the PIO.ini settings in, but got this, don’t know if that’s due to my python context or whether its the PIO.ini flags.

thanks for help.


Dependency Graph
|-- <AccelStepper> 1.61.0
|-- <Circular-Linked-List>
Building in release mode
Checking size .pio\build\ATmega4809\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [=         ]   9.8% (used 602 bytes from 6144 bytes)
Flash: [===       ]  27.9% (used 13736 bytes from 49152 bytes)
Configuring upload protocol...
AVAILABLE: custom
CURRENT: upload_protocol = custom
Uploading .pio\build\ATmega4809\firmware.hex
Could not import runpy module
Traceback (most recent call last):
  File "C:\Users\Paul\.platformio\python3\lib\runpy.py", line 14, in <module>
    import importlib.machinery # importlib first so we can test #15386 via -m
  File "C:\Users\Paul\.platformio\python3\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
*** [upload] Error 1
====================================================================================== [FAILED] Took 1.13 seconds ======================================================================================
The terminal process "C:\Users\Paul\.platformio\penv\Scripts\platformio.exe 'run', '--target', 'upload', '--environment', 'ATmega4809'" terminated with exit code: 1.


Does that command work manually when you execute it in a commandline where you previousy cd-ed into the PlatformIO project directory?

I tried it as follows, (com17 is the correct port) but there were errors:


PS C:\Users\Paul\Documents\PlatformIO\Projects\Live\Stepper> cd ..
PS C:\Users\Paul\Documents\PlatformIO\Projects\Live> cd ..
PS C:\Users\Paul\Documents\PlatformIO\Projects> pymcuprog write -d atmega4809 -t uart -u COM17 -f .pio\atmega4809\firmware.hex
Traceback (most recent call last):
  File "c:\users\paul\appdata\local\programs\python\python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\users\paul\appdata\local\programs\python\python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\Scripts\pymcuprog.exe\__main__.py", line 4, in <module>
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog.py", line 16, in <module>
    from . import pymcuprog_main
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 12, in <module>
    from .backend import Backend, SessionConfig
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\backend.py", line 34, in <module>
    from .hexfileutils import read_memories_from_hex
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\hexfileutils.py", line 8, in <module>
    from intelhex import IntelHex
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\intelhex\__init__.py", line 44, in <module>
    from intelhex.compat import (
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\intelhex\compat.py", line 60, in <module>
    array_tobytes = getattr(array.array, "tobytes", array.array.tostring)
AttributeError: type object 'array.array' has no attribute 'tostring'
PS C:\Users\Paul\Documents\PlatformIO\Projects> 

IntelHEX seems outdated since it doesn’t have the patch to work with your newest Python 3.9 installation (tostring bug when using Python 3.9 · Issue #45 · python-intelhex/intelhex · GitHub). Try executing the command python -m pip install -U intelhex to update the package and retry.

I updated the package and that went fine with a success message, but something odd is happening with the file path in the pymcuprog command - note the double backslashes in the error message. I also tried putting the full path C:…\firmware.hex in place of .pio\build\ATmega4809\firmware.hex, but same problem. Thanks for any ideas.

PS C:\Users\Paul\Documents\PlatformIO\Projects> pymcuprog write -d atmega4809 -t uart -u COM17 -f C:\Users\Paul\Documents\PlatformIO\Projects\Live\Stepper\.pio\build\ATmega4809firmware.hex                              
WARNING: Check failed
Traceback (most recent call last):
  File "c:\users\paul\appdata\local\programs\python\python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\users\paul\appdata\local\programs\python\python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\Scripts\pymcuprog.exe\__main__.py", line 7, in <module>
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog.py", line 179, in main
    return pymcuprog_main.pymcuprog(arguments, logging_level)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 82, in pymcuprog
    _programming_actions(backend, args)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 357, in _programming_actions
    status = _action_write(backend, args)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 262, in _action_write
    result = read_memories_from_hex(args.filename, backend.device_memory_info)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\hexfileutils.py", line 56, in read_memories_from_hex
    hexfile.fromfile(filename, format='hex')
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\intelhex\__init__.py", line 249, in loadfile
    self.loadhex(fobj)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\intelhex\__init__.py", line 199, in loadhex
    fobj = open(fobj, "r")
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\Paul\\Documents\\PlatformIO\\Projects\\Live\\Stepper\\.pio\\build\\ATmega4809firmware.hex'
PS C:\Users\Paul\Documents\PlatformIO\Projects> 

Seems like the last part of the path should be ATmega4809\firmware.hex not ATmega4809firmware.hex in your command.

mmm…thanks, embarrassing mistake only an amateur would make :frowning:

So I have corrected that error and now get this output when uploading.

PS C:\Users\Paul\Documents\PlatformIO\Projects> pymcuprog write -d atmega4809 -t uart -u COM17 -f C:\Users\Paul\Documents\PlatformIO\Projects\Live\Stepper\.pio\build\ATmega4809\firmware.hex
Writing from hex file...
Writing flash...
Traceback (most recent call last):
  File "c:\users\paul\appdata\local\programs\python\python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\users\paul\appdata\local\programs\python\python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\Scripts\pymcuprog.exe\__main__.py", line 7, in <module>
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog.py", line 179, in main
    return pymcuprog_main.pymcuprog(arguments, logging_level)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 82, in pymcuprog
    _programming_actions(backend, args)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 357, in _programming_actions
    status = _action_write(backend, args)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 266, in _action_write
    _write_memory_segments(backend, result, args.verify)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 307, in _write_memory_segments
    backend.write_memory(segment.data, memory_name, segment.offset)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\backend.py", line 526, in write_memory
    self.programmer.write_memory(data=data, memory_name=memory_name, offset=offset_byte)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\programmer.py", line 187, in write_memory
    self.device_model.write(memory, offset, data)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\nvmserialupdi.py", line 127, in write
    self.avr.nvm.write_flash(offset_aligned, chunk)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\serialupdi\nvm.py", line 116, in write_flash
    return self.write_nvm(address, data, use_word_access=True)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\serialupdi\nvm.py", line 181, in write_nvm
    self.readwrite.write_data_words(address, data)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\serialupdi\readwrite.py", line 129, in write_data_words
    return self.datalink.st_ptr_inc16(data)
  File "c:\users\paul\appdata\local\programs\python\python39\lib\site-packages\pymcuprog\serialupdi\link.py", line 144, in st_ptr_inc16
    self.updi_phy.send([data[num], data[num + 1]])
IndexError: array index out of range

Welp, looks like the pymcuprog crashes when indexing the data outside of its range… Either the program has a bug or the input file is malformed (which it should absolutely not be).

Does it behave the same when you give the firmware.bin file instead of the .hex file?

Can you upload the firmware.hex file that is problematic (to e.g., Google Drive or Pastebin or wherever)?

Actually before that, a similiar issue seems to have been known in Unable to write fuses on Atmega 4809 using serial updi · Issue #2 · microchip-pic-avr-tools/pymcuprog · GitHub in an older version of pymcuprog. Does it behave the same after you did a

python -m pip install -U pymcuprog

to update the program to the latest version?

thanks for this. The code uploads, it’s only 13k bytes and it took about 2 minutes. Any way I can improve on that? Seems a long time…EDIT - just timed it, it was 3 minutes!

So upgrading the program worked?

Does adding -c 1M at the end of the command result in a faster upload?

yes upgrading the program worked, just very slow to upload. When I used pyUPDI, that took 28 seconds to laod the same code file.

If I include -c 1M, the UPDI fails to initialise. as follows

PS C:\Users\Paul\Documents\PlatformIO\Projects> pymcuprog write -d atmega4809 -t uart -u COM17 -c 1M -f C:\Users\Paul\Documents\PlatformIO\Projects\Live\Stepper\.pio\build\ATmega4809\firmware.hex
pymcuprog.serialupdi.link - WARNING - Check failed
pymcuprog.serialupdi.link - WARNING - Check failed
Traceback (most recent call last):
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\Scripts\pymcuprog.exe\__main__.py", line 7, in <module>
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\pymcuprog.py", line 285, in main
    return pymcuprog_main.pymcuprog(arguments)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 80, in pymcuprog
    status = _start_session(backend, device_selected, args)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\pymcuprog_main.py", line 549, in _start_session
    backend.start_session(sessionconfig)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\backend.py", line 363, in start_session
    self.programmer.setup_device(
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\programmer.py", line 78, in setup_device
    self.device_model = get_nvm_access_provider(self.transport,
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\nvm.py", line 42, in get_nvm_access_provider
    accessprovider = NvmAccessProviderSerial(transport, device_info, baud=frequency, options=options)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\nvmserialupdi.py", line 51, in __init__
    self.avr = UpdiApplication(port, baud, self.dut)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\serialupdi\application.py", line 81, in __init__
    datalink.init_datalink()
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python39\lib\site-packages\pymcuprog\serialupdi\link.py", line 45, in init_datalink
    raise PymcuprogError("UPDI initialisation failed")
pymcuprog.pymcuprog_errors.PymcuprogError: UPDI initialisation failed

so I tried -c 500000 and that failed to initialise too. It will initialise if i use -c 250000, but it’s still slow to upload at around 2 minutes.

I used pymcuprog --help to see what’s available, but it doesn’t look like any other parameters will help with speed. I’ll probably continue to use pyUPDI as it’s much faster for some reason.
edit - one thing I haven’t been able to work out is what is the purpose of the 1k resistor between Tx and Rx ? What does that do?

It makes the line bidirectional in this case. The value of the resistor might have an influence on the charge and discharge time of the parasitic capacitance, influencing the maximum speed.

Hm that’s disappointing then – pyupdi was set up in the standard case to work with 115200 baud, so if that is significantly faster than pymcuprog with “250,000” baud, something is off. Maybe you can open an issue about that in Issues · microchip-pic-avr-tools/pymcuprog · GitHub.

yes the disparity is a bit odd. I’ve posted a description at pymcuprog.
thanks for help with it.

1 Like

Interesting observation… I will take a look…

New build available on pypi test.

thanks all for help with this. I have it working on the command line now and as posted on pymcuprog it’s a quick upload in under 20 secs :slight_smile:

Just trying to configure pio.ini with this:

;NEW FOR PYMCUPROG
upload_flags =
   -t
   uart
   -d
   $BOARD_MCU
   -u
   $UPLOAD_PORT
   -c
   $UPLOAD_SPEED
upload_command = pymcuprog write $UPLOAD_FLAGS -f $SOURCE

and getting this error, but no worries, I can use from the command line if it’s not an easy fix.

 Executing task in folder Stepper: C:\Users\Paul\.platformio\penv\Scripts\platformio.exe run --target upload --environment ATmega4809 <

Processing ATmega4809 (board: ATmega4809; platform: atmelmegaavr; framework: arduino)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelmegaavr/ATmega4809.html
PLATFORM: Atmel megaAVR (1.4.0) > ATmega4809
HARDWARE: ATMEGA4809 20MHz, 6KB RAM, 48KB Flash
PACKAGES:
 - framework-arduino-megaavr-megacorex 1.0.9
 - tool-avrdude-megaavr 2.60300.210128 (6.3.0)
 - toolchain-atmelavr 2.70300.201015 (7.3.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 22 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <AccelStepper> 1.61.0
|-- <Circular-Linked-List>
Building in release mode
Checking size .pio\build\ATmega4809\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [==        ]  21.6% (used 1326 bytes from 6144 bytes)
Flash: [===       ]  27.7% (used 13617 bytes from 49152 bytes)
Configuring upload protocol...
AVAILABLE: custom
CURRENT: upload_protocol = custom
Uploading .pio\build\ATmega4809\firmware.hex
Could not import runpy module
Traceback (most recent call last):
  File "C:\Users\Paul\.platformio\python3\lib\runpy.py", line 14, in <module>
    import importlib.machinery # importlib first so we can test #15386 via -m
  File "C:\Users\Paul\.platformio\python3\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
*** [upload] Error 1
====================================================================================== [FAILED] Took 1.13 seconds ======================================================================================
The terminal process "C:\Users\Paul\.platformio\penv\Scripts\platformio.exe 'run', '--target', 'upload', '--environment', 'ATmega4809'" terminated with exit code: 1.