diff --git a/flashing/pyocd/.gitignore b/flashing/pyocd/.gitignore new file mode 100644 index 0000000..ba0430d --- /dev/null +++ b/flashing/pyocd/.gitignore @@ -0,0 +1 @@ +__pycache__/ \ No newline at end of file diff --git a/flashing/pyocd/README.md b/flashing/pyocd/README.md new file mode 100644 index 0000000..a8e99b2 --- /dev/null +++ b/flashing/pyocd/README.md @@ -0,0 +1,27 @@ +# Flashing with pyocd + +This is a different approach to flash the firmware on the b-parasites. It is completely optional. + +## Basic instructions + +(Based on the discussion in issue #67) + +The instructions will probably differ slightly depending on your debugging probe and hardware setup. + +The setup is fairly straightforward and documented in the `pyocd` [docs](https://pyocd.io/). + +I used an inexpensive debugging probe from Aliexpress called `nanoDAP` from `Muse Labs` which is less than 10 € and readily available. The J-LINKs are hard to get and quite expensive. In my understanding basically all `CMSIS-DAP`-compatible probes which are recognized by `pyocd` should work. + +After connecting the debugging probe via usb and connecting the b-parasite as described in the wiki, flashing was easy and fast. + +For a complete flashing of softdevice and firmware use the provided python script. Assuming you put the `*.hex` files in default locations it boils down to one simple command: + +``` +python ./flash_firmware.py +``` + +For help and documentation of the available command line flags use + +``` +python ./flash_firmware.py -h +``` \ No newline at end of file diff --git a/flashing/pyocd/flash_firmware.py b/flashing/pyocd/flash_firmware.py new file mode 100644 index 0000000..2233660 --- /dev/null +++ b/flashing/pyocd/flash_firmware.py @@ -0,0 +1,42 @@ +import argparse + +from pathlib import Path + +from pyocd.core.helpers import ConnectHelper +from pyocd.core.target import Target +from pyocd.flash.file_programmer import FileProgrammer + +from mac_address_reader import MacAddressReader + +parser = argparse.ArgumentParser() +parser.add_argument("-s", "--softdevice", action="store", help="Optional file path to softdevice file.", default="../../sdk/s140nrf52720/s140_nrf52_7.2.0_softdevice.hex", type=Path) +parser.add_argument("-f", "--firmware", action="store", help="Optional file path to firmware file.", default="../../code/b-parasite/_build/nrf52840_xxaa.hex", type=Path) +parser.add_argument("--skip-softdevice", action="store_true", help="Skip flashing of the softdevice.") +parser.add_argument("--skip-firmware", action="store_true", help="Skip flashing of firmware.") + +args = parser.parse_args() + +with ConnectHelper.session_with_chosen_probe() as session: + + board = session.board + target: Target = board.target + + if not args.skip_softdevice: + softdevice_path: Path = args.softdevice + print(f"Flashing softdevice {softdevice_path.name}...") + FileProgrammer(session).program(str(softdevice_path)) + + target.reset_and_halt() + target.resume() + + if not args.skip_firmware: + firmware_path: Path = args.firmware + print(f"Flashing firmware {firmware_path.name}...") + FileProgrammer(session).program(str(firmware_path)) + + target.reset_and_halt() + target.resume() + + mac_address_reader = MacAddressReader(target) + mac_address = mac_address_reader.get_static_mac_address() + print(f'Static manufacturer MAC address (DEVICEADDR): {mac_address}') diff --git a/flashing/pyocd/mac_address_reader.py b/flashing/pyocd/mac_address_reader.py new file mode 100644 index 0000000..5e370cd --- /dev/null +++ b/flashing/pyocd/mac_address_reader.py @@ -0,0 +1,36 @@ +from pyocd.core.target import Target + + +class MacAddressReader(): + + MEMORY_ADDRESS = 0x100000A4 + + def __init__(self, target: Target) -> None: + self.target = target + + def get_static_mac_address(self) -> str: + ''' + Reads the static mac address assigned by the manufacturer. + + This chip property is readonly and may be different from the mac address in the application code. + ''' + memory_blocks = self._get_blocks() + + return self._convert_blocks(memory_blocks) + + def _get_blocks(self): + memory_blocks = self.target.read_memory_block32(self.MEMORY_ADDRESS, 2) + + return memory_blocks + + def _convert_blocks(self, memory_blocks: list[int]) -> str: + first_block = f'{memory_blocks[0]:x}'.rjust(8, '0') + + modified_second_block = memory_blocks[1] | 0xc000 # Bitwise OR + + second_block = f'{modified_second_block:x}' + + mac_string = (second_block[4:] + first_block) + prettified_mac = ':'.join(mac_string[i:i+2] for i in range(0, len(mac_string), 2)) + + return prettified_mac.upper() diff --git a/flashing/pyocd/requirements.txt b/flashing/pyocd/requirements.txt new file mode 100644 index 0000000..6e6bf07 --- /dev/null +++ b/flashing/pyocd/requirements.txt @@ -0,0 +1 @@ +pyocd>=0.34.1 \ No newline at end of file