This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I'm working on a USB Type C solution. A TPS65982, a W25Q80 flash connected via SPI, a host microprocessor connected via I2C1. The flash is initially empty. How to get the firmware/configuration into the flash? How to do the bringup of the flash?
I've started with a TPS65982-EVM. Connected it via I2C to the microcontroller. Ported the relevant python script (flash_update_region_0/1.py) to our host system. Update works like a charm via I2C 4CC commands. Can update low or high region. Can destroy one region. Can boot from the other. Can repair the first. Good solution for updates.
Now I've erased the flash. TPS65982 boots, scans the flash and reports via register 0x2D that it can not boot correctly (flash attached, tries region 0 and 1 but fails with CRC error). Reading the flash (FLrd) returns bogus zeros only. Writing/updating the flash (FLwd) does no longer yield the expected results. Reading register 0x03 gives 'BOOT'. So back to my original question: how to do bringup with an empty flash? Are there alternatives to SPI? (maybe SWD?)
Regards, Michael
Michael,
Great line of questioning!
The SPI Flash IC must either be pre-programmed before soldering it down onto a board in production, or a connection to the required SPI Flash IC pins must be made available (SPI_CLK, SPI_SSZ, SPI_MISO, SPI_MOSI, VCC & GND) with a header. A lot of people will use a low-profile 6-pin header and have a latchable wire go over to an external PCB with a larger header connection for SPI Flash programming HW to connect.
In a true production environment, the DediProg SF600 is often used because you can program up to 8 Flash chips at a time. For the most part, we just use the TotalPhase Aardvark to recover the Flash IC when it is completely corrupted or empty. When the Aardvark is used, VIN_3V3 or VBUS must be provided to the TPS65982 to generate LDO_3V3 and power the flash, while the DediProg provides VCC to the Flash when the TPS65982 is un-powered. Some customers prefer to use a socket on the PCB for the SPI Flash so they can swap them out faster to re-program.
Since you've already used the .py Python files to program Region 0/1 separately, you should try the attached .py script that identifies the active Region and updates both Regions in sequence for a Full I2C FW Flash update. This is a full FW update of both Region0 & 1 followed by a 'GAID' command (HW reset) to re-boot the TPS65982. This .py script can be made even more robust by flipping the pointer and inserting a 'GAID' command in the middle of the sequence. Feel free to play around with it and follow-up with any questions you have.
#!/bin/env python #========================================================================== # (c) 2015 TI #-------------------------------------------------------------------------- # Redistribution and use of this file in source and binary forms, with # or without modification, are permitted. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #========================================================================== #========================================================================== # IMPORTS #========================================================================== import sys import time from hi_functions import * from intelhex import IntelHex import struct from hw_interface import * #========================================================================== # CONSTANTS #========================================================================== PAGE_SIZE = 64 handle = hw_interface(config.DEVICE_I2C_ADDR, config.HW_INTERFACE) # header values Ace_ID_Value = 0xACE00001 # Global Variables failure = 1 error_flag = 0 # Local Variables tDelay = 5 #========================================================================== # Functions #========================================================================== # Function to bit-reverse a byte array in place # '{:08b}'.format(x)converts a byte to a bit string, 8 bits, leading 0s # slice operator bitstr[start:end:step] reverses the bit string when step -1 # int(bitstr,2) converts bit string (base 2) back to an integer # write back to the same array def bit_rev(data): index = 0 for x in data: data[index] = int('{:08b}'.format(x)[::-1], 2) index +=1 return data # Need to zero-fill 32-bit arrays when writing to flash, which is initialized to 0xFFFFFFFF def four_byte_array(n): retval = byteArray(n) for i in range(4-len(retval)): retval.append(0) return retval # Main Region0/1 Update function def region_update(region_num): global failure failure = 1 global error_flag error_flag = 0 # Read region 0/1 pointer rp = FLrr(handle, region_num) print 'Region %d pointer currently set to address 0x%x' %(region_num, rp) print 'Enter new value (dec or hex with 0x) or press return to keep:' rpin = raw_input('> ') if rpin != '' : if rpin[:2] == '0x': rp = int(rpin,16) else: rp = int(rpin) while (rp < 0x2000) : print 'Region address must be greater than or equal to 0x2000' print 'Enter new value (dec or hex with 0x):' rpin = raw_input('> ') if rpin != '' : if rpin[:2] == '0x': rp = int(rpin,16) else: rp = int(rpin) # erase region 0 # Max image size is 64K plus a 4K header = 17 sectors FLem(handle, rp, 17) print 'Programming Region %d image at offset 0x%x' %(region_num, rp) FLad(handle, rp) count = 0 # we use a second instance of file in raw mode to write into flash try: f=open(filename, 'rb') except: print "Unable to open file '" + filename + "'" assert 1 # unroll first loop iteration # Read from the file filedata = f.read(PAGE_SIZE) # Write the data to the bus data1 = array('B', filedata) length = len(data1) if (length < 4): print """Input file is not a valid low-region file""" print """A low region files is an application binary (max 64k) with a prepended 4k boot header.""" sys.exit() if (((data1[3] << 24) | (data1[2] << 16) | (data1[1] << 8) | data1[0]) != Ace_ID_Value) : print """Input file is not a valid low-region file""" print """A low region files is an application binary (max 64k) with a prepended 4k boot header.""" sys.exit() #Truncate the array to the exact data size if (length < PAGE_SIZE): del data1[length:] FLwd(handle, data1) while 1: # Read from the file filedata = f.read(PAGE_SIZE) length = len(filedata) if (length == 0): break # Write the data to the bus data1 = array('B', filedata) #Truncate the array to the exact data size if (length < PAGE_SIZE): del data1[length:] FLwd(handle, data1) count += 1 if count == 64: print '4K block written' count = 0 f.close() print 'Region %d write complete' %region_num if region_num == 0: # Erase region 0 data record FLem(handle, 0x0, 1) else: # Erase region 1 data record FLem(handle, 0x1000, 1) # write in the region pointers rpblock = array('B') for i in range(64): rpblock.append(0xFF) rpoffset = rp - 0x2000 rpblock[0] = 0x00 rpblock[1] = 0x20 rpblock[2] = 0x00 rpblock[3] = 0x00 if region_num == 0: # ___ region 0 ___ FLad(handle, 0x0) else: # ___ region 1 ___ FLad(handle, 0x1000) FLwd(handle, rpblock) rpblock[0] = 0xFF rpblock[1] = 0xFF rpblock[2] = 0xFF rpblock[3] = 0xFF rpblock[60] = rpoffset & 0xFF rpblock[61] = (rpoffset >> 8) & 0xFF rpblock[62] = (rpoffset >> 16) & 0xFF rpblock[63] = (rpoffset >> 24) & 0xFF if region_num == 0: # ___ region 0 ___ FLad(handle, 0x1000 - 0x40) else: # ___ region 1 ___ FLad(handle, 0x2000 - 0x40) FLwd(handle, rpblock) # verify boot sequence using FLrr and FLvy rp = FLrr(handle, 0) failure = FLvy(handle, rp) if failure != 0: print 'Verification of region %d FAILED' %region_num error_flag = 2 else: print 'Verification of region %d SUCCEEDED' %region_num error_flag = 0 return error_flag #========================================================================== # MAIN PROGRAM #========================================================================== if __name__ == "__main__": if (len(sys.argv) < 2): print "usage: flash_update <tps65982xxx_low_region.bin> [I2C address]" sys.exit() filename = sys.argv[1] if len(sys.argv) > 2: if sys.argv[2][:2] == '0x': config.DEVICE_I2C_ADDR = int(sys.argv[2],16) else: config.DEVICE_I2C_ADDR = int(sys.argv[2]) # Open the device try : handle.hw_open(config.HW_INTERFACE, config.PORT, config.SPI_PORT, config.BITRATE, config.SPIBITRATE, config.DEVICE_I2C_ADDR) except Exception as e : print e.message sys.exit() while 1: #Break if any errors occur VERSION_REG.read(handle) print 'OLD FW Version in running in APP Mode before FW Update' VERSION_REG.show() #read_reg(handle, 0x2D, 8) #BOOT_OTP register BOOT_FLAGS.read(handle) if BOOT_FLAGS.fieldByName('BootOk').value == 0: error_flag = 1 break elif BOOT_FLAGS.fieldByName('Region1').value == 0: print 'Region 0 running --> Update Region 1 first, then Region 0' region_update(1) while error_flag==2: region_update(1) if error_flag == 0: #insert GAID and delay here before continuing? region_update(0) while error_flag==2: region_update(0) if error_flag == 0: #insert GAID again? print 'Region 1 was updated successfully, then Region 0 was updated successfully' else: error_flag = 99 break elif ((BOOT_FLAGS.fieldByName('Region0').value == 1) and (BOOT_FLAGS.fieldByName('Region1').value == 1)) and \ ((BOOT_FLAGS.fieldByName('Region0Invalid').value == 1) or (BOOT_FLAGS.fieldByName('Region0FlashErr').value == 1) or (BOOT_FLAGS.fieldByName('Region0CRCFail').value == 1)): print 'Region 1 running --> Update Region 0 first, then Region 1' region_update(0) while error_flag==2: region_update(0) if error_flag == 0: #insert GAID and delay here before continuing? region_update(1) while error_flag==2: region_update(1) if error_flag == 0: #insert GAID again? print 'Region 0 was updated successfully, then Region 1 was updated successfully' else: error_flag = 99 break else: error_flag = 3 break print 'Reset after both Regions 0 & 1 Updated' GAID(handle) time.sleep(tDelay) BOOT_FLAGS.read(handle) if BOOT_FLAGS.fieldByName('BootOk').value == 0: error_flag = 4 else: VERSION_REG.read(handle) print 'New FW Version in running in APP Mode after FW Update' VERSION_REG.show() break if error_flag == 0: print 'SUCCESS!!! FW Update of Region 0 & 1 was completed without errors' elif error_flag == 1: print '\nERROR 1: TPS65982 stuck in BOOT Mode before Update attempted' print '\nBOOT_FLAGS register printed below.' print '(Refer to bits [13..3] for details) \n' BOOT_FLAGS.read(handle) BOOT_FLAGS.show() elif error_flag == 2: print '\nERROR 2: Yikes! big mistake' elif error_flag == 3: print '\nERROR 3: Undefined BOOT_FLAGS conditions encountered. No update was attempted' elif error_flag ==4: print '\nFATAL ERROR 4: TPS65982 stuck in BOOT Mode after Update attempted' else: print 'ERROR: Undefined error occurred' # Close the device try: handle.hw_close() except Exception as e: print e.message sys.exit() sys.exit()