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.

LAUNCHXL-F280039C: unresolved symbol Fapi_initializeAPI, first referenced in

Part Number: LAUNCHXL-F280039C
Other Parts Discussed in Thread: C2000WARE

Tool/software:

Hi everyone,

I'm working with the F28003x series and using the Flash API. I have added the F021_API_F28003x_FPU32.lib library to my project, 

However, when I call my own function fapi_init() (which includes Fapi_initializeAPI() inside), I get the following linker error:

unresolved symbol Fapi_initializeAPI, first referenced in ./BL/F28003x_EEPROM.obj

  • It seems like the linker does not recognize or include Fapi_initializeAPI()

code below: 

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




#define RX_MSG_OBJ_ID    1
#define MSG_DATA_LENGTH  8
#define MSGCOUNT        10
#define TX_MSG_OBJ_ID    2

///


// Globals
//

volatile uint32_t rxMsgCount = MSGCOUNT;
uint16_t rxMsgData[4];
uint32_t msgID;
volatile unsigned long i;
volatile uint32_t errorFlag = 0;
CAN_MsgFrameType FrameType;

//
// Function Prototypes
//
__interrupt void canaISR(void);


//
// Main
//
void main(void)
{

    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Initialize GPIO and configure GPIO pins for CANTX/CANRX
    // on module A.
    //
    Device_initGPIO();
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);

    //
    // Initialize the CAN controllers
    //
    CAN_initModule(CANA_BASE);

    //
    // Set up the CAN bus bit rate to 500kHz for each module
    // Refer to the Driver Library User Guide for information on how to set
    // tighter timing control. Additionally, consult the device data sheet
    // for more information about the CAN module clocking.
    //
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 100000, 20);

    //
    // Enable interrupts on the CAN A peripheral.
    //
    CAN_enableInterrupt(CANA_BASE, CAN_INT_IE0 | CAN_INT_ERROR |
                        CAN_INT_STATUS);

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

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    // This registers the interrupt handler in PIE vector table.
    //
    Interrupt_register(INT_CANA0,&canaISR);

    //
    // Enable the CAN-A interrupt signal
    //
    Interrupt_enable(INT_CANA0);




    CAN_enableGlobalInterrupt(CANA_BASE, CAN_GLOBAL_INT_CANINT0);
//    Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, 5);
//
//    oReturnCheck = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS, 120);
//
//    if(oReturnCheck != Fapi_Status_Success)
//    {
//        // Check Flash API documentation for possible errors
//        Sample_Error();
//    }

    fapi_init();
    //
    // Initialize the receive message object used for receiving CAN messages.
    // Message Object Parameters:

    CAN_setupMessageObject(CANA_BASE, RX_MSG_OBJ_ID, 0,
                           CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0,
                           CAN_MSG_OBJ_USE_ID_FILTER | CAN_MSG_OBJ_RX_INT_ENABLE,
                           MSG_DATA_LENGTH);
    //
    // Start CAN module A operations
    //
    CAN_startModule(CANA_BASE);


    //
    // Loop to keep receiving data from another CAN Controller.
    //
    while(1)
    {
    }

    //
    // Stop application after completion.
    //
    asm("   ESTOP0");
}

//
// CAN A ISR - The interrupt service routine called when a CAN interrupt is
//             triggered on CAN module A.
//
__interrupt void
canaISR(void)
{
    uint32_t status;

    //
    // Read the CAN-B interrupt status to find the cause of the interrupt
    //
    status = CAN_getInterruptCause(CANA_BASE);

    //
    // If the cause is a controller status interrupt, then get the status
    //
    if(status == CAN_INT_INT0ID_STATUS)
    {
        //
        // Read the controller status.  This will return a field of status
        // error bits that can indicate various errors.  Error processing
        // is not done in this example for simplicity.  Refer to the
        // API documentation for details about the error status bits.
        // The act of reading this status will clear the interrupt.
        //
        status = CAN_getStatus(CANA_BASE);

        //
        // Check to see if an error occurred.
        //
#ifdef TRANSMIT
        if(((status  & ~(CAN_STATUS_TXOK)) != CAN_STATUS_LEC_MSK) &&
           ((status  & ~(CAN_STATUS_TXOK)) != CAN_STATUS_LEC_NONE))
#else
        if(((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_MSK) &&
           ((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_NONE))
#endif
        {
            //
            // Set a flag to indicate some errors may have occurred.
            //
            errorFlag = 1;
        }
    }
    else if(status == TX_MSG_OBJ_ID)
    {
        //
        // Getting to this point means that the TX interrupt occurred on
        // message object 1, and the message TX is complete.  Clear the
        // message object interrupt.
        //
        CAN_clearInterruptStatus(CANA_BASE, TX_MSG_OBJ_ID);

        //
        // Increment a counter to keep track of how many messages have been
        // transmitted. In a real application this could be used to set flags to
        // indicate when a message is transmitted.
        //
        //txMsgCount++;

        //
        // Since the message was transmitted, clear any error flags.
        //
        errorFlag = 0;

    }

    else if(status == RX_MSG_OBJ_ID)
    {
        //
        // Get the received message
        //
        //CAN_readMessage(CANA_BASE, RX_MSG_OBJ_ID, rxMsgData);
        CAN_readMessageWithID(CANA_BASE,RX_MSG_OBJ_ID,&FrameType,&msgID,rxMsgData);
        UpdaterCAN(msgID);
        //
        // Getting to this point means that the RX interrupt occurred on
        // message object 1, and the message RX is complete.  Clear the
        // message object interrupt.
        //
        CAN_clearInterruptStatus(CANA_BASE, RX_MSG_OBJ_ID);

        //
        // Decrement the counter after a message has been received.
        //

        //
        // Since the message was received, clear any error flags.
        //
        errorFlag = 0;
        //CAN_sendMessage(CANA_BASE, TX_MSG_OBJ_ID, MSG_DATA_LENGTH,txMsgData);
    }

    //
    // If something unexpected caused the interrupt, this would handle it.
    //
    else
    {
        //
        // Spurious interrupt handling can go here.
        //
    }

    //
    // Clear the global interrupt flag for the CAN interrupt line
    //
    CAN_clearGlobalInterruptStatus(CANA_BASE, CAN_GLOBAL_INT_CANINT0);

    //
    // Acknowledge this interrupt located in group 9
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}


//
// End of File
//
//#############################################################################
//
// FILE:   F28003x_EEPROM.c
//
//#############################################################################

#include "EEPROM_Config.h"                   // Include EEPROM Config

// Global Variables
uint16 *Bank_Pointer;
uint16 *Page_Pointer;
uint16 *Sector_End;
uint16 WE_Protection_Mask;
uint32 Bank_Size;
uint16 Bank_Counter = 0;
uint16 Page_Counter = 0;
uint16 Bank_Status[8] = {0};
uint16 Page_Status[8] = {0};
uint16 Erase_Inactive_Unit = 0;
uint16 Erase_Blank_Check = 0;
uint16 NUM_EEPROM_SECTORS;
uint16 Empty_EEPROM = 1;
uint32_t   g_ulBankInitialized = 0;

// Edit this to select Flash Sector location for EEPROM Emulation
// NOTE: INSERT FIRST AND LAST SECTOR NUMBERS ONLY
// Example: To use sectors 1-10, insert {1,10}
// Example: To only use sector 1, insert {1,1}
uint16 FIRST_AND_LAST_SECTOR[2] = {1,1};


//######################### EEPROM_Config ############################
// The purpose of this function is to configure Write/Erase protection masks
// used by the Flash API and check inputs in EEPROM_Config.h for validity.
// If an invalid configuration is encountered, a non-zero code is returned.

int EEPROM_Config_Check(void){

    // FATAL ERRORS

    // Check if using Flash Bank 0 for EEPROM Emulation. If Flash API is
    // running from Flash Bank 0, the code will not execute. User can
    // change the linker command file as needed to do EEPROM on Flash Bank 0
    if (FLASH_BANK_SELECT == FlashBank0StartAddress)
    {
        return 0xFFFF;
    }
    // If using Bank 1
    else if (FLASH_BANK_SELECT == FlashBank1StartAddress) // If using Bank 1
    {
        #if !defined(F28003x) // Verify that appropriate device is being used
            return 0xFFFF;
        #endif
    }

    // If using Bank 2
    else if (FLASH_BANK_SELECT == FlashBank2StartAddress) // If using Bank 2
    {
        #if !defined(F28003x) // Verify that appropriate device is being used
            return 0xFFFF;
        #endif
    } 

    // Derive the number of Flash sectors for EEPROM emulation
    NUM_EEPROM_SECTORS = FIRST_AND_LAST_SECTOR[1] - FIRST_AND_LAST_SECTOR[0] + 1;

    // If invalid amount of EEPROM sectors defined, return error code
    if (NUM_EEPROM_SECTORS > NUM_FLASH_SECTORS || NUM_EEPROM_SECTORS == 0)
    {
        return 0xEEEE;
    }

    if (NUM_EEPROM_SECTORS > 1)
    {

        // Check if SECTOR_NUMBERS is sorted in increasing order and doesn't have duplicates
        if (FIRST_AND_LAST_SECTOR[1] <= FIRST_AND_LAST_SECTOR[0])
        {
            return 0xEEEE;
        }

        // Check if SECTOR_NUMBERS contains invalid sector
        if (FIRST_AND_LAST_SECTOR[0] > NUM_FLASH_SECTORS - 1)
        {
            return 0xEEEE;
        }
        if (FIRST_AND_LAST_SECTOR[1] > NUM_FLASH_SECTORS - 1 || FIRST_AND_LAST_SECTOR[1] < 1)
        {
            return 0xEEEE;
        }
    } else // If only one sector, validate it is input properly
    {

        // Verify that the only sector is valid
        if (FIRST_AND_LAST_SECTOR[0] > NUM_FLASH_SECTORS - 1) {
            return 0xEEEE;
        }
    }


#ifdef PAGE_MODE

    // Calculate size of each EEPROM Bank (16 bit words)
    Bank_Size = 8 + ((EEPROM_PAGE_DATA_SIZE + 8) * NUM_EEPROM_PAGES);

    // Calculate amount of available space (16 bit words)
    uint32 Available_Words = NUM_EEPROM_SECTORS * FLASH_SECTOR_SIZE;

    // Check if size of EEPROM Banks and Pages will fit in EEPROM sectors
    if (Bank_Size * NUM_EEPROM_BANKS > Available_Words)
    {
        return 0xCCCC;
    }

#endif

    // WARNINGS (Not fatal errors)

    uint16 Warning_Flags = 0;

#ifdef PAGE_MODE
    // Notify for extra space (more than one bank leftover)
    if (Available_Words - (Bank_Size * NUM_EEPROM_BANKS ) >= Bank_Size)
    {
        Warning_Flags += 1;
    }

    // Notify if Page is less than 8 16-bit words
    // This wastes Flash space because the _64_BIT_MODE could be used to achieve the same effect; configuration should be optimized.
    // However, emulation can continue.
    if (EEPROM_PAGE_DATA_SIZE < 5)
    {
        Warning_Flags += 2;
    }
#endif

    // Reset Bank Pointer to beginning of EEPROM Unit
    RESET_BANK_POINTER;

    // Configure Write/Erase Protection Masks used by the Flash API
    WE_Protection_Mask = Configure_Protection_Masks(FIRST_AND_LAST_SECTOR, NUM_EEPROM_SECTORS);

    // Erase the EEPROM sectors before programming
    EEPROM_Erase();

    return Warning_Flags;

}
//######################### EEPROM_Config ############################

//######################### Configure_Protection_Masks ############################
// This function calculates the Write/Erase Protection masks needed by the Flash API.
// The masks are used to set CMDWEPROT register
// Bits 0-15 of CMDWEPROT is applicable for sectors 0-15, each bit represents a sector

uint16 Configure_Protection_Masks(uint16* Sector_Numbers, uint16 Num_EEPROM_Sectors)
{
    // Initialize a variable to store the bits indicating which sectors need to have write/erase
    // protection disabled.
    uint16 Protection_Mask_Sectors = 0;
    uint16 Unshifted_Sectors;

    // If we have more than one Flash Sector
    if (Num_EEPROM_Sectors > 1)
    {
        // Configure mask
        Unshifted_Sectors = (uint16) 1 << Num_EEPROM_Sectors;
        Unshifted_Sectors -= 1;
        Protection_Mask_Sectors |= (Unshifted_Sectors << Sector_Numbers[0]);

    } else { // If only using 1 Flash Sector

        if(Sector_Numbers[0] < 16)
        {
            Unshifted_Sectors = (uint16) 1 << Sector_Numbers[0];
            Protection_Mask_Sectors |= Unshifted_Sectors;
        }

    }

    return Protection_Mask_Sectors;

}
//######################### Configure_Protection_Masks ############################

//######################### EEPROM_GET_VALID_BANK ############################
void EEPROM_GetValidBank(uint16 Read_Flag)
{
    //Each page holds N Data Words
    //Page size = 8 Page_Status Words + N Data Words = (8 + N) Words
    //Bank Size = 8 Bank_Status words + NUM_EEPROM_PAGES * Page size = 8 + NUM_EEPROM_PAGES*(8 + N) Words

    uint16 i;

    RESET_BANK_POINTER;     // Reset Bank Pointer to enable search for current Bank
    RESET_PAGE_POINTER;     // Reset Page Pointer to enable search for current Page

    // Find Current Bank
    for(i=0; i < NUM_EEPROM_BANKS; i++)
    {
        Bank_Status[0] = *(Bank_Pointer);       // Read contents of Bank Pointer
        Bank_Status[4] = *(Bank_Pointer + 4);

        if(Bank_Status[0] == EMPTY_BANK)        // Check for Unused Bank
        {
            Bank_Counter = i;                   // Set Bank Counter to number of current page
            return;                             // If Bank is Unused, return as EEPROM is empty
        }

        if(Bank_Status[0] == CURRENT_BANK && Bank_Status[4] != CURRENT_BANK)      // Check for Current Bank
        {
            Bank_Counter = i;                   // Set Bank Counter to number of current bank
            Page_Pointer = Bank_Pointer + 8;    // Set Page Pointer to first page in current bank
            break;                              // Break from loop as current bank has been found
        }

        if(Bank_Status[0] == CURRENT_BANK && Bank_Status[4] == CURRENT_BANK)         // Check for Used Bank
            Bank_Pointer += Bank_Size;          // If Bank has been used, set pointer to next bank

    }

    // Find Current Page
    for(i=0; i < NUM_EEPROM_PAGES; i++)
    {
        Page_Status[0] = *(Page_Pointer);       // Read contents of Page Pointer
        Page_Status[4] = *(Page_Pointer + 4);

        // Check for Blank Page or Current Page
        if(Page_Status[0] == BLANK_PAGE)
        {
            Page_Counter = i;                   // Set Page Counter to number of current page
            break;                              // Break from loop as current page has been found
        }

        if (Page_Status[0] == CURRENT_PAGE && Page_Status[4] != CURRENT_PAGE)
        {
            Page_Counter = i + 1;
            break;
        }

        // Check for Used Page
        if(Page_Status[0] == CURRENT_PAGE && Page_Status[4] == CURRENT_PAGE)
        {
            Page_Pointer += EEPROM_PAGE_DATA_SIZE + 8;                 // If page has been used, set pointer to next page
        }

    }

    // Check for full EEPROM
    if (!Read_Flag)
    {
        if (Bank_Counter == NUM_EEPROM_BANKS - 1 && Page_Counter == NUM_EEPROM_PAGES)
        {
            // Re-Configure Write/Erase Protection Masks used by the Flash API
            WE_Protection_Mask ^= 0xFFFF;

            Erase_Inactive_Unit = 1;                // Set flag to erase inactive (full) Flash Bank
            EEPROM_UpdatePageStatus();              // Update Page Status of previous page
            EEPROM_UpdateBankStatus();              // Update Bank Status of previous page
            Erase_Blank_Check = 1;                  // Set flag to perform blank check on inactive (full) Flash Bank
            EEPROM_Erase();                         // Erase flash sector being used as EEPROM
            RESET_BANK_POINTER;                     // Reset Bank Pointer as EEPROM is empty
            RESET_PAGE_POINTER;                     // Reset Page Pointer as EEPROM is empty
        }
    }

}
//######################### EEPROM_GET_VALID_BANK ############################


//############################# EEPROM_ERASE #################################
void EEPROM_Erase()
{

    Fapi_StatusType  oReturnCheck;

    // Erase the EEPROM Bank
    oReturnCheck = Fapi_issueBankEraseCommand((uint32*) FLASH_BANK_SELECT, WE_Protection_Mask);

    // Wait for completion and check for any programming errors
    EEPROM_CheckStatus(&oReturnCheck);

}
//############################# EEPROM_ERASE #################################

//############################# ERASE_BANK #################################
void Erase_Bank()
{
    Fapi_StatusType  oReturnCheck;

    // Erase the EEPROM Bank
    oReturnCheck = Fapi_issueBankEraseCommand((uint32*) FLASH_BANK_SELECT, WE_Protection_Mask);
    // Wait for completion and check for any programming errors
    EEPROM_CheckStatus(&oReturnCheck);
}

//############################# EEPROM_READ ##################################
void EEPROM_Read(uint16* Read_Buffer)
{

#ifdef PAGE_MODE
    uint16 i;

    // Check for empty EEPROM
    if (Empty_EEPROM)
    {
        Sample_Error(); // Attempting to read data that hasn't been written
    } else
    {
        // Find Current Bank and Current Page
        EEPROM_GetValidBank(1);

        // Increment page pointer to point at first data word
        Page_Pointer += 8;

        // Transfer contents of Current Page to Read Buffer
        for(i=0;i<DATA_SIZE;i++)
        {
            Read_Buffer[i] = *(Page_Pointer++);
        }
    }
#else
    uint16 i;

    // Check for empty EEPROM
    if (Empty_EEPROM)
    {
        Sample_Error(); // Attempting to read data that hasn't been written
    } else
    {
        // Move the bank pointer backwards to read data
        Bank_Pointer -= 4;

        // Transfer contents of Current Page to Read Buffer
        for(i=0;i<4;i++)
        {
            Read_Buffer[i] = *(Bank_Pointer++);
        }
    }

#endif

}
//############################# EEPROM_READ ##################################


//############################ EEPROM_WRITE ##################################
void EEPROM_Write(uint16* Write_Buffer)
{
    EEPROM_GetValidBank(0);                 // Find Current Bank and Current Page
    EEPROM_UpdatePageStatus();              // Update Page Status of previous page
    EEPROM_UpdateBankStatus();              // Update Bank Status of current and previous bank
    EEPROM_UpdatePageData(Write_Buffer);    // Update Page Data of current page
}
//############################ EEPROM_WRITE ##################################


//###################### EEPROM_UPDATE_BANK_STATUS ###########################
void EEPROM_UpdateBankStatus()
{
    // Variables needed for Flash API Functions
    Fapi_StatusType  oReturnCheck;

    Bank_Status[0] = *(Bank_Pointer);       // Read Bank Status from Bank Pointer
    Page_Status[0] = *(Page_Pointer);       // Read Page Status from Page Pointer

    // Program Bank Status for Empty EEPROM
    if (Bank_Status[0] == EMPTY_BANK)
    {

        // Set Bank Status to Current Bank
        Bank_Status[0] = CURRENT_BANK;
        Bank_Status[1] = CURRENT_BANK;
        Bank_Status[2] = CURRENT_BANK;
        Bank_Status[3] = CURRENT_BANK;

        // Program Bank Status to current bank
        oReturnCheck = Fapi_issueProgrammingCommand((uint32*) Bank_Pointer,
                                                    Bank_Status, 4, 0, 0,
                                                    Fapi_AutoEccGeneration);

        // Wait for completion and check for any programming errors
        EEPROM_CheckStatus(&oReturnCheck);

        // Set Page Pointer to first page of current bank
        Page_Counter = 0;
        Page_Pointer = Bank_Pointer + 8;
    }

    // Program Bank Status of full bank and following bank
    if (Bank_Status[0] == CURRENT_BANK && Page_Counter == NUM_EEPROM_PAGES)
    {
        // Set Bank Status to Used Bank
        Bank_Status[0] = CURRENT_BANK;
        Bank_Status[1] = CURRENT_BANK;
        Bank_Status[2] = CURRENT_BANK;
        Bank_Status[3] = CURRENT_BANK;

        // Program Bank Status to full bank
        oReturnCheck = Fapi_issueProgrammingCommand((uint32*) Bank_Pointer + 2,
                                                            Bank_Status, 4, 0, 0,
                                                            Fapi_AutoEccGeneration);

        // Wait for completion and check for any programming errors
        EEPROM_CheckStatus(&oReturnCheck);

        // Increment Bank Pointer to next bank
        Bank_Pointer += Bank_Size;

        if (Bank_Counter == NUM_EEPROM_BANKS - 1 && Page_Counter == NUM_EEPROM_PAGES){
            return;
        }
        else{
        // Set Bank Status to Current Bank
        Bank_Status[0] = CURRENT_BANK;
        Bank_Status[1] = CURRENT_BANK;
        Bank_Status[2] = CURRENT_BANK;
        Bank_Status[3] = CURRENT_BANK;

        // Program Bank Status to current bank
        oReturnCheck = Fapi_issueProgrammingCommand((uint32*) Bank_Pointer,
                                                            Bank_Status, 4, 0, 0,
                                                            Fapi_AutoEccGeneration);

        // Wait for completion and check for any programming errors
        EEPROM_CheckStatus(&oReturnCheck);

        // Set Page Pointer to first page of current bank
        Page_Counter = 0;
        Page_Pointer = Bank_Pointer + 8;
        }
    }
}
//###################### EEPROM_UPDATE_BANK_STATUS ###########################


//###################### EEPROM_UPDATE_PAGE_STATUS ###########################
void EEPROM_UpdatePageStatus()
{

    Fapi_StatusType  oReturnCheck;

    Bank_Status[0] = *(Bank_Pointer);       // Read Bank Status from Bank Pointer
    Page_Status[0] = *(Page_Pointer);       // Read Page Status from Page Pointer

    // Check if Page Status is blank. If so return to EEPROM_WRITE.
    if(Page_Status[0] == BLANK_PAGE)
        return;

    // Program previous page's status to Used Page
    else
    {

        // Set Page Status to Used Page
        Page_Status[0] = CURRENT_PAGE;
        Page_Status[1] = CURRENT_PAGE;
        Page_Status[2] = CURRENT_PAGE;
        Page_Status[3] = CURRENT_PAGE;

        // Program Bank Status to current bank
        oReturnCheck = Fapi_issueProgrammingCommand((uint32*) Page_Pointer + 2,
                                                            Page_Status, 4, 0, 0,
                                                            Fapi_AutoEccGeneration);

        // Wait for completion and check for any programming errors
        EEPROM_CheckStatus(&oReturnCheck);

        // Increment Page Pointer to next page
        Page_Pointer += EEPROM_PAGE_DATA_SIZE + 8;
    }
}
//###################### EEPROM_UPDATE_PAGE_STATUS ###########################

//###################### EEPROM_UPDATE_PAGE_DATA ###########################
void EEPROM_UpdatePageData(uint16* Write_Buffer)
{
    // Variable for write incrementing
    uint16 i;

    // Variables needed for Flash API Functions
    Fapi_StatusType  oReturnCheck;

    for (i = 0; i < EEPROM_PAGE_DATA_SIZE / 4; i++)
    {

        // Variable for page offset (first write position has offset of 2 (64 bits),
        // second has offset of 4 (128 bits), etc.)
        uint32 Page_Offset = 4 + (2 * i);

        // Program data located in Write_Buffer to current page
        oReturnCheck = Fapi_issueProgrammingCommand((uint32*) Page_Pointer + Page_Offset,
                                                    Write_Buffer + (i*4), 4, 0, 0,
                                                    Fapi_AutoEccGeneration);

        // Wait for completion and check for any programming errors
        EEPROM_CheckStatus(&oReturnCheck);
    }


    if(oReturnCheck == Fapi_Status_Success)
    {
        // Set Page Status to Current Page
        Page_Status[0] = CURRENT_PAGE;
        Page_Status[1] = CURRENT_PAGE;
        Page_Status[2] = CURRENT_PAGE;
        Page_Status[3] = CURRENT_PAGE;

        oReturnCheck = Fapi_issueProgrammingCommand((uint32*) Page_Pointer,
                                                    Page_Status, 4, 0, 0,
                                                    Fapi_AutoEccGeneration);

        // Wait for completion and check for any programming errors
        EEPROM_CheckStatus(&oReturnCheck);

        Empty_EEPROM = 0;

    }
    if (Erase_Inactive_Unit)
    {
        // Erase the inactive (full) EEPROM Bank
        Erase_Inactive_Unit = 0;
        // Re-configure Write/Erase Protection Masks for active EEPROM Bank
        WE_Protection_Mask ^= 0xFFFF;
    }
}
//###################### EEPROM_UPDATE_PAGE_DATA ###########################

//###################### EEPROM_CHECKSTATUS ###########################
void EEPROM_CheckStatus(Fapi_StatusType* oReturnCheck)
{
    Fapi_FlashStatusType  oFlashStatus;
    Fapi_FlashStatusWordType oFlashStatusWord;

    uint32_t sectorAddress = FLASH_BANK_SELECT + FIRST_AND_LAST_SECTOR[0] * FLASH_SECTOR_SIZE;
    uint16_t sectorSize = (FIRST_AND_LAST_SECTOR[1] - FIRST_AND_LAST_SECTOR[0] + 1) * (FLASH_SECTOR_SIZE / 2);

    // 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
        Sample_Error();
    }

    //
    // 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 (Erase_Inactive_Unit && Erase_Blank_Check){
        *oReturnCheck = Fapi_doBlankCheck((uint32_t *) sectorAddress,
                                          sectorSize, &oFlashStatusWord);
        Erase_Blank_Check = 0;
    }

    if(*oReturnCheck != Fapi_Status_Success || oFlashStatus != 0)
    {
        //Check FMSTAT and debug accordingly
        Sample_Error();
    }
}
//###################### EEPROM_CHECKSTATUS ###########################


//###################### EEPROM_GET_FOUR_WORD_POINTER ###########################
// NOTE: This function expects that 0xFFFF is invalid data
void EEPROM_Get_64_Bit_Data_Address()
{
    uint16 *End_Address;

    End_Address = (uint16 *)END_OF_SECTOR;  // Set End_Address for sector

    if(Bank_Pointer > End_Address-3)         // Test if EEPROM is full
    {
        // Re-Configure Write/Erase Protection Masks used by the Flash API
        WE_Protection_Mask ^= 0xFFFF;
        Erase_Inactive_Unit = 1;            // Set flag to erase inactive (full) Flash Bank
        Erase_Blank_Check = 1;              // Set flag to perform blank check on inactive (full) Flash Bank
        EEPROM_Erase();                     // Erase flash Bank being used as EEPROM
        Erase_Inactive_Unit = 0;            // Reset flag for erasing inactive (full) Flash Bank)
        RESET_BANK_POINTER;                 // Reset Bank Pointer as EEPROM is empty

    }

}
//###################### EEPROM_GET_SINGLE_POINTER ###########################


//##################### EEPROM_PROGRAM_FOUR_WORDS ###########################
// NOTE: If Num_Words < 4, the missing missing words will be filled with 0xFFFF
// Example: EEPROM_Program_64_Bits(2, 1, 2, 3, 4)
// This results in [0x0001 0x0002 0xFFFF 0xFFFF] being programmed to Flash
void EEPROM_Program_64_Bits(uint16 Num_Words, uint16 * Write_Buffer)
{

    // Variables needed for Flash API Functions
    Fapi_StatusType oReturnCheck;

    // Test for full sector
    EEPROM_Get_64_Bit_Data_Address();

    // Overwrite anything in first 4 Write_Buffer addresses with 0xFFFF if less than 4 words are to be written
    int i;
    for(i = Num_Words; i < 4; i++)
    {
        Write_Buffer[i] = 0xFFFF;
    }

    oReturnCheck = Fapi_issueProgrammingCommand((uint32*) Bank_Pointer,
                                                Write_Buffer, 4, 0, 0,
                                                Fapi_AutoEccGeneration);

    // Wait for completion and check for any programming errors
    EEPROM_CheckStatus(&oReturnCheck);

    Empty_EEPROM = 0;

    // Increment to next location
    Bank_Pointer += 4;


}
//##################### EEPROM_PROGRAM_FOUR_WORDS ###########################

//##################### Fapi_init ###########################

Fapi_StatusType fapi_init(void)
{
    Fapi_StatusType oReturnCheck;
    Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, 5);

    oReturnCheck = Fapi_initializeAPI(F021_CPU0_BASE_ADDRESS, 120);

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

}


//##################### Fapi_Write_EEPROM ###########################


uint32_t Fapi_Write_EEPROM(uint32_t dest_address, uint32_t src_address, uint32_t SizeInBytes)
{
    Fapi_StatusType status = Fapi_Status_Success;

    register uint32_t src = src_address;
    register uint32_t dst = dest_address;
    uint32_t bytes;

    // Out of Bank 3
    if (dest_address < 0xA0000 || dest_address > 0xAFFFF)
        return (2);


    status = Fapi_setActiveFlashBank(Fapi_FlashBank2);
    status = Fapi_setupBankSectorEnable();

    while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);
    while(Fapi_checkFsmForReady() != Fapi_Status_Success);

    //! Erase Bank7 - Sector0
    status = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, (uint32_t *)dst);
    if (status != Fapi_Status_Success)
        return (1);

    while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);
    while(Fapi_checkFsmForReady() != Fapi_Status_Success);

    if (SizeInBytes < 8)
        bytes = SizeInBytes;
    else
        bytes = 8;

    //! Write data to Bank7 - Sector0
    while( SizeInBytes > 0)
    {
    status = Fapi_issueProgrammingCommand((uint32_t *)dst,
                                          (uint8_t *)src,
                                          (uint32_t) bytes,
                                          0,
                                          0,
                                          Fapi_AutoEccGeneration);

        while(Fapi_checkFsmForReady() == Fapi_Status_FsmBusy);
        while(Fapi_checkFsmForReady() != Fapi_Status_Success);

        src += bytes;
        dst += bytes;
        SizeInBytes -= bytes;
        if ( SizeInBytes < 8){
           bytes = SizeInBytes;
        }
    }

    //! success
    return (0);
}

uint32_t Fapi_Read_EEPROM(uint32_t dest_address, uint32_t src_address, uint32_t SizeInBytes)
{
    memcpy((uint32_t *)dest_address, (uint32_t *)src_address, SizeInBytes);

    //! success
    return (0);
}

//##################### Fapi_Write_EEPROM ###########################




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

//##################### SAMPLE_ERROR ###########################
// This is a sample error function, no error handling is implemented in this project,
void Sample_Error() {

     asm(" ESTOP0");

}

//##################### EXAMPLE_DONE ###########################
// This is a sample function that signifies the end of program execution
void Example_Done() {

    asm(" ESTOP0");

}