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.

RTOS/AM5716: QSPI programming issue

Part Number: AM5716

Tool/software: TI-RTOS

Hello.

I have done some testing on the "QSPI_BasicExample_idkAM571x_armTestProject" example project in PDK108. 

When testing the project without changing any code, everything seems to be working fine. however, i have two issues, and need to solve at least one of them.

Issue 1:

I have used the code to copy files to the flash (similar to the flashwriter tool program in pdk/boot) by using memory map mode. However, when using memory map mode in SF25FL_bufferWrite() in S25FL.c, only 1 Byte is transfered per transaction. This is working, but takes too long time. (about 40 seconds for 270 kB).

Is it possible to copy 256 bytes in one transfer (page programming) when using memory map mode?

Issue 2:

If not possible to solve issue 1, i have an issue with config mode writes. in the same example project, 256 bytes are transferred at once when using config mode writes. however, my issue is that from byte number 257, only 0xFF are read back after writing. for the bytes from 1 to 256, everything seems to be working fine in this mode.

The config mode code is not changed in the project, except changing the number of bytes to transfer. (originally it was 200 bytes).

Thanks for your continuous support.

Anders.

  • The RTOS team have been notified. They will respond here.
  • Anders,

    I will need to look into the Issue 1 and get back to you but I do think we understand what is going on with issue 2. The QSPI Basic example is just a confirmation test that QSPI LLD is functionally working and to show an example configuration hence it is currently setup only to program the first sector in the sense that it doesn`t provide the logic to figure out how many sectors need to be programmed. If you see all the operations are performed on blockNum0(sector 0) and the addressValue is based on that sector.

    the corrrect logic to program data greater than sector size is provided in the QSPI flash writer code that we support as part of the boot tools for these devices. Refer to the function SBL_qspiFlashWrite and SBL_qspiFlashRead in the file sbl_soc.c found in the path pdk_am57xx_x_x_x\packages\ti\boot\sbl\soc\am57xx.
    these functions detect the length and then determine how many sectors will need to be programmed on the QSPI flash based on the transfer length and then program the flash one sector at a time until entire binary is programmed to flash. also note each sector needs to be erased before programming as per the flash data sheet.

    Please review and let us know if this meets your requirements.

    Regards,
    Rahul
  • Rahul,

    for issue 2:
    I am sure that the sectors to be programmed are erased before programming to them. To be sure, I have now implemented the code in SBL_qspiFlashWrite and SBL_qspiFlashRead. Same results.
    To be sure that we are speaking of the same things: a block is 64 kB (and sometimes 4kB). I am now testing with max 1kB data. Therefore, I am always writing to block 0. however, the problems occur when writing to byte number 257. Let us call 256 Bytes a page. writing to the first page works fine, but when writing to the second page, the data read back is not correct (only 0xFF).

    in C:\ti\pdk_am57xx_1_0_8\packages\ti\drv\spi\test\qspi_flash\src\Flash_S25FL\S25FL.c,
    the code for dealing with the page programming can be found:

    if(QSPI_OPER_MODE_CFG == object->qspiMode)
    {
    /*
    * Config mode write supports 256 bytes at a time. So if the length is
    * greater than 256, then multiple transactions have to be performed till
    * all the bytes are written.
    */
    while(length > 256)
    {
    SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
    dstOffstAddr = dstOffstAddr + (256 / 4);
    srcAddr += 256;
    length -= 256;
    }
    if(length > 0)
    {
    SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
    }
    }

    FYI: I found out that when starting with offset 0x10000U (starting at the second block), i get 1 byte wrong offset when i read back the data. But I am then able to read back 2 pages that do not have only 0xFF.

    I have done some testing and debugging on this, and it seems that the correct data is sent in to the function QSPI_cmd_mode_write_v1() in C:\ti\pdk_am57xx_1_0_8\packages\ti\drv\spi\src\v1\QSPI_v1.c. It also seems that the data is sent to the flash (at least 0xFF is not sent).

    Do you have any suggestions on what to further debug/test?

    Perhaps you could test writing with config mode with more than 256 Bytes on your system?

    Appreciate your help,

    Anders
  •  Any updates?

    FYI what I am trying to make is a production flashing tool with SD card files as input. The code is working with MMAP mode and transaction length of 1 Byte. The problem is that it takes to long time to program one byte at each transaction. Maybe the easiest issue here is this issue (issue 1). MMAP is the mode meant to be used for programming the flash with boot and app files (?). However, I found config mode to write quite fast as well (unfortunately with wrong data).

    I have done some more debugging on the mmap mode with transaction length of 256 Bytes (and other length as well, same results). In C:\ti\pdk_am57xx_1_0_8\packages\ti\drv\spi\src\v1\QSPI_v1.c

    static void QSPI_mmap_mode_write_v1(SPI_Handle handle,
                                        const SPI_Transaction *transaction)
    {
        QSPI_HwAttrs const  *hwAttrs;          /* QSPI hardware attributes */
        uint32_t mmapWriteCmd = 0U;        /* Mmap command */
        uint32_t count = 0U;               /* transaction length */
        uint8_t *pSrc;                   /* Source address */
        uint8_t *pDst;                   /* Destination address */
        QSPI_v1_Object  *object;               /* QSPI object */
        uint32_t offset;
    
    
        /* Input parameter validation */
        OSAL_Assert(!((handle != NULL) && (transaction != NULL)));
    
        /* Copy flash transaction parameters to local variables */
        pSrc = (uint8_t*)transaction->rxBuf;
        pDst = (uint8_t*)transaction->txBuf;
        count = transaction->count;
    
        /* Get the pointer to the object and hwAttrs */
        hwAttrs = (QSPI_HwAttrs*)handle->hwAttrs;
        object = (QSPI_v1_Object*)handle->object;
    
        /* Compute the flash destination address */
        uint32_t temp_addr = ((uint32_t)hwAttrs->memMappedBaseAddr + (uint32_t)transaction->txBuf);
        pDst = ((uint8_t *)(temp_addr));
    
        // Anders Debug
        uint8_t *pDstOrig = pDst;
        uint8_t *pSrcOrig = pSrc;
        // Anders Debug ends
        
    	offset = (uint32_t)transaction->txBuf;
    
        /* Extract memory map mode command */
        mmapWriteCmd = (uint32_t)object->transferCmd;
    
        QSPISetMemMapWriteCmd(hwAttrs->baseAddr, hwAttrs->chipSelect, mmapWriteCmd);
        QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
            QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
        QSPISetMemAddrSpace(hwAttrs->baseAddr, hwAttrs->chipSelect,
            QSPI_MEM_MAP_PORT_SEL_MEM_MAP_PORT);
    
        QSPIMmapCsEnable(hwAttrs->baseAddr, hwAttrs->chipSelect);
    
        /* 4 byte addressing mode. */
        if(offset > (uint32_t)0xFFFFFF)
        {
            /* Switch to four byte addressing mode */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
        }
    
        while(count)
        {
            *pDst = *pSrc;
            pDst++;
            pSrc++;
            count--;
        }
    
        // anders debug check data of 256 bytes after pDst. pDst is address on flash. Only first Byte is written, others are read as 0xFF.
        int i;
    uint8_t dataDst[256]; for(i=0;i<256;i++) { dataDst[i]=pDstOrig[i]; } uint8_t dataSrc[256]; for(i=0;i<256;i++) { dataSrc[i]=pSrcOrig[i]; } // Anders debug ends /* 4 byte addressing mode. */ if(offset > (uint32_t)0xFFFFFF) { /* Switch back to three byte addressing mode. */ QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect, QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR); } }

    Below is the data in the arrays dataSrc (buffer in local memory) and dataDst (buffer on flash). As you can see, only the first Byte is copied in the function QSPI_mmap_mode_write_v1 in QSPI_v1.c.

    Byte Num dataSrc dataDst
    0 1 1
    1 0 255
    2 0 255
    3 0 255
    4 2 255
    5 0 255
    6 0 255
    7 0 255
    8 3 255
    9 0 255
    10 0 255
    11 0 255
    12 4 255
    13 0 255
    14 0 255
    15 0 255
    16 5 255
    17 0 255
    18 0 255
    19 0 255
    20 6 255
    21 0 255
    22 0 255
    23 0 255
    24 7 255
    25 0 255
    26 0 255
    27 0 255
    28 8 255
    29 0 255
    30 0 255
    31 0 255
    32 9 255
    33 0 255
    34 0 255
    35 0 255
    36 10 255
    37 0 255
    38 0 255
    39 0 255
    40 11 255
    41 0 255
    42 0 255
    43 0 255
    44 12 255
    45 0 255
    46 0 255
    47 0 255
    48 13 255
    49 0 255
    50 0 255
    51 0 255
    52 14 255
    53 0 255
    54 0 255
    55 0 255
    56 15 255
    57 0 255
    58 0 255
    59 0 255
    60 16 255
    61 0 255
    62 0 255
    63 0 255
    64 17 255
    65 0 255
    66 0 255
    67 0 255
    68 18 255
    69 0 255
    70 0 255
    71 0 255
    72 19 255
    73 0 255
    74 0 255
    75 0 255
    76 20 255
    77 0 255
    78 0 255
    79 0 255
    80 21 255
    81 0 255
    82 0 255
    83 0 255
    84 22 255
    85 0 255
    86 0 255
    87 0 255
    88 23 255
    89 0 255
    90 0 255
    91 0 255
    92 24 255
    93 0 255
    94 0 255
    95 0 255
    96 25 255
    97 0 255
    98 0 255
    99 0 255

    I believe there is a small detail that I am forgetting to include when changing the transaction->count from 1 to another number. I have tried to include
    SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength)); before SPI_transfer, but this did not make any difference.

    Appreciate your support,

    Anders.

  • Anders,

    I have not gotten a chance to test this out but can tell you that QSPI flashing and booting is tested by system test using images that are greater than 256 bytes, so I am suprised by your finding that in config mode using the SBL flash writer utility the byte 257 is always read in as 0xFF.

    As part of the readback validate step, the flash writer utility reads the data back from the flash and verifies that the binary data from flash matches with input binary data fromt he SD card. If you can provide your source project or provide instructions to help us replicate this issue then it would be easier for me to help you debug the issue.

    Regards,
    Rahul
  • Rahul,

    Thanks for your response.

    The absolutely easiest way for you to test, would be to use the project "QSPI_BasicExample_idkAM571x_armTestProject" provided in pdk108. I see no practical difference between this project and the flashwriter code. I have attached my modified main file. This file erases the first 10 blocks (from offset 0), and starts writing from offset 0. The file also have a nice UART_printf log, so that you easily see what is written an read back. When using this file, I get all test correct when using a transferlength of 50*2 bytes. But when using 65*4 bytes (more than 256 BYtes) the first test fails. (config mode, single write).

    /**
     *  \file   main_flash_read_test.c
     *
     *  \brief  Example application main file. This application will write and read
     *          the data to/from nor flash through qspi interface.
     *
     */
    
    /*
     * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
     *
     * 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.
     *
     */
    
    
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>
    #include <stdio.h>
    #include <ti/sysbios/knl/Task.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <xdc/runtime/Error.h>
    #include <ti/csl/soc.h>
    /* TI-RTOS Header files */
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    #include "SPI_log.h"
    
    /* Flash header file */
    #include <ti/drv/spi/test/qspi_flash/src/Flash_S25FL/S25FL.h>
    
    #include <ti/board/board.h>
    
    /**********************************************************************
     ************************** Macros ************************************
     **********************************************************************/
    #define QSPI_PER_CNT            (1U)
    #define QSPI_INSTANCE           (1U)
    
    #if defined (SOC_AM335x) || defined (SOC_AM437x)
    #define QSPI_OFFSET             (5U)
    #endif
    #if defined (SOC_AM572x) || defined (SOC_AM571x)
    #define QSPI_OFFSET             (4U)
    #endif
    
    /**********************************************************************
     ************************** Internal functions ************************
     **********************************************************************/
    
    /* Function to generate known data */
    static void GeneratePattern(uint8_t *txBuf, uint8_t *rxBuf, uint32_t length);
    
    /* Data compare function */
    bool VerifyData(unsigned char *expData,
                    unsigned char *rxData,
                    unsigned int length);
    
    #if defined (SOC_AM571x) || defined (SOC_AM572x)
    void QSPI_board_crossbarInit(void);
    #endif
    /**********************************************************************
     ************************** Global Variables **************************
     **********************************************************************/
    
    /* Buffer containing the known data that needs to be written to flash */
    unsigned int txBuf[1024];
    
    /* Buffer containing the received data */
    unsigned int rxBuf[1024];
    
    unsigned int addrValue = 0x000000U;
    
    int transferlengthGlobal = 128;
    
    /* hardware attributes */
    extern QSPI_HwAttrs qspiInitCfg[QSPI_PER_CNT];
    
    /* transfer length */
    uint32_t transferLength = 0;
    
    
    /*
     *  ======== test function ========
     */
    void spi_test(UArg arg0, UArg arg1)
    {
        SPI_Params spiParams;                /* SPI params structure */
        S25FL_Handle flashHandle;            /* Flash handle */
        unsigned int blockNumber = 0U;       /* Block number */
        S25FL_Transaction flashTransaction;  /* Flash transaction structure */
        SPI_Handle handle;                   /* SPI handle */
        QSPI_HwAttrs *hwAttrs;               /* QSPI hardware attributes */
        bool retVal = false;                 /* return value */
        unsigned int rxLines;
        unsigned int qspiMode;
        unsigned int i = 0;
    
        /* Init SPI driver */
        SPI_init();
    
        /* Default SPI configuration parameters */
        SPI_Params_init(&spiParams);
    
        /* Open QSPI driver */
        flashHandle = SF25FL_open(((QSPI_INSTANCE - 1)+(QSPI_OFFSET)), &spiParams);
    
        /* Extract hardware attributes */
        handle = flashHandle->spiHandle;
        hwAttrs = (QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Print flash Id */
        FlashPrintId(flashHandle);
    
        /* Mode: CFG & Rx Lines: SINGLE */
    
        /* For CFG Mode: The parameter "flashTransaction.address" should be assigned
           with the address of the variable which contains the flash offset value*/
    
        qspiMode = QSPI_OPER_MODE_CFG;
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        S25FLFlash_BlockErase(flashHandle, blockNumber);
        S25FLFlash_BlockErase(flashHandle, blockNumber+1);
        S25FLFlash_BlockErase(flashHandle, blockNumber+2);
        S25FLFlash_BlockErase(flashHandle, blockNumber+3);
        S25FLFlash_BlockErase(flashHandle, blockNumber+4);
        S25FLFlash_BlockErase(flashHandle, blockNumber+5);
        S25FLFlash_BlockErase(flashHandle, blockNumber+6);
        S25FLFlash_BlockErase(flashHandle, blockNumber+7);
        S25FLFlash_BlockErase(flashHandle, blockNumber+8);
        S25FLFlash_BlockErase(flashHandle, blockNumber+9);
        S25FLFlash_BlockErase(flashHandle, blockNumber+10);
    
        /* Set the transfer length in number of 32 bit words */
        transferLength = transferlengthGlobal;
    
        /* Generate the data */
        GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
        /* Update transaction parameters */
        flashTransaction.data       = (uint8_t *)&txBuf[0];
        flashTransaction.address = (uint32_t)&addrValue;
        flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
        /* Write buffer to flash */
        retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
        if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
        {
            S25FLFlash_QuadModeEnable(flashHandle);
        }
    
        /* Update transaction parameters */
        flashTransaction.data       = (uint8_t *)&rxBuf[0];
        flashTransaction.address = (uint32_t)&addrValue;
        flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
        /* Read data from flash */
        retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
        SPI_log("\n Printing cfg single below. \n");
        log_buffers(txBuf, rxBuf, transferLength);
    
        /* Verify Data */
        retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
            transferLength);
    
        /* Mode: CFG & Rx Lines: DUAL */
    
        /* Reset receive buffer */
        for(i = 0; i < transferlengthGlobal; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_CFG;
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_DUAL;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            S25FLFlash_BlockErase(flashHandle, blockNumber);
            S25FLFlash_BlockErase(flashHandle, blockNumber+1);
            S25FLFlash_BlockErase(flashHandle, blockNumber+2);
            S25FLFlash_BlockErase(flashHandle, blockNumber+3);
            S25FLFlash_BlockErase(flashHandle, blockNumber+4);
            S25FLFlash_BlockErase(flashHandle, blockNumber+5);
            S25FLFlash_BlockErase(flashHandle, blockNumber+6);
            S25FLFlash_BlockErase(flashHandle, blockNumber+7);
            S25FLFlash_BlockErase(flashHandle, blockNumber+8);
            S25FLFlash_BlockErase(flashHandle, blockNumber+9);
            S25FLFlash_BlockErase(flashHandle, blockNumber+10);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = transferlengthGlobal;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            SPI_log("\n Printing cfg dual below. \n");
            log_buffers(txBuf, rxBuf, transferLength);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: CFG & Rx Lines: QUAD */
    
        /* Reset receive buffer */
        for(i = 0; i < transferlengthGlobal; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_CFG;
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_QUAD;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            S25FLFlash_BlockErase(flashHandle, blockNumber);
            S25FLFlash_BlockErase(flashHandle, blockNumber+1);
            S25FLFlash_BlockErase(flashHandle, blockNumber+2);
            S25FLFlash_BlockErase(flashHandle, blockNumber+3);
            S25FLFlash_BlockErase(flashHandle, blockNumber+4);
            S25FLFlash_BlockErase(flashHandle, blockNumber+5);
            S25FLFlash_BlockErase(flashHandle, blockNumber+6);
            S25FLFlash_BlockErase(flashHandle, blockNumber+7);
            S25FLFlash_BlockErase(flashHandle, blockNumber+8);
            S25FLFlash_BlockErase(flashHandle, blockNumber+9);
            S25FLFlash_BlockErase(flashHandle, blockNumber+10);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = transferlengthGlobal;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            SPI_log("\n Printing cfg quad below. \n");
            log_buffers(txBuf, rxBuf, transferLength);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: MMAP & Rx Lines: SINGLE */
    
        /* For MMAP Mode: The parameter "flashTransaction.address" should be
           assigned with directly the flash offset value */
    
        /* Reset receive buffer */
        for(i = 0; i < transferlengthGlobal; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_MMAP;
        SPI_control(handle, SPI_V1_CMD_SETMEMMORYMAPMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            S25FLFlash_BlockErase(flashHandle, blockNumber);
            S25FLFlash_BlockErase(flashHandle, blockNumber+1);
            S25FLFlash_BlockErase(flashHandle, blockNumber+2);
            S25FLFlash_BlockErase(flashHandle, blockNumber+3);
            S25FLFlash_BlockErase(flashHandle, blockNumber+4);
            S25FLFlash_BlockErase(flashHandle, blockNumber+5);
            S25FLFlash_BlockErase(flashHandle, blockNumber+6);
            S25FLFlash_BlockErase(flashHandle, blockNumber+7);
            S25FLFlash_BlockErase(flashHandle, blockNumber+8);
            S25FLFlash_BlockErase(flashHandle, blockNumber+9);
            S25FLFlash_BlockErase(flashHandle, blockNumber+10);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = transferlengthGlobal;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            SPI_log("\n Printing mmap single below. \n");
            log_buffers(txBuf, rxBuf, transferLength);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: MMAP & Rx Lines: DUAL */
    
        /* Reset receive buffer */
        for(i = 0; i < transferlengthGlobal; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_MMAP;
        SPI_control(handle, SPI_V1_CMD_SETMEMMORYMAPMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_DUAL;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            S25FLFlash_BlockErase(flashHandle, blockNumber);
            S25FLFlash_BlockErase(flashHandle, blockNumber+1);
            S25FLFlash_BlockErase(flashHandle, blockNumber+2);
            S25FLFlash_BlockErase(flashHandle, blockNumber+3);
            S25FLFlash_BlockErase(flashHandle, blockNumber+4);
            S25FLFlash_BlockErase(flashHandle, blockNumber+5);
            S25FLFlash_BlockErase(flashHandle, blockNumber+6);
            S25FLFlash_BlockErase(flashHandle, blockNumber+7);
            S25FLFlash_BlockErase(flashHandle, blockNumber+8);
            S25FLFlash_BlockErase(flashHandle, blockNumber+9);
            S25FLFlash_BlockErase(flashHandle, blockNumber+10);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = transferlengthGlobal;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            SPI_log("\n Printing mmap dual below. \n");
            log_buffers(txBuf, rxBuf, transferLength);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: MMAP & Rx Lines: QUAD */
    
        /* Reset receive buffer */
        for(i = 0; i < transferlengthGlobal; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_MMAP;
        SPI_control(handle, SPI_V1_CMD_SETMEMMORYMAPMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_QUAD;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            /* Erase block, to which data has to be written */
            S25FLFlash_BlockErase(flashHandle, blockNumber);
            S25FLFlash_BlockErase(flashHandle, blockNumber+1);
            S25FLFlash_BlockErase(flashHandle, blockNumber+2);
            S25FLFlash_BlockErase(flashHandle, blockNumber+3);
            S25FLFlash_BlockErase(flashHandle, blockNumber+4);
            S25FLFlash_BlockErase(flashHandle, blockNumber+5);
            S25FLFlash_BlockErase(flashHandle, blockNumber+6);
            S25FLFlash_BlockErase(flashHandle, blockNumber+7);
            S25FLFlash_BlockErase(flashHandle, blockNumber+8);
            S25FLFlash_BlockErase(flashHandle, blockNumber+9);
            S25FLFlash_BlockErase(flashHandle, blockNumber+10);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = transferlengthGlobal;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            SPI_log("\n Printing mmap quad below. \n");
            log_buffers(txBuf, rxBuf, transferLength);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        SF25FL_close(flashHandle);
    
        if(true == retVal)
        {
            SPI_log("\n All tests have passed. \n");
        }
        else
        {
            SPI_log("\n Some tests have failed. \n");
        }
    
        while(1);
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call board init functions */
        Board_initCfg boardCfg;
    
    #if defined (SOC_AM335x) || defined (SOC_AM437x)
        Task_Handle task;
        Error_Block eb;
    
        Error_init(&eb);
        task = Task_create(spi_test, NULL, &eb);
        if (task == NULL) {
            System_printf("Task_create() failed!\n");
            BIOS_exit(0);
        }
    #endif
    
        boardCfg = BOARD_INIT_PINMUX_CONFIG |
            BOARD_INIT_MODULE_CLOCK |
            BOARD_INIT_UART_STDIO;
        Board_init(boardCfg);
    
    #if defined (SOC_AM571x) || defined (SOC_AM572x)
        QSPI_board_crossbarInit();
    #endif
    
        /* Start BIOS */
        BIOS_start();
        return (0);
    }
    
    /*
     *  ======== Board_initQSPI ========
     */
    #if defined (SOC_AM571x) || defined (SOC_AM572x)
    void QSPI_board_crossbarInit(void) {
        CSL_XbarIrqCpuId                   cpu;
        uint32_t                           cpuEvent;
        uint32_t                           xbarIndex;
    #ifdef C66X
    
        /* Configure xbar connect for MCSPI3: DSP_IRQ_38 mapped to MCSPI3 intr */
        cpu = CSL_XBAR_IRQ_CPU_ID_DSP1;
        cpuEvent = 38;
        xbarIndex = cpuEvent - 31;
    
        /* Configure xbar */
        CSL_xbarIrqConfigure (cpu, xbarIndex, CSL_XBAR_QSPI_IRQ);
    
    #elif __ARM_ARCH_7A__
        /* Configure xbar connect for QSPI: MPU_IRQ_35 mapped to QSPI intr */
        *(unsigned int*)0x4A002A80 = (unsigned int)(0x0157001D);
    
    #else
    
        /* Configure xbar connect for MCSPI3: DSP_IRQ_38 mapped to MCSPI3 intr */
        cpu = CSL_XBAR_IRQ_CPU_ID_IPU1;
        cpuEvent = 62;
        xbarIndex = cpuEvent - 22;
    
        /* Configure xbar */
        CSL_xbarIrqConfigure (cpu, xbarIndex, CSL_XBAR_QSPI_IRQ);
    #endif
    
    }
    #endif
    
    /*
     *  ======== CompareData ========
     */
    bool VerifyData(unsigned char *expData,
                    unsigned char *rxData,
                    unsigned int length)
    {
        unsigned int idx = 0;
        unsigned int match = 1;
        bool retVal = false;
        unsigned int lenInBytes = length * 4;
    
        for(idx = 0; ((idx < lenInBytes) && (match != 0)); idx++)
        {
            if(*expData != *rxData) match = 0;
            expData++;
            rxData++;
        }
    
        if(match == 1) retVal = true;
    
        return retVal;
    }
    
    /*
     *  ======== GeneratePattern ========
     */
    static void GeneratePattern(uint8_t *txBuf, uint8_t *rxBuf, uint32_t length)
    {
        unsigned int idx;
        unsigned int lenInBytes = length * 4;
    
        for(idx = 0; idx < lenInBytes; idx++)
        {
            txBuf[idx] = (uint8_t)idx;
            rxBuf[idx] = (uint8_t)0U;
        }
    }
    
    void log_buffers(unsigned int txBuf[], unsigned int rxBuf[], int transferLength)
    {
        int i;
        int countErrors = 0;
        int countSuccess = 0;
        int countPrinted = 0;
    
        int tempAddress = addrValue;
        FILE *f = fopen ("C:\\temp\\test.txt", "w");
        if(f == NULL)
        {
            SPI_log("Error opening file!\n");
        }
    
    
    
        for(i = 0; i < transferLength; i++)
        {
            if(i%64==0)
            {
                SPI_log("-------  NEW PAGE  ------------------------------------------------------------------------------------------------------\n");
            }
            if(txBuf[i]!=rxBuf[i])
            {
                countErrors++;
    
                if(1/*rxBuf[i] != 0xFFFFFFFF*/)
                {
                    countPrinted++;
    
                    SPI_log("txbuf[%u]:%13u\t0x%08X\t", i, txBuf[i], txBuf[i]);
                    SPI_log_bits(sizeof(txBuf[i]), &txBuf[i]);
                    //SPI_log("   0x%08X -> 0x%08X -> 0x%08X",tempAddress, tempAddress+memMappedBaseAddr, tempAddress+baseAddr);
                    SPI_log("\nrxbuf[%u]:%13u\t0x%08X\t", i, rxBuf[i], rxBuf[i]);
                    SPI_log_bits(sizeof(rxBuf[i]), &rxBuf[i]);
                    txBuf[i]==rxBuf[i]?SPI_log("   OK."):SPI_log("   Not Equal.");
                    SPI_log(" Sector: %d. Page: %d. Pos: %d.\n\n", (i*4/65536), i*4/256, i%64);
    
                }
    
            }
            else
            {
                countSuccess++;
    
                if(i%1==0)
                {
                    countPrinted++;
                    SPI_log("txbuf[%u]:%13u\t0x%08X\t", i, txBuf[i], txBuf[i]);
                    SPI_log_bits(sizeof(txBuf[i]), &txBuf[i]);
                    //SPI_log("   0x%08X -> 0x%08X -> 0x%08X",tempAddress, tempAddress+memMappedBaseAddr, tempAddress+baseAddr);
                    SPI_log("\nrxbuf[%u]:%13u\t0x%08X\t", i, rxBuf[i], rxBuf[i]);
                    SPI_log_bits(sizeof(rxBuf[i]), &rxBuf[i]);
                    txBuf[i]==rxBuf[i]?SPI_log("   OK."):SPI_log("   Not Equal.");
                    SPI_log(" Sector: %d. Page: %d. Pos: %d.\n\n", (i*4/65536), i*4/256, i%64);
                }
    
    
            }
    /*
            SPI_log("txbuf[%u]:\t%u\t0x%08X\t", i, txBuf[i], txBuf[i]);
            SPI_log_bits(sizeof(txBuf[i]), &txBuf[i]);
            SPI_log("   0x%08X -> 0x%08X -> 0x%08X",tempAddress, tempAddress+memMappedBaseAddr, tempAddress+baseAddr);
            SPI_log("\nrxbuf[%u]:\t%u\t0x%08X\t", i, rxBuf[i], rxBuf[i]);
            SPI_log_bits(sizeof(rxBuf[i]), &rxBuf[i]);
            txBuf[i]==rxBuf[i]?SPI_log("   OK."):SPI_log("   Not Equal.");
            SPI_log("\n\n");
    */
    
            tempAddress = tempAddress + 4;
        }
        fprintf(f, "Number of errors: %d.\n",countErrors);
        SPI_log("Number of success:  %d.\n",countSuccess);
        SPI_log("Number of errors:  %d.\n",countErrors);
        SPI_log("Number of printed: %d.\n",countPrinted);
        SPI_log("transferLength: %d * 4 Bytes = %d.\n",transferLength,transferLength*4);
        fclose(f);
    }
    
    /*
     * ========== SPI_log_bits ========
     * assumes little endian.
     * prints the bits of a variable
     *
     *
     */
    void SPI_log_bits(size_t const size, void const * const ptr)
    {
        unsigned char *b = (unsigned char*) ptr;
        unsigned char byte;
        int i, j;
    
        for (i=size-1;i>=0;i--)
        {
            for (j=7;j>=0;j--)
            {
                byte = (b[i] >> j) & 1;
                SPI_log("%u", byte);
            }
        }
        //puts("");
    }
    

    UART_printf log when testing config mode single:

    Printing cfg single below.
    ------- NEW PAGE ------------------------------------------------------------------------------------------------------
    txbuf[0]: 50462976 0x03020100 00000011000000100000000100000000
    rxbuf[0]: 50462976 0x03020100 00000011000000100000000100000000 OK. Sector: 0. Page: 0. Pos: 0.
    
    txbuf[1]: 117835012 0x07060504 00000111000001100000010100000100
    rxbuf[1]: 117835012 0x07060504 00000111000001100000010100000100 OK. Sector: 0. Page: 0. Pos: 1.
    
    txbuf[2]: 185207048 0x0b0a0908 00001011000010100000100100001000
    rxbuf[2]: 185207048 0x0b0a0908 00001011000010100000100100001000 OK. Sector: 0. Page: 0. Pos: 2.
    
    txbuf[3]: 252579084 0x0f0e0d0c 00001111000011100000110100001100
    rxbuf[3]: 252579084 0x0f0e0d0c 00001111000011100000110100001100 OK. Sector: 0. Page: 0. Pos: 3.
    
    txbuf[4]: 319951120 0x13121110 00010011000100100001000100010000
    rxbuf[4]: 319951120 0x13121110 00010011000100100001000100010000 OK. Sector: 0. Page: 0. Pos: 4.
    
    txbuf[5]: 387323156 0x17161514 00010111000101100001010100010100
    rxbuf[5]: 387323156 0x17161514 00010111000101100001010100010100 OK. Sector: 0. Page: 0. Pos: 5.
    
    txbuf[6]: 454695192 0x1b1a1918 00011011000110100001100100011000
    rxbuf[6]: 454695192 0x1b1a1918 00011011000110100001100100011000 OK. Sector: 0. Page: 0. Pos: 6.
    
    txbuf[7]: 522067228 0x1f1e1d1c 00011111000111100001110100011100
    rxbuf[7]: 522067228 0x1f1e1d1c 00011111000111100001110100011100 OK. Sector: 0. Page: 0. Pos: 7.
    
    txbuf[8]: 589439264 0x23222120 00100011001000100010000100100000
    rxbuf[8]: 589439264 0x23222120 00100011001000100010000100100000 OK. Sector: 0. Page: 0. Pos: 8.
    
    txbuf[9]: 656811300 0x27262524 00100111001001100010010100100100
    rxbuf[9]: 656811300 0x27262524 00100111001001100010010100100100 OK. Sector: 0. Page: 0. Pos: 9.
    
    txbuf[10]: 724183336 0x2b2a2928 00101011001010100010100100101000
    rxbuf[10]: 724183336 0x2b2a2928 00101011001010100010100100101000 OK. Sector: 0. Page: 0. Pos: 10.
    
    txbuf[11]: 791555372 0x2f2e2d2c 00101111001011100010110100101100
    rxbuf[11]: 791555372 0x2f2e2d2c 00101111001011100010110100101100 OK. Sector: 0. Page: 0. Pos: 11.
    
    txbuf[12]: 858927408 0x33323130 00110011001100100011000100110000
    rxbuf[12]: 858927408 0x33323130 00110011001100100011000100110000 OK. Sector: 0. Page: 0. Pos: 12.
    
    txbuf[13]: 926299444 0x37363534 00110111001101100011010100110100
    rxbuf[13]: 926299444 0x37363534 00110111001101100011010100110100 OK. Sector: 0. Page: 0. Pos: 13.
    
    txbuf[14]: 993671480 0x3b3a3938 00111011001110100011100100111000
    rxbuf[14]: 993671480 0x3b3a3938 00111011001110100011100100111000 OK. Sector: 0. Page: 0. Pos: 14.
    
    txbuf[15]: 1061043516 0x3f3e3d3c 00111111001111100011110100111100
    rxbuf[15]: 1061043516 0x3f3e3d3c 00111111001111100011110100111100 OK. Sector: 0. Page: 0. Pos: 15.
    
    txbuf[16]: 1128415552 0x43424140 01000011010000100100000101000000
    rxbuf[16]: 1128415552 0x43424140 01000011010000100100000101000000 OK. Sector: 0. Page: 0. Pos: 16.
    
    txbuf[17]: 1195787588 0x47464544 01000111010001100100010101000100
    rxbuf[17]: 1195787588 0x47464544 01000111010001100100010101000100 OK. Sector: 0. Page: 0. Pos: 17.
    
    txbuf[18]: 1263159624 0x4b4a4948 01001011010010100100100101001000
    rxbuf[18]: 1263159624 0x4b4a4948 01001011010010100100100101001000 OK. Sector: 0. Page: 0. Pos: 18.
    
    txbuf[19]: 1330531660 0x4f4e4d4c 01001111010011100100110101001100
    rxbuf[19]: 1330531660 0x4f4e4d4c 01001111010011100100110101001100 OK. Sector: 0. Page: 0. Pos: 19.
    
    txbuf[20]: 1397903696 0x53525150 01010011010100100101000101010000
    rxbuf[20]: 1397903696 0x53525150 01010011010100100101000101010000 OK. Sector: 0. Page: 0. Pos: 20.
    
    txbuf[21]: 1465275732 0x57565554 01010111010101100101010101010100
    rxbuf[21]: 1465275732 0x57565554 01010111010101100101010101010100 OK. Sector: 0. Page: 0. Pos: 21.
    
    txbuf[22]: 1532647768 0x5b5a5958 01011011010110100101100101011000
    rxbuf[22]: 1532647768 0x5b5a5958 01011011010110100101100101011000 OK. Sector: 0. Page: 0. Pos: 22.
    
    txbuf[23]: 1600019804 0x5f5e5d5c 01011111010111100101110101011100
    rxbuf[23]: 1600019804 0x5f5e5d5c 01011111010111100101110101011100 OK. Sector: 0. Page: 0. Pos: 23.
    
    txbuf[24]: 1667391840 0x63626160 01100011011000100110000101100000
    rxbuf[24]: 1667391840 0x63626160 01100011011000100110000101100000 OK. Sector: 0. Page: 0. Pos: 24.
    
    txbuf[25]: 1734763876 0x67666564 01100111011001100110010101100100
    rxbuf[25]: 1734763876 0x67666564 01100111011001100110010101100100 OK. Sector: 0. Page: 0. Pos: 25.
    
    txbuf[26]: 1802135912 0x6b6a6968 01101011011010100110100101101000
    rxbuf[26]: 1802135912 0x6b6a6968 01101011011010100110100101101000 OK. Sector: 0. Page: 0. Pos: 26.
    
    txbuf[27]: 1869507948 0x6f6e6d6c 01101111011011100110110101101100
    rxbuf[27]: 1869507948 0x6f6e6d6c 01101111011011100110110101101100 OK. Sector: 0. Page: 0. Pos: 27.
    
    txbuf[28]: 1936879984 0x73727170 01110011011100100111000101110000
    rxbuf[28]: 1936879984 0x73727170 01110011011100100111000101110000 OK. Sector: 0. Page: 0. Pos: 28.
    
    txbuf[29]: 2004252020 0x77767574 01110111011101100111010101110100
    rxbuf[29]: 2004252020 0x77767574 01110111011101100111010101110100 OK. Sector: 0. Page: 0. Pos: 29.
    
    txbuf[30]: 2071624056 0x7b7a7978 01111011011110100111100101111000
    rxbuf[30]: 2071624056 0x7b7a7978 01111011011110100111100101111000 OK. Sector: 0. Page: 0. Pos: 30.
    
    txbuf[31]: 2138996092 0x7f7e7d7c 01111111011111100111110101111100
    rxbuf[31]: 2138996092 0x7f7e7d7c 01111111011111100111110101111100 OK. Sector: 0. Page: 0. Pos: 31.
    
    txbuf[32]: 2206368128 0x83828180 10000011100000101000000110000000
    rxbuf[32]: 2206368128 0x83828180 10000011100000101000000110000000 OK. Sector: 0. Page: 0. Pos: 32.
    
    txbuf[33]: 2273740164 0x87868584 10000111100001101000010110000100
    rxbuf[33]: 2273740164 0x87868584 10000111100001101000010110000100 OK. Sector: 0. Page: 0. Pos: 33.
    
    txbuf[34]: 2341112200 0x8b8a8988 10001011100010101000100110001000
    rxbuf[34]: 2341112200 0x8b8a8988 10001011100010101000100110001000 OK. Sector: 0. Page: 0. Pos: 34.
    
    txbuf[35]: 2408484236 0x8f8e8d8c 10001111100011101000110110001100
    rxbuf[35]: 2408484236 0x8f8e8d8c 10001111100011101000110110001100 OK. Sector: 0. Page: 0. Pos: 35.
    
    txbuf[36]: 2475856272 0x93929190 10010011100100101001000110010000
    rxbuf[36]: 2475856272 0x93929190 10010011100100101001000110010000 OK. Sector: 0. Page: 0. Pos: 36.
    
    txbuf[37]: 2543228308 0x97969594 10010111100101101001010110010100
    rxbuf[37]: 2543228308 0x97969594 10010111100101101001010110010100 OK. Sector: 0. Page: 0. Pos: 37.
    
    txbuf[38]: 2610600344 0x9b9a9998 10011011100110101001100110011000
    rxbuf[38]: 2610600344 0x9b9a9998 10011011100110101001100110011000 OK. Sector: 0. Page: 0. Pos: 38.
    
    txbuf[39]: 2677972380 0x9f9e9d9c 10011111100111101001110110011100
    rxbuf[39]: 2677972380 0x9f9e9d9c 10011111100111101001110110011100 OK. Sector: 0. Page: 0. Pos: 39.
    
    txbuf[40]: 2745344416 0xa3a2a1a0 10100011101000101010000110100000
    rxbuf[40]: 2745344416 0xa3a2a1a0 10100011101000101010000110100000 OK. Sector: 0. Page: 0. Pos: 40.
    
    txbuf[41]: 2812716452 0xa7a6a5a4 10100111101001101010010110100100
    rxbuf[41]: 2812716452 0xa7a6a5a4 10100111101001101010010110100100 OK. Sector: 0. Page: 0. Pos: 41.
    
    txbuf[42]: 2880088488 0xabaaa9a8 10101011101010101010100110101000
    rxbuf[42]: 2880088488 0xabaaa9a8 10101011101010101010100110101000 OK. Sector: 0. Page: 0. Pos: 42.
    
    txbuf[43]: 2947460524 0xafaeadac 10101111101011101010110110101100
    rxbuf[43]: 2947460524 0xafaeadac 10101111101011101010110110101100 OK. Sector: 0. Page: 0. Pos: 43.
    
    txbuf[44]: 3014832560 0xb3b2b1b0 10110011101100101011000110110000
    rxbuf[44]: 3014832560 0xb3b2b1b0 10110011101100101011000110110000 OK. Sector: 0. Page: 0. Pos: 44.
    
    txbuf[45]: 3082204596 0xb7b6b5b4 10110111101101101011010110110100
    rxbuf[45]: 3082204596 0xb7b6b5b4 10110111101101101011010110110100 OK. Sector: 0. Page: 0. Pos: 45.
    
    txbuf[46]: 3149576632 0xbbbab9b8 10111011101110101011100110111000
    rxbuf[46]: 3149576632 0xbbbab9b8 10111011101110101011100110111000 OK. Sector: 0. Page: 0. Pos: 46.
    
    txbuf[47]: 3216948668 0xbfbebdbc 10111111101111101011110110111100
    rxbuf[47]: 3216948668 0xbfbebdbc 10111111101111101011110110111100 OK. Sector: 0. Page: 0. Pos: 47.
    
    txbuf[48]: 3284320704 0xc3c2c1c0 11000011110000101100000111000000
    rxbuf[48]: 3284320704 0xc3c2c1c0 11000011110000101100000111000000 OK. Sector: 0. Page: 0. Pos: 48.
    
    txbuf[49]: 3351692740 0xc7c6c5c4 11000111110001101100010111000100
    rxbuf[49]: 3351692740 0xc7c6c5c4 11000111110001101100010111000100 OK. Sector: 0. Page: 0. Pos: 49.
    
    txbuf[50]: 3419064776 0xcbcac9c8 11001011110010101100100111001000
    rxbuf[50]: 3419064776 0xcbcac9c8 11001011110010101100100111001000 OK. Sector: 0. Page: 0. Pos: 50.
    
    txbuf[51]: 3486436812 0xcfcecdcc 11001111110011101100110111001100
    rxbuf[51]: 3486436812 0xcfcecdcc 11001111110011101100110111001100 OK. Sector: 0. Page: 0. Pos: 51.
    
    txbuf[52]: 3553808848 0xd3d2d1d0 11010011110100101101000111010000
    rxbuf[52]: 3553808848 0xd3d2d1d0 11010011110100101101000111010000 OK. Sector: 0. Page: 0. Pos: 52.
    
    txbuf[53]: 3621180884 0xd7d6d5d4 11010111110101101101010111010100
    rxbuf[53]: 3621180884 0xd7d6d5d4 11010111110101101101010111010100 OK. Sector: 0. Page: 0. Pos: 53.
    
    txbuf[54]: 3688552920 0xdbdad9d8 11011011110110101101100111011000
    rxbuf[54]: 3688552920 0xdbdad9d8 11011011110110101101100111011000 OK. Sector: 0. Page: 0. Pos: 54.
    
    txbuf[55]: 3755924956 0xdfdedddc 11011111110111101101110111011100
    rxbuf[55]: 3755924956 0xdfdedddc 11011111110111101101110111011100 OK. Sector: 0. Page: 0. Pos: 55.
    
    txbuf[56]: 3823296992 0xe3e2e1e0 11100011111000101110000111100000
    rxbuf[56]: 3823296992 0xe3e2e1e0 11100011111000101110000111100000 OK. Sector: 0. Page: 0. Pos: 56.
    
    txbuf[57]: 3890669028 0xe7e6e5e4 11100111111001101110010111100100
    rxbuf[57]: 3890669028 0xe7e6e5e4 11100111111001101110010111100100 OK. Sector: 0. Page: 0. Pos: 57.
    
    txbuf[58]: 3958041064 0xebeae9e8 11101011111010101110100111101000
    rxbuf[58]: 3958041064 0xebeae9e8 11101011111010101110100111101000 OK. Sector: 0. Page: 0. Pos: 58.
    
    txbuf[59]: 4025413100 0xefeeedec 11101111111011101110110111101100
    rxbuf[59]: 4025413100 0xefeeedec 11101111111011101110110111101100 OK. Sector: 0. Page: 0. Pos: 59.
    
    txbuf[60]: 4092785136 0xf3f2f1f0 11110011111100101111000111110000
    rxbuf[60]: 4092785136 0xf3f2f1f0 11110011111100101111000111110000 OK. Sector: 0. Page: 0. Pos: 60.
    
    txbuf[61]: 4160157172 0xf7f6f5f4 11110111111101101111010111110100
    rxbuf[61]: 4160157172 0xf7f6f5f4 11110111111101101111010111110100 OK. Sector: 0. Page: 0. Pos: 61.
    
    txbuf[62]: 4227529208 0xfbfaf9f8 11111011111110101111100111111000
    rxbuf[62]: 4227529208 0xfbfaf9f8 11111011111110101111100111111000 OK. Sector: 0. Page: 0. Pos: 62.
    
    txbuf[63]: 4294901244 0xfffefdfc 11111111111111101111110111111100
    rxbuf[63]: 4294901244 0xfffefdfc 11111111111111101111110111111100 OK. Sector: 0. Page: 0. Pos: 63.
    
    ------- NEW PAGE ------------------------------------------------------------------------------------------------------
    txbuf[64]: 50462976 0x03020100 00000011000000100000000100000000
    rxbuf[64]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 0.
    
    txbuf[65]: 117835012 0x07060504 00000111000001100000010100000100
    rxbuf[65]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 1.
    
    txbuf[66]: 185207048 0x0b0a0908 00001011000010100000100100001000
    rxbuf[66]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 2.
    
    txbuf[67]: 252579084 0x0f0e0d0c 00001111000011100000110100001100
    rxbuf[67]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 3.
    
    txbuf[68]: 319951120 0x13121110 00010011000100100001000100010000
    rxbuf[68]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 4.
    
    txbuf[69]: 387323156 0x17161514 00010111000101100001010100010100
    rxbuf[69]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 5.
    
    txbuf[70]: 454695192 0x1b1a1918 00011011000110100001100100011000
    rxbuf[70]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 6.
    
    txbuf[71]: 522067228 0x1f1e1d1c 00011111000111100001110100011100
    rxbuf[71]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 7.
    
    txbuf[72]: 589439264 0x23222120 00100011001000100010000100100000
    rxbuf[72]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 8.
    
    txbuf[73]: 656811300 0x27262524 00100111001001100010010100100100
    rxbuf[73]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 9.
    
    txbuf[74]: 724183336 0x2b2a2928 00101011001010100010100100101000
    rxbuf[74]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 10.
    
    txbuf[75]: 791555372 0x2f2e2d2c 00101111001011100010110100101100
    rxbuf[75]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 11.
    
    txbuf[76]: 858927408 0x33323130 00110011001100100011000100110000
    rxbuf[76]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 12.
    
    txbuf[77]: 926299444 0x37363534 00110111001101100011010100110100
    rxbuf[77]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 13.
    
    txbuf[78]: 993671480 0x3b3a3938 00111011001110100011100100111000
    rxbuf[78]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 14.
    
    txbuf[79]: 1061043516 0x3f3e3d3c 00111111001111100011110100111100
    rxbuf[79]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 15.
    
    txbuf[80]: 1128415552 0x43424140 01000011010000100100000101000000
    rxbuf[80]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 16.
    
    txbuf[81]: 1195787588 0x47464544 01000111010001100100010101000100
    rxbuf[81]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 17.
    
    txbuf[82]: 1263159624 0x4b4a4948 01001011010010100100100101001000
    rxbuf[82]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 18.
    
    txbuf[83]: 1330531660 0x4f4e4d4c 01001111010011100100110101001100
    rxbuf[83]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 19.
    
    txbuf[84]: 1397903696 0x53525150 01010011010100100101000101010000
    rxbuf[84]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 20.
    
    txbuf[85]: 1465275732 0x57565554 01010111010101100101010101010100
    rxbuf[85]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 21.
    
    txbuf[86]: 1532647768 0x5b5a5958 01011011010110100101100101011000
    rxbuf[86]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 22.
    
    txbuf[87]: 1600019804 0x5f5e5d5c 01011111010111100101110101011100
    rxbuf[87]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 23.
    
    txbuf[88]: 1667391840 0x63626160 01100011011000100110000101100000
    rxbuf[88]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 24.
    
    txbuf[89]: 1734763876 0x67666564 01100111011001100110010101100100
    rxbuf[89]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 25.
    
    txbuf[90]: 1802135912 0x6b6a6968 01101011011010100110100101101000
    rxbuf[90]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 26.
    
    txbuf[91]: 1869507948 0x6f6e6d6c 01101111011011100110110101101100
    rxbuf[91]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 27.
    
    txbuf[92]: 1936879984 0x73727170 01110011011100100111000101110000
    rxbuf[92]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 28.
    
    txbuf[93]: 2004252020 0x77767574 01110111011101100111010101110100
    rxbuf[93]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 29.
    
    txbuf[94]: 2071624056 0x7b7a7978 01111011011110100111100101111000
    rxbuf[94]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 30.
    
    txbuf[95]: 2138996092 0x7f7e7d7c 01111111011111100111110101111100
    rxbuf[95]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 31.
    
    txbuf[96]: 2206368128 0x83828180 10000011100000101000000110000000
    rxbuf[96]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 32.
    
    txbuf[97]: 2273740164 0x87868584 10000111100001101000010110000100
    rxbuf[97]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 33.
    
    txbuf[98]: 2341112200 0x8b8a8988 10001011100010101000100110001000
    rxbuf[98]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 34.
    
    txbuf[99]: 2408484236 0x8f8e8d8c 10001111100011101000110110001100
    rxbuf[99]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 35.
    
    txbuf[100]: 2475856272 0x93929190 10010011100100101001000110010000
    rxbuf[100]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 36.
    
    txbuf[101]: 2543228308 0x97969594 10010111100101101001010110010100
    rxbuf[101]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 37.
    
    txbuf[102]: 2610600344 0x9b9a9998 10011011100110101001100110011000
    rxbuf[102]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 38.
    
    txbuf[103]: 2677972380 0x9f9e9d9c 10011111100111101001110110011100
    rxbuf[103]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 39.
    
    txbuf[104]: 2745344416 0xa3a2a1a0 10100011101000101010000110100000
    rxbuf[104]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 40.
    
    txbuf[105]: 2812716452 0xa7a6a5a4 10100111101001101010010110100100
    rxbuf[105]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 41.
    
    txbuf[106]: 2880088488 0xabaaa9a8 10101011101010101010100110101000
    rxbuf[106]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 42.
    
    txbuf[107]: 2947460524 0xafaeadac 10101111101011101010110110101100
    rxbuf[107]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 43.
    
    txbuf[108]: 3014832560 0xb3b2b1b0 10110011101100101011000110110000
    rxbuf[108]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 44.
    
    txbuf[109]: 3082204596 0xb7b6b5b4 10110111101101101011010110110100
    rxbuf[109]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 45.
    
    txbuf[110]: 3149576632 0xbbbab9b8 10111011101110101011100110111000
    rxbuf[110]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 46.
    
    txbuf[111]: 3216948668 0xbfbebdbc 10111111101111101011110110111100
    rxbuf[111]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 47.
    
    txbuf[112]: 3284320704 0xc3c2c1c0 11000011110000101100000111000000
    rxbuf[112]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 48.
    
    txbuf[113]: 3351692740 0xc7c6c5c4 11000111110001101100010111000100
    rxbuf[113]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 49.
    
    txbuf[114]: 3419064776 0xcbcac9c8 11001011110010101100100111001000
    rxbuf[114]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 50.
    
    txbuf[115]: 3486436812 0xcfcecdcc 11001111110011101100110111001100
    rxbuf[115]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 51.
    
    txbuf[116]: 3553808848 0xd3d2d1d0 11010011110100101101000111010000
    rxbuf[116]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 52.
    
    txbuf[117]: 3621180884 0xd7d6d5d4 11010111110101101101010111010100
    rxbuf[117]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 53.
    
    txbuf[118]: 3688552920 0xdbdad9d8 11011011110110101101100111011000
    rxbuf[118]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 54.
    
    txbuf[119]: 3755924956 0xdfdedddc 11011111110111101101110111011100
    rxbuf[119]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 55.
    
    txbuf[120]: 3823296992 0xe3e2e1e0 11100011111000101110000111100000
    rxbuf[120]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 56.
    
    txbuf[121]: 3890669028 0xe7e6e5e4 11100111111001101110010111100100
    rxbuf[121]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 57.
    
    txbuf[122]: 3958041064 0xebeae9e8 11101011111010101110100111101000
    rxbuf[122]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 58.
    
    txbuf[123]: 4025413100 0xefeeedec 11101111111011101110110111101100
    rxbuf[123]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 59.
    
    txbuf[124]: 4092785136 0xf3f2f1f0 11110011111100101111000111110000
    rxbuf[124]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 60.
    
    txbuf[125]: 4160157172 0xf7f6f5f4 11110111111101101111010111110100
    rxbuf[125]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 61.
    
    txbuf[126]: 4227529208 0xfbfaf9f8 11111011111110101111100111111000
    rxbuf[126]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 62.
    
    txbuf[127]: 4294901244 0xfffefdfc 11111111111111101111110111111100
    rxbuf[127]: 4294967295 0xffffffff 11111111111111111111111111111111 Not Equal. Sector: 0. Page: 1. Pos: 63.
    
    Number of success: 64.
    Number of errors: 64.
    Number of printed: 128.
    transferLength: 128 * 4 Bytes = 512.
    
    Some tests have failed.
    
    

    Hope you understand the log: the first two lines is showing the first 4 bytes sent (txbuf) and data received (rxbuf). txBuf[0] is sending 50462976 (dec) = 0x03020100 (hex) = 00000011000000100000000100000000.

    You can see that from uint32_t number 65 (Byte 257) I am only receiving 0xFF for every Byte.

    If you want, I can also provide my production flash code, but I want you to test this test project first, and verify that your system can handle more than 256 Bytes. I think that is a good starting point for further debugging.

    Thank you for your continuous support,

    Anders.

  • Hello again Rahul,

    in the project and code above, you can test the problem with config mode with length > 256 Bytes. This code will pass on the memory map test. But the SF25FL_bufferWrite only writes one byte at a time in memory map mode, which is too slow for a production flashing tool. In order to test mmap mode with 256 Bytes write at a time, use the same project, but change the code in function SF25FL_BufferWrite (in file C:\ti\pdk_am57xx_1_0_8\packages\ti\drv\spi\test\qspi_flash\src\Flash_S25FL\S25FL.c) to the following:

    /*
     *  ======== SF25FL_bufferWrite ========
     */
    bool SF25FL_bufferWrite(S25FL_Handle flashHandle,
                            S25FL_Transaction* flashTransaction)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        SPI_Transaction transaction;                /* SPI transaction structure */
        unsigned int idx;                           /* index */
        uint32_t dstOffstAddr;                      /* Flash offset address */
        unsigned char *srcAddr;                     /* Address of data buffer */
        uint32_t length;                            /* data length in bytes */
        uint32_t         byteAddr;
        uint32_t         pageSize;
        uint32_t         chunkLen;
        uint32_t         actual;
        unsigned int frmLength;
        unsigned int addrLengthInBytes;
        unsigned int transferType;
        unsigned char transferCmd;
        QSPI_v1_Object  *object;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Copy flash transaction parameters to local variables */
        dstOffstAddr = flashTransaction->address;
        srcAddr = flashTransaction->data;
        length = flashTransaction->dataSize;
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            /*
             * Config mode write supports 256 bytes at a time. So if the length is
             * greater than 256, then multiple transactions have to be performed till
             * all the bytes are written.
             */
            while(length > 256)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
                dstOffstAddr = dstOffstAddr + (256 / 4);
                srcAddr += 256;
                length -= 256;
            }
            if(length > 0)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
            }
        }
    
    
        pageSize = 256;
        byteAddr    = dstOffstAddr & (pageSize - 1); // byteAddr = dstOffstAddr % pageSize-1.
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
         {
             for(actual = 0; actual < length; actual+=chunkLen)
             {
                 // Write enable
                 S25FLFlash_WriteEnable(flashHandle);
    
                 if(length - actual < pageSize - byteAddr)
                 {
                     chunkLen = length - actual; // < 256. goes into here the last time.
                 }
                 else
                 {
                     chunkLen = pageSize - byteAddr; // = 256. goes into here most of the iterations, except last iteration of the loop.
                 }
    
                 transaction.txBuf = (unsigned char *)dstOffstAddr;
                 transaction.rxBuf = srcAddr;
                 transaction.count = chunkLen;
    
                 transferType = SPI_TRANSACTION_TYPE_WRITE;
                 if (dstOffstAddr > 0xFFFFFFU)
                 {
                     transferCmd  = QSPI_LIB_CMD_PAGE_PRG_4B;
                     addrLengthInBytes = 4;
                 }
                 else
                 {
                     transferCmd  = QSPI_LIB_CMD_PAGE_PRG;
                     addrLengthInBytes = 3;
                 }
    
                 /* total transaction frame length in number of words (bytes)*/
                 frmLength = 1 + addrLengthInBytes + chunkLen;
    
                 SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength)); // added by anders debug
    
                 SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
                 SPI_control(handle, SPI_V1_CMD_MMAP_TRANSFER_CMD, (void *)&transferCmd);
    
    
                 retVal = SPI_transfer(handle, &transaction);
    
                 // Check flash status for completion
                 while ((FlashStatus(flashHandle) & 0x1U));
    
                 dstOffstAddr += chunkLen;
                 srcAddr += chunkLen;
             }
         }
        return retVal;
    }

    This is the code I use to try writing 256 Bytes at a time in mmap mode (except the last iteration of the loop, where <256 is written). Only the first byte is correctly read back when using this code. Note that I have added the line
    SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength)); // added by anders debug
    I do not know if this line is needed.

    Thanks for your continuous support,

    Anders.

  • Any updates?

    Appreciate your support,

    Anders.
  • Anders,

    Sorry for the delay in getting back to you on this issue. I am able to now reporduce your issue on my board with thee exaample code that you have provided and I am actively debugging the issue. I will let you know my findings. As far as I can tell the QSPI flash writer code is relying on flash functions defined in the board library while the QSPI example is using locally defined flash functions.

    Regards,
    Rahul
  • Anders,

    I repeated the same experiment with the SBL  QSPI flash writer and don`t see this issue. The QSPI flash writer is setting the QSPI in CONFIG and QUADMODE  and reads a 269 KB file from SD card and programs it to the flash.  after the image is written, the flash writer performs a read back and  verify using a function called checkflash and when I set a break point  in that code, I see the same values in the read and the write buffer for the entire size of the 269 KB image programmed:

    I will compare the code used in the Test example with the QSPI flash Writer code and let you know why the test  fails.

    Regards,

    Rahul

  • Hello Rahul,

    Thank you for your effort in helping me out, I really appreciate it.

    I now tried again to run the precompiled .out file C:\ti\pdk_am57xx_1_0_8\packages\ti\boot\sbl\tools\flashWriter\qspi\bin\idkAM571x\qspi_flash_writer.out

    First of all, I do get the same results as you when looking in memory browser at the beginning of the checkFlash function. However, I notice that config mode is not used. MMAP mode is used, and 1 byte is transferred for each QSPI transfer. Copying the 269 kB file takes about 40 seconds. This is too long time for our project. If 256 Bytes were written for each QSPI transfer, it would take less than 5 seconds. How long time does your card use to program the 269 kB to flash?

    Adding some images to show you that MMAP mode is used. Could you please verify that your flashwriter program is using config mode and uses much less time than 40 seconds? 

    Please note that transaction.count == 1, which means that 1 Byte is tranferred at each SPI_transfer. ALso note that object->qspiMode == QSPI_OPER_MODE_MMAP.

    Appreciate your continuous support,

    Anders.

  • Anders,

    I have confirmed the flashwriter is in MMAP mode and not CONFIG mode and also noticed that the driver is configured to not use interrupts which might be  the reason why it is running so slowly other than the fact that a single byte is written at a time. 

    In the mean time, we have been able to root cause the issue with the QSPI LLD test case and here are the updated files that you can use for validation.

    /**
     *  \file   main_flash_read_test.c
     *
     *  \brief  Example application main file. This application will write and read
     *          the data to/from nor flash through qspi interface.
     *
     */
    
    /*
     * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
     *
     * 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.
     *
     */
    
    
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>
    #include <stdio.h>
    #include <ti/sysbios/knl/Task.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <xdc/runtime/Error.h>
    #include <ti/csl/soc.h>
    /* TI-RTOS Header files */
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    #include "SPI_log.h"
    
    /* Flash header file */
    #include <ti/drv/spi/test/qspi_flash/src/Flash_S25FL/S25FL.h>
    
    #include <ti/board/board.h>
    
    /**********************************************************************
     ************************** Macros ************************************
     **********************************************************************/
    #define QSPI_PER_CNT            (1U)
    #define QSPI_INSTANCE           (1U)
    
    #if defined (SOC_AM335x) || defined (SOC_AM437x)
    #define QSPI_OFFSET             (5U)
    #endif
    #if defined(SOC_AM574x) || defined (SOC_AM572x) || defined (SOC_AM571x)
    #define QSPI_OFFSET             (4U)
    #endif
    
    #define QSPI_TEST_LENGTH        75  /* read/write test data size in 32-bit words */
    
    /**********************************************************************
     ************************** Internal functions ************************
     **********************************************************************/
    
    /* Function to generate known data */
    static void GeneratePattern(uint8_t *txBuf, uint8_t *rxBuf, uint32_t length);
    
    /* Data compare function */
    bool VerifyData(unsigned char *expData,
                    unsigned char *rxData,
                    unsigned int length);
    
    #if defined(SOC_AM574x) || defined (SOC_AM571x) || defined (SOC_AM572x)
    void QSPI_board_crossbarInit(void);
    #endif
    /**********************************************************************
     ************************** Global Variables **************************
     **********************************************************************/
    
    /* Buffer containing the known data that needs to be written to flash */
    unsigned int txBuf[1024];
    
    /* Buffer containing the received data */
    unsigned int rxBuf[1024];
    
    unsigned int addrValue = 0x000000U;
    
    /* hardware attributes */
    extern QSPI_HwAttrs qspiInitCfg[QSPI_PER_CNT];
    
    /* transfer length */
    uint32_t transferLength = 0;
    
    
    /*
     *  ======== test function ========
     */
    void spi_test(UArg arg0, UArg arg1)
    {
        SPI_Params spiParams;                /* SPI params structure */
        S25FL_Handle flashHandle;            /* Flash handle */
        unsigned int blockNumber = 0U;       /* Block number */
        S25FL_Transaction flashTransaction;  /* Flash transaction structure */
        SPI_Handle handle;                   /* SPI handle */
        QSPI_HwAttrs *hwAttrs;               /* QSPI hardware attributes */
        bool retVal = false;                 /* return value */
        unsigned int rxLines;
        unsigned int qspiMode;
        unsigned int i = 0;
    
        /* Init SPI driver */
        SPI_init();
    
        /* Default SPI configuration parameters */
        SPI_Params_init(&spiParams);
    
        /* Open QSPI driver */
        flashHandle = SF25FL_open(((QSPI_INSTANCE - 1)+(QSPI_OFFSET)), &spiParams);
    
        /* Extract hardware attributes */
        handle = flashHandle->spiHandle;
        hwAttrs = (QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Print flash Id */
        FlashPrintId(flashHandle);
    
        /* Mode: CFG & Rx Lines: SINGLE */
    
        /* For CFG Mode: The parameter "flashTransaction.address" should be assigned
           with the address of the variable which contains the flash offset value*/
    
        qspiMode = QSPI_OPER_MODE_CFG;
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        /* Erase block, to which data has to be written */
        S25FLFlash_BlockErase(flashHandle, blockNumber);
    
        /* Set the transfer length in number of 32 bit words */
        transferLength = QSPI_TEST_LENGTH;
    
        /* Generate the data */
        GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
        /* Update transaction parameters */
        flashTransaction.data       = (uint8_t *)&txBuf[0];
        flashTransaction.address = (uint32_t)&addrValue;
        flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
        /* Write buffer to flash */
        retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
        if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
        {
            S25FLFlash_QuadModeEnable(flashHandle);
        }
    
        /* Update transaction parameters */
        flashTransaction.data       = (uint8_t *)&rxBuf[0];
        flashTransaction.address = (uint32_t)&addrValue;
        flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
        /* Read data from flash */
        retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
        /* Verify Data */
        retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
            transferLength);
    
        /* Mode: CFG & Rx Lines: DUAL */
    
        /* Reset receive buffer */
        for(i = 0; i < QSPI_TEST_LENGTH; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_CFG;
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_DUAL;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            /* Erase block, to which data has to be written */
            S25FLFlash_BlockErase(flashHandle, blockNumber);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = QSPI_TEST_LENGTH;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: CFG & Rx Lines: QUAD */
    
        /* Reset receive buffer */
        for(i = 0; i < QSPI_TEST_LENGTH; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_CFG;
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_QUAD;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            /* Erase block, to which data has to be written */
            S25FLFlash_BlockErase(flashHandle, blockNumber);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = QSPI_TEST_LENGTH;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = (uint32_t)&addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: MMAP & Rx Lines: SINGLE */
    
        /* For MMAP Mode: The parameter "flashTransaction.address" should be
           assigned with directly the flash offset value */
    
        /* Reset receive buffer */
        for(i = 0; i < QSPI_TEST_LENGTH; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_MMAP;
        SPI_control(handle, SPI_V1_CMD_SETMEMMORYMAPMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            /* Erase block, to which data has to be written */
            S25FLFlash_BlockErase(flashHandle, blockNumber);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = QSPI_TEST_LENGTH;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: MMAP & Rx Lines: DUAL */
    
        /* Reset receive buffer */
        for(i = 0; i < QSPI_TEST_LENGTH; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_MMAP;
        SPI_control(handle, SPI_V1_CMD_SETMEMMORYMAPMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_DUAL;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            /* Erase block, to which data has to be written */
            S25FLFlash_BlockErase(flashHandle, blockNumber);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = QSPI_TEST_LENGTH;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        /* Mode: MMAP & Rx Lines: QUAD */
    
        /* Reset receive buffer */
        for(i = 0; i < QSPI_TEST_LENGTH; i++)
        {
            rxBuf[i] = 0x00000000;
        }
    
        qspiMode = QSPI_OPER_MODE_MMAP;
        SPI_control(handle, SPI_V1_CMD_SETMEMMORYMAPMODE, (void *)&qspiMode);
        rxLines = QSPI_RX_LINES_QUAD;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        if(true == retVal)
        {
            /* Erase block, to which data has to be written */
            S25FLFlash_BlockErase(flashHandle, blockNumber);
    
            /* Set the transfer length in number of 32 bit words */
            transferLength = QSPI_TEST_LENGTH;
    
            /* Generate the data */
            GeneratePattern((uint8_t *)&txBuf[0], (uint8_t *)&rxBuf[0], transferLength);
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&txBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4;  /* In bytes */
    
            /* Write buffer to flash */
            retVal = SF25FL_bufferWrite(flashHandle, &flashTransaction);
    
            if(QSPI_RX_LINES_QUAD == hwAttrs->rxLines)
            {
                S25FLFlash_QuadModeEnable(flashHandle);
            }
    
            /* Update transaction parameters */
            flashTransaction.data       = (uint8_t *)&rxBuf[0];
            flashTransaction.address = addrValue;
            flashTransaction.dataSize   = transferLength * 4; /* In bytes */
    
            /* Read data from flash */
            retVal = SF25FL_bufferRead(flashHandle, &flashTransaction);
    
            /* Verify Data */
            retVal = VerifyData((unsigned char *)&txBuf[0], (unsigned char *)&rxBuf[0],
                transferLength);
        }
    
        SF25FL_close(flashHandle);
    
        if(true == retVal)
        {
            SPI_log("\n All tests have passed. \n");
        }
        else
        {
            SPI_log("\n Some tests have failed. \n");
        }
    
        while(1);
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call board init functions */
        Board_initCfg boardCfg;
    
    #if defined (SOC_AM335x) || defined (SOC_AM437x)
        Task_Handle task;
        Error_Block eb;
    
        Error_init(&eb);
        task = Task_create(spi_test, NULL, &eb);
        if (task == NULL) {
            System_printf("Task_create() failed!\n");
            BIOS_exit(0);
        }
    #endif
    
        boardCfg = BOARD_INIT_PINMUX_CONFIG |
            BOARD_INIT_MODULE_CLOCK |
            BOARD_INIT_UART_STDIO;
        Board_init(boardCfg);
    
    #if defined (SOC_AM571x) || defined (SOC_AM572x) || defined(SOC_AM574x)
        QSPI_board_crossbarInit();
    #endif
    
        /* Start BIOS */
        BIOS_start();
        return (0);
    }
    
    /*
     *  ======== Board_initQSPI ========
     */
    #if defined (SOC_AM571x) || defined (SOC_AM572x) || defined(SOC_AM574x)
    void QSPI_board_crossbarInit(void) {
        CSL_XbarIrqCpuId                   cpu;
        uint32_t                           cpuEvent;
        uint32_t                           xbarIndex;
    #ifdef C66X
    
        /* Configure xbar connect for MCSPI3: DSP_IRQ_38 mapped to MCSPI3 intr */
        cpu = CSL_XBAR_IRQ_CPU_ID_DSP1;
        cpuEvent = 38;
        xbarIndex = cpuEvent - 31;
    
        /* Configure xbar */
        CSL_xbarIrqConfigure (cpu, xbarIndex, CSL_XBAR_QSPI_IRQ);
    
    #elif __ARM_ARCH_7A__
        /* Configure xbar connect for QSPI: MPU_IRQ_35 mapped to QSPI intr */
        *(unsigned int*)0x4A002A80 = (unsigned int)(0x0157001D);
    
    #else
    
        /* Configure xbar connect for MCSPI3: DSP_IRQ_38 mapped to MCSPI3 intr */
        cpu = CSL_XBAR_IRQ_CPU_ID_IPU1;
        cpuEvent = 62;
        xbarIndex = cpuEvent - 22;
    
        /* Configure xbar */
        CSL_xbarIrqConfigure (cpu, xbarIndex, CSL_XBAR_QSPI_IRQ);
    #endif
    
    }
    #endif
    
    /*
     *  ======== CompareData ========
     */
    bool VerifyData(unsigned char *expData,
                    unsigned char *rxData,
                    unsigned int length)
    {
        unsigned int idx = 0;
        unsigned int match = 1;
        bool retVal = false;
        unsigned int lenInBytes = length * 4;
    
        for(idx = 0; ((idx < lenInBytes) && (match != 0)); idx++)
        {
            if(*expData != *rxData) match = 0;
            expData++;
            rxData++;
        }
    
        if(match == 1) retVal = true;
    
        return retVal;
    }
    
    /*
     *  ======== GeneratePattern ========
     */
    static void GeneratePattern(uint8_t *txBuf, uint8_t *rxBuf, uint32_t length)
    {
        unsigned int idx;
        unsigned int lenInBytes = length * 4;
    
        for(idx = 0; idx < lenInBytes; idx++)
        {
            txBuf[idx] = (uint8_t)idx;
            rxBuf[idx] = (uint8_t)0U;
        }
    }

    /**
     *  \file   S25FL.c
     *
     *  \brief  Flash specific driver implementation.
     *
     */
    
    /*
     * Copyright (C) 2014 - 2017 Texas Instruments Incorporated - http://www.ti.com/
     *
     * 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.
     *
     */
    
    #include "S25FL.h"
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    
    /*!
     *  @brief Flash object containing flash attributes.
     */
    S25FL_Object s25flObject = {NULL,
                                4,
                                S25FL_FLASH_SECTOR_SIZE,
                                S25FL_FLASH_BLOCK_SIZE,
                                S25FL_FLASH_DEVICE_SIZE,
                                S25FL_FLASH_DEVICE_ID};
    
    
    static bool SF25FL_ConfigMode_Write(uint32_t dstOffstAddr,
                                        unsigned char* srcAddr,
                                        uint32_t length,
                                        S25FL_Handle flashHandle);
    
    /*
     *  ======== SF25FL_close ========
     */
    void SF25FL_close(S25FL_Handle handle)
    {
        SPI_close(handle->spiHandle);
    }
    
    /*
     *  ======== SF25FL_open ========
     */
    S25FL_Handle SF25FL_open(unsigned int index, SPI_Params *params)
    {
        S25FL_Handle s25flHandle;
    
        s25flHandle = &s25flObject;
    
        /* Open SPI driver for SF25FL */
        s25flHandle->spiHandle = SPI_open(index, params);
    
        return s25flHandle;
    }
    
    /*
     *  ======== SF25FL_bufferWrite ========
     */
    bool SF25FL_bufferWrite(S25FL_Handle flashHandle,
                            S25FL_Transaction* flashTransaction)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        SPI_Transaction transaction;                /* SPI transaction structure */
        unsigned int idx;                           /* index */
        uint32_t dstOffstAddr;                      /* Flash offset address */
        unsigned char *srcAddr;                     /* Address of data buffer */
        uint32_t length;                            /* data length in bytes */
        unsigned int transferType;
        unsigned char transferCmd;
        QSPI_v1_Object  *object;
        uint32_t offsetValue;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Copy flash transaction parameters to local variables */
        dstOffstAddr = flashTransaction->address;
        srcAddr = flashTransaction->data;
        length = flashTransaction->dataSize;
        offsetValue = *((uint32_t *)dstOffstAddr);
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            /*
             * Config mode write supports 256 bytes at a time. So if the length is
             * greater than 256, then multiple transactions have to be performed till
             * all the bytes are written.
             */
            while(length > 256)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
                *((uint32_t *)dstOffstAddr) += 256;
                srcAddr += 256;
                length -= 256;
            }
            if(length > 0)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
            }
            *((uint32_t *)dstOffstAddr) = offsetValue;
        }
    
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            for(idx = 0; idx < length; idx++)
            {
                /* Write enable */
                S25FLFlash_WriteEnable(flashHandle);
    
                /* Perform the transfer */
                transaction.txBuf = (unsigned char *)dstOffstAddr;
                transaction.rxBuf = srcAddr;
                transaction.count = 1;
    
                transferType = SPI_TRANSACTION_TYPE_WRITE;
                if (dstOffstAddr > 0xFFFFFFU)
                {
                    transferCmd  = QSPI_LIB_CMD_PAGE_PRG_4B;
                }
                else
                {
                    transferCmd  = QSPI_LIB_CMD_PAGE_PRG;
                }
                SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
                SPI_control(handle, SPI_V1_CMD_MMAP_TRANSFER_CMD, (void *)&transferCmd);
                retVal = SPI_transfer(handle, &transaction);
    
                /* Check flash status for completion */
                while ((FlashStatus(flashHandle) & 0x1U));
    
                dstOffstAddr += 1;
                srcAddr += 1;
            }
        }
    
        return retVal;
    }
    
    
    
    bool SF25FL_bufferRead(S25FL_Handle flashHandle,
                           S25FL_Transaction* flashTransaction)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal[4];               /* data to be written */
        SPI_Transaction transaction;             /* SPI transaction structure */
        uint32_t addrLengthInBytes = 3U;         /* Flash address length in bytes */
        uint32_t readCmd;                        /* Read command */
        uint32_t numDummyBits;                   /* Number of dummy bits */
        uint32_t frameLength;                    /* Frame length */
        uint32_t dstOffstAddr;                   /* Flash offset address */
        unsigned char *srcAddr;                  /* Address of data buffer */
        uint32_t length;                         /* data length in bytes */
    /*  unsigned int *tempPtr = (unsigned int *)&writeVal[0]; */ /* temp pointer */
        unsigned int frmLength;
        unsigned int transferType;
        unsigned char transferCmd;
        QSPI_v1_Object  *object;
        uint32_t offsetValue;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Copy flash transaction parameters to local variables */
        dstOffstAddr = (uint32_t)flashTransaction->data;
        srcAddr = (unsigned char *)flashTransaction->address;
        length = flashTransaction->dataSize;
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            offsetValue = *((uint32_t *)srcAddr);
    
            addrLengthInBytes = 3U;
    
            if(offsetValue > 0xFFFFFF)
            {
                /* Enter 32 bit addressing mode */
                addrLengthInBytes = 4;
            }
    
            switch(object->rxLines)
            {
                case QSPI_RX_LINES_SINGLE:
                {
                    if(offsetValue > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE;
                    }
                    numDummyBits = 0U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + addrLengthInBytes;
                    break;
                }
    
                case QSPI_RX_LINES_DUAL:
                {
                    if(offsetValue > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL;
                    }
                    numDummyBits = 8U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + 1 + addrLengthInBytes;
                    break;
                }
    
                case QSPI_RX_LINES_QUAD:
                {
                    if(offsetValue > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD;
                    }
                    numDummyBits = 8U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + 1 + addrLengthInBytes;
                    break;
                }
    
                default:
                break;
            }
    
            /* total transaction frame length */
            frmLength = frameLength;
            SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
            /* Write read command */
            writeVal[0] = readCmd;
            transaction.txBuf = (unsigned char *)&writeVal[0];
            transaction.rxBuf = NULL;
            transaction.count = 1;
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
    
            /* Write dummy bits for fast read if required */
            if(0 != numDummyBits)
            {
                writeVal[0] = 0U;
                transaction.txBuf = (unsigned char *)&writeVal[0];
                transaction.rxBuf = NULL;
                transaction.count = (numDummyBits >> 3);      /* In bytes */
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
                retVal = SPI_transfer(handle, &transaction);
            }
    
            /* Write Address Bytes */
    /*      *tempPtr = (unsigned int)srcAddr; */
    /*      transaction.txBuf = (unsigned char *)tempPtr; */
            transaction.txBuf = (unsigned char *)srcAddr;
            transaction.rxBuf = NULL;
            transaction.count = addrLengthInBytes;
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
    
            /* Read the actual flash data */
            transaction.txBuf = NULL;
            transaction.rxBuf = (unsigned char *)dstOffstAddr;
            transaction.count = length;
    
            transferType = SPI_TRANSACTION_TYPE_READ;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
        }
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            switch(object->rxLines)
            {
                case QSPI_RX_LINES_SINGLE:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE;
                    }
                    break;
                }
    
                case QSPI_RX_LINES_DUAL:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL;
                    }
                    break;
                }
    
                case QSPI_RX_LINES_QUAD:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD;
                    }
                    break;
                }
    
                default:
                break;
            }
    
            /* Perform the transfer */
            transaction.txBuf = srcAddr;
            transaction.rxBuf = (uint8_t *)dstOffstAddr;
            transaction.count = length;
    
            transferType = SPI_TRANSACTION_TYPE_READ;
            transferCmd  = (unsigned char)readCmd;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            SPI_control(handle, SPI_V1_CMD_MMAP_TRANSFER_CMD, (void *)&transferCmd);
            retVal = SPI_transfer(handle, &transaction);
        }
    
        return retVal;
    }
    
    
    bool S25FLFlash_WriteEnable(S25FL_Handle flashHandle)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;                /* return value */
        unsigned char writeVal;             /* data to be written */
        SPI_Transaction transaction;        /* SPI transaction structure */
        unsigned int operMode;              /* temp variable to hold mode */
        unsigned int rxLines;               /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* transaction frame length in words (bytes) */
        frmLength = 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write enable command */
        writeVal = QSPI_LIB_CMD_WRITE_ENABLE;
    
        /* Update transaction parameters */
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count  = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    bool S25FLFlash_Enable4ByteAddrMode(S25FL_Handle flashHandle,
                                        bool enable4ByteMode)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;             /* return value */
        unsigned char writeVal;          /* data to be written */
        SPI_Transaction transaction;     /* SPI transaction structure */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Command to control the 4 byte mode */
        if (true == enable4ByteMode)
        {
            writeVal = QSPI_LIB_CMD_ENTER_4_BYTE_ADDR;
        }
        else
        {
            writeVal = QSPI_LIB_CMD_EXIT_4_BYTE_ADDR;
        }
    
        /* Write 4 byte enable/disable command to flash */
        transaction.count = 1U;                    /* Frame length in bytes */
        transaction.txBuf = (unsigned char *)&writeVal;  /* Value to be written */
        transaction.rxBuf = NULL;                  /* Nothing to read */
        transaction.arg   = NULL;                  /* Not applicable */
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    uint32_t FlashStatus(S25FL_Handle flashHandle)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;             /* return value */
        unsigned char writeVal;          /* data to be written */
        SPI_Transaction transaction;     /* SPI transaction structure */
        uint32_t rxData = 0U;            /* received data */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Total transaction frame length in words (bytes) */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write Address Bytes */
        writeVal = QSPI_LIB_CMD_READ_STATUS_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Read the status register */
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&rxData;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return (rxData & 0xFF);
    }
    
    #if defined(SOC_AM574x) || defined (SOC_AM571x) || defined (SOC_AM572x) || defined (SOC_DRA72x) || defined (SOC_DRA75x) || defined (SOC_DRA78x)
    bool S25FLFlash_QuadModeEnable(S25FL_Handle flashHandle)
    {
        SPI_Transaction transaction;                /* SPI transaction structure */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal = 0U;    /* data to be written */
        uint32_t norStatus;             /* flash status value */
        uint32_t configReg;             /* configuration register value */
        uint32_t data;                  /* data to be written */
        bool retVal = false;            /* return value */
        unsigned int operMode;          /* temp variable to hold mode */
        unsigned int rxLines;           /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read Status register */
        writeVal = QSPI_LIB_CMD_READ_STATUS_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&norStatus;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read command register */
        writeVal = QSPI_LIB_CMD_QUAD_RD_CMD_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&configReg;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Set 2nd bit of configuration register to 1 to enable quad mode */
        configReg |= (QSPI_FLASH_QUAD_ENABLE_VALUE << QSPI_FLASH_QUAD_ENABLE_BIT);
        data = (QSPI_LIB_CMD_WRITE_STATUS_REG << 16) | (norStatus << 8) | configReg;
    
        /* Set transfer length in bytes */
        frmLength = 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
    
        transaction.txBuf = (unsigned char *)&data;
        transaction.rxBuf = NULL;
        transaction.count = 3;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    #endif
    #if defined(SOC_AM437x)
    bool S25FLFlash_QuadModeEnable(S25FL_Handle flashHandle)
    {
        SPI_Transaction transaction;                /* SPI transaction structure */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal = 0U;    /* data to be written */
        uint32_t norStatus;             /* flash status value */
        bool retVal = false;            /* return value */
        unsigned int operMode;          /* temp variable to hold mode */
        unsigned int rxLines;           /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read Status register */
        writeVal = 0x05U;   //QSPI_LIB_CMD_READ_STATUS_REG;  //Cmd for AM437x
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&norStatus;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read command register */
        writeVal = 0x01U;   //QSPI_LIB_CMD_QUAD_RD_CMD_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
    
        /* Set status register 6th bit to 1 for Quad enable
         * Write this value to the status register.
         */
        norStatus &= ~(1U << 0x6U);
        norStatus |= (0x1U << 0x6U);
    
        transaction.txBuf = (unsigned char *)&norStatus;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    #endif
    
    
    
    bool S25FLFlash_BlockErase(S25FL_Handle flashHandle, unsigned int blockNumber)
    {
        uint32_t eraseAddr;    /* Flash erase address */
        uint32_t writeVal;     /* data to be written */
        SPI_Handle handle = flashHandle->spiHandle;  /* SPI handle */
        SPI_Transaction transaction;         /* SPI transaction structure */
        unsigned int addrLenInBytes = 3;     /* address length in bytes */
        bool retVal = false;                 /* return value */
        unsigned int operMode;               /* temp variable to hold mode */
        unsigned int rxLines;                /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
        uint32_t tempAddr;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Compute flash erase address based on the block size */
        eraseAddr = blockNumber * flashHandle->blockSize;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        if(eraseAddr > 0xFFFFFF)
        {
            /* Enter 4 byte addressing mode */
            addrLenInBytes = 4;
        }
    
        tempAddr = ((eraseAddr & 0xFF000000) >> 24) |
                   ((eraseAddr & 0x00FF0000) >> 8)  |
                   ((eraseAddr & 0x0000FF00) << 8)  |
                   ((eraseAddr & 0x000000FF) << 24);
    
        if(addrLenInBytes == 3)
        {
            tempAddr = (tempAddr >> 8) & 0x00FFFFFF;
        }
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
    
        /*total transaction frame length */
        frmLength = 1 + addrLenInBytes;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength));
    
        /* Block erase command */
        if(eraseAddr > 0xFFFFFF)
        {
            writeVal = QSPI_LIB_CMD_BLOCK_ERASE_4B;
        }
        else
        {
            writeVal = QSPI_LIB_CMD_BLOCK_ERASE;
        }
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Send erase address */
        writeVal = tempAddr;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = addrLenInBytes;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Check flash status for write completion */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    void FlashPrintId(S25FL_Handle flashHandle)
    {
        uint32_t writeVal;               /* data to be written */
        SPI_Handle handle = flashHandle->spiHandle;  /* SPI handle */
        SPI_Transaction transaction;     /* SPI transaction structure */
        bool retVal = false;             /* return value */
        unsigned char mfgId = 0;         /* manufacture ID value */
        unsigned char deviceId = 0;      /* device ID value */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Total transaction frame length in bytes */
        frmLength = 1 + 3 + 2;   /* cmd + address + read data */
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write Command */
        writeVal = QSPI_LIB_CMD_READ_MFG_ID;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Write Address Bytes */
        writeVal = 0x0U;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 3;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
    
        /* Read Manufacturer ID
         * The manufacturer ID is of 1 byte(8 bits)
         */
        transaction.txBuf = NULL;
        transaction.rxBuf = &mfgId;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Read Device ID */
        transaction.txBuf = NULL;
        transaction.rxBuf = &deviceId;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Note - This ID is the device ID of the flash device.
         * This ID is read from the flash
         */
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    }
    
    static bool SF25FL_ConfigMode_Write(uint32_t dstOffstAddr,
                                        unsigned char* srcAddr,
                                        uint32_t length,
                                        S25FL_Handle flashHandle)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        uint32_t addrLengthInBytes = 3U;            /* Flash addr length in bytes */
        unsigned int frmLength;
        unsigned char writeVal[4];                  /* data to be written to QSPI */
        SPI_Transaction transaction;                /* SPI transaction structure */
        unsigned int transferType;
        uint32_t offsetValue;
    
    
        addrLengthInBytes = 3U;        /* Flash address length in bytes */
        offsetValue = *((uint32_t *)dstOffstAddr);
    
       /* Extract address word length from the flash's destination offst addr*/
        if(offsetValue > 0xFFFFFF)
        {
            /* Enter 32 bit addressing mode */
            addrLengthInBytes = 4;
        }
    
        /* Write Enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* total transaction frame length in number of words (bytes)*/
        frmLength = 1 + addrLengthInBytes + length;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength));
    
        /* Send Flash write command */
        writeVal[0] = QSPI_LIB_CMD_PAGE_PRG;   /* Flash write command */
        transaction.txBuf = (unsigned char *)&writeVal[0];
        transaction.rxBuf = NULL;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Send flash address offset to which data has to be written */
        transaction.txBuf = (unsigned char *)dstOffstAddr;
        transaction.rxBuf = NULL;
        transaction.count = addrLengthInBytes;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Write buffer data to flash */
        transaction.txBuf = (unsigned char *)srcAddr;
        transaction.rxBuf = NULL;
        transaction.count = length;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Check flash status for write completion */
        while ((FlashStatus(flashHandle) & 0x1U));
    
        return retVal;
    }

    Please try out the update and let us know if you are still seeing issues with CONFIG mode or MMAP mode other than the speed of reading and writing from the flash.

    Regards,

    Rahul

  • Rahul,

    Thanks for your help, and for your files.

    I implemented the new S25FL.c, and can confim that for small buffers of data, the code is working. I am now able to read back correctly more than 1 Page (256 Bytes).

    However, I was not able to boot my card after using the flashwriter code in config mode. (I get errors in checkFlash function). The card is booting when using MMAP mode (but use too long time).

    I noticed that for larger buffers of data, I don't read back correct data in your test file. That seems to be for buffers larger than 64 kB (one block).

    Could you please verify for me that in your working system, you are able to read back data with QSPI_TEST_LENGTH > 16384. ( I am not ).

    Thanks again for your support,

    Anders

  • Hello , Any updates?

    As mentioned, I am able to program and boot the board when using memory map mode, when 1 Byte is copied for each spi_transfer. This takes too long time, so we need to figure out one of two things: how to correctly program more than 1 Byte with mmap mode OR how to program big data buffers with config mode. Starting out, I could only program 256 Bytes correctly with config mode. When using the attached code in your previous post, I am able to program 64 kB (65536 Bytes) with config mode. I appreciate that, but the files I want to program to flash are both larger than 64 kB.

    I have done some more debugging on this issue.

    When debugging, I am trying two things; to copy over files (using the flashwriter code), and to copy over buffers with self-generated data with defined length and offset (using the QSPI_BasicExample_idkAM571x_armTestProject as base code).

    Let's first take a look at the flashwriter code with mmap mode: The file is copied over correctly.

    Now, lets change the code, in order to use cfg mode:

    Now, with cfg mode, I only see 0's in the receive Buffer (0x83000000):

    So, lets take a look at what is happening in the cfg mode (using the test project). First let's tell the code to program 64*256 uint32_t 's (this is 256*64*4 Bytes = 64 kB). (Please note that I have filled txBuf with BBBB, and rxBuf with AAAAA, for debugging purposes. As you can see in the image below, the data is copied over correctly for 64 kB length.

    Let's then see what happens with transferLength 64 kB + 4 Byte. The second uint32_t is filled with 0's (it was populated with AAAAAAAA initially), and the last uint32_t is filled with FFFFFFFF.

    Further, let's see what happens with transferLength 64kB + 8 Bytes. The second and third uint32_t 's are filled with 0's, and the last two uint32_t 's are filled with F's.

    Further, lets see what happens when the transfer length is 2 Blocks (128 kB):

    I am not sure what is happening with config mode with transfer length > 64kB. But I have seen while stepping in the code that the correct numbers are used in QSPI_cmd_mode_write_v1 in the file QSPI_v1.c. The fact that I am not able to boot, indicates that the correct data is not transferred. And I see when using config mode that the read functions is working correct.

    One more thing to test is to change the addrValue in the main test file I sent you to 0x10000. (making the writes start at the second block (64 kB + 1)). This is working for me in mmap mode, but I only read back F's in cfg mode.

    How do you advice me to continue  ?

    I appreciate your assistance.

    Best Regards,

    Anders

  • Hello .
    Any updates?
    I would appreciate if you found the time to write and read back to an address greater than 0x10000.

    Thanks in advance,

    Anders
  • Anders,

    I don`t have any updates to share on this issue as I have not spent any additional time on this issue due to other tasks that have been assigned to me.

    In config mode ,when you want to write more than a block then you will need to compute the blockNum and the offset as done in the flashwriter provided in the boot package. This is what I was going to try next.

    The other thing that we found is that S25FL.c file is a duplicate of functions in the qspi_flash.c file in the board library. The boot package uses the board library functions but the tests use these locally defined functions so I was going to see if the these locally defined functions had some bugs that are causing the issue that you are seeing.

    Regards,
    Rahul


  • We have now found the solution to this issue. You do not need to look for bugs anymore. We are now writing big files to flash with config mode.

    I will provide the solution here later today or Monday.

    Thanks for the files you sent us, they got us in the right direction.

    Regards,
    Anders.
  • Thanks for confirming that you are able to get past this issue and we will appreciate if you can post the solution here for other users who may run into this issue.

    Regards,
    Rahul
  • SOLUTION:

    We noticed that in the S25FLFlash_BlockErase function in (S25FL.c), the bytes of the address were "flipped around", like this:

    However, in the SF25FL_ConfigMode_Write function, this was not done.

    Therefore, we changed to 4 Byte addressing mode (QSPI_LIB_CMD_PAGE_PRG_4B), and flipped the bytes of the destination address in the same way as in the erase function:

     

    /**
     *  \file   S25FL.c
     *
     *  \brief  Flash specific driver implementation.
     *
     */
    
    /*
     * Copyright (C) 2014 - 2017 Texas Instruments Incorporated - http://www.ti.com/
     *
     * 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.
     *
     */
    
    #include "S25FL.h"
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    
    /*!
     *  @brief Flash object containing flash attributes.
     */
    S25FL_Object s25flObject = {NULL,
                                4,
                                S25FL_FLASH_SECTOR_SIZE,
                                S25FL_FLASH_BLOCK_SIZE,
                                S25FL_FLASH_DEVICE_SIZE,
                                S25FL_FLASH_DEVICE_ID};
    
    
    static bool SF25FL_ConfigMode_Write(uint32_t dstOffstAddr,
                                        unsigned char* srcAddr,
                                        uint32_t length,
                                        S25FL_Handle flashHandle);
    
    /*
     *  ======== SF25FL_close ========
     */
    void SF25FL_close(S25FL_Handle handle)
    {
        SPI_close(handle->spiHandle);
    }
    
    /*
     *  ======== SF25FL_open ========
     */
    S25FL_Handle SF25FL_open(unsigned int index, SPI_Params *params)
    {
        S25FL_Handle s25flHandle;
    
        s25flHandle = &s25flObject;
    
        /* Open SPI driver for SF25FL */
        s25flHandle->spiHandle = SPI_open(index, params);
    
        return s25flHandle;
    }
    
    /*
     *  ======== SF25FL_bufferWrite ========
     */
    bool SF25FL_bufferWrite(S25FL_Handle flashHandle,
                            S25FL_Transaction* flashTransaction)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        SPI_Transaction transaction;                /* SPI transaction structure */
        unsigned int idx;                           /* index */
        uint32_t dstOffstAddr;                      /* Flash offset address */
        unsigned char *srcAddr;                     /* Address of data buffer */
        uint32_t length;                            /* data length in bytes */
        unsigned int transferType;
        unsigned char transferCmd;
        QSPI_v1_Object  *object;
        uint32_t offsetValue;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Copy flash transaction parameters to local variables */
        dstOffstAddr = flashTransaction->address;
        srcAddr = flashTransaction->data;
        length = flashTransaction->dataSize;
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            offsetValue = *((uint32_t *)dstOffstAddr);
            /*
             * Config mode write supports 256 bytes at a time. So if the length is
             * greater than 256, then multiple transactions have to be performed till
             * all the bytes are written.
             */
            while(length > 256)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
                *((uint32_t *)dstOffstAddr) += 256;
                srcAddr += 256;
                length -= 256;
            }
            if(length > 0)
            {
                SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
            }
            *((uint32_t *)dstOffstAddr) = offsetValue;
        }
    
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            for(idx = 0; idx < length; idx++)
            {
                /* Write enable */
                S25FLFlash_WriteEnable(flashHandle);
    
                /* Perform the transfer */
                transaction.txBuf = (unsigned char *)dstOffstAddr;
                transaction.rxBuf = srcAddr;
                transaction.count = 1;
    
                transferType = SPI_TRANSACTION_TYPE_WRITE;
                if (dstOffstAddr > 0xFFFFFFU)
                {
                    transferCmd  = QSPI_LIB_CMD_PAGE_PRG_4B;
                }
                else
                {
                    transferCmd  = QSPI_LIB_CMD_PAGE_PRG;
                }
                SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
                SPI_control(handle, SPI_V1_CMD_MMAP_TRANSFER_CMD, (void *)&transferCmd);
                retVal = SPI_transfer(handle, &transaction);
    
                /* Check flash status for completion */
                while ((FlashStatus(flashHandle) & 0x1U));
    
                dstOffstAddr += 1;
                srcAddr += 1;
            }
        }
    
        return retVal;
    }
    
    
    
    bool SF25FL_bufferRead(S25FL_Handle flashHandle,
                           S25FL_Transaction* flashTransaction)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal[4];               /* data to be written */
        SPI_Transaction transaction;             /* SPI transaction structure */
        uint32_t addrLengthInBytes = 3U;         /* Flash address length in bytes */
        uint32_t readCmd;                        /* Read command */
        uint32_t numDummyBits;                   /* Number of dummy bits */
        uint32_t frameLength;                    /* Frame length */
        uint32_t dstOffstAddr;                   /* Flash offset address */
        unsigned char *srcAddr;                  /* Address of data buffer */
        uint32_t length;                         /* data length in bytes */
    /*  unsigned int *tempPtr = (unsigned int *)&writeVal[0]; */ /* temp pointer */
        unsigned int frmLength;
        unsigned int transferType;
        unsigned char transferCmd;
        QSPI_v1_Object  *object;
        uint32_t offsetValue;
        uint32_t tempAddr;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Copy flash transaction parameters to local variables */
        dstOffstAddr = (uint32_t)flashTransaction->data;
        srcAddr = (unsigned char *)flashTransaction->address;
        length = flashTransaction->dataSize;
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            offsetValue = *((uint32_t *)srcAddr);
    
            addrLengthInBytes = 4U;
    
            if(offsetValue > 0xFFFFFF)
            {
                /* Enter 32 bit addressing mode */
                addrLengthInBytes = 4;
            }
    
            switch(object->rxLines)
            {
                case QSPI_RX_LINES_SINGLE:
                {
                    if(offsetValue > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE_4B;
                    }
                    numDummyBits = 0U;
    
                    tempAddr =    ((offsetValue & 0xFF000000) >> 24) |
                                  ((offsetValue & 0x00FF0000) >> 8)  |
                                  ((offsetValue & 0x0000FF00) << 8)  |
                                  ((offsetValue & 0x000000FF) << 24);
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + addrLengthInBytes;
                    break;
                }
    
                case QSPI_RX_LINES_DUAL:
                {
                    if(offsetValue > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL;
                    }
                    numDummyBits = 8U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + 1 + addrLengthInBytes;
                    break;
                }
    
                case QSPI_RX_LINES_QUAD:
                {
                    if(offsetValue > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD;
                    }
                    numDummyBits = 8U;
    
                    /* total transaction frame length in number of words (bytes)*/
                    frameLength = length + 1 + 1 + addrLengthInBytes;
                    break;
                }
    
                default:
                break;
            }
    
            /* total transaction frame length */
            frmLength = frameLength;
            SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
            /* Write read command */
            writeVal[0] = readCmd;
            transaction.txBuf = (unsigned char *)&writeVal[0];
            transaction.rxBuf = NULL;
            transaction.count = 1;
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
    
            /* Write dummy bits for fast read if required */
            if(0 != numDummyBits)
            {
                writeVal[0] = 0U;
                transaction.txBuf = (unsigned char *)&writeVal[0];
                transaction.rxBuf = NULL;
                transaction.count = (numDummyBits >> 3);      /* In bytes */
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
                retVal = SPI_transfer(handle, &transaction);
            }
    
            /* Write Address Bytes */
    /*      *tempPtr = (unsigned int)srcAddr; */
    /*      transaction.txBuf = (unsigned char *)tempPtr; */
            transaction.txBuf = (unsigned char *)&tempAddr;
            transaction.rxBuf = NULL;
            transaction.count = addrLengthInBytes;
    
            transferType = SPI_TRANSACTION_TYPE_WRITE;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
    
            /* Read the actual flash data */
            transaction.txBuf = NULL;
            transaction.rxBuf = (unsigned char *)dstOffstAddr;
            transaction.count = length;
    
            transferType = SPI_TRANSACTION_TYPE_READ;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            retVal = SPI_transfer(handle, &transaction);
        }
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            switch(object->rxLines)
            {
                case QSPI_RX_LINES_SINGLE:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_SINGLE;
                    }
                    break;
                }
    
                case QSPI_RX_LINES_DUAL:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_DUAL;
                    }
                    break;
                }
    
                case QSPI_RX_LINES_QUAD:
                {
                    if(flashTransaction->address > 0xFFFFFF)
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD_4B;
                    }
                    else
                    {
                        readCmd = QSPI_LIB_CMD_READ_QUAD;
                    }
                    break;
                }
    
                default:
                break;
            }
    
            /* Perform the transfer */
            transaction.txBuf = srcAddr;
            transaction.rxBuf = (uint8_t *)dstOffstAddr;
            transaction.count = length;
    
            transferType = SPI_TRANSACTION_TYPE_READ;
            transferCmd  = (unsigned char)readCmd;
            SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
            SPI_control(handle, SPI_V1_CMD_MMAP_TRANSFER_CMD, (void *)&transferCmd);
            retVal = SPI_transfer(handle, &transaction);
        }
    
        return retVal;
    }
    
    
    bool S25FLFlash_WriteEnable(S25FL_Handle flashHandle)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;                /* return value */
        unsigned char writeVal;             /* data to be written */
        SPI_Transaction transaction;        /* SPI transaction structure */
        unsigned int operMode;              /* temp variable to hold mode */
        unsigned int rxLines;               /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* transaction frame length in words (bytes) */
        frmLength = 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write enable command */
        writeVal = QSPI_LIB_CMD_WRITE_ENABLE;
    
        /* Update transaction parameters */
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count  = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    bool S25FLFlash_Enable4ByteAddrMode(S25FL_Handle flashHandle,
                                        bool enable4ByteMode)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;             /* return value */
        unsigned char writeVal;          /* data to be written */
        SPI_Transaction transaction;     /* SPI transaction structure */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Command to control the 4 byte mode */
        if (true == enable4ByteMode)
        {
            writeVal = QSPI_LIB_CMD_ENTER_4_BYTE_ADDR;
        }
        else
        {
            writeVal = QSPI_LIB_CMD_EXIT_4_BYTE_ADDR;
        }
    
        /* Write 4 byte enable/disable command to flash */
        transaction.count = 1U;                    /* Frame length in bytes */
        transaction.txBuf = (unsigned char *)&writeVal;  /* Value to be written */
        transaction.rxBuf = NULL;                  /* Nothing to read */
        transaction.arg   = NULL;                  /* Not applicable */
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    uint32_t FlashStatus(S25FL_Handle flashHandle)
    {
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        bool retVal = false;             /* return value */
        unsigned char writeVal;          /* data to be written */
        SPI_Transaction transaction;     /* SPI transaction structure */
        uint32_t rxData = 0U;            /* received data */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Total transaction frame length in words (bytes) */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write Address Bytes */
        writeVal = QSPI_LIB_CMD_READ_STATUS_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Read the status register */
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&rxData;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return (rxData & 0xFF);
    }
    
    #if defined(SOC_AM574x) || defined (SOC_AM571x) || defined (SOC_AM572x) || defined (SOC_DRA72x) || defined (SOC_DRA75x) || defined (SOC_DRA78x)
    bool S25FLFlash_QuadModeEnable(S25FL_Handle flashHandle)
    {
        SPI_Transaction transaction;                /* SPI transaction structure */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal = 0U;    /* data to be written */
        uint32_t norStatus;             /* flash status value */
        uint32_t configReg;             /* configuration register value */
        uint32_t data;                  /* data to be written */
        bool retVal = false;            /* return value */
        unsigned int operMode;          /* temp variable to hold mode */
        unsigned int rxLines;           /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read Status register */
        writeVal = QSPI_LIB_CMD_READ_STATUS_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&norStatus;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read command register */
        writeVal = QSPI_LIB_CMD_QUAD_RD_CMD_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&configReg;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Set 2nd bit of configuration register to 1 to enable quad mode */
        configReg |= (QSPI_FLASH_QUAD_ENABLE_VALUE << QSPI_FLASH_QUAD_ENABLE_BIT);
        data = (QSPI_LIB_CMD_WRITE_STATUS_REG << 16) | (norStatus << 8) | configReg;
    
        /* Set transfer length in bytes */
        frmLength = 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
    
        transaction.txBuf = (unsigned char *)&data;
        transaction.rxBuf = NULL;
        transaction.count = 3;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    #endif
    #if defined(SOC_AM437x)
    bool S25FLFlash_QuadModeEnable(S25FL_Handle flashHandle)
    {
        SPI_Transaction transaction;                /* SPI transaction structure */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        unsigned char writeVal = 0U;    /* data to be written */
        uint32_t norStatus;             /* flash status value */
        bool retVal = false;            /* return value */
        unsigned int operMode;          /* temp variable to hold mode */
        unsigned int rxLines;           /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read Status register */
        writeVal = 0x05U;   //QSPI_LIB_CMD_READ_STATUS_REG;  //Cmd for AM437x
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        transaction.txBuf = NULL;
        transaction.rxBuf = (unsigned char *)&norStatus;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* Set transfer length in bytes: Reading status register */
        frmLength = 1 + 1;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Read command register */
        writeVal = 0x01U;   //QSPI_LIB_CMD_QUAD_RD_CMD_REG;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
    
        /* Set status register 6th bit to 1 for Quad enable
         * Write this value to the status register.
         */
        norStatus &= ~(1U << 0x6U);
        norStatus |= (0x1U << 0x6U);
    
        transaction.txBuf = (unsigned char *)&norStatus;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    #endif
    
    
    
    bool S25FLFlash_BlockErase(S25FL_Handle flashHandle, unsigned int blockNumber)
    {
        uint32_t eraseAddr;    /* Flash erase address */
        uint32_t writeVal;     /* data to be written */
        SPI_Handle handle = flashHandle->spiHandle;  /* SPI handle */
        SPI_Transaction transaction;         /* SPI transaction structure */
        unsigned int addrLenInBytes = 3;     /* address length in bytes */
        bool retVal = false;                 /* return value */
        unsigned int operMode;               /* temp variable to hold mode */
        unsigned int rxLines;                /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
        uint32_t tempAddr;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* Compute flash erase address based on the block size */
        eraseAddr = blockNumber * flashHandle->blockSize;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        if(eraseAddr > 0xFFFFFF)
        {
            /* Enter 4 byte addressing mode */
            addrLenInBytes = 4;
        }
    
        tempAddr = ((eraseAddr & 0xFF000000) >> 24) |
                   ((eraseAddr & 0x00FF0000) >> 8)  |
                   ((eraseAddr & 0x0000FF00) << 8)  |
                   ((eraseAddr & 0x000000FF) << 24);
    
        if(addrLenInBytes == 3)
        {
            tempAddr = (tempAddr >> 8) & 0x00FFFFFF;
        }
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
    
        /*total transaction frame length */
        frmLength = 1 + addrLenInBytes;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength));
    
        /* Block erase command */
        if(eraseAddr > 0xFFFFFF)
        {
            writeVal = QSPI_LIB_CMD_BLOCK_ERASE_4B;
        }
        else
        {
            writeVal = QSPI_LIB_CMD_BLOCK_ERASE;
        }
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Send erase address */
        writeVal = tempAddr;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = addrLenInBytes;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Check flash status for write completion */
        while (1U == (FlashStatus(flashHandle) & 0x1U));
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    
        return retVal;
    }
    
    
    void FlashPrintId(S25FL_Handle flashHandle)
    {
        uint32_t writeVal;               /* data to be written */
        SPI_Handle handle = flashHandle->spiHandle;  /* SPI handle */
        SPI_Transaction transaction;     /* SPI transaction structure */
        bool retVal = false;             /* return value */
        unsigned char mfgId = 0;         /* manufacture ID value */
        unsigned char deviceId = 0;      /* device ID value */
        unsigned int operMode;           /* temp variable to hold mode */
        unsigned int rxLines;            /* temp variable to hold rx lines */
        unsigned int frmLength;
        unsigned int transferType;
        QSPI_v1_Object  *object;
        unsigned int rxLinesArg;
    
        /* Get the pointer to the object and hwAttrs */
        object = handle->object;
    
        /* These operations require the qspi to be configured in the following mode
           only: tx/rx single line and config mode. */
    
        /* Save the current mode and rxLine configurations */
        operMode = object->qspiMode;
        rxLines  = object->rxLines;
    
        /* Update the mode and rxLines with the required values */
        SPI_control(handle, SPI_V1_CMD_SETCONFIGMODE, NULL);
    
        rxLinesArg = QSPI_RX_LINES_SINGLE;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLinesArg);
    
        /* Total transaction frame length in bytes */
        frmLength = 1 + 3 + 2;   /* cmd + address + read data */
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        /* Write Command */
        writeVal = QSPI_LIB_CMD_READ_MFG_ID;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        if(retVal == false)
        {
            /* Error */
        }
    
        /* Write Address Bytes */
        writeVal = 0x0U;
        transaction.txBuf = (unsigned char *)&writeVal;
        transaction.rxBuf = NULL;
        transaction.count = 3;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
    
        /* Read Manufacturer ID
         * The manufacturer ID is of 1 byte(8 bits)
         */
        transaction.txBuf = NULL;
        transaction.rxBuf = &mfgId;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
        retVal = SPI_transfer(handle, &transaction);
    
        /* Read Device ID */
        transaction.txBuf = NULL;
        transaction.rxBuf = &deviceId;
        transaction.count = 1;
    
        transferType = SPI_TRANSACTION_TYPE_READ;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
    
    
        retVal = SPI_transfer(handle, &transaction);
    
    //    SPI_log("\nDevice ID: %d.\n", deviceId);
    //    SPI_log("Manufacturer ID: %d.\n", mfgId);
    
        /* Note - This ID is the device ID of the flash device.
         * This ID is read from the flash
         */
    
        /* Restore operating mode and rx Lines */
        object->qspiMode = operMode;
        SPI_control(handle, SPI_V1_CMD_SETRXLINES, (void *)&rxLines);
    }
    
    static bool SF25FL_ConfigMode_Write(uint32_t dstOffstAddr,
                                        unsigned char* srcAddr,
                                        uint32_t length,
                                        S25FL_Handle flashHandle)
    {
        bool retVal = false;                        /* return value */
        SPI_Handle handle = flashHandle->spiHandle; /* SPI handle */
        uint32_t addrLengthInBytes;            /* Flash addr length in bytes */
        unsigned int frmLength;
        unsigned char writeVal[4];                  /* data to be written to QSPI */
        SPI_Transaction transaction;                /* SPI transaction structure */
        unsigned int transferType;
        uint32_t offsetValue;
        uint32_t tempAddr;
    
    
        addrLengthInBytes = 4U;        /* Flash address length in bytes */
        offsetValue = *((uint32_t *)dstOffstAddr);
    
       /* Extract address word length from the flash's destination offst addr*/
        if(offsetValue > 0xFFFFFF)
        {
            /* Enter 32 bit addressing mode */
            addrLengthInBytes = 4;
        }
    
        tempAddr = ((offsetValue & 0xFF000000) >> 24) |
                   ((offsetValue & 0x00FF0000) >> 8)  |
                   ((offsetValue & 0x0000FF00) << 8)  |
                   ((offsetValue & 0x000000FF) << 24);
    
        /* Write Enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* total transaction frame length in number of words (bytes)*/
        frmLength = 1 + addrLengthInBytes + length;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, ((void *)&frmLength));
    
        /* Send Flash write command */
        writeVal[0] = QSPI_LIB_CMD_PAGE_PRG_4B;   /* Flash write command */
        transaction.txBuf = (unsigned char *)&writeVal[0];
        transaction.rxBuf = NULL;
        transaction.count = 1U;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Send flash address offset to which data has to be written */
        transaction.txBuf = &tempAddr;//(unsigned char *)dstOffstAddr;
        transaction.rxBuf = NULL;
        transaction.count = addrLengthInBytes;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Write buffer data to flash */
        transaction.txBuf = (unsigned char *)srcAddr;
        transaction.rxBuf = NULL;
        transaction.count = length;
    
        transferType = SPI_TRANSACTION_TYPE_WRITE;
        SPI_control(handle, SPI_V1_CMD_TRANSFERMODE_RW, (void *)&transferType);
        retVal = SPI_transfer(handle, &transaction);
    
        /* Check flash status for write completion */
        while ((FlashStatus(flashHandle) & 0x1U));
    
        return retVal;
    }
    

  • Hi

    I also found some other issues on the QSPI flash driver:

    1.
    S25FLFlash_QuadModeEnable does not work:
    - The Flash Write Enable command is not sent to flash so that the WRR register cannot be changed.
    - The uint32_t stack variables "norStatus" and configReg are passed to the read functions which returns
    8bits of data. The upper 24bits of those variables are unchanged and unititialised.
    Newerthelerr those 32bit values are combied to new status and config register values which gives
    completely undefined values. These are than transferred to the WRR register in flash.
    Luckily the Write Enable Command is not sent so that these values are not accepted by the Flash.
    Otherwise some OPT bits might be set that could turn part or the whole flash as irreversibly
    write protected!
    - Bytes (command, status register value, config register value) are transferred in the wrong order
    (command is output as last byte but must be first)

    As the Quad Mode Enable flag is stored as non-volatile value within the flash one might not notice
    the S25FLFlash_QuadModeEnable does not work if the flag was already set by other means.

    2.
    The Byte flipping (as notes in the post above) is also required for read accesses in config mode.

    3.
    SF25FL_bufferWrite always returns "false" in config mode (retVal inside function never set "true")

    4.
    The function S25FLFlash_Enable4ByteAddrMode (not used) uses undefined flash command values
    QSPI_LIB_CMD_ENTER_4_BYTE_ADDR = 0xB7 is not defined in S25FL256 user manual.
    QSPI_LIB_CMD_EXIT_4_BYTE_ADDR = 0xE9 is defined as Password Unlock.

    5. no bug, but sad anyway:
    The QSPI driver only uses 8bit transfers although the QSPI hardware would offer up to 128bit transfers.
    So this wastes performance which is already very cpu intensive as the QSPI hardware does not offer
    DMA acccess.

    Regards,
    Markus