1# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, 2# Espressif Systems (Shanghai) CO LTD, other contributors as noted. 3# 4# SPDX-License-Identifier: GPL-2.0-or-later 5# PYTHON_ARGCOMPLETE_OK 6__all__ = [ 7 "chip_id", 8 "detect_chip", 9 "dump_mem", 10 "elf2image", 11 "erase_flash", 12 "erase_region", 13 "flash_id", 14 "get_security_info", 15 "image_info", 16 "load_ram", 17 "make_image", 18 "merge_bin", 19 "read_flash", 20 "read_flash_status", 21 "read_mac", 22 "read_mem", 23 "run", 24 "verify_flash", 25 "version", 26 "write_flash", 27 "write_flash_status", 28 "write_mem", 29] 30 31__version__ = "4.8.1" 32 33import argparse 34import inspect 35import os 36import shlex 37import sys 38import time 39import traceback 40 41from esptool.bin_image import intel_hex_to_bin 42from esptool.cmds import ( 43 DETECTED_FLASH_SIZES, 44 chip_id, 45 detect_chip, 46 detect_flash_size, 47 dump_mem, 48 elf2image, 49 erase_flash, 50 erase_region, 51 flash_id, 52 read_flash_sfdp, 53 get_security_info, 54 image_info, 55 load_ram, 56 make_image, 57 merge_bin, 58 read_flash, 59 read_flash_status, 60 read_mac, 61 read_mem, 62 run, 63 verify_flash, 64 version, 65 write_flash, 66 write_flash_status, 67 write_mem, 68) 69from esptool.config import load_config_file 70from esptool.loader import ( 71 DEFAULT_CONNECT_ATTEMPTS, 72 DEFAULT_OPEN_PORT_ATTEMPTS, 73 StubFlasher, 74 ESPLoader, 75 list_ports, 76) 77from esptool.targets import CHIP_DEFS, CHIP_LIST, ESP32ROM 78from esptool.util import ( 79 FatalError, 80 NotImplementedInROMError, 81 flash_size_bytes, 82 strip_chip_name, 83) 84from itertools import chain, cycle, repeat 85 86import serial 87 88 89def main(argv=None, esp=None): 90 """ 91 Main function for esptool 92 93 argv - Optional override for default arguments parsing (that uses sys.argv), 94 can be a list of custom arguments as strings. Arguments and their values 95 need to be added as individual items to the list 96 e.g. "-b 115200" thus becomes ['-b', '115200']. 97 98 esp - Optional override of the connected device previously 99 returned by get_default_connected_device() 100 """ 101 102 external_esp = esp is not None 103 104 parser = argparse.ArgumentParser( 105 description="esptool.py v%s - Espressif chips ROM Bootloader Utility" 106 % __version__, 107 prog="esptool", 108 ) 109 110 parser.add_argument( 111 "--chip", 112 "-c", 113 help="Target chip type", 114 type=strip_chip_name, 115 choices=["auto"] + CHIP_LIST, 116 default=os.environ.get("ESPTOOL_CHIP", "auto"), 117 ) 118 119 parser.add_argument( 120 "--port", 121 "-p", 122 help="Serial port device", 123 default=os.environ.get("ESPTOOL_PORT", None), 124 ) 125 126 parser.add_argument( 127 "--baud", 128 "-b", 129 help="Serial port baud rate used when flashing/reading", 130 type=arg_auto_int, 131 default=os.environ.get("ESPTOOL_BAUD", ESPLoader.ESP_ROM_BAUD), 132 ) 133 134 parser.add_argument( 135 "--port-filter", 136 action="append", 137 help="Serial port device filter, can be vid=NUMBER, pid=NUMBER, name=SUBSTRING", 138 type=str, 139 default=[], 140 ) 141 142 parser.add_argument( 143 "--before", 144 help="What to do before connecting to the chip", 145 choices=["default_reset", "usb_reset", "no_reset", "no_reset_no_sync"], 146 default=os.environ.get("ESPTOOL_BEFORE", "default_reset"), 147 ) 148 149 parser.add_argument( 150 "--after", 151 "-a", 152 help="What to do after esptool.py is finished", 153 choices=["hard_reset", "soft_reset", "no_reset", "no_reset_stub"], 154 default=os.environ.get("ESPTOOL_AFTER", "hard_reset"), 155 ) 156 157 parser.add_argument( 158 "--no-stub", 159 help="Disable launching the flasher stub, only talk to ROM bootloader. " 160 "Some features will not be available.", 161 action="store_true", 162 ) 163 164 # --stub-version can be set with --no-stub so the tests wouldn't fail if this option is implied globally 165 parser.add_argument( 166 "--stub-version", 167 default=os.environ.get("ESPTOOL_STUB_VERSION", StubFlasher.STUB_SUBDIRS[0]), 168 choices=StubFlasher.STUB_SUBDIRS, 169 # not a public option and is not subject to the semantic versioning policy 170 help=argparse.SUPPRESS, 171 ) 172 173 parser.add_argument( 174 "--trace", 175 "-t", 176 help="Enable trace-level output of esptool.py interactions.", 177 action="store_true", 178 ) 179 180 parser.add_argument( 181 "--override-vddsdio", 182 help="Override ESP32 VDDSDIO internal voltage regulator (use with care)", 183 choices=ESP32ROM.OVERRIDE_VDDSDIO_CHOICES, 184 nargs="?", 185 ) 186 187 parser.add_argument( 188 "--connect-attempts", 189 help=( 190 "Number of attempts to connect, negative or 0 for infinite. " 191 "Default: %d." % DEFAULT_CONNECT_ATTEMPTS 192 ), 193 type=int, 194 default=os.environ.get("ESPTOOL_CONNECT_ATTEMPTS", DEFAULT_CONNECT_ATTEMPTS), 195 ) 196 197 subparsers = parser.add_subparsers( 198 dest="operation", help="Run esptool.py {command} -h for additional help" 199 ) 200 201 def add_spi_connection_arg(parent): 202 parent.add_argument( 203 "--spi-connection", 204 "-sc", 205 help="Override default SPI Flash connection. " 206 "Value can be SPI, HSPI or a comma-separated list of 5 I/O numbers " 207 "to use for SPI flash (CLK,Q,D,HD,CS). Not supported with ESP8266.", 208 action=SpiConnectionAction, 209 ) 210 211 parser_load_ram = subparsers.add_parser( 212 "load_ram", help="Download an image to RAM and execute" 213 ) 214 parser_load_ram.add_argument( 215 "filename", help="Firmware image", action=AutoHex2BinAction 216 ) 217 218 parser_dump_mem = subparsers.add_parser( 219 "dump_mem", help="Dump arbitrary memory to disk" 220 ) 221 parser_dump_mem.add_argument("address", help="Base address", type=arg_auto_int) 222 parser_dump_mem.add_argument( 223 "size", help="Size of region to dump", type=arg_auto_int 224 ) 225 parser_dump_mem.add_argument("filename", help="Name of binary dump") 226 227 parser_read_mem = subparsers.add_parser( 228 "read_mem", help="Read arbitrary memory location" 229 ) 230 parser_read_mem.add_argument("address", help="Address to read", type=arg_auto_int) 231 232 parser_write_mem = subparsers.add_parser( 233 "write_mem", help="Read-modify-write to arbitrary memory location" 234 ) 235 parser_write_mem.add_argument("address", help="Address to write", type=arg_auto_int) 236 parser_write_mem.add_argument("value", help="Value", type=arg_auto_int) 237 parser_write_mem.add_argument( 238 "mask", 239 help="Mask of bits to write", 240 type=arg_auto_int, 241 nargs="?", 242 default="0xFFFFFFFF", 243 ) 244 245 def add_spi_flash_subparsers( 246 parent: argparse.ArgumentParser, 247 allow_keep: bool, 248 auto_detect: bool, 249 size_only: bool = False, 250 ): 251 """Add common parser arguments for SPI flash properties""" 252 extra_keep_args = ["keep"] if allow_keep else [] 253 254 if auto_detect and allow_keep: 255 extra_fs_message = ", detect, or keep" 256 flash_sizes = ["detect", "keep"] 257 elif auto_detect: 258 extra_fs_message = ", or detect" 259 flash_sizes = ["detect"] 260 elif allow_keep: 261 extra_fs_message = ", or keep" 262 flash_sizes = ["keep"] 263 else: 264 extra_fs_message = "" 265 flash_sizes = [] 266 267 if not size_only: 268 parent.add_argument( 269 "--flash_freq", 270 "-ff", 271 help="SPI Flash frequency", 272 choices=extra_keep_args 273 + [ 274 "80m", 275 "60m", 276 "48m", 277 "40m", 278 "30m", 279 "26m", 280 "24m", 281 "20m", 282 "16m", 283 "15m", 284 "12m", 285 ], 286 default=os.environ.get("ESPTOOL_FF", "keep" if allow_keep else None), 287 ) 288 parent.add_argument( 289 "--flash_mode", 290 "-fm", 291 help="SPI Flash mode", 292 choices=extra_keep_args + ["qio", "qout", "dio", "dout"], 293 default=os.environ.get("ESPTOOL_FM", "keep" if allow_keep else "qio"), 294 ) 295 296 parent.add_argument( 297 "--flash_size", 298 "-fs", 299 help="SPI Flash size in MegaBytes " 300 "(1MB, 2MB, 4MB, 8MB, 16MB, 32MB, 64MB, 128MB) " 301 "plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1)" + extra_fs_message, 302 choices=flash_sizes 303 + [ 304 "256KB", 305 "512KB", 306 "1MB", 307 "2MB", 308 "2MB-c1", 309 "4MB", 310 "4MB-c1", 311 "8MB", 312 "16MB", 313 "32MB", 314 "64MB", 315 "128MB", 316 ], 317 default=os.environ.get("ESPTOOL_FS", "keep" if allow_keep else "1MB"), 318 ) 319 add_spi_connection_arg(parent) 320 321 parser_write_flash = subparsers.add_parser( 322 "write_flash", help="Write a binary blob to flash" 323 ) 324 325 parser_write_flash.add_argument( 326 "addr_filename", 327 metavar="<address> <filename>", 328 help="Address followed by binary filename, separated by space", 329 action=AddrFilenamePairAction, 330 ) 331 parser_write_flash.add_argument( 332 "--erase-all", 333 "-e", 334 help="Erase all regions of flash (not just write areas) before programming", 335 action="store_true", 336 ) 337 338 add_spi_flash_subparsers(parser_write_flash, allow_keep=True, auto_detect=True) 339 parser_write_flash.add_argument( 340 "--no-progress", "-p", help="Suppress progress output", action="store_true" 341 ) 342 parser_write_flash.add_argument( 343 "--verify", 344 help="Verify just-written data on flash " 345 "(mostly superfluous, data is read back during flashing)", 346 action="store_true", 347 ) 348 parser_write_flash.add_argument( 349 "--encrypt", 350 help="Apply flash encryption when writing data " 351 "(required correct efuse settings)", 352 action="store_true", 353 ) 354 # In order to not break backward compatibility, 355 # our list of encrypted files to flash is a new parameter 356 parser_write_flash.add_argument( 357 "--encrypt-files", 358 metavar="<address> <filename>", 359 help="Files to be encrypted on the flash. " 360 "Address followed by binary filename, separated by space.", 361 action=AddrFilenamePairAction, 362 ) 363 parser_write_flash.add_argument( 364 "--ignore-flash-encryption-efuse-setting", 365 help="Ignore flash encryption efuse settings ", 366 action="store_true", 367 ) 368 parser_write_flash.add_argument( 369 "--force", 370 help="Force write, skip security and compatibility checks. Use with caution!", 371 action="store_true", 372 ) 373 374 compress_args = parser_write_flash.add_mutually_exclusive_group(required=False) 375 compress_args.add_argument( 376 "--compress", 377 "-z", 378 help="Compress data in transfer (default unless --no-stub is specified)", 379 action="store_true", 380 default=None, 381 ) 382 compress_args.add_argument( 383 "--no-compress", 384 "-u", 385 help="Disable data compression during transfer " 386 "(default if --no-stub is specified)", 387 action="store_true", 388 ) 389 390 subparsers.add_parser("run", help="Run application code in flash") 391 392 parser_image_info = subparsers.add_parser( 393 "image_info", help="Dump headers from a binary file (bootloader or application)" 394 ) 395 parser_image_info.add_argument( 396 "filename", help="Image file to parse", action=AutoHex2BinAction 397 ) 398 parser_image_info.add_argument( 399 "--version", 400 "-v", 401 help="Output format version (1 - legacy, 2 - extended)", 402 choices=["1", "2"], 403 default="1", 404 ) 405 406 parser_make_image = subparsers.add_parser( 407 "make_image", help="Create an application image from binary files" 408 ) 409 parser_make_image.add_argument("output", help="Output image file") 410 parser_make_image.add_argument( 411 "--segfile", "-f", action="append", help="Segment input file" 412 ) 413 parser_make_image.add_argument( 414 "--segaddr", 415 "-a", 416 action="append", 417 help="Segment base address", 418 type=arg_auto_int, 419 ) 420 parser_make_image.add_argument( 421 "--entrypoint", 422 "-e", 423 help="Address of entry point", 424 type=arg_auto_int, 425 default=0, 426 ) 427 428 parser_elf2image = subparsers.add_parser( 429 "elf2image", help="Create an application image from ELF file" 430 ) 431 parser_elf2image.add_argument("input", help="Input ELF file") 432 parser_elf2image.add_argument( 433 "--output", 434 "-o", 435 help="Output filename prefix (for version 1 image), " 436 "or filename (for version 2 single image)", 437 type=str, 438 ) 439 parser_elf2image.add_argument( 440 "--version", 441 "-e", 442 help="Output image version", 443 choices=["1", "2", "3"], 444 default="1", 445 ) 446 parser_elf2image.add_argument( 447 # it kept for compatibility 448 # Minimum chip revision (deprecated, consider using --min-rev-full) 449 "--min-rev", 450 "-r", 451 help=argparse.SUPPRESS, 452 type=int, 453 choices=range(256), 454 metavar="{0, ... 255}", 455 default=0, 456 ) 457 parser_elf2image.add_argument( 458 "--min-rev-full", 459 help="Minimal chip revision (in format: major * 100 + minor)", 460 type=int, 461 choices=range(65536), 462 metavar="{0, ... 65535}", 463 default=0, 464 ) 465 parser_elf2image.add_argument( 466 "--max-rev-full", 467 help="Maximal chip revision (in format: major * 100 + minor)", 468 type=int, 469 choices=range(65536), 470 metavar="{0, ... 65535}", 471 default=65535, 472 ) 473 parser_elf2image.add_argument( 474 "--secure-pad", 475 action="store_true", 476 help="Pad image so once signed it will end on a 64KB boundary. " 477 "For Secure Boot v1 images only.", 478 ) 479 parser_elf2image.add_argument( 480 "--secure-pad-v2", 481 action="store_true", 482 help="Pad image to 64KB, so once signed its signature sector will" 483 "start at the next 64K block. For Secure Boot v2 images only.", 484 ) 485 parser_elf2image.add_argument( 486 "--elf-sha256-offset", 487 help="If set, insert SHA256 hash (32 bytes) of the input ELF file " 488 "at specified offset in the binary.", 489 type=arg_auto_int, 490 default=None, 491 ) 492 parser_elf2image.add_argument( 493 "--dont-append-digest", 494 dest="append_digest", 495 help="Don't append a SHA256 digest of the entire image after the checksum. " 496 "This argument is not supported and ignored for ESP8266.", 497 action="store_false", 498 default=True, 499 ) 500 parser_elf2image.add_argument( 501 "--use_segments", 502 help="If set, ELF segments will be used instead of ELF sections " 503 "to generate the image.", 504 action="store_true", 505 ) 506 parser_elf2image.add_argument( 507 "--flash-mmu-page-size", 508 help="Change flash MMU page size.", 509 choices=["64KB", "32KB", "16KB", "8KB"], 510 ) 511 parser_elf2image.add_argument( 512 "--pad-to-size", 513 help="The block size with which the final binary image after padding " 514 "must be aligned to. Value 0xFF is used for padding, similar to erase_flash", 515 default=None, 516 ) 517 parser_elf2image.add_argument( 518 "--ram-only-header", 519 help="Order segments of the output so IRAM and DRAM are placed at the " 520 "beginning and force the main header segment number to RAM segments " 521 "quantity. This will make the other segments invisible to the ROM " 522 "loader. Use this argument with care because the ROM loader will load " 523 "only the RAM segments although the other segments being present in " 524 "the output. Implies --dont-append-digest", 525 action="store_true", 526 default=None, 527 ) 528 529 add_spi_flash_subparsers(parser_elf2image, allow_keep=False, auto_detect=False) 530 531 subparsers.add_parser("read_mac", help="Read MAC address from OTP ROM") 532 533 subparsers.add_parser("chip_id", help="Read Chip ID from OTP ROM") 534 535 parser_flash_id = subparsers.add_parser( 536 "flash_id", help="Read SPI flash manufacturer and device ID" 537 ) 538 add_spi_connection_arg(parser_flash_id) 539 540 parser_read_status = subparsers.add_parser( 541 "read_flash_status", help="Read SPI flash status register" 542 ) 543 544 add_spi_connection_arg(parser_read_status) 545 parser_read_status.add_argument( 546 "--bytes", 547 help="Number of bytes to read (1-3)", 548 type=int, 549 choices=[1, 2, 3], 550 default=2, 551 ) 552 553 parser_write_status = subparsers.add_parser( 554 "write_flash_status", help="Write SPI flash status register" 555 ) 556 557 add_spi_connection_arg(parser_write_status) 558 parser_write_status.add_argument( 559 "--non-volatile", 560 help="Write non-volatile bits (use with caution)", 561 action="store_true", 562 ) 563 parser_write_status.add_argument( 564 "--bytes", 565 help="Number of status bytes to write (1-3)", 566 type=int, 567 choices=[1, 2, 3], 568 default=2, 569 ) 570 parser_write_status.add_argument("value", help="New value", type=arg_auto_int) 571 572 parser_read_flash = subparsers.add_parser( 573 "read_flash", help="Read SPI flash content" 574 ) 575 add_spi_flash_subparsers( 576 parser_read_flash, allow_keep=True, auto_detect=True, size_only=True 577 ) 578 parser_read_flash.add_argument("address", help="Start address", type=arg_auto_int) 579 parser_read_flash.add_argument( 580 "size", 581 help="Size of region to dump. Use `ALL` to read to the end of flash.", 582 type=arg_auto_size, 583 ) 584 parser_read_flash.add_argument("filename", help="Name of binary dump") 585 parser_read_flash.add_argument( 586 "--no-progress", "-p", help="Suppress progress output", action="store_true" 587 ) 588 589 parser_verify_flash = subparsers.add_parser( 590 "verify_flash", help="Verify a binary blob against flash" 591 ) 592 parser_verify_flash.add_argument( 593 "addr_filename", 594 help="Address and binary file to verify there, separated by space", 595 action=AddrFilenamePairAction, 596 ) 597 parser_verify_flash.add_argument( 598 "--diff", "-d", help="Show differences", choices=["no", "yes"], default="no" 599 ) 600 add_spi_flash_subparsers(parser_verify_flash, allow_keep=True, auto_detect=True) 601 602 parser_erase_flash = subparsers.add_parser( 603 "erase_flash", help="Perform Chip Erase on SPI flash" 604 ) 605 parser_erase_flash.add_argument( 606 "--force", 607 help="Erase flash even if security features are enabled. Use with caution!", 608 action="store_true", 609 ) 610 add_spi_connection_arg(parser_erase_flash) 611 612 parser_erase_region = subparsers.add_parser( 613 "erase_region", help="Erase a region of the flash" 614 ) 615 parser_erase_region.add_argument( 616 "--force", 617 help="Erase region even if security features are enabled. Use with caution!", 618 action="store_true", 619 ) 620 add_spi_connection_arg(parser_erase_region) 621 parser_erase_region.add_argument( 622 "address", help="Start address (must be multiple of 4096)", type=arg_auto_int 623 ) 624 parser_erase_region.add_argument( 625 "size", 626 help="Size of region to erase (must be multiple of 4096). " 627 "Use `ALL` to erase to the end of flash.", 628 type=arg_auto_size, 629 ) 630 631 parser_read_flash_sfdp = subparsers.add_parser( 632 "read_flash_sfdp", 633 help="Read SPI flash SFDP (Serial Flash Discoverable Parameters)", 634 ) 635 add_spi_flash_subparsers(parser_read_flash_sfdp, allow_keep=True, auto_detect=True) 636 parser_read_flash_sfdp.add_argument("addr", type=arg_auto_int) 637 parser_read_flash_sfdp.add_argument("bytes", type=int) 638 639 parser_merge_bin = subparsers.add_parser( 640 "merge_bin", 641 help="Merge multiple raw binary files into a single file for later flashing", 642 ) 643 644 parser_merge_bin.add_argument( 645 "--output", "-o", help="Output filename", type=str, required=True 646 ) 647 parser_merge_bin.add_argument( 648 "--format", 649 "-f", 650 help="Format of the output file", 651 choices=["raw", "uf2", "hex"], 652 default="raw", 653 ) 654 uf2_group = parser_merge_bin.add_argument_group("UF2 format") 655 uf2_group.add_argument( 656 "--chunk-size", 657 help="Specify the used data part of the 512 byte UF2 block. " 658 "A common value is 256. By default the largest possible value will be used.", 659 default=None, 660 type=arg_auto_chunk_size, 661 ) 662 uf2_group.add_argument( 663 "--md5-disable", 664 help="Disable MD5 checksum in UF2 output", 665 action="store_true", 666 ) 667 add_spi_flash_subparsers(parser_merge_bin, allow_keep=True, auto_detect=False) 668 669 raw_group = parser_merge_bin.add_argument_group("RAW format") 670 raw_group.add_argument( 671 "--target-offset", 672 "-t", 673 help="Target offset where the output file will be flashed", 674 type=arg_auto_int, 675 default=0, 676 ) 677 raw_group.add_argument( 678 "--fill-flash-size", 679 help="If set, the final binary file will be padded with FF " 680 "bytes up to this flash size.", 681 choices=[ 682 "256KB", 683 "512KB", 684 "1MB", 685 "2MB", 686 "4MB", 687 "8MB", 688 "16MB", 689 "32MB", 690 "64MB", 691 "128MB", 692 ], 693 ) 694 parser_merge_bin.add_argument( 695 "addr_filename", 696 metavar="<address> <filename>", 697 help="Address followed by binary filename, separated by space", 698 action=AddrFilenamePairAction, 699 ) 700 701 subparsers.add_parser("get_security_info", help="Get some security-related data") 702 703 subparsers.add_parser("version", help="Print esptool version") 704 705 # internal sanity check - every operation matches a module function of the same name 706 for operation in subparsers.choices.keys(): 707 assert operation in globals(), "%s should be a module function" % operation 708 709 # Enable argcomplete only on Unix-like systems 710 if sys.platform != "win32": 711 try: 712 import argcomplete 713 714 argcomplete.autocomplete(parser) 715 except ImportError: 716 pass 717 718 argv = expand_file_arguments(argv or sys.argv[1:]) 719 720 args = parser.parse_args(argv) 721 print("esptool.py v%s" % __version__) 722 load_config_file(verbose=True) 723 724 StubFlasher.set_preferred_stub_subdir(args.stub_version) 725 726 # Parse filter arguments into separate lists 727 args.filterVids = [] 728 args.filterPids = [] 729 args.filterNames = [] 730 for f in args.port_filter: 731 kvp = f.split("=") 732 if len(kvp) != 2: 733 raise FatalError("Option --port-filter argument must consist of key=value") 734 if kvp[0] == "vid": 735 args.filterVids.append(arg_auto_int(kvp[1])) 736 elif kvp[0] == "pid": 737 args.filterPids.append(arg_auto_int(kvp[1])) 738 elif kvp[0] == "name": 739 args.filterNames.append(kvp[1]) 740 else: 741 raise FatalError("Option --port-filter argument key not recognized") 742 743 # operation function can take 1 arg (args), 2 args (esp, arg) 744 # or be a member function of the ESPLoader class. 745 746 if args.operation is None: 747 parser.print_help() 748 sys.exit(1) 749 750 # Forbid the usage of both --encrypt, which means encrypt all the given files, 751 # and --encrypt-files, which represents the list of files to encrypt. 752 # The reason is that allowing both at the same time increases the chances of 753 # having contradictory lists (e.g. one file not available in one of list). 754 if ( 755 args.operation == "write_flash" 756 and args.encrypt 757 and args.encrypt_files is not None 758 ): 759 raise FatalError( 760 "Options --encrypt and --encrypt-files " 761 "must not be specified at the same time." 762 ) 763 764 operation_func = globals()[args.operation] 765 operation_args = inspect.getfullargspec(operation_func).args 766 767 if ( 768 operation_args[0] == "esp" 769 ): # operation function takes an ESPLoader connection object 770 if args.before != "no_reset_no_sync": 771 initial_baud = min( 772 ESPLoader.ESP_ROM_BAUD, args.baud 773 ) # don't sync faster than the default baud rate 774 else: 775 initial_baud = args.baud 776 777 if args.port is None: 778 ser_list = get_port_list(args.filterVids, args.filterPids, args.filterNames) 779 print("Found %d serial ports" % len(ser_list)) 780 else: 781 ser_list = [args.port] 782 open_port_attempts = os.environ.get( 783 "ESPTOOL_OPEN_PORT_ATTEMPTS", DEFAULT_OPEN_PORT_ATTEMPTS 784 ) 785 try: 786 open_port_attempts = int(open_port_attempts) 787 except ValueError: 788 raise SystemExit("Invalid value for ESPTOOL_OPEN_PORT_ATTEMPTS") 789 if open_port_attempts != 1: 790 if args.port is None or args.chip == "auto": 791 print( 792 "WARNING: The ESPTOOL_OPEN_PORT_ATTEMPTS (open_port_attempts) option can only be used with --port and --chip arguments." 793 ) 794 else: 795 esp = esp or connect_loop( 796 args.port, 797 initial_baud, 798 args.chip, 799 open_port_attempts, 800 args.trace, 801 args.before, 802 ) 803 esp = esp or get_default_connected_device( 804 ser_list, 805 port=args.port, 806 connect_attempts=args.connect_attempts, 807 initial_baud=initial_baud, 808 chip=args.chip, 809 trace=args.trace, 810 before=args.before, 811 ) 812 813 if esp is None: 814 raise FatalError( 815 "Could not connect to an Espressif device " 816 "on any of the %d available serial ports." % len(ser_list) 817 ) 818 819 if esp.secure_download_mode: 820 print("Chip is %s in Secure Download Mode" % esp.CHIP_NAME) 821 else: 822 print("Chip is %s" % (esp.get_chip_description())) 823 print("Features: %s" % ", ".join(esp.get_chip_features())) 824 print("Crystal is %dMHz" % esp.get_crystal_freq()) 825 read_mac(esp, args) 826 827 if not args.no_stub: 828 if esp.secure_download_mode: 829 print( 830 "WARNING: Stub loader is not supported in Secure Download Mode, " 831 "setting --no-stub" 832 ) 833 args.no_stub = True 834 elif not esp.IS_STUB and esp.stub_is_disabled: 835 print( 836 "WARNING: Stub loader has been disabled for compatibility, " 837 "setting --no-stub" 838 ) 839 args.no_stub = True 840 else: 841 try: 842 esp = esp.run_stub() 843 except Exception: 844 # The CH9102 bridge (PID: 0x55D4) can have issues on MacOS 845 if sys.platform == "darwin" and esp._get_pid() == 0x55D4: 846 print( 847 "\nNote: If issues persist, " 848 "try installing the WCH USB-to-Serial MacOS driver." 849 ) 850 raise 851 852 if args.override_vddsdio: 853 esp.override_vddsdio(args.override_vddsdio) 854 855 if args.baud > initial_baud: 856 try: 857 esp.change_baud(args.baud) 858 except NotImplementedInROMError: 859 print( 860 "WARNING: ROM doesn't support changing baud rate. " 861 "Keeping initial baud rate %d" % initial_baud 862 ) 863 864 def _define_spi_conn(spi_connection): 865 """Prepare SPI configuration string and value for flash_spi_attach()""" 866 clk, q, d, hd, cs = spi_connection 867 spi_config_txt = f"CLK:{clk}, Q:{q}, D:{d}, HD:{hd}, CS:{cs}" 868 value = (hd << 24) | (cs << 18) | (d << 12) | (q << 6) | clk 869 return spi_config_txt, value 870 871 # Override the common SPI flash parameter stuff if configured to do so 872 if hasattr(args, "spi_connection") and args.spi_connection is not None: 873 spi_config = args.spi_connection 874 if args.spi_connection == "SPI": 875 value = 0 876 elif args.spi_connection == "HSPI": 877 value = 1 878 else: 879 esp.check_spi_connection(args.spi_connection) 880 # Encode the pin numbers as a 32-bit integer with packed 6-bit values, 881 # the same way the ESP ROM takes them 882 spi_config, value = _define_spi_conn(args.spi_connection) 883 print(f"Configuring SPI flash mode ({spi_config})...") 884 esp.flash_spi_attach(value) 885 elif args.no_stub: 886 if esp.CHIP_NAME != "ESP32" or esp.secure_download_mode: 887 print("Enabling default SPI flash mode...") 888 # ROM loader doesn't enable flash unless we explicitly do it 889 esp.flash_spi_attach(0) 890 else: 891 # ROM doesn't attach in-package flash chips 892 spi_chip_pads = esp.get_chip_spi_pads() 893 spi_config_txt, value = _define_spi_conn(spi_chip_pads) 894 if spi_chip_pads != (0, 0, 0, 0, 0): 895 print( 896 "Attaching flash from eFuses' SPI pads configuration" 897 f"({spi_config_txt})..." 898 ) 899 else: 900 print("Enabling default SPI flash mode...") 901 esp.flash_spi_attach(value) 902 903 # XMC chip startup sequence 904 XMC_VENDOR_ID = 0x20 905 906 def is_xmc_chip_strict(): 907 id = esp.flash_id() 908 rdid = ((id & 0xFF) << 16) | ((id >> 16) & 0xFF) | (id & 0xFF00) 909 910 vendor_id = (rdid >> 16) & 0xFF 911 mfid = (rdid >> 8) & 0xFF 912 cpid = rdid & 0xFF 913 914 if vendor_id != XMC_VENDOR_ID: 915 return False 916 917 matched = False 918 if mfid == 0x40: 919 if cpid >= 0x13 and cpid <= 0x20: 920 matched = True 921 elif mfid == 0x41: 922 if cpid >= 0x17 and cpid <= 0x20: 923 matched = True 924 elif mfid == 0x50: 925 if cpid >= 0x15 and cpid <= 0x16: 926 matched = True 927 return matched 928 929 def flash_xmc_startup(): 930 # If the RDID value is a valid XMC one, may skip the flow 931 fast_check = True 932 if fast_check and is_xmc_chip_strict(): 933 return # Successful XMC flash chip boot-up detected by RDID, skipping. 934 935 sfdp_mfid_addr = 0x10 936 mf_id = esp.read_spiflash_sfdp(sfdp_mfid_addr, 8) 937 if mf_id != XMC_VENDOR_ID: # Non-XMC chip detected by SFDP Read, skipping. 938 return 939 940 print( 941 "WARNING: XMC flash chip boot-up failure detected! " 942 "Running XMC25QHxxC startup flow" 943 ) 944 esp.run_spiflash_command(0xB9) # Enter DPD 945 esp.run_spiflash_command(0x79) # Enter UDPD 946 esp.run_spiflash_command(0xFF) # Exit UDPD 947 time.sleep(0.002) # Delay tXUDPD 948 esp.run_spiflash_command(0xAB) # Release Power-Down 949 time.sleep(0.00002) 950 # Check for success 951 if not is_xmc_chip_strict(): 952 print("WARNING: XMC flash boot-up fix failed.") 953 print("XMC flash chip boot-up fix successful!") 954 955 # Check flash chip connection 956 if not esp.secure_download_mode: 957 try: 958 flash_id = esp.flash_id() 959 if flash_id in (0xFFFFFF, 0x000000): 960 print( 961 "WARNING: Failed to communicate with the flash chip, " 962 "read/write operations will fail. " 963 "Try checking the chip connections or removing " 964 "any other hardware connected to IOs." 965 ) 966 if ( 967 hasattr(args, "spi_connection") 968 and args.spi_connection is not None 969 ): 970 print( 971 "Some GPIO pins might be used by other peripherals, " 972 "try using another --spi-connection combination." 973 ) 974 975 except FatalError as e: 976 raise FatalError(f"Unable to verify flash chip connection ({e}).") 977 978 # Check if XMC SPI flash chip booted-up successfully, fix if not 979 if not esp.secure_download_mode: 980 try: 981 flash_xmc_startup() 982 except FatalError as e: 983 esp.trace(f"Unable to perform XMC flash chip startup sequence ({e}).") 984 985 if hasattr(args, "flash_size"): 986 print("Configuring flash size...") 987 if args.flash_size == "detect": 988 flash_size = detect_flash_size(esp, args) 989 elif args.flash_size == "keep": 990 flash_size = detect_flash_size(esp, args=None) 991 if not esp.IS_STUB: 992 print( 993 "WARNING: In case of failure, please set a specific --flash_size." 994 ) 995 else: 996 flash_size = args.flash_size 997 998 if flash_size is not None: # Secure download mode 999 esp.flash_set_parameters(flash_size_bytes(flash_size)) 1000 # Check if stub supports chosen flash size 1001 if ( 1002 esp.IS_STUB 1003 and esp.CHIP_NAME != "ESP32-S3" 1004 and flash_size_bytes(flash_size) > 16 * 1024 * 1024 1005 ): 1006 print( 1007 "WARNING: Flasher stub doesn't fully support flash size larger " 1008 "than 16MB, in case of failure use --no-stub." 1009 ) 1010 1011 if getattr(args, "size", "") == "all": 1012 if esp.secure_download_mode: 1013 raise FatalError( 1014 "Detecting flash size is not supported in secure download mode. " 1015 "Set an exact size value." 1016 ) 1017 # detect flash size 1018 flash_id = esp.flash_id() 1019 size_id = flash_id >> 16 1020 size_str = DETECTED_FLASH_SIZES.get(size_id) 1021 if size_str is None: 1022 raise FatalError( 1023 "Detecting flash size failed. Set an exact size value." 1024 ) 1025 print(f"Detected flash size: {size_str}") 1026 args.size = flash_size_bytes(size_str) 1027 1028 if esp.IS_STUB and hasattr(args, "address") and hasattr(args, "size"): 1029 if esp.CHIP_NAME != "ESP32-S3" and args.address + args.size > 0x1000000: 1030 print( 1031 "WARNING: Flasher stub doesn't fully support flash size larger " 1032 "than 16MB, in case of failure use --no-stub." 1033 ) 1034 1035 try: 1036 operation_func(esp, args) 1037 finally: 1038 try: # Clean up AddrFilenamePairAction files 1039 for address, argfile in args.addr_filename: 1040 argfile.close() 1041 except AttributeError: 1042 pass 1043 1044 # Handle post-operation behaviour (reset or other) 1045 if operation_func == load_ram: 1046 # the ESP is now running the loaded image, so let it run 1047 print("Exiting immediately.") 1048 elif args.after == "hard_reset": 1049 esp.hard_reset() 1050 elif args.after == "soft_reset": 1051 print("Soft resetting...") 1052 # flash_finish will trigger a soft reset 1053 esp.soft_reset(False) 1054 elif args.after == "no_reset_stub": 1055 print("Staying in flasher stub.") 1056 else: # args.after == 'no_reset' 1057 print("Staying in bootloader.") 1058 if esp.IS_STUB: 1059 esp.soft_reset(True) # exit stub back to ROM loader 1060 1061 if not external_esp: 1062 esp._port.close() 1063 1064 else: 1065 operation_func(args) 1066 1067 1068def arg_auto_int(x): 1069 return int(x, 0) 1070 1071 1072def arg_auto_size(x): 1073 x = x.lower() 1074 return x if x == "all" else arg_auto_int(x) 1075 1076 1077def arg_auto_chunk_size(string: str) -> int: 1078 num = int(string, 0) 1079 if num & 3 != 0: 1080 raise argparse.ArgumentTypeError("Chunk size should be a 4-byte aligned number") 1081 return num 1082 1083 1084def get_port_list(vids=[], pids=[], names=[]): 1085 if list_ports is None: 1086 raise FatalError( 1087 "Listing all serial ports is currently not available. " 1088 "Please try to specify the port when running esptool.py or update " 1089 "the pyserial package to the latest version" 1090 ) 1091 ports = [] 1092 for port in list_ports.comports(): 1093 if sys.platform == "darwin" and port.device.endswith( 1094 ("Bluetooth-Incoming-Port", "wlan-debug") 1095 ): 1096 continue 1097 if vids and (port.vid is None or port.vid not in vids): 1098 continue 1099 if pids and (port.pid is None or port.pid not in pids): 1100 continue 1101 if names and ( 1102 port.name is None or all(name not in port.name for name in names) 1103 ): 1104 continue 1105 ports.append(port.device) 1106 return sorted(ports) 1107 1108 1109def expand_file_arguments(argv): 1110 """ 1111 Any argument starting with "@" gets replaced with all values read from a text file. 1112 Text file arguments can be split by newline or by space. 1113 Values are added "as-is", as if they were specified in this order 1114 on the command line. 1115 """ 1116 new_args = [] 1117 expanded = False 1118 for arg in argv: 1119 if arg.startswith("@"): 1120 expanded = True 1121 with open(arg[1:], "r") as f: 1122 for line in f.readlines(): 1123 new_args += shlex.split(line) 1124 else: 1125 new_args.append(arg) 1126 if expanded: 1127 print(f"esptool.py {' '.join(new_args)}") 1128 return new_args 1129 return argv 1130 1131 1132def connect_loop( 1133 port: str, 1134 initial_baud: int, 1135 chip: str, 1136 max_retries: int, 1137 trace: bool = False, 1138 before: str = "default_reset", 1139): 1140 chip_class = CHIP_DEFS[chip] 1141 esp = None 1142 print(f"Serial port {port}") 1143 1144 first = True 1145 ten_cycle = cycle(chain(repeat(False, 9), (True,))) 1146 retry_loop = chain( 1147 repeat(False, max_retries - 1), (True,) if max_retries else cycle((False,)) 1148 ) 1149 1150 for last, every_tenth in zip(retry_loop, ten_cycle): 1151 try: 1152 esp = chip_class(port, initial_baud, trace) 1153 if not first: 1154 # break the retrying line 1155 print("") 1156 esp.connect(before) 1157 return esp 1158 except ( 1159 FatalError, 1160 serial.serialutil.SerialException, 1161 IOError, 1162 OSError, 1163 ) as err: 1164 if esp and esp._port: 1165 esp._port.close() 1166 esp = None 1167 if first: 1168 print(err) 1169 print("Retrying failed connection", end="", flush=True) 1170 first = False 1171 if last: 1172 raise err 1173 if every_tenth: 1174 # print a dot every second 1175 print(".", end="", flush=True) 1176 time.sleep(0.1) 1177 1178 1179def get_default_connected_device( 1180 serial_list, 1181 port, 1182 connect_attempts, 1183 initial_baud, 1184 chip="auto", 1185 trace=False, 1186 before="default_reset", 1187): 1188 _esp = None 1189 for each_port in reversed(serial_list): 1190 print("Serial port %s" % each_port) 1191 try: 1192 if chip == "auto": 1193 _esp = detect_chip( 1194 each_port, initial_baud, before, trace, connect_attempts 1195 ) 1196 else: 1197 chip_class = CHIP_DEFS[chip] 1198 _esp = chip_class(each_port, initial_baud, trace) 1199 _esp.connect(before, connect_attempts) 1200 break 1201 except (FatalError, OSError) as err: 1202 if port is not None: 1203 raise 1204 print("%s failed to connect: %s" % (each_port, err)) 1205 if _esp and _esp._port: 1206 _esp._port.close() 1207 _esp = None 1208 return _esp 1209 1210 1211class SpiConnectionAction(argparse.Action): 1212 """ 1213 Custom action to parse 'spi connection' override. 1214 Values are SPI, HSPI, or a sequence of 5 pin numbers separated by commas. 1215 """ 1216 1217 def __call__(self, parser, namespace, value, option_string=None): 1218 if value.upper() in ["SPI", "HSPI"]: 1219 values = value.upper() 1220 elif "," in value: 1221 values = value.split(",") 1222 if len(values) != 5: 1223 raise argparse.ArgumentError( 1224 self, 1225 f"{value} is not a valid list of comma-separate pin numbers. " 1226 "Must be 5 numbers - CLK,Q,D,HD,CS.", 1227 ) 1228 try: 1229 values = tuple(int(v, 0) for v in values) 1230 except ValueError: 1231 raise argparse.ArgumentError( 1232 self, 1233 f"{values} is not a valid argument. " 1234 "All pins must be numeric values", 1235 ) 1236 else: 1237 raise argparse.ArgumentError( 1238 self, 1239 f"{value} is not a valid spi-connection value. " 1240 "Values are SPI, HSPI, or a sequence of 5 pin numbers - CLK,Q,D,HD,CS.", 1241 ) 1242 setattr(namespace, self.dest, values) 1243 1244 1245class AutoHex2BinAction(argparse.Action): 1246 """Custom parser class for auto conversion of input files from hex to bin""" 1247 1248 def __call__(self, parser, namespace, value, option_string=None): 1249 try: 1250 with open(value, "rb") as f: 1251 # if hex file was detected replace hex file with converted temp bin 1252 # otherwise keep the original file 1253 value = intel_hex_to_bin(f).name 1254 except IOError as e: 1255 raise argparse.ArgumentError(self, e) 1256 setattr(namespace, self.dest, value) 1257 1258 1259class AddrFilenamePairAction(argparse.Action): 1260 """Custom parser class for the address/filename pairs passed as arguments""" 1261 1262 def __init__(self, option_strings, dest, nargs="+", **kwargs): 1263 super(AddrFilenamePairAction, self).__init__( 1264 option_strings, dest, nargs, **kwargs 1265 ) 1266 1267 def __call__(self, parser, namespace, values, option_string=None): 1268 # validate pair arguments 1269 pairs = [] 1270 for i in range(0, len(values), 2): 1271 try: 1272 address = int(values[i], 0) 1273 except ValueError: 1274 raise argparse.ArgumentError( 1275 self, 'Address "%s" must be a number' % values[i] 1276 ) 1277 try: 1278 argfile = open(values[i + 1], "rb") 1279 except IOError as e: 1280 raise argparse.ArgumentError(self, e) 1281 except IndexError: 1282 raise argparse.ArgumentError( 1283 self, 1284 "Must be pairs of an address " 1285 "and the binary filename to write there", 1286 ) 1287 # check for intel hex files and convert them to bin 1288 argfile = intel_hex_to_bin(argfile, address) 1289 pairs.append((address, argfile)) 1290 1291 # Sort the addresses and check for overlapping 1292 end = 0 1293 for address, argfile in sorted(pairs, key=lambda x: x[0]): 1294 argfile.seek(0, 2) # seek to end 1295 size = argfile.tell() 1296 argfile.seek(0) 1297 sector_start = address & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) 1298 sector_end = ( 1299 (address + size + ESPLoader.FLASH_SECTOR_SIZE - 1) 1300 & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) 1301 ) - 1 1302 if sector_start < end: 1303 message = "Detected overlap at address: 0x%x for file: %s" % ( 1304 address, 1305 argfile.name, 1306 ) 1307 raise argparse.ArgumentError(self, message) 1308 end = sector_end 1309 setattr(namespace, self.dest, pairs) 1310 1311 1312def _main(): 1313 try: 1314 main() 1315 except FatalError as e: 1316 print(f"\nA fatal error occurred: {e}") 1317 sys.exit(2) 1318 except serial.serialutil.SerialException as e: 1319 print(f"\nA serial exception error occurred: {e}") 1320 print( 1321 "Note: This error originates from pySerial. " 1322 "It is likely not a problem with esptool, " 1323 "but with the hardware connection or drivers." 1324 ) 1325 print( 1326 "For troubleshooting steps visit: " 1327 "https://docs.espressif.com/projects/esptool/en/latest/troubleshooting.html" 1328 ) 1329 sys.exit(1) 1330 except StopIteration: 1331 print(traceback.format_exc()) 1332 print("A fatal error occurred: The chip stopped responding.") 1333 sys.exit(2) 1334 1335 1336if __name__ == "__main__": 1337 _main() 1338