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.

CC2640R2F: External Flash Memory MX25R8035F Read Write Issue

Part Number: CC2640R2F

Hi,

I am using CC2640R2F launchpad to read write on board external flash memory MX25R8035F. I am using simplelink_cc2640r2_sdk_1_40_00_45 for external flash memory drivers(ExtFlash.c and ExtFlash.h).

I am able to write to particular address and can read same value from that address only once. If I write other value to that address, I can't read that value(getting any random values).

For example if I write "TEST" to address 0x00100 then I can read "TEST" from 0x00100.

Again if I write "ABCD" to address 0x00100 then I read "@@@@" from 0x00100.

This means I can't over write other values to that address.

SPI configration:

Bitrate: 4MHz

FrameFormat : 0

Mode: Blocking

What could be the problem? 

Appreciate your support.

Thanks.

  • How do you write this external flash? Do you refer to nvsspi example at dev.ti.com/.../ ?
  • 1055.ExtFlash.c
    /*
     * Copyright (c) 2015-2017, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * 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.
     */
    
    /** ============================================================================
     *  @file       ExtFlash.c
     *
     *  @brief      External flash storage implementation.
     *  ============================================================================
     */
    
    /* -----------------------------------------------------------------------------
    *  Includes
    * ------------------------------------------------------------------------------
    */
    #include "Board.h"
    #include "ExtFlash.h"
    #include "string.h"
    #include <ti/drivers/spi/SPICC26XXDMA.h>
    #include <ti/drivers/dma/UDMACC26XX.h>
    #include <ti/devices/DeviceFamily.h>
    #include DeviceFamily_constructPath(driverlib/ssi.h)
    
    /* -----------------------------------------------------------------------------
    *  Constants and macros
    * ------------------------------------------------------------------------------
    */
    
    /*
     * Implementation for JEDEC compatible Flash
     *
     */
    #define SPI_BIT_RATE              4000000
    
    /* Instruction codes */
    #define BLS_CODE_PROGRAM          0x02 /**< Page Program */
    #define BLS_CODE_READ             0x03 /**< Read Data */
    #define BLS_CODE_READ_STATUS      0x05 /**< Read Status Register */
    #define BLS_CODE_WRITE_ENABLE     0x06 /**< Write Enable */
    #define BLS_CODE_SECTOR_ERASE     0x20 /**< Sector Erase */
    #define BLS_CODE_MDID             0x90 /**< Manufacturer Device ID */
    
    #define BLS_CODE_DP               0xB9 /**< Power down */
    #define BLS_CODE_RDP              0xAB /**< Power standby */
    
    /* Erase instructions */
    #define BLS_CODE_ERASE_4K         0x20 /**< Sector Erase */
    #define BLS_CODE_ERASE_32K        0x52
    #define BLS_CODE_ERASE_64K        0xD8
    #define BLS_CODE_ERASE_ALL        0xC7 /**< Mass Erase */
    
    /* Bitmasks of the status register */
    #define BLS_STATUS_SRWD_BM        0x80
    #define BLS_STATUS_BP_BM          0x0C
    #define BLS_STATUS_WEL_BM         0x02
    #define BLS_STATUS_WIP_BM         0x01
    
    #define BLS_STATUS_BIT_BUSY       0x01 /**< Busy bit of the status register */
    
    /* Part specific constants */
    #define BLS_PROGRAM_PAGE_SIZE     256
    #define BLS_ERASE_SECTOR_SIZE     4096
    
    /* Manufacturer IDs */
    #define MF_MACRONIX               0xC2
    #define MF_WINBOND                0xEF
    
    /* -----------------------------------------------------------------------------
    *  Private functions
    * ------------------------------------------------------------------------------
    */
    static bool Spi_open(uint32_t bitRate);
    static void Spi_close(void);
    static void Spi_flash(void);
    static int Spi_read(uint8_t *buf, size_t length);
    static int Spi_write(const uint8_t *buf, size_t length);
    static int ExtFlash_waitReady(void);
    static int ExtFlash_powerDown(void);
    
    /* -----------------------------------------------------------------------------
    *  Local variables
    * ------------------------------------------------------------------------------
    */
    static PIN_Config BoardFlashPinTable[] =
    {
        Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Ext. flash chip select */
    
        PIN_TERMINATE
    };
    
    static PIN_Handle hFlashPin = NULL;
    static PIN_State pinState;
    
    // Supported flash devices
    static ExtFlashInfo_t flashInfo[] =
    {
        {
            .manfId = MF_MACRONIX,  // Macronics
            .devId = 0x15,          // MX25R1635F
            .deviceSize = 0x200000  // 2 MByte (16 Mbit)
        },
        {
            .manfId = MF_MACRONIX,  // Macronics
            .devId = 0x14,          // MX25R8035F
            .deviceSize = 0x100000  // 1 MByte (8 Mbit)
        },
        {
            .manfId = MF_WINBOND,   // WinBond
            .devId = 0x12,          // W25X40CL
            .deviceSize = 0x080000  // 512 KByte (4 Mbit)
        },
        {
            .manfId = MF_WINBOND,   // WinBond
            .devId = 0x11,          // W25X20CL
            .deviceSize = 0x040000  // 256 KByte (2 Mbit)
        },
        {
            .manfId = 0x0,
            .devId = 0x0,
            .deviceSize = 0x0
        }
    };
    
    // Flash information
    static ExtFlashInfo_t *pFlashInfo = NULL;
    static uint8_t infoBuf[2];
    
    // SPI interface
    static SPI_Handle spiHandle = NULL;
    static SPI_Params spiParams;
    
    /* -----------------------------------------------------------------------------
    *  Functions
    * ------------------------------------------------------------------------------
    */
    
    /*******************************************************************************
     * @fn          extFlashSelect
     *
     * @brief       Select the external flash on the SensorTag
     *
     * @param       none
     *
     * @return      none
     */
    static void extFlashSelect(void)
    {
        PIN_setOutputValue(hFlashPin,Board_SPI_FLASH_CS,Board_FLASH_CS_ON);
    }
    
    /*******************************************************************************
    * @fn          extFlashDeselect
    *
    * @brief       Deselect the external flash on the SensorTag
    *
    * @param       none
    *
    * @return      none
    */
    static void extFlashDeselect(void)
    {
        PIN_setOutputValue(hFlashPin,Board_SPI_FLASH_CS,Board_FLASH_CS_OFF);
    }
    
    /*******************************************************************************
    * @fn       ExtFlash_info
    *
    * @brief    Get information about the mounted flash
    *
    * @param    none
    *
    * @return   return flash info record (all fields are zero if not found)
    *******************************************************************************/
    ExtFlashInfo_t *ExtFlash_info(void)
    {
        return pFlashInfo;
    }
    
    /*******************************************************************************
    * @fn       extFlashPowerDown
    *
    * @brief    Put the device in power save mode. No access to data; only
    *           the status register is accessible.
    *
    * @param    none
    *
    * @return   Returns true if transactions succeed
    *******************************************************************************/
    static bool extFlashPowerDown(void)
    {
        uint8_t cmd;
        bool success;
    
        cmd = BLS_CODE_DP;
        extFlashSelect();
        success = Spi_write(&cmd,sizeof(cmd)) == 0;
        extFlashDeselect();
    
        return success;
    }
    
    /*******************************************************************************
    * @fn       extFlashPowerStandby
    *
    * @brief    Take device out of power save mode and prepare it for normal operation
    *
    * @param    none
    *
    * @return   Returns true if command successfully written
    *******************************************************************************/
    static bool extFlashPowerStandby(void)
    {
        uint8_t cmd;
        bool success;
    
        cmd = BLS_CODE_RDP;
        extFlashSelect();
        success = Spi_write(&cmd,sizeof(cmd)) == 0;
        extFlashDeselect();
    
        if (success)
        {
            if (ExtFlash_waitReady() != 0)
            {
                success = false;
            }
        }
    
        return success;
    }
    
    /**
    * Read flash information (manufacturer and device ID)
    * @return True when successful.
    */
    static bool ExtFlash_readInfo(void)
    {
        const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 };
    
        extFlashSelect();
    
        int ret = Spi_write(wbuf, sizeof(wbuf));
        if (ret)
        {
            extFlashDeselect();
            return false;
        }
    
        ret = Spi_read(infoBuf, sizeof(infoBuf));
        extFlashDeselect();
    
        return ret == 0;
    }
    
    /**
    * Verify the flash part.
    * @return True when successful.
    */
    
    static bool extFlashVerifyPart(void)
    {
        if (!ExtFlash_readInfo())
        {
            return false;
        }
    
        pFlashInfo = flashInfo;
        while (pFlashInfo->deviceSize > 0)
        {
            if (infoBuf[0] == pFlashInfo->manfId && infoBuf[1] == pFlashInfo->devId)
            {
                break;
            }
            pFlashInfo++;
        }
    
        return pFlashInfo->deviceSize > 0;
    }
    
    /**
    * Wait till previous erase/program operation completes.
    * @return Zero when successful.
    */
    static int ExtFlash_waitReady(void)
    {
        const uint8_t wbuf[1] = { BLS_CODE_READ_STATUS };
        int ret;
    
        /* Throw away all garbage */
        extFlashSelect();
        Spi_flash();
        extFlashDeselect();
    
        for (;;)
        {
            uint8_t buf;
    
            extFlashSelect();
            Spi_write(wbuf, sizeof(wbuf));
            ret = Spi_read(&buf,sizeof(buf));
            extFlashDeselect();
    
            if (ret)
            {
                /* Error */
                return -2;
            }
            if (!(buf & BLS_STATUS_BIT_BUSY))
            {
                /* Now ready */
                break;
            }
        }
    
        return 0;
    }
    
    /**
    * Wait until the part has entered power down (JDEC readout fails).
    * @return Zero when successful.
    */
    static int ExtFlash_powerDown(void)
    {
        uint8_t i;
    
        i = 0;
        while (i<10)
        {
            if (!ExtFlash_readInfo())
            {
                return 0;
            }
            i++;
        }
    
        return -1;
    }
    
    /**
    * Enable write.
    * @return Zero when successful.
    */
    static int ExtFlash_writeEnable(void)
    {
        const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE };
    
        extFlashSelect();
        int ret = Spi_write(wbuf,sizeof(wbuf));
        extFlashDeselect();
    
        if (ret)
        {
            return -3;
        }
        return 0;
    }
    
    
    /* See ExtFlash.h file for description */
    bool ExtFlash_open(void)
    {
        bool f;
    
        hFlashPin = PIN_open(&pinState, BoardFlashPinTable);
    
        if (hFlashPin == NULL)
        {
            return false;
        }
    
        /* Initialise SPI. Subsequent calls will do nothing. */
        SPI_init();
    
        /* Make sure SPI is available */
        f = Spi_open(SPI_BIT_RATE);
    
        if (f)
        {
            /* Put the part is standby mode */
            f = extFlashPowerStandby();
    
            if (f)
            {
                /* Verify manufacturer and device ID */
                f = extFlashVerifyPart();
            }
    
            if (!f)
            {
                ExtFlash_close();
            }
        }
    
        return f;
    }
    
    /* See ExtFlash.h file for description */
    void ExtFlash_close(void)
    {
        if (hFlashPin != NULL)
        {
            // Put the part in low power mode
            extFlashPowerDown();
            if (pFlashInfo->manfId == MF_WINBOND)
            {
                ExtFlash_powerDown();
            }
    
            /* Make sure SPI lines have a defined state */
            Spi_close();
    
            PIN_close(hFlashPin);
            hFlashPin = NULL;
        }
    }
    
    /* See ExtFlash.h file for description */
    bool ExtFlash_read(size_t offset, size_t length, uint8_t *buf)
    {
        uint8_t wbuf[4];
    
        /* Wait till previous erase/program operation completes */
        int ret = ExtFlash_waitReady();
        if (ret)
        {
            return false;
        }
    
        /* SPI is driven with very low frequency (1MHz < 33MHz fR spec)
        * in this temporary implementation.
        * and hence it is not necessary to use fast read. */
        wbuf[0] = BLS_CODE_READ;
        wbuf[1] = (offset >> 16) & 0xff;
        wbuf[2] = (offset >> 8) & 0xff;
        wbuf[3] = offset & 0xff;
    
        extFlashSelect();
    
        if (Spi_write(wbuf, sizeof(wbuf)))
        {
            /* failure */
            extFlashDeselect();
            return false;
        }
    
        ret = Spi_read(buf, length);
    
        extFlashDeselect();
    
        return ret == 0;
    }
    
    /* See ExtFlash.h file for description */
    bool ExtFlash_write(size_t offset, size_t length, const uint8_t *buf)
    {
        uint8_t wbuf[4];
    
        while (length > 0)
        {
            /* Wait till previous erase/program operation completes */
            int ret = ExtFlash_waitReady();
            if (ret)
            {
                return false;
            }
    
            ret = ExtFlash_writeEnable();
            if (ret)
            {
                return false;
            }
    
            size_t ilen; /* interim length per instruction */
    
            ilen = BLS_PROGRAM_PAGE_SIZE - (offset % BLS_PROGRAM_PAGE_SIZE);
            if (length < ilen)
            {
                ilen = length;
            }
    
            wbuf[0] = BLS_CODE_PROGRAM;
            wbuf[1] = (offset >> 16) & 0xff;
            wbuf[2] = (offset >> 8) & 0xff;
            wbuf[3] = offset & 0xff;
    
            offset += ilen;
            length -= ilen;
    
            /* Up to 100ns CS hold time (which is not clear
            * whether it's application only in between reads)
            * is not imposed here since above instructions
            * should be enough to delay
            * as much. */
            extFlashSelect();
    
            if (Spi_write(wbuf, sizeof(wbuf)))
            {
                /* failure */
                extFlashDeselect();
                return false;
            }
    
            if (Spi_write(buf,ilen))
            {
                /* failure */
                extFlashDeselect();
                return false;
            }
            buf += ilen;
            extFlashDeselect();
        }
    
        return true;
    }
    
    /* See ExtFlash.h file for description */
    bool ExtFlash_erase(size_t offset, size_t length)
    {
        /* Note that Block erase might be more efficient when the floor map
        * is well planned for OTA but to simplify for the temporary implementation,
        * sector erase is used blindly. */
        uint8_t wbuf[4];
        size_t i, numsectors;
    
        wbuf[0] = BLS_CODE_SECTOR_ERASE;
    
        {
            size_t endoffset = offset + length - 1;
            offset = (offset / BLS_ERASE_SECTOR_SIZE) * BLS_ERASE_SECTOR_SIZE;
            numsectors = (endoffset - offset + BLS_ERASE_SECTOR_SIZE - 1) /
                BLS_ERASE_SECTOR_SIZE;
        }
    
        for (i = 0; i < numsectors; i++)
        {
            /* Wait till previous erase/program operation completes */
            int ret = ExtFlash_waitReady();
            if (ret)
            {
                return false;
            }
    
            ret = ExtFlash_writeEnable();
            if (ret)
            {
                return false;
            }
    
            wbuf[1] = (offset >> 16) & 0xff;
            wbuf[2] = (offset >> 8) & 0xff;
            wbuf[3] = offset & 0xff;
    
            extFlashSelect();
    
            if (Spi_write(wbuf, sizeof(wbuf)))
            {
                /* failure */
                extFlashDeselect();
                return false;
            }
            extFlashDeselect();
    
            offset += BLS_ERASE_SECTOR_SIZE;
        }
    
        return true;
    }
    
    /* See ExtFlash.h file for description */
    bool ExtFlash_test(void)
    {
        bool ret;
    
        ret = ExtFlash_open();
        if (ret)
        {
            ExtFlash_close();
        }
    
        return ret;
    }
    
    /*******************************************************************************
    *
    *   SPI interface
    *
    *******************************************************************************/
    
    /*******************************************************************************
    * @fn          Spi_write
    *
    * @brief       Write to an SPI device
    *
    * @param       buf - pointer to data buffer
    * @param       len - number of bytes to write
    *
    * @return      '0' if success, -1 if failed
    */
    static int Spi_write(const uint8_t *buf, size_t len)
    {
        SPI_Transaction masterTransaction;
    
        masterTransaction.count  = len;
        masterTransaction.txBuf  = (void*)buf;
        masterTransaction.arg    = NULL;
        masterTransaction.rxBuf  = NULL;
    
        return SPI_transfer(spiHandle, &masterTransaction) ? 0 : -1;
    }
    
    
    /*******************************************************************************
    * @fn          Spi_read
    *
    * @brief       Read from an SPI device
    *
    * @param       buf - pointer to data buffer
    * @param       len - number of bytes to write
    *
    * @return      '0' if success, -1 if failed
    */
    static int Spi_read(uint8_t *buf, size_t len)
    {
        SPI_Transaction masterTransaction;
    
        masterTransaction.count = len;
        masterTransaction.txBuf = NULL;
        masterTransaction.arg = NULL;
        masterTransaction.rxBuf = buf;
    
        return SPI_transfer(spiHandle, &masterTransaction) ? 0 : -1;
    }
    
    
    /*******************************************************************************
    * @fn          Spi_open
    *
    * @brief       Open the RTOS SPI driver
    *
    * @param       bitRate - transfer speed in bits/sec
    *
    * @return      true if success
    */
    static bool Spi_open(uint32_t bitRate)
    {
        /*  Configure SPI as master */
        SPI_Params_init(&spiParams);
        spiParams.bitRate = bitRate;
        spiParams.mode = SPI_MASTER;
        spiParams.transferMode = SPI_MODE_BLOCKING;
    
        /* Attempt to open SPI. */
        spiHandle = SPI_open(Board_SPI0, &spiParams);
    
        return spiHandle != NULL;
    }
    
    /*******************************************************************************
    * @fn          Spi_close
    *
    * @brief       Close the RTOS SPI driver
    *
    * @return      none
    */
    static void Spi_close(void)
    {
        if (spiHandle != NULL)
        {
            // Close the RTOS driver
            SPI_close(spiHandle);
            spiHandle = NULL;
        }
    }
    
    
    /*******************************************************************************
    * @fn          Spi_flash
    *
    * @brief       Get rid of garbage from the slave
    *
    * @param       none
    *
    * @return      none
    */
    static void Spi_flash(void)
    {
        /* make sure SPI hardware module is done  */
        while(SSIBusy(((SPICC26XXDMA_HWAttrsV1*)spiHandle->hwAttrs)->baseAddr))
        { };
    }
    
    0407.ExtFlash.h

    Hi,

    Really sorry for late reply.

    I am using external flash drivers provided by TI(ExtFlash.c and ExtFlash.h). 

    Please find attached files.

  • Hi Digital Eye,

    Have you checked out the NVS driver for external storage? You would have to download a newer SDK version, however, it is a much improved driver compared to the ExtFlash API.
  • Part Number: CC2640R2F

    This is a reply to DigitalEye 

    In regards to his question

    I am using CC2640R2F launchpad to read write on board external flash memory MX25R8035F. I am using simplelink_cc2640r2_sdk_1_40_00_45 for external flash memory drivers(ExtFlash.c and ExtFlash.h).

    I am able to write to particular address and can read same value from that address only once. If I write other value to that address, I can't read that value(getting any random values).

    For example if I write "TEST" to address 0x00100 then I can read "TEST" from 0x00100.

    Again if I write "ABCD" to address 0x00100 then I read "@@@@" from 0x00100.

    This is, unfortunately, a property of the MX25R8035F if you read the fine print in the datasheet, you find that "Writes" are not "writes" that you think.

    You no doubt sent a "Clear" command to the Flash and then wrote your "TEST"  to the memory read it back and it was all OK.

    A little background on the Flash memory internals of this particular chip, The Flash memory achieves its very Low power by cheating a bit ... the "Clear" command you sent actually set ALL the bits in the cleared block to '1's 

    Then when you write to a particular memory location the "Write" command simply toggles the bits that need to be '0's and ONLY those bits   so every time you write to the same location depending on the new data you write all you are doing is toggling more bits to "0" hence the reason you get rubbish out very quickly when you  keep writing to the same location.

    if you need to rewite to the same location you need to CLEAR at least that block again  ( smallest block size is 4K i think for that chip) ...

    The memory is designed more as static long term storage data or for storing an image of code that you might have downloaded for an OTA update... 

    It sucks if you want to use it as an extension of any Dynamic working memory such as using it as a circular buffer collecting live data continuously.

    ... If its any consolation I got caught out too the first time i encountered this chip.

    I hope this helps

    WIlliam