FPGAwars/apio

`scons.py` - misorders `extra_args` to `dfu-util`

benagricola opened this issue · 11 comments

Trying to program a pico-ice using apio upload, triggering dfu-util and receiving the following error:

(base) ➜  fpga git:(main) ✗ apio upload                                                                          
[Mon Apr 29 20:42:46 2024] Processing pico-ice
---
dfu-util -d 1209:b1c0 -a 0 -D --reset hardware.bin
Error: Unexpected argument: hardware.bin
Usage: dfu-util [options] ...

This is because the --reset argument is inserted between the -D arg and the build file.

My quick fix for this locally was to put the extra_args block above the args block but I don't know if this would cause issues with other programmers.

@Obijuan, I believe this can be closed. (I can't).

thanks @zapta ! :-)

@zapta I've given you rights to manage pull request and issues. Now you should be able to close issues opened by others. Thanks a lot for your work. You are on fire! :-)

I'm still getting this error - I installed with pip install apio. Do I need a workaround or is there a fix in the works?

❯ apio upload
[Mon Sep 30 19:38:20 2024] Processing pico-ice
---------------------------------------------------------------------------------------------------------------
dfu-util -d 1209:b1c0 -a 0 -D --reset hardware.bin
Error: Unexpected argument: hardware.bin
Usage: dfu-util [options] ...
-h --help			Print this help message
-V --version			Print the version number
-v --verbose			Print verbose debug statements
-l --list			List currently attached DFU capable devices
-e --detach			Detach currently attached DFU capable devices
-E --detach-delay seconds	Time to wait before reopening a device after detach
-d --device <vendor>:<product>[,<vendor_dfu>:<product_dfu>]
Specify Vendor/Product ID(s) of DFU device
-n --devnum <dnum>		Match given device number (devnum from --list)
-p --path <bus-port. ... .port>	Specify path to DFU device
-c --cfg <config_nr>		Specify the Configuration of DFU device
-i --intf <intf_nr>		Specify the DFU Interface number
-S --serial <serial_string>[,<serial_string_dfu>]
Specify Serial String of DFU device
-a --alt <alt>		Specify the Altsetting of the DFU Interface
by name or by number
-t --transfer-size <size>	Specify the number of bytes per USB Transfer
-U --upload <file>		Read firmware from device into <file>
-Z --upload-size <bytes>	Specify the expected upload size in bytes
-D --download <file>		Write firmware from <file> into device
-R --reset			Issue USB Reset signalling once we're finished
-w --wait			Wait for device to appear
-s --dfuse-address address<:...>	ST DfuSe mode string, specifying target
address for raw file download or upload (not
applicable for DfuSe file (.dfu) downloads).
Add more DfuSe options separated with ':'
leave		Leave DFU mode (jump to application)
mass-erase	Erase the whole device (requires "force")
unprotect	Erase read protected device (requires "force")
will-reset	Expect device to reset (e.g. option bytes write)
force		You really know what you are doing!
<length>	Length of firmware to upload from device
scons: *** [upload] Error 64
========================================= [ ERROR ] Took 0.10 seconds =========================================

Hi @znmeb, The fix will be included in the next stable release. Meanwhile, here is a workaround that will allow you to work with your board.

  1. Locate the pip packages directory.

Type pip show apio and identify the packages directory marked as Location:. Change to that directory and you will find there a directory called apio

  1. Remove the --reset from the board definition.

Edit the file apio/resources/boards.json and remove the extra args line for your board. To test, run apio upload and make sure the --reset is not gone from the dfu command.

"extra_args": "--reset"

  1. Add the "--reset" at the end of the generated programmer command.

Edit the file apio/resources/ice40/SConstruct and change the upload target line

upload_target = env.Alias('upload', bitstream_target, '{0} $SOURCE'.format(PROG))

from

upload_target = env.Alias('upload', bitstream_target, '{0} $SOURCE'.format(PROG))

to (adding --reset after $SOURCE)

upload_target = env.Alias('upload', bitstream_target, '{0} $SOURCE --reset'.format(PROG))

To undo the patch run pip uninstall apio and then pip install apio. Let us know if any have any questions.

OK ... it's working as far as I can tell. There is an apparently spurious error at the end; it looks like it's resetting twice when it only needs to reset once:

❯ apio build --top-module top
Warning! No TOP-MODULE in apio.ini
[Thu Oct  3 14:59:08 2024] Processing pico-ice
---------------------------------------------------------------------------------------------------------------
yosys -p "synth_ice40 -top top -json hardware.json" -q top.v
nextpnr-ice40 --up5k --package sg48 --json hardware.json --asc hardware.asc --pcf up5k.pcf -q
icepack hardware.asc hardware.bin
========================================= [SUCCESS] Took 0.86 seconds =========================================
❯ apio upload --top-module top
Warning! No TOP-MODULE in apio.ini
[Thu Oct  3 14:59:20 2024] Processing pico-ice
---------------------------------------------------------------------------------------------------------------
dfu-util -d 1209:b1c0 -a 0 -D hardware.bin --reset
dfu-util 0.11-dev

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Warning: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release
Opening DFU capable USB device...
Device ID 1209:b1c0
Run-Time device DFU version 0101
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 0101
Device returned transfer size 256
Copying data from PC to DFU device
Download	[=========================] 100%       104090 bytes
Download done.
DFU state(7) = dfuMANIFEST, status(0) = No error condition is present
DFU state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
Resetting USB to switch back to runtime mode
Done!
Resetting USB to switch back to Run-Time mode
dfu-util: error resetting after download: LIBUSB_ERROR_OTHER
scons: *** [upload] Error 74
========================================= [ ERROR ] Took 3.52 seconds =========================================

Thanks all for taking care of the maintenance of the dfu-util invocation!

The double-reset does not seem to be an APIO bug.

  1. The first reset is because dfu-util detects that the board is in "waiting reset" mode:
    https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/src/dfu_load.c#l204

  2. The second reset because dfu-util was asked to reset the board explicitly:
    https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/src/main.c#l780

It might not be required to reset the board twice though.
Not sure why this was not working before... The MANIFEST_SYNC DFU status tells the host that the transfer is done, and was there since a long time.

The board is likely up and running despite the error message.

Yes, the board is definitely up and running - I verified that with both of the "ice_apio" examples.

Thanks for the update. What is the conclusion regarding that board, does it require the --reset at the end or is it better without it?

https://github.com/FPGAwars/apio/blob/develop/apio/resources/boards.json#L610

That's a question for @josuah ... I'm still learning both apio and the pico-ice.

Thanks for the update. What is the conclusion regarding that board, does it require the --reset at the end or is it better without it?

Sorry for the long delay, we were preparing an event and now it is over.

Maybe it is good to keep the --reset for now. Then we may be able to tests on several platforms again at next release to be sure that it is not required at all.

Thank you all for investigating this situation!