mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/dfu_select_device' into 'master'
Add ability to select a device for DFU flashing Closes IDF-1652 See merge request espressif/esp-idf!8956
This commit is contained in:
commit
7283b99c97
@ -64,6 +64,22 @@ which relies on `dfu-util <http://dfu-util.sourceforge.net/>`_. Please see :ref:
|
|||||||
installing ``dfu-util``. ``dfu-util`` needs additional setup for :ref:`api_guide_dfu_flash_win` or setting up an
|
installing ``dfu-util``. ``dfu-util`` needs additional setup for :ref:`api_guide_dfu_flash_win` or setting up an
|
||||||
:ref:`api_guide_dfu_flash_udev`. Mac OS users should be able to use ``dfu-util`` without further setup.
|
:ref:`api_guide_dfu_flash_udev`. Mac OS users should be able to use ``dfu-util`` without further setup.
|
||||||
|
|
||||||
|
If there are more boards with the same chip connected then ``idf.py dfu-list`` can be used to list the available
|
||||||
|
devices, for example::
|
||||||
|
|
||||||
|
Found Runtime: [303a:0002] ver=0723, devnum=4, cfg=1, intf=2, path="1-10", alt=0, name="UNKNOWN", serial="0"
|
||||||
|
Found Runtime: [303a:0002] ver=0723, devnum=6, cfg=1, intf=2, path="1-2", alt=0, name="UNKNOWN", serial="0"
|
||||||
|
|
||||||
|
Consequently, the desired device can be selected for flashing by the ``--path`` argument. For example, the devices
|
||||||
|
listed above can be flashed individually by the following commands::
|
||||||
|
|
||||||
|
idf.py dfu-flash --path 1-10
|
||||||
|
idf.py dfu-flash --path 1-2
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The vendor and product identificators are set based on the selected chip target by the ``idf.py set-target``
|
||||||
|
command and it is not selectable during the ``idf.py dfu-flash`` call.
|
||||||
|
|
||||||
See :ref:`api_guide_dfu_flash_errors` and their solutions.
|
See :ref:`api_guide_dfu_flash_errors` and their solutions.
|
||||||
|
|
||||||
.. _api_guide_dfu_flash_udev:
|
.. _api_guide_dfu_flash_udev:
|
||||||
|
@ -3,8 +3,12 @@
|
|||||||
|
|
||||||
function(__add_dfu_targets)
|
function(__add_dfu_targets)
|
||||||
idf_build_get_property(target IDF_TARGET)
|
idf_build_get_property(target IDF_TARGET)
|
||||||
if(NOT "${target}" STREQUAL "esp32s2")
|
if("${target}" STREQUAL "esp32")
|
||||||
return()
|
return()
|
||||||
|
elseif("${target}" STREQUAL "esp32s2")
|
||||||
|
set(dfu_pid "2")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "DFU PID unknown for ${target}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_build_get_property(python PYTHON)
|
idf_build_get_property(python PYTHON)
|
||||||
@ -14,13 +18,21 @@ function(__add_dfu_targets)
|
|||||||
COMMAND ${python} ${idf_path}/tools/mkdfu.py write
|
COMMAND ${python} ${idf_path}/tools/mkdfu.py write
|
||||||
-o "${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
|
-o "${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
|
||||||
--json "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json"
|
--json "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json"
|
||||||
|
--pid "${dfu_pid}"
|
||||||
DEPENDS gen_project_binary bootloader
|
DEPENDS gen_project_binary bootloader
|
||||||
VERBATIM
|
VERBATIM
|
||||||
USES_TERMINAL)
|
USES_TERMINAL)
|
||||||
|
|
||||||
|
add_custom_target(dfu-list
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-D ESP_DFU_LIST="1"
|
||||||
|
-P ${idf_path}/tools/cmake/run_dfu_util.cmake
|
||||||
|
USES_TERMINAL)
|
||||||
|
|
||||||
add_custom_target(dfu-flash
|
add_custom_target(dfu-flash
|
||||||
COMMAND dfu-util
|
COMMAND ${CMAKE_COMMAND}
|
||||||
-D "${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
|
-D ESP_DFU_BIN="${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
|
||||||
VERBATIM
|
-D ESP_DFU_PID="${dfu_pid}"
|
||||||
|
-P ${idf_path}/tools/cmake/run_dfu_util.cmake
|
||||||
USES_TERMINAL)
|
USES_TERMINAL)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
28
tools/cmake/run_dfu_util.cmake
Normal file
28
tools/cmake/run_dfu_util.cmake
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# A CMake script to run dfu-util from within ninja or make
|
||||||
|
# or another cmake-based build runner
|
||||||
|
#
|
||||||
|
# It is recommended to NOT USE this CMake script directly
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
set(TOOL "dfu-util")
|
||||||
|
set(CMD "${TOOL}")
|
||||||
|
|
||||||
|
if(${ESP_DFU_LIST})
|
||||||
|
list(APPEND CMD "--list")
|
||||||
|
else()
|
||||||
|
# The following works even when ESP_DFU_PID is not defined.
|
||||||
|
list(APPEND CMD "-d" "303a:${ESP_DFU_PID}")
|
||||||
|
|
||||||
|
if(NOT $ENV{ESP_DFU_PATH} STREQUAL "")
|
||||||
|
list(APPEND CMD "--path" $ENV{ESP_DFU_PATH})
|
||||||
|
endif()
|
||||||
|
list(APPEND CMD "-D" ${ESP_DFU_BIN})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message("Command list: ${CMD}")
|
||||||
|
execute_process(COMMAND ${CMD} RESULT_VARIABLE result)
|
||||||
|
|
||||||
|
if(${result})
|
||||||
|
message(FATAL_ERROR "${TOOL} failed")
|
||||||
|
endif()
|
@ -10,11 +10,11 @@ def action_extensions(base_actions, project_path):
|
|||||||
ensure_build_directory(args, ctx.info_name)
|
ensure_build_directory(args, ctx.info_name)
|
||||||
run_target(target_name, args)
|
run_target(target_name, args)
|
||||||
|
|
||||||
def dfu_flash_target(target_name, ctx, args):
|
def dfu_flash_target(target_name, ctx, args, path):
|
||||||
ensure_build_directory(args, ctx.info_name)
|
ensure_build_directory(args, ctx.info_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
run_target(target_name, args)
|
run_target(target_name, args, {"ESP_DFU_PATH": path})
|
||||||
except FatalError:
|
except FatalError:
|
||||||
# Cannot capture the error from dfu-util here so the best advise is:
|
# Cannot capture the error from dfu-util here so the best advise is:
|
||||||
print('Please have a look at the "Device Firmware Upgrade through USB" chapter in API Guides of the '
|
print('Please have a look at the "Device Firmware Upgrade through USB" chapter in API Guides of the '
|
||||||
@ -28,10 +28,24 @@ def action_extensions(base_actions, project_path):
|
|||||||
"short_help": "Build the DFU binary",
|
"short_help": "Build the DFU binary",
|
||||||
"dependencies": ["all"],
|
"dependencies": ["all"],
|
||||||
},
|
},
|
||||||
|
"dfu-list": {
|
||||||
|
"callback": dfu_target,
|
||||||
|
"short_help": "List DFU capable devices",
|
||||||
|
"dependencies": [],
|
||||||
|
},
|
||||||
"dfu-flash": {
|
"dfu-flash": {
|
||||||
"callback": dfu_flash_target,
|
"callback": dfu_flash_target,
|
||||||
"short_help": "Flash the DFU binary",
|
"short_help": "Flash the DFU binary",
|
||||||
"order_dependencies": ["dfu"],
|
"order_dependencies": ["dfu"],
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"names": ["--path"],
|
||||||
|
"default": "",
|
||||||
|
"help": "Specify path to DFU device. The default empty path works if there is just one "
|
||||||
|
"ESP device with the same product identificator. See the device list for paths "
|
||||||
|
"of available devices."
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,8 +107,6 @@ DFUSuffix = namedtuple(
|
|||||||
"DFUSuffix", ["bcd_device", "pid", "vid", "bcd_dfu", "sig", "len"]
|
"DFUSuffix", ["bcd_device", "pid", "vid", "bcd_dfu", "sig", "len"]
|
||||||
)
|
)
|
||||||
ESPRESSIF_VID = 12346
|
ESPRESSIF_VID = 12346
|
||||||
# TODO: set PID based on the chip type (add a command line argument)
|
|
||||||
DFUSUFFIX_DEFAULT = DFUSuffix(0xFFFF, 0xFFFF, ESPRESSIF_VID, 0x0100, b"UFD", 16)
|
|
||||||
# This CRC32 gets added after DFUSUFFIX_STRUCT
|
# This CRC32 gets added after DFUSUFFIX_STRUCT
|
||||||
DFUCRC_STRUCT = b"<I"
|
DFUCRC_STRUCT = b"<I"
|
||||||
|
|
||||||
@ -126,8 +124,9 @@ def pad_bytes(b, multiple, padding=b"\x00"): # type: (bytes, int, bytes) -> byt
|
|||||||
|
|
||||||
|
|
||||||
class EspDfuWriter(object):
|
class EspDfuWriter(object):
|
||||||
def __init__(self, dest_file): # type: (typing.BinaryIO) -> None
|
def __init__(self, dest_file, pid): # type: (typing.BinaryIO) -> None
|
||||||
self.dest = dest_file
|
self.dest = dest_file
|
||||||
|
self.pid = pid
|
||||||
self.entries = [] # type: typing.List[bytes]
|
self.entries = [] # type: typing.List[bytes]
|
||||||
self.index = [] # type: typing.List[DFUInfo]
|
self.index = [] # type: typing.List[DFUInfo]
|
||||||
|
|
||||||
@ -151,7 +150,8 @@ class EspDfuWriter(object):
|
|||||||
out_data = pad_bytes(out_data, cpio_block_size)
|
out_data = pad_bytes(out_data, cpio_block_size)
|
||||||
|
|
||||||
# Add DFU suffix and CRC
|
# Add DFU suffix and CRC
|
||||||
out_data += struct.pack(DFUSUFFIX_STRUCT, *DFUSUFFIX_DEFAULT)
|
dfu_suffix = DFUSuffix(0xFFFF, self.pid, ESPRESSIF_VID, 0x0100, b"UFD", 16)
|
||||||
|
out_data += struct.pack(DFUSUFFIX_STRUCT, *dfu_suffix)
|
||||||
out_data += struct.pack(DFUCRC_STRUCT, dfu_crc(out_data))
|
out_data += struct.pack(DFUCRC_STRUCT, dfu_crc(out_data))
|
||||||
|
|
||||||
# Finally write the entire binary
|
# Finally write the entire binary
|
||||||
@ -187,7 +187,7 @@ class EspDfuWriter(object):
|
|||||||
|
|
||||||
|
|
||||||
def action_write(args):
|
def action_write(args):
|
||||||
writer = EspDfuWriter(args['output_file'])
|
writer = EspDfuWriter(args['output_file'], args['pid'])
|
||||||
for addr, f in args['files']:
|
for addr, f in args['files']:
|
||||||
print('Adding {} at {:#x}'.format(f, addr))
|
print('Adding {} at {:#x}'.format(f, addr))
|
||||||
writer.add_file(addr, f)
|
writer.add_file(addr, f)
|
||||||
@ -205,6 +205,10 @@ def main():
|
|||||||
help='Filename for storing the output DFU image',
|
help='Filename for storing the output DFU image',
|
||||||
required=True,
|
required=True,
|
||||||
type=argparse.FileType("wb"))
|
type=argparse.FileType("wb"))
|
||||||
|
write_parser.add_argument("--pid",
|
||||||
|
required=True,
|
||||||
|
type=lambda h: int(h, 16),
|
||||||
|
help='Hexa-decimal product indentificator')
|
||||||
write_parser.add_argument("--json",
|
write_parser.add_argument("--json",
|
||||||
help='Optional file for loading "flash_files" dictionary with <address> <file> items')
|
help='Optional file for loading "flash_files" dictionary with <address> <file> items')
|
||||||
write_parser.add_argument("files",
|
write_parser.add_argument("files",
|
||||||
@ -241,6 +245,7 @@ def main():
|
|||||||
|
|
||||||
cmd_args = {'output_file': args.output_file,
|
cmd_args = {'output_file': args.output_file,
|
||||||
'files': files,
|
'files': files,
|
||||||
|
'pid': args.pid,
|
||||||
}
|
}
|
||||||
|
|
||||||
{'write': action_write
|
{'write': action_write
|
||||||
|
Binary file not shown.
@ -35,6 +35,7 @@ class TestHelloWorldExample(unittest.TestCase):
|
|||||||
self.addCleanup(os.unlink, f.name)
|
self.addCleanup(os.unlink, f.name)
|
||||||
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
|
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
|
||||||
'-o', f.name,
|
'-o', f.name,
|
||||||
|
'--pid', '2',
|
||||||
add_args])
|
add_args])
|
||||||
p = pexpect.spawn(cmd, timeout=10)
|
p = pexpect.spawn(cmd, timeout=10)
|
||||||
self.addCleanup(p.terminate, force=True)
|
self.addCleanup(p.terminate, force=True)
|
||||||
@ -81,6 +82,7 @@ class TestHelloWorldExample(unittest.TestCase):
|
|||||||
|
|
||||||
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
|
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
|
||||||
'-o', output,
|
'-o', output,
|
||||||
|
'--pid', '2',
|
||||||
' '.join(['0x1000', bootloader,
|
' '.join(['0x1000', bootloader,
|
||||||
'0x8000', os.path.join(current_dir, '1', '2.bin'),
|
'0x8000', os.path.join(current_dir, '1', '2.bin'),
|
||||||
'0x10000', os.path.join(current_dir, '1', '3.bin')
|
'0x10000', os.path.join(current_dir, '1', '3.bin')
|
||||||
|
Loading…
Reference in New Issue
Block a user