From b00c7d291274e685346d8d1d17c751e0f812b2c0 Mon Sep 17 00:00:00 2001 From: Mikaela Szekely Date: Wed, 6 Jan 2021 11:52:51 -0700 Subject: [PATCH] host: chipcon command: support reading from Intel hex --- host/greatfet/commands/greatfet_chipcon.py | 25 ++++++++++++++++++---- host/greatfet/programmers/chipcon.py | 15 +++++++------ host/setup.py | 3 ++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/host/greatfet/commands/greatfet_chipcon.py b/host/greatfet/commands/greatfet_chipcon.py index 1a4ee5e4..1943c9c3 100644 --- a/host/greatfet/commands/greatfet_chipcon.py +++ b/host/greatfet/commands/greatfet_chipcon.py @@ -4,9 +4,11 @@ from __future__ import print_function -import ast +import io import argparse +from intelhex import IntelHex + from greatfet.utils import GreatFETArgumentParser, log_silent, log_verbose @@ -42,6 +44,8 @@ def main(): parser.add_argument('-E', '--mass-erase', action='store_true', help="Erase the entire flash memory") parser.add_argument('-w', '--write', metavar='', type=argparse.FileType('rb'), help="Write data from file") + parser.add_argument("--bin", action='store_true', default=False, + help="Disable Intel hex detection and flash as-is.") args = parser.parse_args() @@ -65,7 +69,7 @@ def main(): mass_erase_flash(chipcon, log_function) if args.write: - program_flash(chipcon, args.write, args.address, args.erase, args.verify, log_function) + program_flash(chipcon, args.write, args.address, args.erase, args.verify, args.bin, log_function) def chip_id(programmer): @@ -83,9 +87,22 @@ def mass_erase_flash(programmer, log_function): programmer.mass_erase_flash() -def program_flash(programmer, in_file, start_address, erase, verify, log_function): - log_function("Writing data to flash...") +def program_flash(programmer, in_file, start_address, erase, verify, force_bin, log_function): image_array = in_file.read() + + if image_array.startswith(b':') and not force_bin: + + print("File type detected as Intel Hex -- converting to binary before flashing...") + print("To force flashing as-is, pass --bin.") + + # HACK: The IntelHex class expects a filename or file-like object, but...we've already read the file. + # So let's wrap it in a file-like object. Normally, we'd use io.BytesIO, + # except IntelHex wants strings, not bytes objects. So... + intel_hex = IntelHex(io.StringIO(image_array.decode('ascii'))) + image_array = intel_hex.tobinstr() + + + log_function("Writing data to flash...") programmer.program_flash(image_array, erase=erase, verify=verify, start=start_address) diff --git a/host/greatfet/programmers/chipcon.py b/host/greatfet/programmers/chipcon.py index c81fae57..833030cf 100644 --- a/host/greatfet/programmers/chipcon.py +++ b/host/greatfet/programmers/chipcon.py @@ -217,7 +217,7 @@ def write_flash_page(self, linear_address, input_data, erase_page=True): # should only be included in the routine when the erase_page_1 = 1. # The pseudo-code does not refer to this parameter! routine_part1 = [ - 0x75, 0xAD, ((linear_address >> 8) // FLASH_WORD_SIZE) & 0x7E, # MOV FADDRH, #imm + 0x75, 0xAD, ((linear_address >> 8) // FLASH_WORD_SIZE) & 0x7E, # MOV FADDRH, #imm 0x75, 0xAC, 0x00, # MOV FADDRL, #00 ] routine_erase = [ @@ -253,7 +253,7 @@ def write_flash_page(self, linear_address, input_data, erase_page=True): else: routine = routine_part1 + routine_part2 - self.write_xdata_memory(0xF000, input_data) + self.write_xdata_memory(0xF000, input_data[:FLASH_PAGE_SIZE]) self.write_xdata_memory(0xF000 + FLASH_PAGE_SIZE, routine) self.run_instruction(0x75, 0xC7, 0x51) # MOV MEMCRT, (bank * 16) + 1 self.set_pc(0xF000 + FLASH_PAGE_SIZE) @@ -276,12 +276,12 @@ def read_flash_page(self, linear_address): return self.read_code_memory(linear_address & 0xFFFF, FLASH_PAGE_SIZE) - def read_flash(self, *, start_address=0, length=0): + def read_flash(self, *, start_address=0, length): """ Read a chunk of flash memory. Parameters: - length -- The length (in bytes) of the amount of flash memory that you want to read. start_address -- The address in flash memory you want to begin reading data from. + length -- The length (in bytes) of the amount of flash memory that you want to read. """ flash_data = bytearray() for i in range(start_address, length, FLASH_PAGE_SIZE): @@ -308,7 +308,7 @@ def program_flash(self, image_array, *, erase=True, verify=True, start=0): Parameters: image_array -- The data to be written to the flash. erase -- Used to specify whether or not the flash needs to be erased before programming. - verify - Used to specify whether or not the data was flashed correctly. + verify -- Used to specify whether or not the data was flashed correctly. start -- The address to begin writing data to the flash. """ @@ -316,7 +316,8 @@ def program_flash(self, image_array, *, erase=True, verify=True, start=0): self.mass_erase_flash() data = bytearray(image_array) - address = 0 + address = start + while data: time.sleep(0.1) # Grab a page... @@ -324,7 +325,7 @@ def program_flash(self, image_array, *, erase=True, verify=True, start=0): del data[:FLASH_PAGE_SIZE] # ... and write it to flash. - self.write_flash_page(address, page, False) + self.write_flash_page(address - start, page, False) address += FLASH_PAGE_SIZE time.sleep(0.1) diff --git a/host/setup.py b/host/setup.py index e60adb0f..428d7151 100644 --- a/host/setup.py +++ b/host/setup.py @@ -77,7 +77,8 @@ def read(fname): 'tqdm', 'cmsis_svd', 'tabulate', - 'prompt_toolkit<3.1.0' + 'prompt_toolkit<3.1.0', + 'intelhex', ], description='Python library for hardware hacking with the GreatFET', long_description=read('README.md'),