//#############################################################################
//
// FILE:   flashapi_ex1_programming.c
//
// TITLE:  Flash programming example
//
//! \addtogroup driver_example_list
//! <h1> Flash Programming with AutoECC, DataAndECC, DataOnly and EccOnly </h1>
//!
//! This example demonstrates how to program Flash using API's following options
//! 1. AutoEcc generation
//! 2. DataOnly and EccOnly
//! 3. DataAndECC
//!
//! \b External \b Connections \n
//!  - None.
//!
//! \b Watch \b Variables \n
//!  - None.
//!
//
//#############################################################################
// $Copyright:
// Copyright (C) 2026 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.
// $
//#############################################################################

//
// Included Files
//
#include "driverlib.h"
#include "device.h"
#include <stdio.h>

//
// Include Flash API include file
//
#include "F021_F28003x_C28x.h"

// Include Flash API example header file
//
#include "flash_programming_f28003x.h"

//
// Defines
//

//
// Length (in 16-bit words) of data buffer used for program
//
#define  WORDS_IN_FLASH_BUFFER    0x100

//
// Globals
//

//
// Data Buffers used for program operation using the flash API program function
//
#pragma  DATA_SECTION(Buffer,"DataBufferSection");
uint16   Buffer[WORDS_IN_FLASH_BUFFER];
uint32   *Buffer32 = (uint32 *)Buffer;


//
// Prototype of the functions used in this example
//
void Example_Error(Fapi_StatusType status);
void Example_Done(void);
void Example_CallFlashAPI(void);
void FMSTAT_Fail(void);
void ECC_Fail(void);

void Example_EraseBanks(void);
void Example_EraseSector(void);
void Example_ProgramUsingAutoECC(void);
void Example_ProgramBankUsingAutoECC(void);
void Example_ProgramUsingDataOnlyECCOnly(void);
void Example_ProgramUsingDataAndECC(void);
void Flash_DisablePrefetch_SW_Workaround(uint32_t ctrlBase);
void Flash_EnablePrefetch_SW_Workaround(uint32_t ctrlBase);
__interrupt void nmiISR(void);

//
// Main
//
void main(void)
{
    //
    // Initialize device clock and peripherals
    // Copy the Flash initialization code from Flash to RAM
    // Copy the Flash API from Flash to RAM
    // Configure Flash wait-states, fall back power mode, performance features
    // and ECC
    //
    Device_init();

    //
    // Initialize GPIO
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();
    
    //
    // Clear all the NMI and Flash error status flags.
    //
    EALLOW;
    HWREG(FLASH0ECC_BASE + FLASH_O_ERR_STATUS_CLR) = 0xFFFFFFFFU;
    HWREG(FLASH0ECC_BASE + FLASH_O_ERR_INTCLR) = 0xFFFFFFFFU;
    EDIS;

    SysCtl_clearAllNMIFlags();

    //
    // Plug the NMI and Flash correctable error ISRs.
    //
    Interrupt_register(INT_NMI, &nmiISR);
    // Interrupt_register(INT_FLASH_CORR_ERR, corrErrorISR);
    Interrupt_enable(INT_FLASH_CORR_ERR);
    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // At 120MHz, execution wait-states for external oscillator is 5. Modify the
    // wait-states when the system clock frequency is changed.
    //
    Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, 5);


    //
    // Flash API functions should not be executed from the same bank on which
    // erase/program operations are in progress.
    // Also, note that there should not be any access to the Flash bank on
    // which erase/program operations are in progress.  Hence below function
    // is mapped to RAM for execution.
    //
    Example_CallFlashAPI();


    //
    // Example is done here
    //
    Example_Done();
}

//
// nmiISR -  The interrupt service routine called when the NMI is generated
//           on an uncorrectable Flash ECC error.
//
volatile bool nmiISRFlag;
uint16_t nmiStatus;
volatile bool errorISRFlag;

__interrupt void nmiISR(void)
{
    //
    // Set a flag indicating the NMI ISR occurred and get the NMI status.
    //
    nmiISRFlag = true;
    nmiStatus = SysCtl_getNMIFlagStatus();
    
    //
    // Clear all the flags.
    //
    uint16 nmi_sts = SysCtl_getNMIFlagStatus();
    SysCtl_clearAllNMIFlags();

    if (nmiStatus == (SYSCTL_NMI_FLUNCERR | SYSCTL_NMI_NMIINT))
    {
        uint32_t err_addr_low = Flash_getUncorrectableErrorAddressLow(FLASH0ECC_BASE);
        uint32_t err_addr_high = Flash_getUncorrectableErrorAddressHigh(FLASH0ECC_BASE);
        
        Flash_clearUncorrectableInterruptFlag(FLASH0ECC_BASE);
        EALLOW;
        HWREG(FLASH0ECC_BASE + FLASH_O_ERR_STATUS_CLR) = 0xFFFFFFFFU;
        EDIS;

        // Erase Flash Banks
        Example_EraseSector();

        if(err_addr_low)
        {
            printf("Uncorrectable error at addr = 0x%lx\n", err_addr_low);
        }

        if(err_addr_high)
        {
            printf("Uncorrectable error at addr = 0x%lx\n", err_addr_high);
        }
    }
}

//*****************************************************************************
//  Example_CallFlashAPI
//
//  This function will interface to the flash API.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************
#ifdef __cplusplus
#pragma CODE_SECTION(".TI.ramfunc");
#else
#pragma CODE_SECTION(Example_CallFlashAPI, ".TI.ramfunc");
#endif
void Example_CallFlashAPI(void)
{
    uint16 i = 0;
    Fapi_StatusType  oReturnCheck;

    //
    // Initialize the Flash API by providing the Flash register base address
    // and operating frequency(in MHz).
    // This function is required to initialize the Flash API based on System
    // frequency before any other Flash API operation can be performed.
    // This function must also be called whenever System frequency or RWAIT is
    // changed.
    //
    oReturnCheck = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS, 
                                      DEVICE_SYSCLK_FREQ/1000000U);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        Example_Error(oReturnCheck);
    }

    //
    // Disable prefetch mechanism before changing wait states
    //
    Flash_DisablePrefetch_SW_Workaround(FLASH0CTRL_BASE);
    //
    // Initialize the Flash banks and FMC for erase and program operations.
    // Fapi_setActiveFlashBank() function sets the Flash banks and FMC for
    // further Flash operations to be performed on the banks.
    //
    oReturnCheck = Fapi_setActiveFlashBank(Fapi_FlashBank0);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        Example_Error(oReturnCheck);
    }
    //
    // Enable prefetch mechanism before changing wait states
    //
    Flash_EnablePrefetch_SW_Workaround(FLASH0CTRL_BASE);

    //
    // Erase bank 1 before programming
    //
    Example_EraseBanks();
    //
    // Fill a buffer with data to program into the flash.
    //
    for(i=0; i < WORDS_IN_FLASH_BUFFER; i++)
    {
        Buffer[i] = i;
    }

    //
    // Program the sector using DataOnly and ECCOnly options
    //
    Example_ProgramUsingDataOnlyECCOnly();

    //
    // Erase bank 1 before programming
    //
    Example_EraseBanks();

}


//*****************************************************************************
//  Example_ProgramUsingDataOnlyECCOnly
//
//  Example function to Program data in Flash using "DataOnly" option and ECC
//  using "EccOnly" option.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************
#ifdef __cplusplus
#pragma CODE_SECTION(".TI.ramfunc");
#else
#pragma CODE_SECTION(Example_ProgramUsingDataOnlyECCOnly, ".TI.ramfunc");
#endif
void Example_ProgramUsingDataOnlyECCOnly(void)
{
    uint32 u32Index = 0;
    uint16 i = 0;
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType  oFlashStatusWord;

    //
    // Program data using "DataOnly" option and ECC using "EccOnly" option.
    //
    // When DataOnly option is used, Flash API will program only the data
    // portion in Flash at the address specified.
    //
    // When EccOnly option is used, Flash API will program only the ECC portion
    // in Flash ECC memory space (Flash main array address should be provided
    // for this function and not the corresponding ECC address).
    // Fapi_calculateEcc is used to calculate the corresponding ECC of the data.
    //
    // Note that data buffer (Buffer) is aligned on 64-bit boundary for verify
    // reasons.
    //
    // In this example, 0x100 bytes are programmed in Flash Sector6
    // along with the specified ECC.
    //

    for(i=0, u32Index = Bone_Sector1_start;
       (u32Index < (Bone_Sector1_start + WORDS_IN_FLASH_BUFFER));
       i+= 8, u32Index+= 8)
    {

        oReturnCheck = Fapi_issueProgrammingCommand((uint32 *)u32Index,Buffer+i,
                                                        8, 0, 0, Fapi_DataOnly);

        //
        // Wait until the Flash program operation is over
        //
        while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            Example_Error(oReturnCheck);
        }

        //
        // Read FMSTAT register contents to know the status of FSM after
        // program command to see if there are any program operation related
        // errors
        //
        oFlashStatus = Fapi_getFsmStatus();
        if(oFlashStatus != 0)
        {
            //Check FMSTAT and debug accordingly
            FMSTAT_Fail();
        }


        //
        // Verify the programmed values.  Trigger ECC NMI
        //
        oReturnCheck = Fapi_doVerify((uint32 *)u32Index,
                                     4, Buffer32+(i/2),
                                     &oFlashStatusWord);

        if(oReturnCheck != Fapi_Status_Success)
        {
            //
            // Check Flash API documentation for possible errors
            //
            Example_Error(oReturnCheck);
        }
    }
}

//*****************************************************************************
//  Example_EraseBanks
//
//  Example function to Erase data of a sector in Flash.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************
#ifdef __cplusplus
#pragma CODE_SECTION(".TI.ramfunc");
#else
#pragma CODE_SECTION(Example_EraseBanks, ".TI.ramfunc");
#endif
void Example_EraseBanks(void)
{
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType  oFlashStatusWord;
    uint32 u32CurrentAddress;

    u32CurrentAddress = Bzero_Sector8_start;
    oReturnCheck = Fapi_issueBankEraseCommand((uint32 *)u32CurrentAddress, 0x001F);

    // Wait until FSM is done with bank erase operation
    while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady)
    {
         //
         // Initialize the Erase Pulses to zero after issuing max pulses
         //
         if(HWREG(FLASH0CTRL_BASE + FLASH_O_ACC_EP) > MAX_ERASE_PULSE)
         {
             EALLOW;

             //
             // Enable Flash Optimization
             //
             HWREG(FLASH0CTRL_BASE + FLASH_O_OPT) = OPT_ENABLE;

             HWREG(FLASH0CTRL_BASE + FLASH_O_ERA_PUL) =
                     HWREG(FLASH0CTRL_BASE + FLASH_O_ERA_PUL) &
                     ~(uint32_t)FLASH_ERA_PUL_MAX_ERA_PUL_M;

             //
             // Disable Flash Optimization
             //
             HWREG(FLASH0CTRL_BASE + FLASH_O_OPT) = OPT_DISABLE;

             EDIS;
         }
    }

    if(oReturnCheck != Fapi_Status_Success)
    {
        // Check Flash API documentation for possible errors
        Example_Error(oReturnCheck);
    }

    // Read FMSTAT register contents to know the status of FSM after
    // erase command to see if there are any erase operation related errors
    oFlashStatus = Fapi_getFsmStatus();
    if(oFlashStatus != 0)
    {
        // Check Flash API documentation for FMSTAT and debug accordingly
        // Fapi_getFsmStatus() function gives the FMSTAT register contents.
        // Check to see if any of the EV bit, ESUSP bit, CSTAT bit or
        // VOLTSTAT bit is set (Refer to API documentation for more details).
        FMSTAT_Fail();
    }

    u32CurrentAddress = Bone_Sector0_start;
    oReturnCheck = Fapi_issueBankEraseCommand((uint32 *)u32CurrentAddress, 0x0000);

    // Wait until FSM is done with bank erase operation
    while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady)
    {
        //
        // Initialize the Erase Pulses to zero after issuing max pulses
        //
        if(HWREG(FLASH0CTRL_BASE + FLASH_O_ACC_EP) > MAX_ERASE_PULSE)
        {
            EALLOW;

            //
            // Enable Flash Optimization
            //
            HWREG(FLASH0CTRL_BASE + FLASH_O_OPT) = OPT_ENABLE;

            HWREG(FLASH0CTRL_BASE + FLASH_O_ERA_PUL) =
                    HWREG(FLASH0CTRL_BASE + FLASH_O_ERA_PUL) &
                    ~(uint32_t)FLASH_ERA_PUL_MAX_ERA_PUL_M;

            //
            // Disable Flash Optimization
            //
            HWREG(FLASH0CTRL_BASE + FLASH_O_OPT) = OPT_DISABLE;

            EDIS;
         }
    }

    if(oReturnCheck != Fapi_Status_Success)
    {
        // Check Flash API documentation for possible errors
        Example_Error(oReturnCheck);
    }

    // Read FMSTAT register contents to know the status of FSM after
    // erase command to see if there are any erase operation related errors
    oFlashStatus = Fapi_getFsmStatus();
    if(oFlashStatus != 0)
    {
        // Check Flash API documentation for FMSTAT and debug accordingly
        // Fapi_getFsmStatus() function gives the FMSTAT register contents.
        // Check to see if any of the EV bit, ESUSP bit, CSTAT bit or
        // VOLTSTAT bit is set (Refer to API documentation for more details).
        FMSTAT_Fail();
    }

    // Do blank check
    // Verify that Bank0 sectors 5-15 and Bank 1 sectors 0-15 are erased.
    // The Erase command itself does a verify as it goes.
    // Hence erase verify by CPU reads (Fapi_doBlankCheck()) is optional.
    u32CurrentAddress = Bzero_Sector5_start;
    oReturnCheck = Fapi_doBlankCheck((uint32 *)u32CurrentAddress,
                   (27*Sector8KB_u32length),
                   &oFlashStatusWord);

    if(oReturnCheck != Fapi_Status_Success)
    {
        // Check Flash API documentation for error info
        Example_Error(oReturnCheck);
    }
}

//*****************************************************************************
//  Example_EraseSector
//
//  Example function to Erase data of a sector in Flash.
//  Flash API functions used in this function are executed from RAM in this
//  example.
//*****************************************************************************
#ifdef __cplusplus
#pragma CODE_SECTION(".TI.ramfunc");
#else
#pragma CODE_SECTION(Example_EraseSector, ".TI.ramfunc");
#endif
void Example_EraseSector(void)
{
    Fapi_StatusType  oReturnCheck;
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType  oFlashStatusWord;

    //
    // Issue ClearMore command
    //
    oReturnCheck = Fapi_issueAsyncCommand(Fapi_ClearMore);

    //
    // Wait until FSM is done with erase sector operation
    //
    while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady){}

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        Example_Error(oReturnCheck);
    }

    //
    // Erase the sector that is programmed in the above example
    // Erase Sector1
    //
    oReturnCheck = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector,
                   (uint32 *)Bone_Sector1_start);
    //
    // Wait until FSM is done with erase sector operation
    //
    while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady){}

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for possible errors
        //
        Example_Error(oReturnCheck);
    }

    //
    // Read FMSTAT register contents to know the status of FSM after
    // erase command to see if there are any erase operation related errors
    //
    oFlashStatus = Fapi_getFsmStatus();
        if(oFlashStatus != 0)
    {
        //
        // Check Flash API documentation for FMSTAT and debug accordingly
        // Fapi_getFsmStatus() function gives the FMSTAT register contents.
        // Check to see if any of the EV bit, ESUSP bit, CSTAT bit or
        // VOLTSTAT bit is set (Refer to API documentation for more details).
        //
        FMSTAT_Fail();
    }

    //
    // Verify that Sector1 is erased
    //
    oReturnCheck = Fapi_doBlankCheck((uint32 *)Bone_Sector1_start,
                   Sector8KB_u32length,
                   &oFlashStatusWord);

    if(oReturnCheck != Fapi_Status_Success)
    {
        //
        // Check Flash API documentation for error info
        //
        Example_Error(oReturnCheck);
    }
}

/* Below is the code for Flash_DisablePrefetch_SW_Workaround().  */

//*****************************************************************************
//
//! Disables flash prefetch mechanism and adds 7 cycle delay
//!
//! \param ctrlBase is the base address of the flash wrapper control registers.
//!
//! \return None.
//
//*****************************************************************************

#ifdef __cplusplus
#pragma CODE_SECTION(".TI.ramfunc");
#else
#pragma CODE_SECTION(Flash_DisablePrefetch_SW_Workaround, ".TI.ramfunc");
#endif
void Flash_DisablePrefetch_SW_Workaround(uint32_t ctrlBase)
{
    //
    // Check the arguments.
    //
    ASSERT(Flash_isCtrlBaseValid(ctrlBase));

    //
    // Disable flash prefetch
    //
    Flash_disablePrefetch(ctrlBase);

    //
    // Force a pipeline flush to ensure that the write to the last register
    // configured occurs before returning.
    //
    FLASH_DELAY_CONFIG;
}

/* Below is the code for Flash_EnablePrefetch_SW_Workaround()  */

//*****************************************************************************
//
//! Enables flash prefetch mechanism and adds 7 cycle delay
//!
//! \param ctrlBase is the base address of the flash wrapper control registers.
//!
//! \return None.
//
//*****************************************************************************

#ifdef __cplusplus
#pragma CODE_SECTION(".TI.ramfunc");
#else
#pragma CODE_SECTION(Flash_EnablePrefetch_SW_Workaround, ".TI.ramfunc");
#endif
void Flash_EnablePrefetch_SW_Workaround(uint32_t ctrlBase)
{
    //
    // Check the arguments.
    //
    ASSERT(Flash_isCtrlBaseValid(ctrlBase));

    //
    // Disable flash prefetch
    //
    Flash_enablePrefetch(ctrlBase);

    //
    // Force a pipeline flush to ensure that the write to the last register
    // configured occurs before returning.
    //
    FLASH_DELAY_CONFIG;
}

//******************************************************************************
// For this example, just stop here if an API error is found
//******************************************************************************
void Example_Error(Fapi_StatusType status)
{
    //
    //  Error code will be in the status parameter
    //
    __asm("    ESTOP0");
}

//******************************************************************************
//  For this example, once we are done just stop here
//******************************************************************************
void Example_Done(void)
{
    __asm("    ESTOP0");
}

//******************************************************************************
// For this example, just stop here if FMSTAT fail occurs
//******************************************************************************
void FMSTAT_Fail(void)
{
    __asm("    ESTOP0");
}

//******************************************************************************
// For this example, just stop here if ECC fail occurs
//******************************************************************************
void ECC_Fail(void)
{
    __asm("    ESTOP0");
}

//
// End of File
//
