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.

Recommended Flash IC for TPS65981

Other Parts Discussed in Thread: TPS65981, TPS65982, TPS6598X-CONFIG, TPS65982-EVM, TPS65982-HIUTILITY

I have hunted up and down the datasheets and forum posts and have not found a clear solution.

General question: The TPS65981 now has a higher operating temperature and we'd like to use a small (3x3 mm or smaller) flash IC; does TI have any recommendations?

Specific questions: Based on what's currently available on Digikey, the AT25DF041B-MAHNHR is in stock, has a small (8-UDFN (2x3)) package, and a temperature range up to 125 degC.  Will this part work with the TPS65981?

I suspect, the answer to be "yes, the AT25DF041 will work fine" based on the following...

Minimum flash size:

  • The current '81 datasheet recommends both the W25Q20CL (2M-bit minimum size is required) and the W25Q80DV (8M-bit).  So I think it's safe to assume anything >= 2M-bit should suffice.
  • I found a forum post entitled "TPS65982 Suggested EEPROM" (https://e2e.ti.com/support/interface/usb/f/1008/p/541721/1981721) which says the MX25L512E-ZUI-10G  should work as well.  This is only 512K; so 2-4Mbit should be fine!

Flash interface:

  • The datasheet does a good job enumerating some requirements for a flash device in section 9.5.1 SPI Master Interface.
    • >= 8M-bit (wait, really?)
    • 12 MHz SPI clock (this is repeated later in the electrical description)
    • Mode 0
    • Sector erase size of 4kB at a "minimum".  I believe this is a typo?  Considering how the TPS65981's flash is layed out at (typically) increments of 4K and that smaller is generally considered better, I suspect smaller than 4kB would be OK, but larger would not.  Either way, if we find a flash chip which does exactly 4kB (like the AT25DF041 ) then we're good.
  • According to the post "Does the TPS65982 work with the Spansion S25FL116K Flash device" (http://e2e.ti.com/support/interface/usb/f/1008/t/436867

  • There seems to have been a formatting error with the lists and http links.  Here's the remainder of my question in plain text:

    According to the post "Does the TPS65982 work with the Spansion S25FL116K Flash device" (link), the erase size should be exactly 4kB.

    According to another post (oh no! I lost the link), just about any flash with the right required voltage, speed, and size should work.

    But not all flash ICs have the same command interface! There is a lot of commonality among the flash devices, but the recommended W25Q20CL has ~12 commands that are not supported by the AT25DF041. Granted, these different commands are not for the typical the read / erase / program functions. Compared to the flash device mentioned in the "Suggested EEPROM" post linked above, the AT25DF041 supports every command the MX25L512E-ZUI-10G does with the exception of only 1 command. Unfortunately, this one command is "Read SFDP (5Ah)" which could theoretically provide driver software with a lot more information about the differences between the two devices.

    I've come across datasheets for a other devices that enumerate exactly which SPI Flash commands are required. Is there such a list for the TPS65981?

    So what's the verdict? Will the Adesto part work or is there a recommended alternative?

  • Aaron,

    I've read a lot of the datasheets for SPI Flash ICs that are compatible with the TPS6598x, and the most important specs are supporting SPI Mode 0 and a Sector Erase size of 4kB (Command '20h').

    The minimum amount of memory needed can easily be determined by opening the TPS6598X-CONFIG Config Tool and Saving the Flash .bin binary file for a TPS65981 configuration. It should be ~193kB, so the minimum Flash size would be 256kB, but none of the vendors I researched sell any size less than 512kB.

    Although, if you are like me and don't enjoy reading SPI Flash IC datasheets, then you may want to get some free samples from your vendor in the correct package (SOIC-8 for the TPS65982-EVM) and soldering them on to test the SPI Master/Slave compatibility of the TPS6598X with the Flash chip. This is what I did with Macronix to verify compatibility, and confirmed the specs in the datasheet after the fact.
  • Thanks!
    The Adesto part has all the basic SPI Flash read/write/program commands, so we'll give it a shot. I'll post again with our results.
    I also used the configuration tool to produce a full flash image and confirmed that the binary size is ~193kB.
  • Well, it doesn't work. We put the SOIC-8 Adesto part on the EVM board and the TPS6598x Utilities GUI was unable to program it using the FTDI interface available on the EVM. By "unable to program" I mean it completed the erase/program/verify steps only to report that the flash failed the verify step. It's possible it failed the step because only 4Mb were written (it's a smaller part than the original one on the EVM board), I don't know what the GUI was doing or what criteria it uses for failure. I rebooted the board anyway and it reported that both region 0 and region 1 headers were invalid.

    I replaced the new flash IC with an old one (we got extras just in case) and the programming process worked fine. I put a new Adesto part on again and it failed again.

    Any recommendations? We'd really rather not design a large package, low temp, EOL part into our new board.
  • Aaron,

    Try looking at this post and running the attached Python script from the Command Line instead of the GUI:
    e2e.ti.com/.../512830

    If you start with a SPI Flash IC that was programmed directly by a SPI HW interface (like the Aardvark), this should prevent you from bricking the flash and could give you some insight into where the programming went wrong instead of giving you a blanket "error" message.

    You might need to walk through the code a little to debug and figure out which command failed, but the Command Line will help you jump to the right location faster.

    If the error message occurs very early on, for example during the "Boot Flags" I2C Register Read, it would mean that the TPS65982 could not even load the application code from the Flash IC and is stuck in Boot Mode.
  • Yah. By having Region 0 and 1 invalid, it stays in boot mode.

    Why should I expect the Aardvark to perform any better than the FTDI chip for SPI flash writing? I suppose we could order an Aardvark now (and we will if we get this USB design to production), but I don't see how that should be necessary with the EVM's on-board FTDI SPI /I2C chip. Shouldn't the GUI, using the "SPI FW Update" menu be able to entirely overwrite the flash as needed?
  • "SPI FW Update" is a program written for the FTDI chip to communicate to the SPI Flash IC, but it was written for the recommended Flash chip (Winbond).

    The Aardvark or DediProg are compatible with any Flash chip because they have the Flash's characteristics stored in a file.

    If you need support with the FTDI SPI FW update, I recommend starting a new thread, or running the "SPI FW Update" program from the Command Line and seeing if it executes successfully.
  • Brian,

    The command line python scripts were a good start. I added some debugging code to determine where the breakdown occurred. Between the python debugging and diving into the flash datasheets, I found that the old Winbon flash has all it's data unprotected by default. The newer Adesto part has everything software-protected by default. I added a few spi commands to the FTDI python code and the command line program is now working (and attached to this post).

    I tried using the TI host interface for updating (the 4CC commands) since this is a different flash writing implementation than the python code. The FW update did not work this way.



    Lessons learned:

    Adesto part seems to be READ just fine by the TPS65981.

    The TPS65981 in-system FW update features will not work on the Adesto part because they assume the flash is already unlocked.

    Pre-programming the Adesto part with an appropriate programmer is required.



    In summary, the Adesto part will work just fine as long as we program it appropriately during manufacture and do not plan to do field updates without access to the SPI bus.



    Thanks for all your help!
  • Oops.  Can't attache ".py" files, so I changed it to ".txt".

    #!/bin/env python
    
    #==========================================================================
    # IMPORTS
    #==========================================================================
    import sys
    import time
    
    from ftdi import *
    
    #==========================================================================
    # CONSTANTS
    #==========================================================================
    SPI_PAGE_SIZE = 256
    
    FLASH_COMMAND_WRITE_ENABLE               = 0x06
    FLASH_COMMAND_WRITE_ENABLE_STATUS        = 0x50
    FLASH_COMMAND_WRITE_DISABLE              = 0x04
    FLASH_COMMAND_READ_STATUS                = 0x05
    FLASH_COMMAND_WRITE_STATUS               = 0x01
    # READ_DATA requires SPI CLK < 33 MHz
    FLASH_COMMAND_READ_DATA                  = 0x03
    # FAST_READ supports 50 MHz clock
    FLASH_COMMAND_FAST_READ                  = 0x0B    
    FLASH_COMMAND_FAST_READ_DUAL_OUTPUT      = 0x3B
    FLASH_COMMAND_FAST_READ_DUAL_IO          = 0xBB
    FLASH_COMMAND_PAGE_PROGRAM               = 0x02
    FLASH_COMMAND_SECTOR_ERASE               = 0x20
    FLASH_COMMAND_BLOCK_ERASE_32K            = 0x52
    FLASH_COMMAND_BLOCK_ERASE_64K            = 0xD8
    FLASH_COMMAND_CHIP_ERASE                 = 0xC7
    FLASH_COMMAND_POWER_DOWN                 = 0xB9
    FLASH_COMMAND_RELEASE_POWER_DOWN         = 0xAB
    
    
    
    f_spi_write = ftdi.SPI_Write
    f_spi_write.argtypes = [c_uint, POINTER(c_ubyte), c_uint, POINTER(c_uint), c_uint]
    f_spi_write.restype = c_uint
    
    #==========================================================================
    # FUNCTIONS
    #==========================================================================
    def byteArray(n):
        strArray = bin(n)[2:].zfill(8*((len(bin(n)[2:])-1) / 8) + 8)
    
        ret = array('B')
    
        for i in range(len(strArray)/8):
            if i != 0:
                ret.append(int(strArray[-i*8-8:-i*8],2))
            else:
                ret.append(int(strArray[-8:],2))
    
        return ret
    
    def fsw_basic(handle, data_out):
        sizeTransferred = c_uint(0)
        transferOptions = c_uint(SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE)
    
        # Get the address of the data array to transmit
        temp_ptr, _ = data_out.buffer_info()
        data_out_p = cast(temp_ptr, POINTER(c_ubyte))
    
        return f_spi_write(handle, data_out_p, len(data_out), byref(sizeTransferred), transferOptions)
        
    
    # w25q80 uses 8-bit command followed by 3-byte address
    # data out is what you write
    # data in is what you read
    def ftdi_spi_write(handle, cmd, addr, data_out, data_in):
        data_send = array('B', [ cmd ])
    
        revArray = byteArray(addr)
        for i in range(3-len(byteArray(addr))):
            revArray.append(0)
    
        for i in range(3):
            data_send.append(revArray[2-i])
    
        data_send.extend(data_out)
    
        data_receive = array('B', [0,0,0,0])
        data_receive.extend(data_in)
    
        sizeTransferred = c_uint(0)
        transferOptions = c_uint(SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE)
    
        # Get the address of the data array to transmit
        temp_ptr, _ = data_send.buffer_info()
        data_send_p = cast(temp_ptr, POINTER(c_ubyte))
    
    
        return f_spi_write(handle, data_send_p, len(data_send), byref(sizeTransferred), transferOptions)
    
    def ftdi_spi_unlockWriteProtection(handle):  # AAR line
        # Send write enable command
        data_out = array('B', [FLASH_COMMAND_WRITE_ENABLE])  # AAR line
        fsw_basic(handle, data_out)  # AAR line
        # Send zeros to status register
        data_out = array('B', [FLASH_COMMAND_WRITE_STATUS, 0])  # AAR line
        fsw_basic(handle, data_out)  # AAR line
    
    
    def ftdi_spi_writeMemory (handle, addr, data_in):
        # Write to the SPI FLASH
        ftdi_spi_unlockWriteProtection(handle)  # AAR line
    
        # Send write enable command
        data_out = array('B', [ FLASH_COMMAND_WRITE_ENABLE ])
        fsw_basic(handle, data_out)
    
        # Assemble write command and address
        data_out = array('B', [ 0 for i in range(SPI_PAGE_SIZE) ])
    
        # Assemble a page of data
        for i in range(min(SPI_PAGE_SIZE, len(data_in))):
            data_out[i] = data_in[i]
    
        # Truncate the array to the exact data size
        del data_out[i+1:]
    
        # Write the transaction
        ftdi_spi_write(handle, FLASH_COMMAND_PAGE_PROGRAM, addr, data_out, data_in)
    #    aa_sleep_ms(10)
    
        # Wait until data page is written
        ftdi_flash_block_busy(handle)
    
        if(len(data_in) > SPI_PAGE_SIZE):
            print 'SPI Write attempt of block size greater than page size of %d' %SPI_PAGE_SIZE 
            sys.exit()
    
        if(((addr + len(data_in) - 1) & 0xFFFFFF00) != (addr & 0xFFFFFF00)):
            print 'SPI Write attempt wraps past page boundary. This causes unpredicatble write behavior.'  
            sys.exit()
    
    
    def ftdi_spi_readMemory (handle, addr, length):
        data_in = array('B', [ 0 for i in range(length + 4) ])
        data_out = array('B', [ 0 for i in range(length + 4) ])
    
        f_spi_read_write = ftdi.SPI_ReadWrite
        f_spi_read_write.argtypes = [c_uint, POINTER(c_ubyte), POINTER(c_ubyte), c_uint, POINTER(c_uint), c_uint]
        f_spi_read_write.restype = c_uint
    
        sizeTransferred = c_uint(0)
        transferOptions = c_uint(SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE)
    
        revArray = byteArray(addr)
        for i in range(3-len(byteArray(addr))):
            revArray.append(0)
    
        data_out[0] = FLASH_COMMAND_READ_DATA
        data_out[1] = revArray[2]
        data_out[2] = revArray[1]
        data_out[3] = revArray[0]
    
        # Get the address of the data array to transmit
        temp_ptr, _ = data_in.buffer_info()
        data_in_p = cast(temp_ptr, POINTER(c_ubyte))
    
        temp_ptr, _ = data_out.buffer_info()
        data_out_p = cast(temp_ptr, POINTER(c_ubyte))
    
        f_spi_read_write(handle, data_in_p, data_out_p, len(data_in), byref(sizeTransferred), transferOptions)
    
        if (sizeTransferred.value != length + 4):
            print "error: read %d bytes (expected %d)" % (sizeTransferred.value, length)
    
        return (sizeTransferred.value - 4, data_in[4:])
    
    
    def ftdi_flash_block_busy(handle):
        data_in = array('B', [0, 0])
        data_out = array('B', [FLASH_COMMAND_READ_STATUS, 0])
    
        f_spi_read_write = ftdi.SPI_ReadWrite
        f_spi_read_write.argtypes = [c_uint, POINTER(c_ubyte), POINTER(c_ubyte), c_uint, POINTER(c_uint), c_uint]
        f_spi_read_write.restype = c_uint
    
        sizeTransferred = c_uint(0)
        transferOptions = c_uint(SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE)
    
        # Get the address of the data array to transmit
        temp_ptr, _ = data_in.buffer_info()
        data_in_p = cast(temp_ptr, POINTER(c_ubyte))
    
        temp_ptr, _ = data_out.buffer_info()
        data_out_p = cast(temp_ptr, POINTER(c_ubyte))
    
        f_spi_read_write(handle, data_in_p, data_out_p, len(data_in), byref(sizeTransferred), transferOptions)
    
        #print "Status: 0x%2X " % (data_in[1])  # AAR line
        while(data_in[1] & 0x1):
            f_spi_read_write(handle, data_in_p, data_out_p, len(data_in), byref(sizeTransferred), transferOptions)
            #print "Status: 0x%2X " % (data_in[1]) #  AAR line
    
        # 0 = success
        return 0
        
    def ftdi_flash_sector_erase_spi(handle, addr, numSector):
        address = addr & 0xFFFFF000
    
        # Erase Sectors
        # no data, so make dummy array of len zero
        ftdi_spi_unlockWriteProtection(handle)  # AAR line
        dummy = array('B', [])
        for i in range(numSector):
            # have to write enable before each erase command
            fsw_basic(handle, array('B', [FLASH_COMMAND_WRITE_ENABLE]))
            ftdi_spi_write(handle, FLASH_COMMAND_SECTOR_ERASE, address, dummy, dummy)
            address += 0x1000
            ftdi_flash_block_busy(handle)
    
    #==========================================================================
    # MAIN PROGRAM
    #==========================================================================
    if __name__ == "__main__":
        
        print 'This file is a helper file for programming SPI flash'
        print 'It should be imported into a python environment or another script'
        print 'using:'
        print 'from aardvark_spi import *'
        sys.exit()
    

  • Whoa, great debug work for the FTDI chip in the Python code in such a short time! Thanks for sharing the .py (.txt) file. Hopefully the team can use this to expand the capabilities of the TPS65982-HIUTILITY Tool SW.

    Glad you got the FW update procedure working, as this can be the most frustrating part of the process sometimes.

    You are 100% correct: the SPI Flash ICs always need to be programmed off-board before the assembly of the PCB (or on-board intrusively with a header directly connected to Flash via SPI pins). The most common HW tool for Production is the DediProg SF600Plus with the Production GUI for "gang" programming.