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 Full FW Update (Region 0 & Region 1) over I2C - new Python script for HI-Utility Tool

Other Parts Discussed in Thread: TPS65982-HIUTILITY, TPS65982

ATTACHMENTS:

flash_update_fullFW_I2C_Enhanced.py
#!/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_0x00 = 0xACE00001
Ace_ID_Value_Add = 0x267E4C8C


# 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
    global rp0
    rp0 = 0
    global rp1
    rp1 = 0

    # Read region 0/1 pointer
    rp = FLrr(handle, region_num)
    rp0 = FLrr(handle, 0)
    rp1 = FLrr(handle, 1)

    #print 'Region %d pointer currently set to address 0x%x' %(region_num, rp)
    if rp == Ace_ID_Value_Add:
        print 'Image in Flash memory is a "Low-Region.bin" file with offset 0x00, ' \
              'but needs to be a "Flash.bin" file with 2 regions'
        error_flag = 1
    elif (rp == 0x2000) or (rp == 0x20000):
        print 'Region %d pointer currently set to address 0x%x' %(region_num, rp)

        # 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_0x00) :
            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()

        # erase region 0 or 1
        # 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)

        #Truncate the array to the exact data size
        if (length < PAGE_SIZE):
            del data1[length:]

        FLwd(handle, data1)

        count = 0
        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

        # verify boot sequence using FLrr and FLvy
        rp = FLrr(handle, region_num)
        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

            # # write in the region pointers
            # rpblock0 = array('B')
            # rpblock1 = array('B')
            #
            # for i in range(64):
            #     rpblock0.append(0xFF)
            #     rpblock1.append(0xFF)
            #
            # if rp0 == 0x2000:
            #     rpblock0[0] = 0x00
            #     rpblock0[1] = 0x00
            #     rpblock0[2] = 0x02
            #     rpblock0[3] = 0x00
            #
            #     rpblock1[0] = 0x00
            #     rpblock1[1] = 0x20
            #     rpblock1[2] = 0x00
            #     rpblock1[3] = 0x00
            # else:
            #     rpblock0[0] = 0x00
            #     rpblock0[1] = 0x20
            #     rpblock0[2] = 0x00
            #     rpblock0[3] = 0x00
            #
            #     rpblock1[0] = 0x00
            #     rpblock1[1] = 0x00
            #     rpblock1[2] = 0x02
            #     rpblock1[3] = 0x00
            #
            # # Erase region 0 data record
            # FLem(handle, 0x0, 1)
            # # ___ region 0 ___
            # FLad(handle, 0x0)
            # FLwd(handle, rpblock0)
            #
            # rpblock0[0] = 0xFF
            # rpblock0[1] = 0xFF
            # rpblock0[2] = 0xFF
            # rpblock0[3] = 0xFF
            #
            # rpblock0[60] = 0x00
            # rpblock0[61] = 0x00
            # rpblock0[62] = 0x00
            # rpblock0[63] = 0x00
            # # ___ region 0 ___
            # FLad(handle, 0x1000 - 0x40)
            # FLwd(handle, rpblock0)
            #
            # # Erase region 1 data record
            # FLem(handle, 0x1000, 1)
            # # ___ region 1 ___
            # FLad(handle, 0x1000)
            # FLwd(handle, rpblock1)
            #
            # rpblock1[0] = 0xFF
            # rpblock1[1] = 0xFF
            # rpblock1[2] = 0xFF
            # rpblock1[3] = 0xFF
            #
            # rpblock1[60] = 0x00
            # rpblock1[61] = 0x00
            # rpblock1[62] = 0x00
            # rpblock1[63] = 0x00
            #
            # # ___ region 1 ___
            # FLad(handle, 0x2000 - 0x40)
            # FLwd(handle, rpblock1)
    else:
        print 'FW Pointer in Flash image set to unknown value (not 0x2000 or 0x20000). ' \
              'If you are using a TBT system, please contact Intel for Alpine Ridge FW update method.' \
              'If this is a non-TBT system, please download a "flash-image.bin" file from the TPS6598X Config-Tool' \
              'and try again'
        error_flag = 1

    return error_flag

def flip_reg_ptrs():

    global rp0
    rp0 = 0
    global rp1
    rp1 = 0

    # Read region 0/1 pointer
    rp0 = FLrr(handle, 0)
    rp1 = FLrr(handle, 1)

    # write in the region pointers
    rpblock0 = array('B')
    rpblock1 = array('B')

    for i in range(64):
        rpblock0.append(0xFF)
        rpblock1.append(0xFF)

    if rp0 == 0x2000:
        rpblock0[0] = 0x00
        rpblock0[1] = 0x00
        rpblock0[2] = 0x02
        rpblock0[3] = 0x00

        rpblock1[0] = 0x00
        rpblock1[1] = 0x20
        rpblock1[2] = 0x00
        rpblock1[3] = 0x00
    else:
        rpblock0[0] = 0x00
        rpblock0[1] = 0x20
        rpblock0[2] = 0x00
        rpblock0[3] = 0x00

        rpblock1[0] = 0x00
        rpblock1[1] = 0x00
        rpblock1[2] = 0x02
        rpblock1[3] = 0x00

    # Erase region 0 data record
    FLem(handle, 0x0, 1)
    # ___ region 0 ___
    FLad(handle, 0x0)
    FLwd(handle, rpblock0)

    rpblock0[0] = 0xFF
    rpblock0[1] = 0xFF
    rpblock0[2] = 0xFF
    rpblock0[3] = 0xFF

    rpblock0[60] = 0x00
    rpblock0[61] = 0x00
    rpblock0[62] = 0x00
    rpblock0[63] = 0x00
    # ___ region 0 ___
    FLad(handle, 0x1000 - 0x40)
    FLwd(handle, rpblock0)

    # Erase region 1 data record
    FLem(handle, 0x1000, 1)
    # ___ region 1 ___
    FLad(handle, 0x1000)
    FLwd(handle, rpblock1)

    rpblock1[0] = 0xFF
    rpblock1[1] = 0xFF
    rpblock1[2] = 0xFF
    rpblock1[3] = 0xFF

    rpblock1[60] = 0x00
    rpblock1[61] = 0x00
    rpblock1[62] = 0x00
    rpblock1[63] = 0x00

    # ___ region 1 ___
    FLad(handle, 0x2000 - 0x40)
    FLwd(handle, rpblock1)

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

        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)
            if error_flag == 0:
                flip_reg_ptrs()

            #Reset before continuing
            GAID(handle)
            time.sleep(tDelay)
            if error_flag == 0:
                print 'Region 1 was updated successfully and Region Pointers are flipped'
                #Check to see if BOOT is OK before updating 2nd Region
                BOOT_FLAGS.read(handle)
                if BOOT_FLAGS.fieldByName('BootOk').value == 0:
                    error_flag = 4
                    break
                else:
                    BOOT_FLAGS.show()
                    VERSION_REG.read(handle)
                    print 'New FW Version in running in APP Mode after Region 1 Update'
                    VERSION_REG.show()
                region_update(1)
                if error_flag == 0:
                    flip_reg_ptrs()
                print 'Reset after both Regions Updated'
                GAID(handle)
                time.sleep(tDelay)
                if error_flag == 0:
                    print 'Region 1, then Region 0 was updated successfully and Pointers reverted to original values'
                else:
                    error_flag = 5
                    break
            else:
                error_flag = 2
                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)
            #Reset before continuing
            GAID(handle)
            time.sleep(tDelay)
            if error_flag == 0:
                print 'Region 0 was updated successfully'
                #Check to see if BOOT is OK before updating 2nd Region
                BOOT_FLAGS.read(handle)
                if BOOT_FLAGS.fieldByName('BootOk').value == 0:
                    error_flag = 4
                    break
                else:
                    BOOT_FLAGS.show()
                    VERSION_REG.read(handle)
                    print 'New FW Version in running in APP Mode after Region 0 Update'
                    VERSION_REG.show()
                region_update(1)
                print 'Reset after both Regions Updated'
                GAID(handle)
                time.sleep(tDelay)
                if error_flag == 0:
                    print 'Region 0, then Region 1 was updated successfully'
                else:
                    error_flag = 5
                    break
            else:
                error_flag = 2
                break
        else:
            error_flag = 3
            break

        BOOT_FLAGS.read(handle)
        if BOOT_FLAGS.fieldByName('BootOk').value == 0:
            error_flag = 6
        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: 1st Region update attempted but not successful or not verified. ' \
              'Either incorrect ".bin" file existed in Flash or new "Low-region.bin" file may be corrupted'
    elif error_flag == 3:
        print '\nERROR 3: Undefined BOOT_FLAGS conditions encountered. No update was attempted'
    elif error_flag ==4:
        print '\nERROR 4: TPS65982 stuck in BOOT Mode after 1st Region Update attempted'
    elif error_flag ==5:
        print '\nERROR 5: 2nd Region Update failed, but 1st Region update was successful and Verified'
    else:
        print 'ERROR: TPS65982 stuck in Boot Mode after 2nd Region update'
          
    # Close the device
    try:
        handle.hw_close()        
    except Exception as e:
        print e.message
        sys.exit()

    sys.exit()

Py_I2C_FullFWUpdate_Final_Reg0-1_SUCCESS_printout_05-11-2016.txt
C:\Py_I2C_Full_FWUpdate>flash_update_fullFW_I2C_Enhanced.py config82_v1.7.6_low_region.bin

TPS65982 Debug Tool Version 1.1

I2C Bitrate set to 400 kHz
I2C Bus lock timeout set to 150 ms
SPI Bitrate set to 8000 kHz
OLD FW Version in running in APP Mode before FW Update
VERSION          0001.03.00

Region 1 running --> Update Region 0 first, then Region 1
Success
Success
Success
Region 0 pointer currently set to address 0x2000
Programming Region 0 image at offset 0x2000
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
Region 0 write complete
Success
Verification of region 0 SUCCEEDED
Region 0 was updated successfully
Boot Flags (0x2d)
        [0:0]     BootOk                      True
        [1:1]     ExtPhvSwitch                False
        [2:2]     DeadBatteryFlag             False
        [3:3]     SpiFlashPresent             True
        [4:4]     Region0                     True
        [5:5]     Region1                     False
        [6:6]     Region0Invalid              False
        [7:7]     Region1Invalid              False
        [8:8]     Region0FlashErr             False
        [9:9]     Region1FlashErr             False
        [11:11]   UartCRCFail                 False
        [12:12]   Region0CRCFail              False
        [13:13]   Region1CRCFail              False
        [14:14]   CustomerOTPInvalid          False
        [16:15]   OneCallI2COtpBits           0x1
        [22:22]   Debug Ctl 1 state at boot   low
        [23:23]   Debug Ctl 2 state at boot   low
        [26:24]   DevNumber                   0
        [27:27]   UartBoot                    False
        [28:28]   UartOverflowErr             False
        [29:29]   IntPhvSwitch                False
        [30:30]   UartRetryErr                False
        [31:31]   UartTimeoutErr              False
        [33:32]   OTPValid                    2
        [34:34]   SWD Disable                 False
        [36:36]   Vout3v3Ctl                  True
        [37:37]   WaitForVin3V3               False
        [41:40]   OneCallI2cOtpBits           1
        [54:50]   Vout3v3Threshold            6
New FW Version in running in APP Mode after Region 0 Update
VERSION          0001.07.06

Success
Success
Success
Region 1 pointer currently set to address 0x20000
Programming Region 1 image at offset 0x20000
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
Region 1 write complete
Success
Verification of region 1 SUCCEEDED
Reset after both Regions Updated
Region 0, then Region 1 was updated successfully
New FW Version in running in APP Mode after FW Update
VERSION          0001.07.06

SUCCESS!!! FW Update of Region 0 & 1 was completed without errors

C:\Py_I2C_Full_FWUpdate>

Py_I2C_FullFWUpdate_Final_Reg1-0_SUCCESS_printout_05-11-2016.txt
C:\Py_I2C_Full_FWUpdate>flash_update_fullFW_I2C_Enhanced.py config82_v1.7.6_low_region.bin

TPS65982 Debug Tool Version 1.1

I2C Bitrate set to 400 kHz
I2C Bus lock timeout set to 150 ms
SPI Bitrate set to 8000 kHz
OLD FW Version in running in APP Mode before FW Update
VERSION          0001.03.00

Region 0 running --> Update Region 1 first, then Region 0
Success
Success
Success
Region 1 pointer currently set to address 0x20000
Programming Region 1 image at offset 0x20000
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
Region 1 write complete
Success
Verification of region 1 SUCCEEDED
Success
Success
Region 1 was updated successfully and Region Pointers are flipped
Boot Flags (0x2d)
        [0:0]     BootOk                      True
        [1:1]     ExtPhvSwitch                False
        [2:2]     DeadBatteryFlag             False
        [3:3]     SpiFlashPresent             True
        [4:4]     Region0                     True
        [5:5]     Region1                     False
        [6:6]     Region0Invalid              False
        [7:7]     Region1Invalid              False
        [8:8]     Region0FlashErr             False
        [9:9]     Region1FlashErr             False
        [11:11]   UartCRCFail                 False
        [12:12]   Region0CRCFail              False
        [13:13]   Region1CRCFail              False
        [14:14]   CustomerOTPInvalid          False
        [16:15]   OneCallI2COtpBits           0x1
        [22:22]   Debug Ctl 1 state at boot   low
        [23:23]   Debug Ctl 2 state at boot   low
        [26:24]   DevNumber                   0
        [27:27]   UartBoot                    False
        [28:28]   UartOverflowErr             False
        [29:29]   IntPhvSwitch                False
        [30:30]   UartRetryErr                False
        [31:31]   UartTimeoutErr              False
        [33:32]   OTPValid                    2
        [34:34]   SWD Disable                 False
        [36:36]   Vout3v3Ctl                  True
        [37:37]   WaitForVin3V3               False
        [41:40]   OneCallI2cOtpBits           1
        [54:50]   Vout3v3Threshold            6
New FW Version in running in APP Mode after Region 1 Update
VERSION          0001.07.06

Success
Success
Success
Region 1 pointer currently set to address 0x2000
Programming Region 1 image at offset 0x2000
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
4K block written
Region 1 write complete
Success
Verification of region 1 SUCCEEDED
Success
Success
Reset after both Regions Updated
Region 1, then Region 0 was updated successfully and Pointers reverted to original values
New FW Version in running in APP Mode after FW Update
VERSION          0001.07.06

SUCCESS!!! FW Update of Region 0 & 1 was completed without errors

C:\Py_I2C_Full_FWUpdate>

__________________________________________________________________________________________________________________________

If you have been developing a product with the TPS65982 and attempted to update the FW in the SPI Flash memory using I2C, then you may have downloaded the TPS65982-HIUTILITY Host Interface Utility Tool.

The Host Interface Utility Tool allows you to access the Host Interface of the TPS65982: Read from Registers, Write to Registers, Send 4CC ASCII Commands, and even Update the FW of the TPS65982 over I2C using a friendly GUI.

After learning about the operation of the part using the GUI, you may want to start writing your own code to control the TPS65982. Although jumping straight to writing C-code for an Embedded Processor sounds like fun, it can be difficult to translate a GUI to code.

An easy intermediate step to take would be to open the TPS6598X Utilities Command Line prompt, edit the Python scripts, and test to see if your system reacts in the expected way.

The Host Interface Utility GUI currently allows you to update Region 0 and Region 1 of the FW separately:

But the final implementation of code may require that Both Regions 0 & 1 are updated at the same time! Using the "flash_update_region_0.py" and "flash_update_region_1.py" scripts as a reference, a new Python script was written to combine these 2 scripts into 1 function, then call that function twice and update both regions of the FW at the same time. Here is what it looks like when the original "flash_update_region_0.py" script is run from the CMD Line:

For example, let's say I released a product with FW version 1.3.0 and I want to update my product in the field to the latest FW version. At the time of writing this example Python script, FW version 1.7.6 was the latest. Updating Region 0 and Region 1 separately works, but how should they be combined into a single program that I can then port to code for an Embedded Processor?

The new script, "flash_update_fullFW_I2C_Enhanced.py", updates both Region 0 and Region 1 sequentially and Resets the TPS65982 to load the new FW version. The script was edited in the PyCharm IDE Free version, and here is what it looks like when it is running:

The full "flash_update_fullFW_I2C_Enhanced.py" script is attached to this post, along with .txt files of the Printout showing that the program is a Success after updating Region 1 first, then Region 0 or updating Region 0 first, then Region 1. If errors are encountered, the program aborts and the errors are explained in plain text.

To run this script without making changes, simply drag and drop it into the same folder as the existing Python Host Interface utilities scripts, and open the CMD Line to run it: