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.

CCS/PROCESSOR-SDK-AM437X: Fails writing flash on AM437x Industiral Development Kit using the example project provided.

Part Number: PROCESSOR-SDK-AM437X

Tool/software: Code Composer Studio

Hello, 

I am trying to write to flash on the AM437x Industrial Development Kit.

I have access to the QSPI_BasicExample_idkAM437x_armExampleProject.

I have also integrated the spi_test() and spi_read_write() from the example.

Here is the problem: If this number is changed to anything below 64, it works. When this number is 64 or greater it fails.

void spi_test()
{
    SPI_Params   spiParams;              /* SPI params structure */
    S25FL_Handle flashHandle;            /* Flash handle */
    bool         retVal = false;         /* return value */

    /* 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);

    /* Print flash Id */
    FlashPrintId(flashHandle);

    /* Set the transfer length in number of 32 bit words */
    transferLength = 50;

    /* read/write test on block 0, address 0 */
    retVal = spi_read_write(flashHandle, 0, transferLength);
    if (retVal == true)
    {
        /* read/write test on block 256, address 16M */
        retVal = spi_read_write(flashHandle, 256, transferLength);
    }

    SF25FL_close(flashHandle);

    if(true == retVal)
    {
        DebugLog::Write("\n All tests have passed. \n");
    }
    else
    {
        DebugLog::Write("\n Some tests have failed. \n");
    }

    while(1);
}

I have narrowed it to failing at the highlighted line below in the function in the class S25FL.cbool SF25FL_bufferWrite(S25FL_Handle flashHandle, S25FL_Transaction* flashTransaction)

 

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;
    }
}

Seeing as I am using example code, I am wondering why this is failing.

Any help would be greatly appreciated.

  • The RTOS team have been notified. They will respond here.
  • I think it may have to do with the file: QSPI_v1.h because it says it is implementing drivers for the AM572x and that isn't even the correct board.

    Not sure if this is the issue or how to resolve it.
  • Chris,

    What is the version of Processor SDK RTOS that you are using. This issue seems to have been reported before for AM57x so I suspect the issue also impacts the AM437x example. The fix for the issue has been discussed here:

    https://e2e.ti.com/support/processors/f/791/t/663039

     If you want to use QSPI flash writer to program this memory for boot or running code in XIP mode then I would recommend using the QSPI flash writer app from here:

    pdk_am437x_1_0_xx\packages\ti\starterware\examples\qspi\flash_writer

    You can find the pre-built binary for this application at the following location:

    pdk_am437x_1_0_xx\packages\ti\starterware\binary\qspi_app_flash_writer\bin\am43xx-evm\gcc

    Regards,

    Rahul

  • Thank you for your response.

    I took those two files and started doing some testing.

    I can still get it to fail with those two files.

    In the file: 'main_flash_read_test.c' line 120
    `unsigned int blockNumber = 0U;`

    If you change that to anything above 63, it fails.

    Do you know the reason for this or how to fix it?

    P.S. I attached the two files that were given in that other question.

    /**
     *  \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;
    }

  • Hi ,

    Unfortunately the S25FL flash driver do have some bugs.

    Pasting a bug list from  here.

    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

    I will try to help you. First of all, I can see that you try to use memory map mode write. This write mode is slow, as you have to call SPI_control two times, and SPI_transfer one time FOR EACH BYTE you are writing. You should try to use config mode when writing.

    In my code, I use config mode (single mode) when writing, and mmap mode (quad mode) when reading.

    Second, i see you have an issue with a number > 64. I assume this is the number of uint32_t 's to write to flash. A hint is that 64*4 = 255 = 0xFF, so only 1 byte are used for the offsetValue. If you compare the S25FLFlash_BlockErase and SF25FL_ConfigMode_Write, you can see that the offsetValue bytes are correctly "flipped / switched around" in the erase function, but this is not done in the write function. Try doing that in the SF25FL_ConfigMode_Write function as well. "Luckily", this works for only 1 byte addressing, but is not tested for big data sets.

     

    If you want to read in quad mode. (It does not seem to be necessary when writing, as the single/quad is not the limitation when writing), you have to re-write the S25FLFlash_QuadModeEnable function as well. This small function has a lot of code error, and do not work at all. You can easily be fooled to think that the function is working if you manage to set the quad mode enable one time, as this bit is non-volatile on flash. Please find attached the S25FL.c we are using in our codebase.

     please see the attachment S25FL.c for a fix of the quad mode enable function.

    Also see attachment QSPI_v1.c for a improvement of QSPI_cmd_mode_write_v1(..), with support for up to  128 bit transfers.

    /**
     *  \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>
    #include <ti/drv/spi/test/qspi_flash/src/SPI_log.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;
    
        //SPI_log("In function SF25FL_bufferWrite. 1\n");
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            offsetValue = *((uint32_t *)dstOffstAddr);
            //SPI_log("In function SF25FL_bufferWrite. (cfg mode) 2\n");
            /*
             * 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 */
        uint8_t norStatus = 0xFF;             /* flash status value */
        uint8_t configReg = 0xFF;             /* configuration register value */
        //uint32_t configReg2 = 0xFFFFFFFF;   //for test          /* configuration register 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);
    
    #define READ_STATUS_BEFORE
    #ifdef READ_STATUS_BEFORE
        /* 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);
        //SPI_log("read status reg 1. time: norStatus: 0x%08X.\n",norStatus);
    
        /* 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);
    
        //SPI_log("read configReg reg 1. time: configReg: 0x%08X.\n",configReg);
    #endif
    
        /* Set 2nd bit of configuration register to 1 to enable quad mode */
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* Wait */
        while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
    
        /* Set transfer length in bytes */
        frmLength = 3;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        // WRITING INSTRUCTION
        writeVal = QSPI_LIB_CMD_WRITE_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);
    
        /* Wait till the status register is being written */
        //while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
        // WRITING STATUS REGISTER
    
        /* Flash write enable */
        // setting status reg to 0, for testing
        //norStatus = 0;
        writeVal = (unsigned char)norStatus;
    
        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);
    
        /* Wait till the status register is being written */
        //while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
    
        // WRITING COMMAND REGISTER
    
        //data = (QSPI_LIB_CMD_WRITE_STATUS_REG << 16) | (norStatus << 8) | configReg;
    
    
        // setting cfg reg to 0, for testing
        //configReg = 0;
        //SPI_log("configReg before changing value: 0x%08X.\n",configReg);
        configReg |= (QSPI_FLASH_QUAD_ENABLE_VALUE << QSPI_FLASH_QUAD_ENABLE_BIT);
        //configReg &= ~(1 << 1); // test for setting quad bit to 0.
    
        //SPI_log("configReg after changing value: 0x%08X.\n",configReg);
    
        writeVal = (unsigned char)configReg;
    
        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);
    
        //SPI_log("Before wait.\n");
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
        //SPI_log("After waiting for status reg to be written.\n");
    
    
    #ifdef READ_STATUS_AFTER
    //Anders debug read status reg 2. time starts
    
        /* 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 *)&configReg2;
        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("configReg2 when reading 2. time: 0x%08X.\n",configReg2);
    
    
    //Anders debug read status reg 2. time ends
    #endif
        /* 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;
    }
    
    /**
     *  \file   QSPI_v1.c
     *
     *  \brief  QSPI IP Version 1 specific driver APIs implementation.
     *
     *   This file contains the driver APIs for QSPI controller.
     */
    
    /*
     * Copyright (C) 2014-2015 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 <stdint.h>
    #include <stddef.h>
    #include <stdbool.h>
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    #include <ti/csl/src/ip/qspi/V1/qspi.h>
    #include <ti/csl/src/ip/qspi/V1/hw_qspi.h>
    #include <ti/drv/spi/src/SPI_osal.h>
    
    
    #include <ti/drv/spi/test/qspi_flash/src/SPI_log.h>
    
    /*#define WORD_INTERRUPT*/
    
    /* QSPI AM57x functions */
    static void       QSPI_close_v1(SPI_Handle handle);
    static void       QSPI_init_v1(SPI_Handle handle);
    static SPI_Handle QSPI_open_v1(SPI_Handle handle, const SPI_Params *params);
    static bool       QSPI_transfer_v1(SPI_Handle handle,
                                          SPI_Transaction *transaction);
    static void       QSPI_primeTransfer_v1(SPI_Handle handle,
                                              const SPI_Transaction *transaction);
    static void       QSPI_transferCallback_v1(SPI_Handle handle,
                                                  SPI_Transaction *msg);
    static int32_t QSPI_control_v1(SPI_Handle handle, uint32_t cmd, const void *arg);
    static void QSPI_transferCancel_v1(SPI_Handle handle);
    static void QSPI_hwiFxn_v1(uintptr_t arg);
    static void QSPI_read_v1(SPI_Handle handle, const SPI_Transaction *transaction);
    static void QSPI_write_v1(SPI_Handle handle, const SPI_Transaction *transaction);
    static void QSPI_mmap_mode_write_v1(SPI_Handle handle,
                                        const SPI_Transaction *transaction);
    static void QSPI_cmd_mode_write_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction);
    static void QSPI_cmd_mode_read_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction);
    static void QSPI_mmap_mode_read_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction);
    static void QSPIMmapCsEnable(uint32_t baseAddr, uint32_t chipSelect);
    
    typedef enum QSPI_intrPollMode_s {
        SPI_OPER_MODE_BLOCKING = 0U,  /*! Interrupt based blocking mode */
        SPI_OPER_MODE_POLLING,        /*! Non interrupt based blocking mode */
        SPI_OPER_MODE_CALLBACK        /*! Interrupt based call back mode */
    } QSPI_intrPollMode;
    
    
    
    /* SPI function table for QSPI AM57x implementation */
    const SPI_FxnTable QSPI_FxnTable_v1 = {
        &QSPI_close_v1,
        &QSPI_control_v1,
        &QSPI_init_v1,
        &QSPI_open_v1,
        &QSPI_transfer_v1,
        &QSPI_transferCancel_v1,
        NULL
    };
    
    #define   CTRL_CORE_CONTROL_IO_2       (0x4A002558U)
    #define   QSPI_MMAP_CS_SHIFT           (0x8U)
    
    /*
     *  ======== QSPI_close_v1 ========
     */
    static void QSPI_close_v1(SPI_Handle handle)
    {
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Mask I2C interrupts */
        QSPIintDisable(hwAttrs->baseAddr,
            (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD));
    
        /* Destruct the Hwi */
        if(SPI_OPER_MODE_POLLING != object->intrPollMode)
        {
            SPI_osalHardwareIntDestruct(object->hwi,hwAttrs->eventId);
        }
    
        /* Destruct the instance lock */
        SPI_osalDeleteBlockingLock(object->mutex);
    
        /* Destruct the transfer completion lock */
        if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
        {
            SPI_osalDeleteBlockingLock(object->transferComplete);
        }
    
        /* Open flag is set false */
        object->isOpen = (bool)false;
        }
    
        return;
    }
    
    /*
     *  ======== QSPI_hwiFxn_v1 ========
     *  Hwi interrupt handler to service the QSPI peripheral
     *
     *  The handler is a generic handler for a QSPI object.
     */
    static void QSPI_hwiFxn_v1(uintptr_t arg)
    {
        uint32_t            intrStatus;
        QSPI_v1_Object      *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)(((SPI_Handle)arg)->object);
        hwAttrs = (const QSPI_HwAttrs *)(((SPI_Handle)arg)->hwAttrs);
    
        /* Read the interrupt status register */
        intrStatus = QSPIintStatus(hwAttrs->baseAddr);
    
        /* If word count interrupt */
        if(intrStatus & QSPI_INTR_MASK_WORD)
        {
            /* Clear interrupt status */
            QSPIintClear(hwAttrs->baseAddr, QSPI_INTR_MASK_WORD);
    
            /* Call the call back function */
            object->qspiParams.transferCallbackFxn((SPI_Handle)arg, NULL);
        }
    
        /* If word count interrupt */
        if(intrStatus & QSPI_INTR_MASK_FRAME)
        {
            /* Clear interrupt status */
            QSPIintClear(hwAttrs->baseAddr, QSPI_INTR_MASK_FRAME);
    
            /* Call the call back function */
            object->qspiParams.transferCallbackFxn((SPI_Handle)arg, NULL);
        }
    
        return;
    }
    
    /*
     *  ======== QSPI_init_v1 ========
     */
    static void QSPI_init_v1(SPI_Handle handle)
    {
        /* Input parameter validation */
        if (handle != NULL)
        {
            /* Mark the object as available */
            ((QSPI_v1_Object *)(handle->object))->isOpen = (bool)false;
        }
    }
    
    
    /*
     *  ======== QSPI_open_v1 ========
     */
    static SPI_Handle QSPI_open_v1(SPI_Handle handle, const SPI_Params *params)
    {
    
    #ifdef anders
        SemaphoreP_Params     semParams;
        uint32_t       key;
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs /*const*/  *hwAttrs = NULL;
        OsalRegisterIntrParams_t interruptRegParams;
        uint8_t ret_flag = 0u;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
    #ifdef TEST_QSPI
        hwAttrs = (/*const*/ QSPI_HwAttrs *)handle->hwAttrs;
        hwAttrs->intrNum = 135;
    #endif
    	hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    #endif
    
    	SemaphoreP_Params     semParams;
        uint32_t       key;
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
        OsalRegisterIntrParams_t interruptRegParams;
        uint8_t ret_flag = 0u;
    
        /* Input parameter validation */
        OSAL_Assert(handle == NULL);
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Determine if the device index was already opened */
        key = SPI_osalHardwareIntDisable();
        if(object->isOpen == (bool)true) {
            SPI_osalHardwareIntRestore(key);
            handle = NULL;
        }
        else
        {
          /* Mark the handle as being used */
          object->isOpen = (bool)true;
          SPI_osalHardwareIntRestore(key);
    
          /* Store the I2C parameters */
          if (params == NULL) {
            /* No params passed in, so use the defaults */
            SPI_Params_init(&(object->qspiParams));
          }
          else {
            /* Copy the params contents */
            object->qspiParams = *params;
          }
    
          /* Copy the controller mode from hardware attributes to object */
          object->qspiMode = hwAttrs->operMode;
          object->rxLines  = hwAttrs->rxLines;
    
          /* Extract QSPI operating mode based on hwAttrs and input parameters */
          if(SPI_MODE_BLOCKING == object->qspiParams.transferMode)
          {
            if(true == hwAttrs->intrEnable)
            {
                object->intrPollMode = SPI_OPER_MODE_BLOCKING;
            }
            else
            {
                object->intrPollMode = SPI_OPER_MODE_POLLING;
            }
          }
          else
          {
            object->intrPollMode = SPI_OPER_MODE_CALLBACK;
          }
    
    
          /* Extract the polling mode from hardware attributes. */
          if(SPI_OPER_MODE_POLLING != object->intrPollMode)
          {
    		/* register interrrupt when the 1st channel of the instance is opened */
            Osal_RegisterInterrupt_initParams(&interruptRegParams);             
    
            interruptRegParams.corepacConfig.name=NULL;
            interruptRegParams.corepacConfig.priority = 0x20;
            interruptRegParams.corepacConfig.corepacEventNum = hwAttrs->eventId;
            interruptRegParams.corepacConfig.intVecNum=hwAttrs->intrNum; /* Host Interrupt vector */
            interruptRegParams.corepacConfig.isrRoutine  = (void (*)(uintptr_t))(&QSPI_hwiFxn_v1);
            interruptRegParams.corepacConfig.arg         = (uintptr_t)handle;
    
            SPI_osalRegisterInterrupt(&interruptRegParams,&(object->hwi));
    
            if(object->hwi == NULL) {
                QSPI_close_v1(handle);
                ret_flag = 1u;
                handle = NULL;
            }
          }
    
          if(ret_flag == 0u)
          {
            /*
             * Construct thread safe handles for this QSPI peripheral
             * Semaphore to provide exclusive access to the QSPI peripheral
             */
            SPI_osalSemParamsInit(&semParams);
            semParams.mode = SemaphoreP_Mode_BINARY;
            object->mutex = SPI_osalCreateBlockingLock(1U, &semParams);
    
            /*
             * Store a callback function that posts the transfer complete
             * semaphore for synchronous mode
             */
            if (object->intrPollMode == SPI_OPER_MODE_BLOCKING) {
              /*
               * Semaphore to cause the waiting task to block for the QSPI
               * to finish
               */
              object->transferComplete = SPI_osalCreateBlockingLock(0, &semParams);
    
              /* Store internal callback function */
              object->qspiParams.transferCallbackFxn = &QSPI_transferCallback_v1;
            }
            if(object->intrPollMode == SPI_OPER_MODE_CALLBACK){
              /* Check to see if a callback function was defined for async mode */
              OSAL_Assert(object->qspiParams.transferCallbackFxn == NULL);
            }
    
            /* Setting IDLE mode for QSPI controller */
            QSPIconfigIdleMode(hwAttrs->baseAddr, QSPI_SYSCONFIG_IDLE_MODE_NO_IDLE);
    
            /* Set clock mode in mode 3 */
            QSPISetClkMode(hwAttrs->baseAddr, hwAttrs->chipSelect, hwAttrs->frmFmt);
            QSPISetCsPol(hwAttrs->baseAddr, hwAttrs->chipSelect, hwAttrs->csPol);
            QSPISetDataDelay(hwAttrs->baseAddr, hwAttrs->chipSelect,
                              hwAttrs->dataDelay);
    
            /* Enable clock and set divider value */
            QSPISetPreScaler(hwAttrs->baseAddr, 0x0U);
    
            /* Clear the interrupts and interrupt status */
            QSPIintDisable(hwAttrs->baseAddr,
                (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD)) ;
            QSPIintClear(hwAttrs->baseAddr,
                (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD));
    
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr,
                          hwAttrs->chipSelect,
                          QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
    
            /* Enable memory mapped port by default */
            QSPISetMemAddrSpace(hwAttrs->baseAddr,
                    hwAttrs->chipSelect,
                    QSPI_MEM_MAP_PORT_SEL_MEM_MAP_PORT);
    
    
            QSPIMmapCsEnable(hwAttrs->baseAddr, hwAttrs->chipSelect);
    
            /* Return the address of the spiObjectArray[i] configuration structure */
          }
        }
        //}
        return(handle);
    }
    
    static void QSPIMmapCsEnable(uint32_t baseAddr, uint32_t chipSelect)
    {
    #if !defined(SOC_AM437x)
        uint32_t regVal;
    
        regVal = HW_RD_REG32(CTRL_CORE_CONTROL_IO_2);
        regVal |= ((chipSelect + 1U) << QSPI_MMAP_CS_SHIFT);
        HW_WR_REG32(CTRL_CORE_CONTROL_IO_2, regVal);
    #endif
    }
    
    /*
     *  ======== QSPI_primeTransfer_v1 =======
     */
    static void QSPI_primeTransfer_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Store the new internal counters and pointers */
        object->writeBufIdx = (uint8_t*)transaction->txBuf;
        object->writeCountIdx = transaction->count;
    
        object->readBufIdx = (uint8_t*)transaction->rxBuf;
        object->readCountIdx = transaction->count;
    
    
        /* Interrupt mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable the word count interrupt */
            QSPIintEnable(hwAttrs->baseAddr, QSPI_INTR_MASK_WORD);
    #else
            /* Enable the frame count interrupt */
            QSPIintEnable(hwAttrs->baseAddr, QSPI_INTR_MASK_FRAME);
    #endif
        }
    
        /* Polling Mode */
        if(object->intrPollMode == SPI_OPER_MODE_POLLING)
        {
            /* No Specific implementation is needed here. */
        }
    
        /* Identify the direction of transfer (whether read/write) */
        if(SPI_TRANSACTION_TYPE_READ == object->transactionType)
        {
            QSPI_read_v1(handle, transaction);
        }
    
        if(SPI_TRANSACTION_TYPE_WRITE == object->transactionType)
        {
            QSPI_write_v1(handle, transaction);
        }
    }
    
    
    static void QSPI_mmap_mode_read_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction)
    {
        QSPI_HwAttrs const  *hwAttrs = NULL;
        uint32_t *pDst = NULL;
        uint32_t *pSrc = NULL;
        uint8_t *pDst_8 = NULL;
        uint8_t *pSrc_8 = NULL;
        uint32_t count;
        uint32_t mmapReadCmd = 0U;
        QSPI_v1_Object  *object;
        uint32_t offset;
        const uint32_t nNumBytesToTransfer = 4;
    
        /* Input parameter validation */
        OSAL_Assert(!((handle != NULL) && (transaction != NULL)));
    
        pDst = (uint32_t *)transaction->rxBuf;
        pSrc = (uint32_t *)transaction->txBuf;
        count = transaction->count;
    
        /* Get the pointer to the object and hwAttrs */
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
        object = (QSPI_v1_Object*)handle->object;
    
        uint32_t temp_addr = ((uint32_t)hwAttrs->memMappedBaseAddr + (uint32_t)transaction->txBuf);
        pSrc = ((uint32_t *)(temp_addr)); // change this to 8 or 16 as well
    
        offset = (uint32_t)transaction->txBuf;
    
        /* Extract memory map mode read command */
        mmapReadCmd = (uint32_t)object->transferCmd;
    
        /* Set the number of address bytes to three */
        QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
            QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
    
    
        /* 4 byte addressing mode */
        if(offset > (uint32_t)0xFFFFFF)
        {
            /* Enable 4 byte addressing mode */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
        }
    
        /* validate receive lines */
        OSAL_Assert(object->rxLines > 2);
    
        switch(object->rxLines)
        {
            case QSPI_RX_LINES_SINGLE:
            {
                QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    mmapReadCmd);
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_NORMAL);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x0U);
    
                while(count)
                {
                    // Do the normal memory to memory transfer. Copy will be in bytes
                    *pDst = *pSrc;
                    pDst++;
                    pSrc++;
                    count--;
                }
                break;
            }
    
            case QSPI_RX_LINES_DUAL:
            {
                QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    mmapReadCmd);
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_DUAL);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x8U);
                while(count)
                {
                    // Do the normal memory to memory transfer. Copy will be in bytes
                    *pDst = *pSrc;
                    pDst++;
                    pSrc++;
                    count--;
                }
                break;
            }
    
            case QSPI_RX_LINES_QUAD:
            {
                QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    mmapReadCmd);
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_QUAD);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x8U);
    
    /*
                uint32_t addr = hwAttrs->baseAddr + QSPI_SPI_CMD_REG;
                HW_WR_FIELD32(addr, QSPI_SPI_CMD_REG_FLEN, frameLength-1);
    */
    /*
                if((count %  frameLength) != 0)
                {
                    count += frameLength -(count %  frameLength);
                }
    */
                /*
                SPI_log("\n*pDst = %d. before \n",*pDst);
                pDst++;
                SPI_log("*pDst = %d. after ++\n",*pDst);
                pDst=pDst+4;
                SPI_log("*pDst = %d. after +=4\n",*pDst);
                */
                int anders = 0;
                while(count)
                {
                    if(count >= nNumBytesToTransfer)
                    {
                        /* Do the normal memory to memory transfer. Copy will be in bytes */
                        *pDst = *pSrc;
    //                    UART_printf("%d. 0x%08x. (%d - %d).\n",anders, *pDst, (anders*4)+1, (anders*4)+4);
                        anders++;
                        pDst++;
                        pSrc++;
                        count-=nNumBytesToTransfer;
                    }
                    else
                    {
                        /* Do the normal memory to memory transfer. Copy will be in bytes */
                        pDst_8 = (uint8_t*)pDst;
                        pSrc_8 = (uint8_t*)pSrc;
                        while(count)
                        {
                            *pDst_8 = *pSrc_8;
                            anders++;
    //                        UART_printf("%d. 0x%02x. (%d - %d).\n",anders, *pDst, (anders*4)+1, (anders*4)+4);
                            pDst_8++;
                            pSrc_8++;
                            count--;
                        }
                    }
                }
                break;
            }
    
            default:
            break;
        }
    
    
    
        /* 4 byte addressing mode */
        if(offset > (uint32_t)0xFFFFFF)
        {
            /*
             * After the transfer switch back to 3 byte addressing mode.
             * This is the default mode.
             */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
        }
    }
    
    static void QSPI_cmd_mode_read_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;    /* QSPI hardware attributes */
        uint32_t count = 0U;         /* transfer length in bytes */
        uint32_t wordLenBytes = 0U;  /* Word length in number of bytes */
        uint32_t cmd = 0;           /* transmit command */
        uint32_t dataVal[4] = {0U, 0U, 0U, 0U};  /* data to be written */
        uint32_t idx;/*, idx1, idx2, idx3;*/  /* indexes */
        uint32_t numWords = 0U;          /* number of words */
        uint8_t *dstAddr;              /* destination address */
    
        /* Input parameter validation */
        OSAL_Assert(!((handle != NULL) && (transaction != NULL)));
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        dstAddr = object->readBufIdx;
    
    
        /*formulate the command */
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FLEN, (object->frmLength - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WLEN, (object->qspiParams.dataSize - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CSNUM, hwAttrs->chipSelect);
    
        /* validate receive lines */
        OSAL_Assert(object->rxLines > 2);
    
        switch(object->rxLines)
        {
            case QSPI_RX_LINES_SINGLE:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_FOUR_PIN_READ_SINGLE);
                break;
            }
            case QSPI_RX_LINES_DUAL:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_FOUR_PIN_READ_DUAL);
                break;
            }
            case QSPI_RX_LINES_QUAD:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_SIX_PIN_READ_QUAD);
                break;
            }
    
            default:
            break;
        }
    
        /* Enable interrupts in the polling mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, true);
    #else
            /* Enable frame count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, true);
    #endif
    
        }
        else
        {
            /* Disable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, false);
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, false);
        }
    
        /* Extract frame length in bytes */
        count = transaction->count;
    
        /* Extract word length in number of bytes */
        wordLenBytes = (object->qspiParams.dataSize >> 3U);
    //    UART_printf("%d\n",wordLenBytes);
    
        //int anders6 = 0;
        //int anders7 = 0;
    
    
        /* Write the data into shift registers */
        while(count)
        {
    
        /* Write tx command to command register */
        QSPIsetCommandReg(hwAttrs->baseAddr, cmd);
    #ifdef WORD_INTERRUPT
            /* interrupt mode */
            if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
            {
                /* wait for the lock posted form the word completion interrupt */
                SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
            }
    
            if(SPI_OPER_MODE_POLLING == object->intrPollMode)
            {
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
            }
    #else
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
    #endif
    
    
            if(wordLenBytes <= 4U)
            {
                numWords = 1U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Write the extracted data into receive buffer */
                for(idx = 0U; idx < wordLenBytes; idx++)
                {
                    /*
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
                        (0x000000FFU));
                        */
    //                if(wordLenBytes == 4)
    //                {
                        *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                               (0x000000FFU));
    //                }
    //                else
    //                {
    //                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
    //                                        (0x000000FFU));
    //                }
    
    
                    //uint8_t temp = dataVal[0] & 0x000000FFU;
                    if(1)//(wordLenBytes == 4))
                    {
                        //UART_printf("count = %d. i = %d. dataVal[0] = 0x%08x.  *dstAddr = 0x%02x.\n",count, anders6++, dataVal[0],*dstAddr);
    //                    UART_printf("%d. %d. 0x%02x.\n",count, anders6++, *dstAddr);
                    }
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 4U) && (wordLenBytes <= 8U))
            {
                numWords = 2U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U * ((4-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 4U; idx < wordLenBytes; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 8U) && (wordLenBytes <= 12U))
            {
                numWords = 3U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[2] >> (8U * ((4-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 4U; idx < 8U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U * ((8-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 8U; idx < wordLenBytes; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 12U) && (wordLenBytes <= 16U))
            {
                numWords = 4U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[3] >> (8U * ((4-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 4U; idx < 8U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[2] >> (8U * ((8-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
                for(idx = 8U; idx < 12U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U * ((12-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 12U; idx < wordLenBytes; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
            }
            else
            {
                /* Not supported */
            }
    
            /* Update the number of bytes to be transmitted */
            count -= wordLenBytes;
        }
        /* Update read buffer index in the object */
        object->readBufIdx = dstAddr;
    }
    
    
    static void QSPI_read_v1(SPI_Handle handle, const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;
    
        object = (QSPI_v1_Object*)handle->object;
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            QSPI_mmap_mode_read_v1(handle, transaction);
        }
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            QSPI_cmd_mode_read_v1(handle, transaction);
        }
    }
    
    
    
    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;
    
        /* 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 = (const 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));
    
        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--;
        }
    
        /* 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);
        }
    }
    
    
    static void QSPI_cmd_mode_write_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;    /* QSPI hardware attributes */
        uint32_t count = 0U;         /* transfer length in bytes */
        uint32_t wordLenBytes = 0U;  /* Word length in number of bytes */
        uint32_t cmd = 0;           /* transmit command */
        uint32_t dataVal[4] = {0U, 0U, 0U, 0U};  /* data to be written */
        uint32_t idx, idx1, idx2, idx3;          /* indexes */
        uint32_t numWords = 0U;                  /* number of words */
        uint8_t *srcAddr;                      /* Source address */
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        srcAddr = object->writeBufIdx;
    
        /* formulate the command */
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FLEN, (object->frmLength - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WLEN, (object->qspiParams.dataSize - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CSNUM, hwAttrs->chipSelect);
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
            QSPI_SPI_CMD_REG_CMD_FOUR_PIN_WRITE_SINGLE);
    
    
        /* Enable interrupts in the polling mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, true);
    #else
            /* Enable frame count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, true);
    #endif
    
        }
        else
        {
            /* Disable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, false);
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, false);
        }
    
    
        /* Extract frame length in bytes */
        count = transaction->count;
    
        /* Extract word length in number of bytes */
        wordLenBytes = (object->qspiParams.dataSize >> 3U);
    
        /* Write the data into shift registers */
        while(count)
        {
            dataVal[0] = 0;
            dataVal[1] = 0;
            dataVal[2] = 0;
            dataVal[3] = 0;
    
            if(wordLenBytes <= 4U)
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < wordLenBytes; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 1U;
            }
            else if((wordLenBytes > 4U) && (wordLenBytes <= 8U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < wordLenBytes; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 2U;
            }
            else if((wordLenBytes > 8U) && (wordLenBytes <= 12U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    dataVal[2] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 3U;
            }
            else if((wordLenBytes > 12U) && (wordLenBytes <= 16U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    dataVal[2] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx3 = 12U; idx3 < 16U; idx3++)
                {
                    dataVal[3] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 4U;
            }
            else
            {
                /* Not supported */
            }
    
            /* Write data to data registers */
            QSPIwriteData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
            /* Write tx command to command register */
            QSPIsetCommandReg(hwAttrs->baseAddr, cmd);
    
    #ifdef WORD_INTERRUPT
            /* interrupt mode */
            if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
            {
                /* wait for the lock posted form the word completion interrupt */
                SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
            }
    
            if(SPI_OPER_MODE_POLLING == object->intrPollMode)
            {
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
            }
    #else
    
            /* Wait for the QSPI busy status */
            QSPIWaitIdle(hwAttrs->baseAddr);
    #endif
    
    
            /* Update the number of bytes to be transmitted */
            count -= wordLenBytes;
        }
    
        /* Update write buffer index in the object */
        object->writeBufIdx = srcAddr;
    }
    
    
    static void QSPI_write_v1(SPI_Handle handle, const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;         /* QSPI object */
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            QSPI_mmap_mode_write_v1(handle, transaction);
        }
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            QSPI_cmd_mode_write_v1(handle, transaction);
        }
    }
    
    
    /*
     *  ======== i2c_am57x_transfer ========
     */
    static bool QSPI_transfer_v1(SPI_Handle handle, SPI_Transaction *transaction)
    {
        bool  ret = false;                /* return value */
        QSPI_v1_Object   *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;     /* QSPI hardware attributes */
    
        /* Input parameter validation */
        if ((handle != NULL) && (transaction != NULL))
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Check if anything needs to be written or read */
        if (0 != transaction->count)
        {
            transaction->status=SPI_TRANSFER_STARTED;
    		/* Acquire the lock for this particular I2C handle */
            SPI_osalPendLock(object->mutex, SemaphoreP_WAIT_FOREVER);
    
            /* Book keeping of transmit and receive buffers. */
            object->writeBufIdx = (uint8_t *)transaction->txBuf;
            object->writeCountIdx = transaction->count;
            object->readBufIdx =  (uint8_t *)transaction->rxBuf;
            object->readCountIdx = transaction->count;
    
    
             /*
             * QSPI_primeTransfer_v1 is a longer process and
             * protection is needed from the QSPI interrupt
             */
            if (SPI_OPER_MODE_POLLING != object->intrPollMode)
            {
                SPI_osalHardwareIntrEnable(hwAttrs->eventId,hwAttrs->intrNum);
            }
    
            QSPI_primeTransfer_v1(handle, transaction);
    
            if (object->intrPollMode == SPI_OPER_MODE_BLOCKING) {
    #ifdef WORD_INTERRUPT
                /* transfer is completed and semaphore is posted. */
                ret = (bool)true;
    #else
                /* If the word count is zero then wait for semaphore */
                if(object->frmLength == QSPIgetStatusWordCount(hwAttrs->baseAddr))
                {
                  /* wait for the lock posted form the word completion interrupt */
                  SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
                }
    
                /* transfer is completed and semaphore is posted. */
    			transaction->status=SPI_TRANSFER_COMPLETED;
                ret = (bool)true;
    #endif
            }
            else {
                /* Always return true if in Asynchronous mode */
                ret = (bool)true;
            }
    
            /* Release the lock for this particular I2C handle */
            SPI_osalPostLock(object->mutex);
        } else {
    	   transaction->status=SPI_TRANSFER_CANCELED;
    	}
        }
    
        /* Return the number of bytes transferred by the I2C */
        return (ret);
    }
    
    /*
     *  ======== QSPI_transferCallback_v1 ========
     */
    static void QSPI_transferCallback_v1(SPI_Handle handle, SPI_Transaction *msg)
    {
        QSPI_v1_Object   *object;            /* QSPI object */
    
        /* Get the pointer to the object */
        object = (QSPI_v1_Object*)handle->object;
    
        if(msg!=NULL) {
    	   msg->status=SPI_TRANSFER_COMPLETED;
    	}
    	
    	/* Indicate transfer complete */
        SPI_osalPostLock(object->transferComplete);
    }
    
    /*
     *  ======== QSPI_control_v1 ========
     */
    static int32_t QSPI_control_v1(SPI_Handle handle, uint32_t cmd, const void *arg)
    {
        QSPI_v1_Object   *object;            /* QSPI object */
        int32_t retVal = SPI_STATUS_ERROR;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object */
        object = (QSPI_v1_Object*)handle->object;
    
        switch (cmd)
        {
            case SPI_V1_CMD_SETFRAMELENGTH:
            {
                object->frmLength = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_MMAP_TRANSFER_CMD:
            {
                object->transferCmd = *(uint8_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_TRANSFERMODE_RW:
            {
                object->transactionType = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETCONFIGMODE:
            {
                object->qspiMode = QSPI_OPER_MODE_CFG;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETRXLINES:
            {
                object->rxLines = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETMEMMORYMAPMODE:
            {
                object->qspiMode = QSPI_OPER_MODE_MMAP;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            default:
            retVal = SPI_STATUS_UNDEFINEDCMD;
            break;
        }
        }
    
        return retVal;
    }
    
    
    /*
     *  ======== QSPI_transferCancel_v1 ========
     */
    static void QSPI_transferCancel_v1(SPI_Handle handle)
    {
        return;
    }
    

    Best Regards,

    Anders Viken.

  • An example of using cfg write single and mmap read quad:

    // Anders debug: use config mode for file transfer to flash (page programming).
    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);


    SPI_log("Begin flashing '%s' into Flash\n", fileName);
    if ((ret = SBL_qspiFlashWrite(&flashHandle, (uint8_t *) destAddr, length, offsetAddr)))
    {
    SPI_log("SBL_qspiFlash: received ERROR %d\n", ret);
    //return -1;
    }
    else
    {
    SPI_log("Finished flashing '%s' with size %d kB at offset 0x%08X\n", fileName, length/1024, offsetAddr);
    }

    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);
    //SPI_log("Reading. Using Memory Map Mode.\n");

    // SPI_log("Reading and verifying flashed image\n");
    if ((ret = SBL_qspiFlashRead(&flashHandle, (uint8_t *) checkAddr, length, offsetAddr)))
    {
    SPI_log("SBL_qspiFlash: received ERROR %d\n", ret);
    }
    else
    {
    // SPI_log("Finished reading flashed image! \n");
    }

  • Thanks for your response, I do agree that it is slow so I will confirm that it is okay to write in config mode.

    I have done some preliminary testing and it looks as though it is working.

    I did have to edit something in S25FL.c however to get it to work. (It never sets the return value to true) 

    I just added two `retVal = ` otherwise it always returned false even if it worked.

    if(QSPI_OPER_MODE_CFG == object->qspiMode)
    {
        offsetValue = *((uint32_t *)dstOffstAddr);
        //SPI_log("In function SF25FL_bufferWrite. (cfg mode) 2\n");
         /*
         * 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)
        {
            retVal = SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
            *((uint32_t *)dstOffstAddr) += 256;
            srcAddr += 256;
            length -= 256;
        }
        if(length > 0)
        {
            retVal = SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
        }
        *((uint32_t *)dstOffstAddr) = offsetValue;
    }
    

    Thanks for all of everyone's help. 

    If anyone wants any of my code in case it helps their development, let me know.

    Regards,

    Chris

  • ,

    After Further testing, I have a question:

    I am trying to do direct memory reads instead of block reads.

    So in my read/write I pass the address in the block I want to access.

    In essence: instead of the address being 0x00000U, I make the address : (63* S25FL_FLASH_BLOCK_SIZE) and it works perfectly.

    However, I am back to the same issue when the number is bigger than 63. When the number is 64 or more, it does the write and read "successfully", but the data returned from the read is not even close to what it should be.

    Has anyone attacked this using direct memory read and write?


  • Did you try to use memory map mode read, as I suggested. As I see it, that is a way of "direct memory reads", as you can choose the address offset on flash, and the length to read from that address. Try reading in single line mode first, before attacking the quad mode issue. It will be slow, but you will read correct data (use the S25FL.c file i attached earlier). Then, enable quad mode when reading. It will still be slow, but faster than single line mode. Then, if you need more speed, you can use up to 128 bit transfers, instead of 8 bit transfers (take a look at the QSPI_v1 file attached earlier).
    I'm not sure about the > 64 issue you are having, I have not seen that while using my code files (and I have done alot of testing). There is as mentioned a problem with addresses that should be "byte flipped around". Try to make a diff between your and mine S25FL.c file..

    A tip when testing, try writing 0x01 in all the bytes in the first block (S25FL_FLASH_BLOCK_SIZE), 0x02 in all the bytes in the second block, etc.., you might find out something when reading back.

    Anders.
  • ,  

    I am using your S2FL.c file (Anders). It's improvements have helped me come this far. (only in config mode. I have not seen any changes to MMAP mode.)

    Here are a few conclusions I have come too:

    1. In order to be able to read/write in QSPI_OPER_MODE_MMAP, you must leave out this snippet upon initialization:

    m_qSpiMode = QSPI_OPER_MODE_MMAP;
    SPI_control(m_spiHandle, SPI_V1_CMD_SETCONFIGMODE, (void *)&m_qSpiMode);

    It seems that the default is MMAP mode, and this line of code somehow sets it to config mode. 

    2. When operating in QSPI_OPER_MODE_MMAP, you can only write up to block 63. I have done what you suggested with writing and reading of values to the corresponding blocks. It seems at any point up to the number 63 it works correctly. (FYI, the math I am doing for MMAP mode is: 63 * S25FL_FLASH_BLOCK_SIZE) When you replace the 63 with a 64, it fails here under SF25FL_bufferWrite(........):

    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;
        }
    }

    I have figured out what I believe to be the fix for the write: Here is the updated code to what I believe to be the fix.

    if(QSPI_OPER_MODE_MMAP == object->qspiMode)
    {
        tempAddr = ((dstOffstAddr & 0xFF000000) >> 24) |
                   ((dstOffstAddr & 0x00FF0000) >> 8)  |
                   ((dstOffstAddr & 0x0000FF00) << 8)  |
                   ((dstOffstAddr & 0x000000FF) << 24);
    
        for(idx = 0; idx < length; idx++)
        {
            /* Write enable */
            S25FLFlash_WriteEnable(flashHandle);
    
            /* Perform the transfer */
            transaction.txBuf = (unsigned char *)tempAddr;//(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));
    
            tempAddr += 1;
            dstOffstAddr += 1;
            srcAddr += 1;
        }
    }

    3. Same as 2. but read fails as well. In function SF25FL_bufferRead(...)

    if(QSPI_OPER_MODE_MMAP == object->qspiMode)
    {
        switch(object->rxLines)
        {
            case QSPI_RX_LINES_SINGLE:
            {
                //deleted this to save room on post.
            }
    
            case QSPI_RX_LINES_DUAL:
            {
                //deleted this to save room on post.
            }
    
            case QSPI_RX_LINES_QUAD:
            {
                //deleted this to save room on post.
            }
    
            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);
    }

    I have figured out what I believe to be the fix for the read: Here is the updated code to what I believe to be the fix.

    if(QSPI_OPER_MODE_MMAP == object->qspiMode)
    {
    	/* Copy flash transaction parameters to local variables */
    	dstOffstAddr = flashTransaction->address;
    	srcAddr = flashTransaction->data;
    	length = flashTransaction->dataSize;
    
    	switch(object->rxLines)
    	{
    		case QSPI_RX_LINES_SINGLE:
    		{
    			//Deleted to save room for post.
    		}
    
    		case QSPI_RX_LINES_DUAL:
    		{
    			//Deleted to save room for post.
    		}
    
    		case QSPI_RX_LINES_QUAD:
    		{
    			//Deleted to save room for post.
    		}
    
    		default:
    		break;
    	}
    
    	tempAddr = ((dstOffstAddr & 0xFF000000) >> 24) |
    		   ((dstOffstAddr & 0x00FF0000) >> 8)  |
    		   ((dstOffstAddr & 0x0000FF00) << 8)  |
    		   ((dstOffstAddr & 0x000000FF) << 24);
    
    	/* Perform the transfer */
    	transaction.txBuf = (unsigned char *)tempAddr;
    	transaction.rxBuf = srcAddr;
    	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);
    }

    The reason I reassigned the variables how there are within the if statement is because I did not want to affect config mode. This is solely a fix for MMAP mode.

     

    TO CLARIFY: This has only been tested with 3 byte address mode. Meaning that you can write blocks 0 - 255. I will next be trying to tackle 4 byte address mode and see if I can get that to work. If time permits on my project I will try to see if I can further improve Config Mode.

    I have attached my S25FL.c file which is the same as yours with some improvements to MMAP mode options.

    /**
     *  \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>
    #include <ti/drv/spi/test/qspi_flash/src/SPI_log.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;
        uint32_t tempAddr;
        /* 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;
    
        //SPI_log("In function SF25FL_bufferWrite. 1\n");
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            offsetValue = *((uint32_t *)dstOffstAddr);
            //SPI_log("In function SF25FL_bufferWrite. (cfg mode) 2\n");
            /*
             * 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)
            {
               retVal = SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
                *((uint32_t *)dstOffstAddr) += 256;
                srcAddr += 256;
                length -= 256;
            }
            if(length > 0)
            {
                retVal = SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
            }
            *((uint32_t *)dstOffstAddr) = offsetValue;
        }
    
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            tempAddr = ((dstOffstAddr & 0xFF000000) >> 24) |
                       ((dstOffstAddr & 0x00FF0000) >> 8)  |
                       ((dstOffstAddr & 0x0000FF00) << 8)  |
                       ((dstOffstAddr & 0x000000FF) << 24);
    
            for(idx = 0; idx < length; idx++)
            {
                /* Write enable */
                S25FLFlash_WriteEnable(flashHandle);
    
                /* Perform the transfer */
                transaction.txBuf = (unsigned char *)tempAddr;//(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));
    
                tempAddr += 1;
                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 */
        srcAddr = (unsigned char *)flashTransaction->address;
        dstOffstAddr = (uint32_t)flashTransaction->data;
        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)
        {
            /* Copy flash transaction parameters to local variables */
            dstOffstAddr = flashTransaction->address;
            srcAddr = flashTransaction->data;
            length = flashTransaction->dataSize;
    
            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;
            }
    
            tempAddr = ((dstOffstAddr & 0xFF000000) >> 24) |
                       ((dstOffstAddr & 0x00FF0000) >> 8)  |
                       ((dstOffstAddr & 0x0000FF00) << 8)  |
                       ((dstOffstAddr & 0x000000FF) << 24);
    
            /* Perform the transfer */
            transaction.txBuf = (unsigned char *)tempAddr;
            transaction.rxBuf = srcAddr;
            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 */
        uint8_t norStatus = 0xFF;             /* flash status value */
        uint8_t configReg = 0xFF;             /* configuration register value */
        //uint32_t configReg2 = 0xFFFFFFFF;   //for test          /* configuration register 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);
    
    #define READ_STATUS_BEFORE
    #ifdef READ_STATUS_BEFORE
        /* 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);
        //SPI_log("read status reg 1. time: norStatus: 0x%08X.\n",norStatus);
    
        /* 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);
    
        //SPI_log("read configReg reg 1. time: configReg: 0x%08X.\n",configReg);
    #endif
    
        /* Set 2nd bit of configuration register to 1 to enable quad mode */
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* Wait */
        while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
    
        /* Set transfer length in bytes */
        frmLength = 3;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        // WRITING INSTRUCTION
        writeVal = QSPI_LIB_CMD_WRITE_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);
    
        /* Wait till the status register is being written */
        //while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
        // WRITING STATUS REGISTER
    
        /* Flash write enable */
        // setting status reg to 0, for testing
        //norStatus = 0;
        writeVal = (unsigned char)norStatus;
    
        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);
    
        /* Wait till the status register is being written */
        //while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
    
        // WRITING COMMAND REGISTER
    
        //data = (QSPI_LIB_CMD_WRITE_STATUS_REG << 16) | (norStatus << 8) | configReg;
    
    
        // setting cfg reg to 0, for testing
        //configReg = 0;
        //SPI_log("configReg before changing value: 0x%08X.\n",configReg);
        configReg |= (QSPI_FLASH_QUAD_ENABLE_VALUE << QSPI_FLASH_QUAD_ENABLE_BIT);
        //configReg &= ~(1 << 1); // test for setting quad bit to 0.
    
        //SPI_log("configReg after changing value: 0x%08X.\n",configReg);
    
        writeVal = (unsigned char)configReg;
    
        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);
    
        //SPI_log("Before wait.\n");
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
        //SPI_log("After waiting for status reg to be written.\n");
    
    
    #ifdef READ_STATUS_AFTER
    //Anders debug read status reg 2. time starts
    
        /* 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 *)&configReg2;
        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("configReg2 when reading 2. time: 0x%08X.\n",configReg2);
    
    
    //Anders debug read status reg 2. time ends
    #endif
        /* 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;
    }
    

  • ,

    After further testing of QSPI_v1.c, I have run into a few issues.

    First, in: QSPI_mmap_mode_read_v1 there is a line of code that takes the already byte flipped address and checks to see if its bigger than 16MB. Shown below:

    This will always fail because the address has been byte flipped. So if the address was 0x01000000, and you did the byte flop which is required to get things working, it would change it to 0x00000001. While this does require 4 byte addressing, it will never pass.

    • This is in both the read and write functions of QSPI_v1.c
      • static void QSPI_mmap_mode_read_v1(SPI_Handle handle,const SPI_Transaction *transaction)
      • static void QSPI_mmap_mode_write_v1(SPI_Handle handle,const SPI_Transaction *transaction)

    The way I fixed this was to byte flip the address back as such:

    This now ensures that the address 0x01000000 will in fact be that when checking to see if 4 address bytes are needed.

    However it fails on this line in that same read_v1 function:

    It also fails at this same line when in:

    • QSPI_RX_LINES_SINGLE
    • QSPI_RX_LINES_DUAL
    • QSPI_RX_LINES_QUAD

    Any input to help me solve this problem would be greatly appreciated.

  • Hi Chris Taylor90 (5797900)

    I have previously only tested with less than 16 MB, so I have never got to test the if(offset > 0xFFFFFF) tests. But it seems like you are right:

    • If you start on an address offset on flash smaller than 16 MB, and write/read ONLY on address offsets < 16 MB, the code should work fine. ( 3 byte address mode is selected).
    • If you start on an address offset on flash greater than 16 MB, and write/read ONLY on address offsets > 16 MB, the code should work fine. (4 byte address mode is selected).
    • If, however, as I think is the case for you, you start with an address offset < 16 MB (<= 0xFFFFFF), and some of the data to read/write is > 16 MB, 3 byte address mode will be used, and therefore the program will start to read/write from offset 0 on flash (instead of 0x01000000).

    A solution / workaround would be to ALWAYS use 4 byte addressing. It seems like the 3 Byte addressing mode is used for backward compatibility, and that it should be fine to use 4 byte addressing mode, even when using an address offset < 16MB. So instead of having the  if(offset > 0xFFFFFF) tests in the code, use 4B commands. And also set addrLengthInBytes = 4.

    Let me now if this helps, I would like to implement this in my codebase as well.

    Anders.

  • ,

    With some frustration and testing I have reached this point.

    Let me first back up: In my previous posts I had been doing byte address flipping in MMAP mode. It occurred to me that this is NOT OKAY. Memory Mapped mode should be 1 to 1. Due to this, I removed all byte flipping from memory mapped mode.

    First, it was required to setup the MMU correctly allowing more than 16 MB.  Default config on mine was only 16, so I added this (in my BoardInit.c) which allows all 64 MB to be accessed.

    This solved my problem of not being able to access anything greater than 63. 

    I am now ****able**** to write up to block 1024 which is 64MB.

    The reason 'able' is starred is because I can write and read from there but the read does not return the correct data.

    Here is a sample run through of my program THAT WORKS:

    Block Number I want to access: 255. So the memory mapped address is (255 * S25FL_FLASH_BLOCK_SIZE)  Decimal: [16,711,680]  Hex: [FF 0000]

    It travels all the way down to drivers to the Function:

    For reference, at this point in time: (I am writing 12 values [12,11,10,...1] into flash memory at block 255, as shown in the pDst.

     And the QSPI_QPSI_SETUP_REG_0 reads:  00120203h (Which is correct at this point in time because this address is less than 0xFFFFFF) [We are currently in 3 Byte address mode]

    Then I progress and let the SPI write 1 byte at a time. 

    Then I get to the read.

    At this point in time for reference:

    This shows that in flash the 12 is correct because again I should be reading from 12-1 from flash into a buffer.

    As I progress through the read, I can see the above pointers incrementing correctly. Shown:

    I let the read finish, I do the VerifyData function and it is successful.


    Now we get to the breaking point. For this example I am going to change the block I am trying to access from 255 to 256.

     

    Here is a sample run through of my program THAT DOES NOT WORK:

    Block Number I want to access: 256. So the memory mapped address is (256 * S25FL_FLASH_BLOCK_SIZE)  Decimal: [16,777,216]  Hex: [100 0000] which is exactly 16 MB.

    So I progress to the Write function (same one as above) and for reference here is the variables:

    So again, it seems to me that the variables are correctly pointed.

    Then comes the QSPI_QSPI_SETUP_REG_0 which still read 00120203h until the offset is checked:


    After this the register reads: 00120303h which is correct, it has now entered 4 byte mode.

    Now following this register change, it does the write to memory:

    My variables (pDst and pSrc) are still the same as shown above with the highlighted pDst.

    However, Once I execute this line of code [*pDst = *pSrc] the values should change, but they are still:

    When looking at actual memory, the value did not change either:

    That highlighted portion should read FFFFFF0C (AFTER FURTHER TESTING, YOU CANNOT TRUST THE VIRTUAL MEMORY MAP FOR ANYTHING OVER THE ORIGINALLY ALLOTTED 16 MB)

    After it executes the single loop through that shown while loop, it does another check to set back into 3 byte address mode.


    Now it does the read function: Copies everything back over correctly I think.


    After this, it travels all the way back up.  I have some testing on the top layer and here is my response:

    I have not been able to figure out why the first entry is incorrect. 

    I read the data back from flash front and backward and still come up with this result.

    Due to this, my thoughts are that the error is in the read.

    I have attached my relevant files with the change so you diff them if you would like.

    Any input on this would be awesome.

    /**
     *  \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>
    #include <ti/drv/spi/test/qspi_flash/src/SPI_log.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;
        uint32_t tempAddr;
        /* 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;
    
        //SPI_log("In function SF25FL_bufferWrite. 1\n");
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            offsetValue = *((uint32_t *)dstOffstAddr);
            //SPI_log("In function SF25FL_bufferWrite. (cfg mode) 2\n");
            /*
             * 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)
            {
               retVal = SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, 256, flashHandle);
                *((uint32_t *)dstOffstAddr) += 256;
                srcAddr += 256;
                length -= 256;
            }
            if(length > 0)
            {
                retVal = SF25FL_ConfigMode_Write(dstOffstAddr, srcAddr, length, flashHandle);
            }
            *((uint32_t *)dstOffstAddr) = offsetValue;
        }
    
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            if (dstOffstAddr > 0xFFFFFFU)
            {
                transferCmd  = QSPI_LIB_CMD_PAGE_PRG_4B;
                S25FLFlash_Enable4ByteAddrMode(flashHandle, true);
            }
            else
            {
                transferCmd  = QSPI_LIB_CMD_PAGE_PRG;
            }
    
    
            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;
    
                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;
            }
    
            if (dstOffstAddr > 0xFFFFFFU)
            {
                S25FLFlash_Enable4ByteAddrMode(flashHandle, false);
            }
        }
        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 */
        srcAddr = (unsigned char *)flashTransaction->address;
        dstOffstAddr = (uint32_t)flashTransaction->data;
        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)
        {
            /* Copy flash transaction parameters to local variables */
            dstOffstAddr = flashTransaction->address;
            srcAddr = flashTransaction->data;
            length = flashTransaction->dataSize;
    
            /* Enable 4 byte addr mode */
            if(flashTransaction->address > 0xFFFFFF)
            {
                S25FLFlash_Enable4ByteAddrMode(flashHandle, true);
            }
    
            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 = (unsigned char *)dstOffstAddr;
            transaction.rxBuf = srcAddr;
            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);
    
            if(flashTransaction->address > 0xFFFFFF)
            {
                S25FLFlash_Enable4ByteAddrMode(flashHandle, false);
            }
    
        }
    
        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 */
        uint8_t norStatus = 0xFF;             /* flash status value */
        uint8_t configReg = 0xFF;             /* configuration register value */
        //uint32_t configReg2 = 0xFFFFFFFF;   //for test          /* configuration register 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);
    
    #define READ_STATUS_BEFORE
    #ifdef READ_STATUS_BEFORE
        /* 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);
        //SPI_log("read status reg 1. time: norStatus: 0x%08X.\n",norStatus);
    
        /* 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);
    
        //SPI_log("read configReg reg 1. time: configReg: 0x%08X.\n",configReg);
    #endif
    
        /* Set 2nd bit of configuration register to 1 to enable quad mode */
    
        /* Flash write enable */
        S25FLFlash_WriteEnable(flashHandle);
    
        /* Wait */
        while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
    
        /* Set transfer length in bytes */
        frmLength = 3;
        SPI_control(handle, SPI_V1_CMD_SETFRAMELENGTH, (void *)&frmLength);
    
        // WRITING INSTRUCTION
        writeVal = QSPI_LIB_CMD_WRITE_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);
    
        /* Wait till the status register is being written */
        //while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
        // WRITING STATUS REGISTER
    
        /* Flash write enable */
        // setting status reg to 0, for testing
        //norStatus = 0;
        writeVal = (unsigned char)norStatus;
    
        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);
    
        /* Wait till the status register is being written */
        //while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
    
        // WRITING COMMAND REGISTER
    
        //data = (QSPI_LIB_CMD_WRITE_STATUS_REG << 16) | (norStatus << 8) | configReg;
    
    
        // setting cfg reg to 0, for testing
        //configReg = 0;
        //SPI_log("configReg before changing value: 0x%08X.\n",configReg);
        configReg |= (QSPI_FLASH_QUAD_ENABLE_VALUE << QSPI_FLASH_QUAD_ENABLE_BIT);
        //configReg &= ~(1 << 1); // test for setting quad bit to 0.
    
        //SPI_log("configReg after changing value: 0x%08X.\n",configReg);
    
        writeVal = (unsigned char)configReg;
    
        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);
    
        //SPI_log("Before wait.\n");
    
        /* Wait till the status register is being written */
        while (1U == (FlashStatus(flashHandle) & 0x1U)){};
    
        //SPI_log("After waiting for status reg to be written.\n");
    
    
    #ifdef READ_STATUS_AFTER
    //Anders debug read status reg 2. time starts
    
        /* 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 *)&configReg2;
        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("configReg2 when reading 2. time: 0x%08X.\n",configReg2);
    
    
    //Anders debug read status reg 2. time ends
    #endif
        /* 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 = 0x35U;// 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;
    }
    

    /**
     *  \file   QSPI_v1.c
     *
     *  \brief  QSPI IP Version 1 specific driver APIs implementation.
     *
     *   This file contains the driver APIs for QSPI controller.
     */
    
    /*
     * Copyright (C) 2014-2015 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 <stdint.h>
    #include <stddef.h>
    #include <stdbool.h>
    #include <ti/drv/spi/SPI.h>
    #include <ti/drv/spi/soc/QSPI_v1.h>
    #include <ti/csl/src/ip/qspi/V1/qspi.h>
    #include <ti/csl/src/ip/qspi/V1/hw_qspi.h>
    #include <ti/drv/spi/src/SPI_osal.h>
    
    
    #include <ti/drv/spi/test/qspi_flash/src/SPI_log.h>
    
    /*#define WORD_INTERRUPT*/
    
    /* QSPI AM57x functions */
    static void       QSPI_close_v1(SPI_Handle handle);
    static void       QSPI_init_v1(SPI_Handle handle);
    static SPI_Handle QSPI_open_v1(SPI_Handle handle, const SPI_Params *params);
    static bool       QSPI_transfer_v1(SPI_Handle handle,
                                          SPI_Transaction *transaction);
    static void       QSPI_primeTransfer_v1(SPI_Handle handle,
                                              const SPI_Transaction *transaction);
    static void       QSPI_transferCallback_v1(SPI_Handle handle,
                                                  SPI_Transaction *msg);
    static int32_t QSPI_control_v1(SPI_Handle handle, uint32_t cmd, const void *arg);
    static void QSPI_transferCancel_v1(SPI_Handle handle);
    static void QSPI_hwiFxn_v1(uintptr_t arg);
    static void QSPI_read_v1(SPI_Handle handle, const SPI_Transaction *transaction);
    static void QSPI_write_v1(SPI_Handle handle, const SPI_Transaction *transaction);
    static void QSPI_mmap_mode_write_v1(SPI_Handle handle,
                                        const SPI_Transaction *transaction);
    static void QSPI_cmd_mode_write_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction);
    static void QSPI_cmd_mode_read_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction);
    static void QSPI_mmap_mode_read_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction);
    static void QSPIMmapCsEnable(uint32_t baseAddr, uint32_t chipSelect);
    
    typedef enum QSPI_intrPollMode_s {
        SPI_OPER_MODE_BLOCKING = 0U,  /*! Interrupt based blocking mode */
        SPI_OPER_MODE_POLLING,        /*! Non interrupt based blocking mode */
        SPI_OPER_MODE_CALLBACK        /*! Interrupt based call back mode */
    } QSPI_intrPollMode;
    
    
    
    /* SPI function table for QSPI AM57x implementation */
    const SPI_FxnTable QSPI_FxnTable_v1 = {
        &QSPI_close_v1,
        &QSPI_control_v1,
        &QSPI_init_v1,
        &QSPI_open_v1,
        &QSPI_transfer_v1,
        &QSPI_transferCancel_v1,
        NULL
    };
    
    #define   CTRL_CORE_CONTROL_IO_2       (0x4A002558U)
    #define   QSPI_MMAP_CS_SHIFT           (0x8U)
    
    /*
     *  ======== QSPI_close_v1 ========
     */
    static void QSPI_close_v1(SPI_Handle handle)
    {
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Mask I2C interrupts */
        QSPIintDisable(hwAttrs->baseAddr,
            (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD));
    
        /* Destruct the Hwi */
        if(SPI_OPER_MODE_POLLING != object->intrPollMode)
        {
            SPI_osalHardwareIntDestruct(object->hwi,hwAttrs->eventId);
        }
    
        /* Destruct the instance lock */
        SPI_osalDeleteBlockingLock(object->mutex);
    
        /* Destruct the transfer completion lock */
        if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
        {
            SPI_osalDeleteBlockingLock(object->transferComplete);
        }
    
        /* Open flag is set false */
        object->isOpen = (bool)false;
        }
    
        return;
    }
    
    /*
     *  ======== QSPI_hwiFxn_v1 ========
     *  Hwi interrupt handler to service the QSPI peripheral
     *
     *  The handler is a generic handler for a QSPI object.
     */
    static void QSPI_hwiFxn_v1(uintptr_t arg)
    {
        uint32_t            intrStatus;
        QSPI_v1_Object      *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)(((SPI_Handle)arg)->object);
        hwAttrs = (const QSPI_HwAttrs *)(((SPI_Handle)arg)->hwAttrs);
    
        /* Read the interrupt status register */
        intrStatus = QSPIintStatus(hwAttrs->baseAddr);
    
        /* If word count interrupt */
        if(intrStatus & QSPI_INTR_MASK_WORD)
        {
            /* Clear interrupt status */
            QSPIintClear(hwAttrs->baseAddr, QSPI_INTR_MASK_WORD);
    
            /* Call the call back function */
            object->qspiParams.transferCallbackFxn((SPI_Handle)arg, NULL);
        }
    
        /* If word count interrupt */
        if(intrStatus & QSPI_INTR_MASK_FRAME)
        {
            /* Clear interrupt status */
            QSPIintClear(hwAttrs->baseAddr, QSPI_INTR_MASK_FRAME);
    
            /* Call the call back function */
            object->qspiParams.transferCallbackFxn((SPI_Handle)arg, NULL);
        }
    
        return;
    }
    
    /*
     *  ======== QSPI_init_v1 ========
     */
    static void QSPI_init_v1(SPI_Handle handle)
    {
        /* Input parameter validation */
        if (handle != NULL)
        {
            /* Mark the object as available */
            ((QSPI_v1_Object *)(handle->object))->isOpen = (bool)false;
        }
    }
    
    
    /*
     *  ======== QSPI_open_v1 ========
     */
    static SPI_Handle QSPI_open_v1(SPI_Handle handle, const SPI_Params *params)
    {
    
    #ifdef anders
        SemaphoreP_Params     semParams;
        uint32_t       key;
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs /*const*/  *hwAttrs = NULL;
        OsalRegisterIntrParams_t interruptRegParams;
        uint8_t ret_flag = 0u;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
    #ifdef TEST_QSPI
        hwAttrs = (/*const*/ QSPI_HwAttrs *)handle->hwAttrs;
        hwAttrs->intrNum = 135;
    #endif
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    #endif
    
        SemaphoreP_Params     semParams;
        uint32_t       key;
        QSPI_v1_Object   *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
        OsalRegisterIntrParams_t interruptRegParams;
        uint8_t ret_flag = 0u;
    
        /* Input parameter validation */
        OSAL_Assert(handle == NULL);
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Determine if the device index was already opened */
        key = SPI_osalHardwareIntDisable();
        if(object->isOpen == (bool)true) {
            SPI_osalHardwareIntRestore(key);
            handle = NULL;
        }
        else
        {
          /* Mark the handle as being used */
          object->isOpen = (bool)true;
          SPI_osalHardwareIntRestore(key);
    
          /* Store the I2C parameters */
          if (params == NULL) {
            /* No params passed in, so use the defaults */
            SPI_Params_init(&(object->qspiParams));
          }
          else {
            /* Copy the params contents */
            object->qspiParams = *params;
          }
    
          /* Copy the controller mode from hardware attributes to object */
          object->qspiMode = hwAttrs->operMode;
          object->rxLines  = hwAttrs->rxLines;
    
          /* Extract QSPI operating mode based on hwAttrs and input parameters */
          if(SPI_MODE_BLOCKING == object->qspiParams.transferMode)
          {
            if(true == hwAttrs->intrEnable)
            {
                object->intrPollMode = SPI_OPER_MODE_BLOCKING;
            }
            else
            {
                object->intrPollMode = SPI_OPER_MODE_POLLING;
            }
          }
          else
          {
            object->intrPollMode = SPI_OPER_MODE_CALLBACK;
          }
    
    
          /* Extract the polling mode from hardware attributes. */
          if(SPI_OPER_MODE_POLLING != object->intrPollMode)
          {
            /* register interrrupt when the 1st channel of the instance is opened */
            Osal_RegisterInterrupt_initParams(&interruptRegParams);             
    
            interruptRegParams.corepacConfig.name=NULL;
            interruptRegParams.corepacConfig.priority = 0x20;
            interruptRegParams.corepacConfig.corepacEventNum = hwAttrs->eventId;
            interruptRegParams.corepacConfig.intVecNum=hwAttrs->intrNum; /* Host Interrupt vector */
            interruptRegParams.corepacConfig.isrRoutine  = (void (*)(uintptr_t))(&QSPI_hwiFxn_v1);
            interruptRegParams.corepacConfig.arg         = (uintptr_t)handle;
    
            SPI_osalRegisterInterrupt(&interruptRegParams,&(object->hwi));
    
            if(object->hwi == NULL) {
                QSPI_close_v1(handle);
                ret_flag = 1u;
                handle = NULL;
            }
          }
    
          if(ret_flag == 0u)
          {
            /*
             * Construct thread safe handles for this QSPI peripheral
             * Semaphore to provide exclusive access to the QSPI peripheral
             */
            SPI_osalSemParamsInit(&semParams);
            semParams.mode = SemaphoreP_Mode_BINARY;
            object->mutex = SPI_osalCreateBlockingLock(1U, &semParams);
    
            /*
             * Store a callback function that posts the transfer complete
             * semaphore for synchronous mode
             */
            if (object->intrPollMode == SPI_OPER_MODE_BLOCKING) {
              /*
               * Semaphore to cause the waiting task to block for the QSPI
               * to finish
               */
              object->transferComplete = SPI_osalCreateBlockingLock(0, &semParams);
    
              /* Store internal callback function */
              object->qspiParams.transferCallbackFxn = &QSPI_transferCallback_v1;
            }
            if(object->intrPollMode == SPI_OPER_MODE_CALLBACK){
              /* Check to see if a callback function was defined for async mode */
              OSAL_Assert(object->qspiParams.transferCallbackFxn == NULL);
            }
    
            /* Setting IDLE mode for QSPI controller */
            QSPIconfigIdleMode(hwAttrs->baseAddr, QSPI_SYSCONFIG_IDLE_MODE_NO_IDLE);
    
            /* Set clock mode in mode 3 */
            QSPISetClkMode(hwAttrs->baseAddr, hwAttrs->chipSelect, hwAttrs->frmFmt);
            QSPISetCsPol(hwAttrs->baseAddr, hwAttrs->chipSelect, hwAttrs->csPol);
            QSPISetDataDelay(hwAttrs->baseAddr, hwAttrs->chipSelect,
                              hwAttrs->dataDelay);
    
            /* Enable clock and set divider value */
            QSPISetPreScaler(hwAttrs->baseAddr, 0x0U);
    
            /* Clear the interrupts and interrupt status */
            QSPIintDisable(hwAttrs->baseAddr,
                (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD)) ;
            QSPIintClear(hwAttrs->baseAddr,
                (QSPI_INTR_MASK_FRAME | QSPI_INTR_MASK_WORD));
    
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr,
                          hwAttrs->chipSelect,
                          QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
    
            /* Enable memory mapped port by default */
            QSPISetMemAddrSpace(hwAttrs->baseAddr,
                    hwAttrs->chipSelect,
                    QSPI_MEM_MAP_PORT_SEL_MEM_MAP_PORT);
    
    
            QSPIMmapCsEnable(hwAttrs->baseAddr, hwAttrs->chipSelect);
    
            /* Return the address of the spiObjectArray[i] configuration structure */
          }
        }
        //}
        return(handle);
    }
    
    static void QSPIMmapCsEnable(uint32_t baseAddr, uint32_t chipSelect)
    {
    #if !defined(SOC_AM437x)
        uint32_t regVal;
    
        regVal = HW_RD_REG32(CTRL_CORE_CONTROL_IO_2);
        regVal |= ((chipSelect + 1U) << QSPI_MMAP_CS_SHIFT);
        HW_WR_REG32(CTRL_CORE_CONTROL_IO_2, regVal);
    #endif
    }
    
    /*
     *  ======== QSPI_primeTransfer_v1 =======
     */
    static void QSPI_primeTransfer_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;
        QSPI_HwAttrs const  *hwAttrs = NULL;
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Store the new internal counters and pointers */
        object->writeBufIdx = (uint8_t*)transaction->txBuf;
        object->writeCountIdx = transaction->count;
    
        object->readBufIdx = (uint8_t*)transaction->rxBuf;
        object->readCountIdx = transaction->count;
    
    
        /* Interrupt mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable the word count interrupt */
            QSPIintEnable(hwAttrs->baseAddr, QSPI_INTR_MASK_WORD);
    #else
            /* Enable the frame count interrupt */
            QSPIintEnable(hwAttrs->baseAddr, QSPI_INTR_MASK_FRAME);
    #endif
        }
    
        /* Polling Mode */
        if(object->intrPollMode == SPI_OPER_MODE_POLLING)
        {
            /* No Specific implementation is needed here. */
        }
    
        /* Identify the direction of transfer (whether read/write) */
        if(SPI_TRANSACTION_TYPE_READ == object->transactionType)
        {
            QSPI_read_v1(handle, transaction);
        }
    
        if(SPI_TRANSACTION_TYPE_WRITE == object->transactionType)
        {
            QSPI_write_v1(handle, transaction);
        }
    }
    
    
    static void QSPI_mmap_mode_read_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction)
    {
        QSPI_HwAttrs const  *hwAttrs = NULL;
        uint32_t *pDst = NULL;
        uint32_t *pSrc = NULL;
        uint8_t *pDst_8 = NULL;
        uint8_t *pSrc_8 = NULL;
        uint32_t count;
        uint32_t mmapReadCmd = 0U;
        QSPI_v1_Object  *object;
        uint32_t offset;
        const uint32_t nNumBytesToTransfer = 4;
    
        /* Input parameter validation */
        OSAL_Assert(!((handle != NULL) && (transaction != NULL)));
    
        pDst = (uint32_t *)transaction->rxBuf;
        pSrc = (uint32_t *)transaction->txBuf;
        count = transaction->count;
    
        /* Get the pointer to the object and hwAttrs */
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
        object = (QSPI_v1_Object*)handle->object;
    
        uint32_t temp_addr = ((uint32_t)hwAttrs->memMappedBaseAddr + (uint32_t)transaction->txBuf);
        pSrc = ((uint32_t *)(temp_addr)); // change this to 8 or 16 as well
    
        offset = (uint32_t)transaction->txBuf;
    
        /* Extract memory map mode read command */
        mmapReadCmd = (uint32_t)object->transferCmd;
    
        QSPISetMemMapReadCmd(hwAttrs->baseAddr, hwAttrs->chipSelect,
            mmapReadCmd);
    
        /* 3 or 4 byte addressing mode. */
        if(offset < (uint32_t)0xFFFFFF)
        {
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
        }
        else//if(offset > (uint32_t)0xFFFFFF)
        {
            /* Switch to four byte addressing mode */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
        }
    
        /* validate receive lines */
        OSAL_Assert(object->rxLines > 2);
    
        switch(object->rxLines)
        {
            case QSPI_RX_LINES_SINGLE:
            {
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_NORMAL);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x0U);
    
                while(count)
                {
                    // Do the normal memory to memory transfer. Copy will be in bytes
                    *pDst = *pSrc;
                    pDst++;
                    pSrc++;
                    count--;
                }
                break;
            }
    
            case QSPI_RX_LINES_DUAL:
            {
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_DUAL);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x8U);
                while(count)
                {
                    // Do the normal memory to memory transfer. Copy will be in bytes
                    *pDst = *pSrc;
                    pDst++;
                    pSrc++;
                    count--;
                }
                break;
            }
    
            case QSPI_RX_LINES_QUAD:
            {
                QSPISetMemMapReadType(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    QSPI_MEM_MAP_READ_TYPE_QUAD);
                QSPISetMemMapNumDummyBits(hwAttrs->baseAddr, hwAttrs->chipSelect,
                    0x8U);
    
    /*
                uint32_t addr = hwAttrs->baseAddr + QSPI_SPI_CMD_REG;
                HW_WR_FIELD32(addr, QSPI_SPI_CMD_REG_FLEN, frameLength-1);
    */
    /*
                if((count %  frameLength) != 0)
                {
                    count += frameLength -(count %  frameLength);
                }
    */
                /*
                SPI_log("\n*pDst = %d. before \n",*pDst);
                pDst++;
                SPI_log("*pDst = %d. after ++\n",*pDst);
                pDst=pDst+4;
                SPI_log("*pDst = %d. after +=4\n",*pDst);
                */
                int anders = 0;
                while(count)
                {
                    if(false)//count >= nNumBytesToTransfer)
                    {
                        /* Do the normal memory to memory transfer. Copy will be in bytes */
                        *pDst = *pSrc;
    //                    UART_printf("%d. 0x%08x. (%d - %d).\n",anders, *pDst, (anders*4)+1, (anders*4)+4);
                        anders++;
                        pDst++;
                        pSrc++;
                        count-=nNumBytesToTransfer;
                    }
                    else
                    {
                        /* Do the normal memory to memory transfer. Copy will be in bytes */
                        pDst_8 = (uint8_t*)pDst;
                        pSrc_8 = (uint8_t*)pSrc;
                        while(count)
                        {
                            *pDst_8 = *pSrc_8;
                            anders++;
    //                        UART_printf("%d. 0x%02x. (%d - %d).\n",anders, *pDst, (anders*4)+1, (anders*4)+4);
                            pDst_8++;
                            pSrc_8++;
                            count--;
                        }
                    }
                }
                break;
            }
    
            default:
            break;
        }
    
        /* 4 byte addressing mode */
        if(offset > (uint32_t)0xFFFFFF)
        {
            /*
             * After the transfer switch back to 3 byte addressing mode.
             * This is the default mode.
             */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
        }
    }
    
    static void QSPI_cmd_mode_read_v1(SPI_Handle handle,
                                      const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;    /* QSPI hardware attributes */
        uint32_t count = 0U;         /* transfer length in bytes */
        uint32_t wordLenBytes = 0U;  /* Word length in number of bytes */
        uint32_t cmd = 0;           /* transmit command */
        uint32_t dataVal[4] = {0U, 0U, 0U, 0U};  /* data to be written */
        uint32_t idx;/*, idx1, idx2, idx3;*/  /* indexes */
        uint32_t numWords = 0U;          /* number of words */
        uint8_t *dstAddr;              /* destination address */
    
        /* Input parameter validation */
        OSAL_Assert(!((handle != NULL) && (transaction != NULL)));
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        dstAddr = object->readBufIdx;
    
    
        /*formulate the command */
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FLEN, (object->frmLength - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WLEN, (object->qspiParams.dataSize - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CSNUM, hwAttrs->chipSelect);
    
        /* validate receive lines */
        OSAL_Assert(object->rxLines > 2);
    
        switch(object->rxLines)
        {
            case QSPI_RX_LINES_SINGLE:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_FOUR_PIN_READ_SINGLE);
                break;
            }
            case QSPI_RX_LINES_DUAL:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_FOUR_PIN_READ_DUAL);
                break;
            }
            case QSPI_RX_LINES_QUAD:
            {
                HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
                    QSPI_SPI_CMD_REG_CMD_SIX_PIN_READ_QUAD);
                break;
            }
    
            default:
            break;
        }
    
        /* Enable interrupts in the polling mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, true);
    #else
            /* Enable frame count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, true);
    #endif
    
        }
        else
        {
            /* Disable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, false);
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, false);
        }
    
        /* Extract frame length in bytes */
        count = transaction->count;
    
        /* Extract word length in number of bytes */
        wordLenBytes = (object->qspiParams.dataSize >> 3U);
    //    UART_printf("%d\n",wordLenBytes);
    
        //int anders6 = 0;
        //int anders7 = 0;
    
    
        /* Write the data into shift registers */
        while(count)
        {
    
        /* Write tx command to command register */
        QSPIsetCommandReg(hwAttrs->baseAddr, cmd);
    #ifdef WORD_INTERRUPT
            /* interrupt mode */
            if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
            {
                /* wait for the lock posted form the word completion interrupt */
                SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
            }
    
            if(SPI_OPER_MODE_POLLING == object->intrPollMode)
            {
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
            }
    #else
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
    #endif
    
    
            if(wordLenBytes <= 4U)
            {
                numWords = 1U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Write the extracted data into receive buffer */
                for(idx = 0U; idx < wordLenBytes; idx++)
                {
                    /*
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
                        (0x000000FFU));
                        */
    //                if(wordLenBytes == 4)
    //                {
                        *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                               (0x000000FFU));
    //                }
    //                else
    //                {
    //                    *dstAddr = (uint8_t)((dataVal[0] >> (8U - (8U * (idx + 1U)))) &
    //                                        (0x000000FFU));
    //                }
    
    
                    //uint8_t temp = dataVal[0] & 0x000000FFU;
                    if(1)//(wordLenBytes == 4))
                    {
                        //UART_printf("count = %d. i = %d. dataVal[0] = 0x%08x.  *dstAddr = 0x%02x.\n",count, anders6++, dataVal[0],*dstAddr);
    //                    UART_printf("%d. %d. 0x%02x.\n",count, anders6++, *dstAddr);
                    }
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 4U) && (wordLenBytes <= 8U))
            {
                numWords = 2U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U * ((4-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 4U; idx < wordLenBytes; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 8U) && (wordLenBytes <= 12U))
            {
                numWords = 3U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[2] >> (8U * ((4-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 4U; idx < 8U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U * ((8-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 8U; idx < wordLenBytes; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
            }
            else if((wordLenBytes > 12U) && (wordLenBytes <= 16U))
            {
                numWords = 4U;
    
                /* Read data from the data registers */
                QSPIreadData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
    
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[3] >> (8U * ((4-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 4U; idx < 8U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[2] >> (8U * ((8-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
                for(idx = 8U; idx < 12U; idx++)
                {
                    // always four bytes
                    *dstAddr = (uint8_t)((dataVal[1] >> (8U * ((12-0-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
                for(idx = 12U; idx < wordLenBytes; idx++)
                {
                    *dstAddr = (uint8_t)((dataVal[0] >> (8U * ((wordLenBytes-1)-idx))) &
                                           (0x000000FFU));
                    dstAddr++;
                }
    
            }
            else
            {
                /* Not supported */
            }
    
            /* Update the number of bytes to be transmitted */
            count -= wordLenBytes;
        }
        /* Update read buffer index in the object */
        object->readBufIdx = dstAddr;
    }
    
    
    static void QSPI_read_v1(SPI_Handle handle, const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;
    
        object = (QSPI_v1_Object*)handle->object;
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            QSPI_mmap_mode_read_v1(handle, transaction);
        }
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            QSPI_cmd_mode_read_v1(handle, transaction);
        }
    }
    
    
    
    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;
    
        /* 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 = (const QSPI_HwAttrs *)handle->hwAttrs;
        object = (QSPI_v1_Object*)handle->object;
    
        offset   = (uint32_t)transaction->txBuf;
    
        /* Compute the flash destination address */
        uint32_t temp_addr = ((uint32_t)hwAttrs->memMappedBaseAddr + (uint32_t)transaction->txBuf);
        pDst = ((uint8_t *)(temp_addr));
    
        /* Extract memory map mode command */
        mmapWriteCmd = (uint32_t)object->transferCmd;
    
        QSPISetMemMapWriteCmd(hwAttrs->baseAddr, hwAttrs->chipSelect, mmapWriteCmd);
    
        /* 3 or 4 byte addressing mode. */
        if(offset < (uint32_t)0xFFFFFF)
        {
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_THREE);
        }
        else//if(offset > (uint32_t)0xFFFFFF)
        {
            /* Switch to four byte addressing mode */
            QSPISetMemMapNumAddrBytes(hwAttrs->baseAddr, hwAttrs->chipSelect,
                QSPI_MEM_MAP_NUM_ADDR_BYTES_FOUR);
        }
    
        QSPISetMemAddrSpace(hwAttrs->baseAddr, hwAttrs->chipSelect,
            QSPI_MEM_MAP_PORT_SEL_MEM_MAP_PORT);
    
        QSPIMmapCsEnable(hwAttrs->baseAddr, hwAttrs->chipSelect);
    
        while(count)
        {
            *pDst = *pSrc;
            pDst++;
            pSrc++;
            count--;
        }
    
        /* 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_THREE);
        }
    }
    
    
    static void QSPI_cmd_mode_write_v1(SPI_Handle handle,
                                       const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;    /* QSPI hardware attributes */
        uint32_t count = 0U;         /* transfer length in bytes */
        uint32_t wordLenBytes = 0U;  /* Word length in number of bytes */
        uint32_t cmd = 0;           /* transmit command */
        uint32_t dataVal[4] = {0U, 0U, 0U, 0U};  /* data to be written */
        uint32_t idx, idx1, idx2, idx3;          /* indexes */
        uint32_t numWords = 0U;                  /* number of words */
        uint8_t *srcAddr;                      /* Source address */
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        srcAddr = object->writeBufIdx;
    
        /* formulate the command */
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FLEN, (object->frmLength - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WLEN, (object->qspiParams.dataSize - 1));
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CSNUM, hwAttrs->chipSelect);
        HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_CMD,
            QSPI_SPI_CMD_REG_CMD_FOUR_PIN_WRITE_SINGLE);
    
    
        /* Enable interrupts in the polling mode */
        if(object->intrPollMode != SPI_OPER_MODE_POLLING)
        {
    #ifdef WORD_INTERRUPT
            /* Enable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, true);
    #else
            /* Enable frame count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, true);
    #endif
    
        }
        else
        {
            /* Disable word count interrupt */
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_WIRQ, false);
            HW_SET_FIELD32(cmd, QSPI_SPI_CMD_REG_FIRQ, false);
        }
    
    
        /* Extract frame length in bytes */
        count = transaction->count;
    
        /* Extract word length in number of bytes */
        wordLenBytes = (object->qspiParams.dataSize >> 3U);
    
        /* Write the data into shift registers */
        while(count)
        {
            dataVal[0] = 0;
            dataVal[1] = 0;
            dataVal[2] = 0;
            dataVal[3] = 0;
    
            if(wordLenBytes <= 4U)
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < wordLenBytes; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 1U;
            }
            else if((wordLenBytes > 4U) && (wordLenBytes <= 8U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < wordLenBytes; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 2U;
            }
            else if((wordLenBytes > 8U) && (wordLenBytes <= 12U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    dataVal[2] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 3U;
            }
            else if((wordLenBytes > 12U) && (wordLenBytes <= 16U))
            {
                /* Formulate the 32 bit word to write to data register */
                for(idx = 0U; idx < 4U; idx++)
                {
                    dataVal[0] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx1 = 4U; idx1 < 8U; idx1++)
                {
                    dataVal[1] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx2 = 8U; idx2 < 12U; idx2++)
                {
                    dataVal[2] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                for(idx3 = 12U; idx3 < 16U; idx3++)
                {
                    dataVal[3] |= (((uint32_t)(*srcAddr) << (8u - (8u * (idx + 1u)))));
                    srcAddr++;
                }
    
                numWords = 4U;
            }
            else
            {
                /* Not supported */
            }
    
            /* Write data to data registers */
            QSPIwriteData(hwAttrs->baseAddr, &dataVal[0], (int32_t)numWords);
    
            /* Write tx command to command register */
            QSPIsetCommandReg(hwAttrs->baseAddr, cmd);
    
    #ifdef WORD_INTERRUPT
            /* interrupt mode */
            if(SPI_OPER_MODE_BLOCKING == object->intrPollMode)
            {
                /* wait for the lock posted form the word completion interrupt */
                SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
            }
    
            if(SPI_OPER_MODE_POLLING == object->intrPollMode)
            {
                /* Wait for the QSPI busy status */
                QSPIWaitIdle(hwAttrs->baseAddr);
            }
    #else
    
            /* Wait for the QSPI busy status */
            QSPIWaitIdle(hwAttrs->baseAddr);
    #endif
    
    
            /* Update the number of bytes to be transmitted */
            count -= wordLenBytes;
        }
    
        /* Update write buffer index in the object */
        object->writeBufIdx = srcAddr;
    }
    
    
    static void QSPI_write_v1(SPI_Handle handle, const SPI_Transaction *transaction)
    {
        QSPI_v1_Object  *object = NULL;         /* QSPI object */
    
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
    
        if(QSPI_OPER_MODE_MMAP == object->qspiMode)
        {
            QSPI_mmap_mode_write_v1(handle, transaction);
        }
    
        if(QSPI_OPER_MODE_CFG == object->qspiMode)
        {
            QSPI_cmd_mode_write_v1(handle, transaction);
        }
    }
    
    
    /*
     *  ======== i2c_am57x_transfer ========
     */
    static bool QSPI_transfer_v1(SPI_Handle handle, SPI_Transaction *transaction)
    {
        bool  ret = false;                /* return value */
        QSPI_v1_Object   *object;         /* QSPI object */
        QSPI_HwAttrs const  *hwAttrs;     /* QSPI hardware attributes */
    
        /* Input parameter validation */
        if ((handle != NULL) && (transaction != NULL))
        {
        /* Get the pointer to the object and hwAttrs */
        object = (QSPI_v1_Object*)handle->object;
        hwAttrs = (const QSPI_HwAttrs *)handle->hwAttrs;
    
        /* Check if anything needs to be written or read */
        if (0 != transaction->count)
        {
            transaction->status=SPI_TRANSFER_STARTED;
            /* Acquire the lock for this particular I2C handle */
            SPI_osalPendLock(object->mutex, SemaphoreP_WAIT_FOREVER);
    
            /* Book keeping of transmit and receive buffers. */
            object->writeBufIdx = (uint8_t *)transaction->txBuf;
            object->writeCountIdx = transaction->count;
            object->readBufIdx =  (uint8_t *)transaction->rxBuf;
            object->readCountIdx = transaction->count;
    
    
             /*
             * QSPI_primeTransfer_v1 is a longer process and
             * protection is needed from the QSPI interrupt
             */
            if (SPI_OPER_MODE_POLLING != object->intrPollMode)
            {
                SPI_osalHardwareIntrEnable(hwAttrs->eventId,hwAttrs->intrNum);
            }
    
            QSPI_primeTransfer_v1(handle, transaction);
    
            if (object->intrPollMode == SPI_OPER_MODE_BLOCKING) {
    #ifdef WORD_INTERRUPT
                /* transfer is completed and semaphore is posted. */
                ret = (bool)true;
    #else
                /* If the word count is zero then wait for semaphore */
                if(object->frmLength == QSPIgetStatusWordCount(hwAttrs->baseAddr))
                {
                  /* wait for the lock posted form the word completion interrupt */
                  SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
                }
    
                /* transfer is completed and semaphore is posted. */
                transaction->status=SPI_TRANSFER_COMPLETED;
                ret = (bool)true;
    #endif
            }
            else {
                /* Always return true if in Asynchronous mode */
                ret = (bool)true;
            }
    
            /* Release the lock for this particular I2C handle */
            SPI_osalPostLock(object->mutex);
        } else {
           transaction->status=SPI_TRANSFER_CANCELED;
        }
        }
    
        /* Return the number of bytes transferred by the I2C */
        return (ret);
    }
    
    /*
     *  ======== QSPI_transferCallback_v1 ========
     */
    static void QSPI_transferCallback_v1(SPI_Handle handle, SPI_Transaction *msg)
    {
        QSPI_v1_Object   *object;            /* QSPI object */
    
        /* Get the pointer to the object */
        object = (QSPI_v1_Object*)handle->object;
    
        if(msg!=NULL) {
           msg->status=SPI_TRANSFER_COMPLETED;
        }
    
        /* Indicate transfer complete */
        SPI_osalPostLock(object->transferComplete);
    }
    
    /*
     *  ======== QSPI_control_v1 ========
     */
    static int32_t QSPI_control_v1(SPI_Handle handle, uint32_t cmd, const void *arg)
    {
        QSPI_v1_Object   *object;            /* QSPI object */
        int32_t retVal = SPI_STATUS_ERROR;
    
        /* Input parameter validation */
        if (handle != NULL)
        {
        /* Get the pointer to the object */
        object = (QSPI_v1_Object*)handle->object;
    
        switch (cmd)
        {
            case SPI_V1_CMD_SETFRAMELENGTH:
            {
                object->frmLength = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_MMAP_TRANSFER_CMD:
            {
                object->transferCmd = *(uint8_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_TRANSFERMODE_RW:
            {
                object->transactionType = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETCONFIGMODE:
            {
                object->qspiMode = QSPI_OPER_MODE_CFG;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETRXLINES:
            {
                object->rxLines = *(uint32_t *)arg;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            case SPI_V1_CMD_SETMEMMORYMAPMODE:
            {
                object->qspiMode = QSPI_OPER_MODE_MMAP;
                retVal = SPI_STATUS_SUCCESS;
                break;
            }
    
            default:
            retVal = SPI_STATUS_UNDEFINEDCMD;
            break;
        }
        }
    
        return retVal;
    }
    
    
    /*
     *  ======== QSPI_transferCancel_v1 ========
     */
    static void QSPI_transferCancel_v1(SPI_Handle handle)
    {
        return;
    }
    

    /**
     * @file   BoardInit.c
     *
     * @brief  This file calls functions to initialize the Capstone AM437x chip and peripherals
     */
    /** ============================================================================*/
    
    //#define _TIMEVAL_DEFINED    1
    
    #include <ti/sysbios/family/arm/a8/Mmu.h>
    
    #include <ti/starterware/include/types.h>
    #include <ti/starterware/include/hw/hw_types.h>
    #include <ti/starterware/include/hw/hw_control_am43xx.h>
    #include <ti/starterware/include/hw/am437x.h>
    #include <ti/starterware/include/ethernet.h>
    
    #include <ti/drv/emac/emac_drv.h>
    #include <ti/drv/emac/src/v4/emac_drv_v4.h>
    
    #include <ti/board/board.h>
    
    /* UART Header files */
    #include <ti/drv/uart/UART.h>
    #include <ti/drv/uart/UART_stdio.h>
    
    /* GPIO header files and defines*/
    #include <ti/drv/gpio/GPIO.h>
    #include <ti/drv/gpio/soc/GPIO_v1.h>
    
    #include <ti/ndk/inc/netmain.h>
    #include <ti/ndk/inc/stkmain.h>
    
    
    extern int CpswEmacInit (STKEVENT_Handle hEvent);
    
    
    #define MAX_TABLE_ENTRIES   3
    static int nimu_device_index = 0U;
    NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[MAX_TABLE_ENTRIES];
    
    ///* GPIO Driver board specific pin configuration structure */
    //GPIO_PinConfig gpioPinConfigs[] = {
    //    /* Input pin with interrupt enabled */
    //    GPIO_DEVICE_CONFIG(( GPIO_USER0_LED_PORT_NUM + 1 ), GPIO_USER0_LED_PIN_NUM) |
    //    GPIO_CFG_IN_INT_RISING | GPIO_CFG_INPUT,
    //
    //    /* Output pin */
    //    GPIO_DEVICE_CONFIG( (GPIO_USER0_LED_PORT_NUM + 1), GPIO_USER0_LED_PIN_NUM) |
    //    GPIO_CFG_OUTPUT
    //};
    //
    ///* GPIO Driver call back functions */
    //GPIO_CallbackFxn gpioCallbackFunctions[] = {
    //    NULL,
    //    NULL
    //};
    //
    ///* GPIO Driver configuration structure */
    //GPIO_v1_Config GPIO_v1_config = {
    //    gpioPinConfigs,
    //    gpioCallbackFunctions,
    //    sizeof(gpioPinConfigs) / sizeof(GPIO_PinConfig),
    //    sizeof(gpioCallbackFunctions) / sizeof(GPIO_CallbackFxn),
    //    0,
    //    };
    
    /* ========================================================================== */
    /*                          Function Definitions                              */
    /* ========================================================================== */
    
    void CpswPortMacModeSelect(uint32_t portNum, uint32_t macMode)
    {
        uint32_t regVal = 0U;
    
        regVal = HW_RD_REG32(SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL);
    
        switch(macMode)
        {
            case ETHERNET_MAC_TYPE_MII:
            case ETHERNET_MAC_TYPE_GMII:
                if(1U == portNum)
                {
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
                }
                else if(2U == portNum)
                {
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
                }
                else
                {
                    /* This error does not happen because of check done already */
                }
                break;
    
            case ETHERNET_MAC_TYPE_RMII: /* RMII */
                if(1U == portNum)
                {
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 1U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
                }
                else if(2U == portNum)
                {
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 1U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
                }
                else
                {
                    /* This error does not happen because of check done already */
                }
                break;
    
            case ETHERNET_MAC_TYPE_RGMII: /* RGMII */
                if(1U == portNum)
                {
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII1, 2U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII1_IDMODE, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII1_IO_CLK_EN, 0U);
                }
                else if(2U == portNum)
                {
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_GMII2, 2U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RGMII2_IDMODE, 0U);
                    HW_SET_FIELD(regVal, CTRL_GMII_SEL_RMII2_IO_CLK_EN, 0U);
                }
                else
                {
                    /* This error does not happen because of check done already */
                }
                break;
    
             default:
             break;
        }
    
        HW_WR_REG32((SOC_CONTROL_MODULE_REG + CTRL_GMII_SEL), regVal);
    }
    
    
    #define SYS_MMU_BUFFERABLE      1
    #define SYS_MMU_CACHEABLE       2
    #define SYS_MMU_SHAREABLE       4
    #define SYS_MMU_NO_EXECUTE      8
    typedef struct _sys_mmu_entry
    {
    
        void* address;
        /**< Address to be entered in MMU table. */
        unsigned int attributes;
        /**< Attributes of the memory. */
    }SYS_MMU_ENTRY;
    
    
    SYS_MMU_ENTRY applMmuEntries[] = {
        {(void*)0x30000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30100000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30200000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30300000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30400000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30500000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30600000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30700000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30800000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30900000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30A00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30B00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30C00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30D00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30E00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x30F00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31100000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31200000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31300000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31400000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31500000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31600000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31700000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31800000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31900000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31A00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31B00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31C00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31D00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31E00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x31F00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32100000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32200000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32300000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32400000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32500000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32600000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32700000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32800000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32900000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32A00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32B00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32C00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32D00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32E00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x32F00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33100000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33200000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33300000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33400000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33500000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33600000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33700000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33800000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33900000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33A00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33B00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33C00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33D00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33E00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
        {(void*)0x33F00000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Cacheable
    
    
        {(void*)0x40300000,0},  //OCMCRAM  - Cacheable
        {(void*)0x44D00000, SYS_MMU_BUFFERABLE},  //PRCM - Non bufferable| Non Cacheable
        {(void*)0x44E00000, SYS_MMU_BUFFERABLE},  //Clock Module, PRM, GPIO0, UART0, I2C0, - Non bufferable| Non Cacheable
        {(void*)0x47900000,SYS_MMU_BUFFERABLE},  //QSPI MMR Maddr0space
        {(void*)0x48000000, SYS_MMU_BUFFERABLE},  //UART1,UART2,I2C1,McSPI0,McASP0 CFG,McASP1 CFG,DMTIMER,GPIO1 -Non bufferable| Non Cacheable
        {(void*)0x48100000,0},  //I2C2,McSPI1,UART3,UART4,UART5, GPIO2,GPIO3,MMC1 - Non bufferable| Non Cacheable
        {(void*)0x48200000, SYS_MMU_BUFFERABLE},  //
        {(void*)0x48300000, SYS_MMU_BUFFERABLE},  //PWM - Non bufferable| Non Cacheable
        {(void*)0x49000000, SYS_MMU_BUFFERABLE},   //EDMA3CC - Non bufferable| Non Cacheable
        {(void*)0x4A000000, SYS_MMU_BUFFERABLE},  //L4 FAST CFG- Non bufferable| Non Cacheable
        {(void*)0x4A100000, SYS_MMU_BUFFERABLE},  //CPSW - Non bufferable| Non Cacheable
        {(void*)0x54400000, SYS_MMU_BUFFERABLE},  //PRU-ICSS0/1 -Bufferable| Non Cacheable | Shareable
        {(void*)0x80000000,SYS_MMU_CACHEABLE},  //QSPI CS0 Maddr1space - Non bufferable| Non Cacheable
        {(void*)0xFFFFFFFF,0xFFFFFFFF}
    };
    int SDKMMUInit(SYS_MMU_ENTRY mmuEntries[])
    {
        unsigned short itr = 0;
        Mmu_FirstLevelDescAttrs attrs;
    
        if(NULL == mmuEntries)
            return -1;
    
        Mmu_disable();
    
    
        Mmu_initDescAttrs(&attrs);
    
        attrs.type = Mmu_FirstLevelDesc_SECTION;
        attrs.domain = 0;
        attrs.imp = 1;
        attrs.accPerm = 3;
    
    
        for(itr = 0 ; mmuEntries[itr].address != (void*)0xFFFFFFFF ; itr++)
        {
            attrs.bufferable = ((mmuEntries[itr].attributes) & SYS_MMU_BUFFERABLE) && 1 ;
            attrs.cacheable  = ((mmuEntries[itr].attributes) & SYS_MMU_CACHEABLE) && 1;
            if (!attrs.bufferable && !attrs.cacheable)
                attrs.tex = 0; //tex is initialized to 1 and need this to force strongly ordered
            attrs.shareable  = ((mmuEntries[itr].attributes) & SYS_MMU_SHAREABLE) && 1;
            attrs.noexecute  = ((mmuEntries[itr].attributes) & SYS_MMU_NO_EXECUTE) && 1;
            Mmu_setFirstLevelDesc((Ptr)(mmuEntries[itr].address), (Ptr)(mmuEntries[itr].address) , &attrs);  // PWM
        }
    
        Mmu_enable();
        return 0;
    }
    
    int BoardInit()
    {
        Board_initCfg boardCfg;
    
        // Init the memory manager
        SDKMMUInit(applMmuEntries);
    
        // Init the board and pinmux using utility from the PDK
        boardCfg = BOARD_INIT_PINMUX_CONFIG | BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
        if (Board_init(boardCfg) != 0)
            return -1;
    
    
        /* Chip configuration MII/RMII selection */
        CpswPortMacModeSelect(1, ETHERNET_MAC_TYPE_RGMII);
        CpswPortMacModeSelect(2, ETHERNET_MAC_TYPE_RGMII);
    
        NIMUDeviceTable[nimu_device_index++].init =  &CpswEmacInit ;
        NIMUDeviceTable[nimu_device_index].init =  NULL ;
    
    
        // ok
        return 0;
    }