diff --git a/tockloader/board_interface.py b/tockloader/board_interface.py index 9ba0368..22a6363 100644 --- a/tockloader/board_interface.py +++ b/tockloader/board_interface.py @@ -316,6 +316,18 @@ class BoardInterface: "flush_command": "probe-rs download {binary} --binary-format bin --base-address 0x10000000 --chip CY8C624AAZI-S2D44", }, }, + "stm32wle5jc": { + "description": "Seeed Studio LoRa-E5 board based on the STM32WLE5JC SoC", + "arch": "cortex-m4", + "page_size": 2048, + "no_attribute_table": True, + "openocd": { + "prefix": "source [find interface/stlink.cfg]; \ + transport select hla_swd; \ + source [find target/stm32wlx.cfg];", + "address_maximum": 0x08040000, + }, + }, } def __init__(self, args): diff --git a/tockloader/openocd.py b/tockloader/openocd.py index 3274234..20b2db2 100644 --- a/tockloader/openocd.py +++ b/tockloader/openocd.py @@ -17,7 +17,7 @@ import time from .board_interface import BoardInterface -from .exceptions import TockLoaderException +from .exceptions import TockLoaderException, ChannelAddressErrorException # global static variable for collecting temp files for Windows collect_temp_files = [] @@ -33,6 +33,7 @@ def __init__(self, args): # Store the serial number if provided self.openocd_serial_number = getattr(self.args, "openocd_serial_number") + self.address_maximum = None def attached_board_exists(self): # Get a list of attached devices, check if that list has at least @@ -84,6 +85,8 @@ def open_link_to_board(self): self.openocd_prefix = board["openocd"]["prefix"] if self.openocd_commands == {} and "commands" in board["openocd"]: self.openocd_commands = board["openocd"]["commands"] + if self.address_maximum == None and "address_maximum" in board["openocd"]: + self.address_maximum = board["openocd"]["address_maximum"] # And we may need to setup other common board settings. self._configure_from_known_boards() @@ -248,6 +251,11 @@ def _list_emulators(self): openocd_cmd=self.openocd_cmd ) ) + openocd_commands.append( + '{openocd_cmd} -c "source [find interface/stlink.cfg]; transport select hla_swd; source [find target/stm32wlx.cfg]; init; exit;"'.format( + openocd_cmd=self.openocd_cmd + ) + ) # These are the magic strings in the output of openocd we are looking # for. If there is a better way to do this then we should change. But, @@ -259,6 +267,7 @@ def _list_emulators(self): ("(mfg: 0x049 (Xilinx), part: 0x3631, ver: 0x1)", "arty"), ("SWD DPIDR 0x2ba01477", "microbit_v2"), ("stm32f4x.cpu", "stm32f4discovery"), + ("stm32wlx.cpu", "stm32wle5jc"), ] emulators = [] @@ -306,6 +315,9 @@ def flash_binary(self, address, binary, pad=False): # The "normal" flash command uses `program`. command = "program {{binary}} verify {address:#x}; reset;" + if self.address_maximum and address + len(binary) > self.address_maximum: + raise ChannelAddressErrorException() + # Check if the configuration wants to override the default program command. if "program" in self.openocd_commands: command = self.openocd_commands["program"] @@ -329,6 +341,9 @@ def flash_binary(self, address, binary, pad=False): self._run_openocd_commands(command, binary) def read_range(self, address, length): + if self.address_maximum and address + length > self.address_maximum: + raise ChannelAddressErrorException() + # The normal read command uses `dump_image`. command = "dump_image {{binary}} {address:#x} {length};" @@ -360,6 +375,9 @@ def read_range(self, address, length): return read def clear_bytes(self, address): + if self.address_maximum and address >= self.address_maximum: + raise ChannelAddressErrorException() + logging.debug("Clearing bytes starting at {:#0x}".format(address)) binary = bytes([0xFF] * 8) diff --git a/tockloader/tockloader.py b/tockloader/tockloader.py index 18a3867..6df4e36 100644 --- a/tockloader/tockloader.py +++ b/tockloader/tockloader.py @@ -145,6 +145,9 @@ class TockLoader: "cy8cproto_62_4343_w": { "start_address": 0x10100000, }, + "stm32wle5jc": { + "start_address": 0x8018000, + }, }, } @@ -1669,14 +1672,25 @@ def is_valid(slices): optional_binary = app.get_binary(app_address) if optional_binary: logging.info("Flashing app {} binary to board.".format(app)) - self.channel.flash_binary(app_address, optional_binary) + try: + self.channel.flash_binary(app_address, optional_binary) + except ChannelAddressErrorException: + logging.info( + "Failed to find space to flash app {}.".format(app) + ) + pass app_address = app_address + app.get_size() # Then erase the next page if we have not already rewritten all # existing apps. This ensures that flash is clean at the end of the # installed apps and makes sure the kernel will find the correct end # of applications. - self.channel.clear_bytes(app_address) + try: + self.channel.clear_bytes(app_address) + except ChannelAddressErrorException: + # We are at the end of flash and there are no bytes + # left to clear. + pass def _replace_with_padding(self, app): """ @@ -1717,7 +1731,10 @@ def _extract_all_app_headers(self, verbose=False, extract_app_binary=False): logging.debug( "Reading for app header @{:#x}, {} bytes".format(address, header_length) ) - flash = self.channel.read_range(address, header_length) + try: + flash = self.channel.read_range(address, header_length) + except ChannelAddressErrorException: + break # if there was an error, the binary array will be empty if len(flash) < header_length: