diff --git a/tools/mesptool.py b/tools/mesptool.py new file mode 100644 index 0000000000000..087bf9d1e5441 --- /dev/null +++ b/tools/mesptool.py @@ -0,0 +1,233 @@ +# This file is part of the MicroPython project, http://micropython.org/ +# +# The MIT License (MIT) +# +# Copyright (c) 2022 Ibrahim Abdelkader +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# A minimal esptool implementation to communicate with ESP32 ROM bootloader. +# Note this tool does Not support advanced features, other ESP chips or stub loading. +# This is only meant to be used for updating the U-blox Nina module firmware. + +import os +import struct +from machine import Pin +from machine import UART +from micropython import const +from time import sleep + + +class mesptool: + FLASH_ID = const(0) + FLASH_BLOCK_SIZE = const(64 * 1024) + FLASH_SECTOR_SIZE = const(4 * 1024) + FLASH_PAGE_SIZE = const(256) + + CMD_SYNC = const(0x08) + CMD_CHANGE_BAUDRATE = const(0x0F) + CMD_SPI_ATTACH = const(0x0D) + CMD_SPI_FLASH_MD5 = const(0x13) + CMD_SPI_FLASH_PARAMS = const(0x0B) + CMD_SPI_FLASH_BEGIN = const(0x02) + CMD_SPI_FLASH_DATA = const(0x03) + CMD_SPI_FLASH_END = const(0x04) + + ESP_ERRORS = { + 0x05: "Received message is invalid", + 0x06: "Failed to act on received message", + 0x07: "Invalid CRC in message", + 0x08: "Flash write error", + 0x09: "Flash read error", + 0x0A: "Flash read length error", + 0x0B: "Deflate error", + } + + def __init__( + self, reset=3, gpio0=2, uart_id=1, uart_tx=Pin(8), uart_rx=Pin(9), log_enabled=False + ): + self.uart_id = uart_id + self.uart_tx = uart_tx + self.uart_rx = uart_rx + self.uart_buf = 4096 + self.uart_baudrate = 115200 + self.log = log_enabled + self.reset_pin = Pin(reset, Pin.OUT, Pin.PULL_UP) + self.gpio0_pin = Pin(gpio0, Pin.OUT, Pin.PULL_UP) + self.set_baudrate(115200) + + def _log(self, data, out=True): + if self.log: + size = len(data) + print( + f"out({size}) => " if out else f"in({size}) <= ", + "".join("%.2x" % (i) for i in data[0:10]), + ) + + def set_baudrate(self, baudrate, timeout=350): + if baudrate != self.uart_baudrate: + print(f"Changing baudrate => {baudrate}") + self.uart_drain() + self.command(CMD_CHANGE_BAUDRATE, struct.pack("= 8: + (inout, cmd_id, size, val) = struct.unpack(" {seq+erase_blocks}...") + self.command( + self.CMD_SPI_FLASH_BEGIN, + struct.pack( + "