diff --git a/programmer/.gitignore b/programmer/.gitignore index 25fe328..197949b 100644 --- a/programmer/.gitignore +++ b/programmer/.gitignore @@ -9,6 +9,10 @@ __pycache__/ *~ tinyprog/full_version.py +# due to pip install . (for development) +# https://github.com/pypa/pip/issues/6213 +pip-wheel-metadata + # due to using tox and pytest .tox .coverage diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py index 3648c38..9b673e0 100644 --- a/programmer/tinyprog/__init__.py +++ b/programmer/tinyprog/__init__.py @@ -114,9 +114,20 @@ def __str__(self): return self.port_name def __enter__(self): + # Timeouts: + # - Read: 2.0 seconds (timeout) + # - Write: 5.0 seconds (writeTimeout) + # + # Rationale: hitting the writeTimeout is fatal, so it pays to be + # patient in case there is a brief delay; readTimeout is less + # fatal, but can result in short reads if it is hit, so we want + # a timeout high enough that is never hit normally. In practice + # 1.0 seconds is *usually* enough, so the chosen values are double + # and five times the "usually enough" values. + # try: self.ser = serial.Serial( - self.port_name, timeout=1.0, writeTimeout=1.0).__enter__() + self.port_name, timeout=2.0, writeTimeout=5.0).__enter__() except serial.SerialException as e: raise PortError("Failed to open serial port:\n%s" % str(e)) @@ -514,17 +525,36 @@ def program_sectors(self, addr, data): minor_write_data = current_write_data[ minor_offset:minor_offset + minor_sector_size] + # The TinyFPGA firmware and/or flash chip does not handle + # partial minor sector writes properly, so pad out a final + # write of a partial to a whole minor sector, if we are + # writing aligned to the SPI flash internal minor sectors. + # + # Due to the way SPI flash works, writing 0xff *without + # erasing* should be a no-opt, because 0xff is what you + # get after erasing, and you can only write 0 bits. + current_minor_addr = current_addr + minor_offset + + if (((current_minor_addr % minor_sector_size) == 0) and + (len(minor_write_data) < minor_sector_size)): + assert((current_minor_addr % minor_sector_size) == 0) + + pad_len = minor_sector_size - len(minor_write_data) + padding = b'\xff' * pad_len + + minor_write_data = bytearray(minor_write_data) + minor_write_data.extend(padding) + assert(len(minor_write_data) == minor_sector_size) + # if the minor data is all 0xFF then it will match # the erased bits and doesn't need to be re-sent - if minor_write_data == chr(0xFF) * len(minor_write_data): - pbar.update(len(minor_write_data)) - continue; + if minor_write_data != chr(0xFF) * len(minor_write_data): + self.write( + current_addr + minor_offset, + minor_write_data, + disable_progress=True, + max_length=256) - self.write( - current_addr + minor_offset, - minor_write_data, - disable_progress=True, - max_length=256) minor_read_data = self.read( current_addr + minor_offset, len(minor_write_data),