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.

TPS65982 bringup via I2C

Other Parts Discussed in Thread: TPS65982, TPS65982-EVM

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()
    

  • Thanks for your clarification. I was afraid this would be your answer. I suggest a datasheet update to clearly make a distinction between bringup of flash and update.

    Thanks also for your Python suggestion, this will be handy during update.

    Regards, Michael
  • Michael,

    Thank you for your feedback on the datasheet. Since the TPS65982 is a pretty even split between HW & FW capabilities, we try to make a clear distinction on what goes in the datasheet (HW) and what goes into the TPS6598X FW User's Guide (FW). Here, I could see this change fitting in either document well, or simply fitting the "bring-up" vs. "upgrade" distinction into the Intro of an App Note.

    I hope the Python script works well for you. I will be posting an App Note regarding C-code Examples for FW update in the near future, so I'll post a link here when it's published.
  • Michael,

    Please find my latest e2e Post here on this subject: e2e.ti.com/.../512830
    This is a Python script that is updated even further, or "enhanced", to update Region 1 (or 0), then Reset the TPS65982 to load the new FW, then update Region 0 (or 1) and Reset again.

    In the ideal flow (Region 0 is valid and running before the FW Update), after updating Region 1 the Flash image pointers are flipped and the new FW version can be confirmed as valid before moving on to update Region 0.