1157 lines
38 KiB
C
1157 lines
38 KiB
C
//*****************************************************************************
|
|
//
|
|
// eeprom.c - Driver for programming the on-chip EEPROM.
|
|
//
|
|
// Copyright (c) 2010-2020 Texas Instruments Incorporated. All rights reserved.
|
|
// Software License Agreement
|
|
//
|
|
// 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.
|
|
//
|
|
// This is part of revision 2.2.0.295 of the Tiva Peripheral Driver Library.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include "inc/hw_eeprom.h"
|
|
#include "inc/hw_flash.h"
|
|
#include "inc/hw_ints.h"
|
|
#include "inc/hw_sysctl.h"
|
|
#include "inc/hw_types.h"
|
|
#include "driverlib/debug.h"
|
|
#include "driverlib/flash.h"
|
|
#include "driverlib/interrupt.h"
|
|
#include "driverlib/sysctl.h"
|
|
#include "driverlib/eeprom.h"
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! \addtogroup eeprom_api
|
|
//! @{
|
|
//
|
|
//*****************************************************************************
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Useful macros to extract the number of EEPROM blocks available on the target
|
|
// device and the total EEPROM storage in bytes from the EESIZE register.
|
|
//
|
|
//*****************************************************************************
|
|
#define BLOCKS_FROM_EESIZE(x) (((x) & EEPROM_EESIZE_BLKCNT_M) >> \
|
|
EEPROM_EESIZE_BLKCNT_S)
|
|
#define SIZE_FROM_EESIZE(x) ((((x) & EEPROM_EESIZE_WORDCNT_M) >> \
|
|
EEPROM_EESIZE_WORDCNT_S) * 4)
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Useful macro to extract the offset from a linear address.
|
|
//
|
|
//*****************************************************************************
|
|
#define OFFSET_FROM_ADDR(x) (((x) >> 2) & 0x0F)
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// The key value required to initiate a mass erase.
|
|
//
|
|
//*****************************************************************************
|
|
#define EEPROM_MASS_ERASE_KEY ((uint32_t)0xE37B << EEPROM_EEDBGME_KEY_S)
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// This function implements a workaround for a bug in Blizzard rev A silicon.
|
|
// It ensures that only the 1KB flash sector containing a given EEPROM address
|
|
// is erased if an erase/copy operation is required as a result of a following
|
|
// EEPROM write.
|
|
//
|
|
//*****************************************************************************
|
|
static void
|
|
_EEPROMSectorMaskSet(uint32_t ui32Address)
|
|
{
|
|
uint32_t ui32Mask;
|
|
|
|
//
|
|
// Determine which page contains the passed EEPROM address. The 2KB EEPROM
|
|
// is implemented in 16KB of flash with each 1KB sector of flash holding
|
|
// values for 32 consecutive EEPROM words (or 128 bytes).
|
|
//
|
|
ui32Mask = ~(1 << (ui32Address >> 7));
|
|
|
|
SysCtlDelay(10);
|
|
HWREG(0x400FD0FC) = 3;
|
|
SysCtlDelay(10);
|
|
HWREG(0x400AE2C0) = ui32Mask;
|
|
SysCtlDelay(10);
|
|
HWREG(0x400FD0FC) = 0;
|
|
SysCtlDelay(10);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Clear the FSM sector erase mask to ensure that any following main array
|
|
// flash erase operations operate as expected.
|
|
//
|
|
//*****************************************************************************
|
|
static void
|
|
_EEPROMSectorMaskClear(void)
|
|
{
|
|
SysCtlDelay(10);
|
|
HWREG(0x400FD0FC) = 3;
|
|
SysCtlDelay(10);
|
|
HWREG(0x400AE2C0) = 0;
|
|
SysCtlDelay(10);
|
|
HWREG(0x400FD0FC) = 0;
|
|
SysCtlDelay(10);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Block until the EEPROM peripheral is not busy.
|
|
//
|
|
//*****************************************************************************
|
|
static void
|
|
_EEPROMWaitForDone(void)
|
|
{
|
|
//
|
|
// Is the EEPROM still busy?
|
|
//
|
|
while(HWREG(EEPROM_EEDONE) & EEPROM_EEDONE_WORKING)
|
|
{
|
|
//
|
|
// Spin while EEPROM is busy.
|
|
//
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Performs any necessary recovery in case of power failures during write.
|
|
//!
|
|
//! This function \b must be called after SysCtlPeripheralEnable() and before
|
|
//! the EEPROM is accessed. It is used to check for errors in the EEPROM state
|
|
//! such as from power failure during a previous write operation. The function
|
|
//! detects these errors and performs as much recovery as possible.
|
|
//!
|
|
//! If \b EEPROM_INIT_ERROR is returned, the EEPROM was unable to recover its
|
|
//! state. If power is stable when this occurs, this indicates a fatal
|
|
//! error and is likely an indication that the EEPROM memory has exceeded its
|
|
//! specified lifetime write/erase specification. If the supply voltage is
|
|
//! unstable when this return code is observed, retrying the operation once the
|
|
//! voltage is stabilized may clear the error.
|
|
//!
|
|
//! Failure to call this function after a reset may lead to incorrect operation
|
|
//! or permanent data loss if the EEPROM is later written.
|
|
//!
|
|
//! \return Returns \b EEPROM_INIT_OK if no errors were detected or \b
|
|
//! EEPROM_INIT_ERROR if the EEPROM peripheral cannot currently recover from
|
|
//! an interrupted write or erase operation.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMInit(void)
|
|
{
|
|
uint32_t ui32Status;
|
|
|
|
//
|
|
// Insert a small delay (6 cycles + call overhead) to guard against the
|
|
// possibility that this function is called immediately after the EEPROM
|
|
// peripheral is enabled. Without this delay, there is a slight chance
|
|
// that the first EEPROM register read will fault if you are using a
|
|
// compiler with a ridiculously good optimizer!
|
|
//
|
|
SysCtlDelay(2);
|
|
|
|
//
|
|
// Make sure the EEPROM has finished any ongoing processing.
|
|
//
|
|
_EEPROMWaitForDone();
|
|
|
|
//
|
|
// Read the EESUPP register to see if any errors have been reported.
|
|
//
|
|
ui32Status = HWREG(EEPROM_EESUPP);
|
|
|
|
//
|
|
// Did an error of some sort occur during initialization?
|
|
//
|
|
if(ui32Status & (EEPROM_EESUPP_PRETRY | EEPROM_EESUPP_ERETRY))
|
|
{
|
|
return(EEPROM_INIT_ERROR);
|
|
}
|
|
|
|
//
|
|
// Perform a second EEPROM reset.
|
|
//
|
|
SysCtlPeripheralReset(SYSCTL_PERIPH_EEPROM0);
|
|
|
|
//
|
|
// Wait for the EEPROM to complete its reset processing once again.
|
|
//
|
|
SysCtlDelay(2);
|
|
_EEPROMWaitForDone();
|
|
|
|
//
|
|
// Read EESUPP once again to determine if any error occurred.
|
|
//
|
|
ui32Status = HWREG(EEPROM_EESUPP);
|
|
|
|
//
|
|
// Was an error reported following the second reset?
|
|
//
|
|
if(ui32Status & (EEPROM_EESUPP_PRETRY | EEPROM_EESUPP_ERETRY))
|
|
{
|
|
return(EEPROM_INIT_ERROR);
|
|
}
|
|
|
|
//
|
|
// The EEPROM does not indicate that any error occurred.
|
|
//
|
|
return(EEPROM_INIT_OK);
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Determines the size of the EEPROM.
|
|
//!
|
|
//! This function returns the size of the EEPROM in bytes.
|
|
//!
|
|
//! \return Returns the total number of bytes in the EEPROM.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMSizeGet(void)
|
|
{
|
|
//
|
|
// Return the size of the EEPROM in bytes.
|
|
//
|
|
return(SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Determines the number of blocks in the EEPROM.
|
|
//!
|
|
//! This function may be called to determine the number of blocks in the
|
|
//! EEPROM. Each block is the same size and the number of bytes of storage
|
|
//! contained in a block may be determined by dividing the size of the device,
|
|
//! obtained via a call to the EEPROMSizeGet() function, by the number of
|
|
//! blocks returned by this function.
|
|
//!
|
|
//! \return Returns the total number of blocks in the device EEPROM.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMBlockCountGet(void)
|
|
{
|
|
//
|
|
// Extract the number of blocks and return it to the caller.
|
|
//
|
|
#ifdef EEPROM_SIZE_LIMIT
|
|
//
|
|
// If a size limit has been specified, fake the number of blocks to match.
|
|
//
|
|
return(EEPROM_SIZE_LIMIT / 48);
|
|
#else
|
|
//
|
|
// Return the actual number of blocks supported by the hardware.
|
|
//
|
|
return(BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
#endif
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Reads data from the EEPROM.
|
|
//!
|
|
//! \param pui32Data is a pointer to storage for the data read from the EEPROM.
|
|
//! This pointer must point to at least \e ui32Count bytes of available memory.
|
|
//! \param ui32Address is the byte address within the EEPROM from which data is
|
|
//! to be read. This value must be a multiple of 4.
|
|
//! \param ui32Count is the number of bytes of data to read from the EEPROM.
|
|
//! This value must be a multiple of 4.
|
|
//!
|
|
//! This function may be called to read a number of words of data from a
|
|
//! word-aligned address within the EEPROM. Data read is copied into the
|
|
//! buffer pointed to by the \e pui32Data parameter.
|
|
//!
|
|
//! \return None.
|
|
//
|
|
//*****************************************************************************
|
|
void
|
|
EEPROMRead(uint32_t *pui32Data, uint32_t ui32Address, uint32_t ui32Count)
|
|
{
|
|
//
|
|
// Check parameters in a debug build.
|
|
//
|
|
ASSERT(pui32Data);
|
|
ASSERT(ui32Address < SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
ASSERT((ui32Address + ui32Count) <=
|
|
SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
ASSERT((ui32Address & 3) == 0);
|
|
ASSERT((ui32Count & 3) == 0);
|
|
|
|
//
|
|
// Set the block and offset appropriately to read the first word.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = EEPROMBlockFromAddr(ui32Address);
|
|
HWREG(EEPROM_EEOFFSET) = OFFSET_FROM_ADDR(ui32Address);
|
|
|
|
//
|
|
// Convert the byte count to a word count.
|
|
//
|
|
ui32Count /= 4;
|
|
|
|
//
|
|
// Read each word in turn.
|
|
//
|
|
while(ui32Count)
|
|
{
|
|
//
|
|
// Read the next word through the autoincrementing register.
|
|
//
|
|
*pui32Data = HWREG(EEPROM_EERDWRINC);
|
|
|
|
//
|
|
// Move on to the next word.
|
|
//
|
|
pui32Data++;
|
|
ui32Count--;
|
|
|
|
//
|
|
// Do we need to move to the next block? This is the case if the
|
|
// offset register has just wrapped back to 0. Note that we only
|
|
// write the block register if we have more data to read. If this
|
|
// register is written, the hardware expects a read or write operation
|
|
// next. If a mass erase is requested instead, the mass erase will
|
|
// fail.
|
|
//
|
|
if(ui32Count && (HWREG(EEPROM_EEOFFSET) == 0))
|
|
{
|
|
HWREG(EEPROM_EEBLOCK) += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Writes data to the EEPROM.
|
|
//!
|
|
//! \param pui32Data points to the first word of data to write to the EEPROM.
|
|
//! \param ui32Address defines the byte address within the EEPROM that the data
|
|
//! is to be written to. This value must be a multiple of 4.
|
|
//! \param ui32Count defines the number of bytes of data that is to be written.
|
|
//! This value must be a multiple of 4.
|
|
//!
|
|
//! This function may be called to write data into the EEPROM at a given
|
|
//! word-aligned address. The call is synchronous and returns only after
|
|
//! all data has been written or an error occurs.
|
|
//!
|
|
//! \return Returns 0 on success or non-zero values on failure. Failure codes
|
|
//! are logical OR combinations of \b EEPROM_RC_WRBUSY, \b EEPROM_RC_NOPERM,
|
|
//! \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and \b EEPROM_RC_WORKING.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMProgram(uint32_t *pui32Data, uint32_t ui32Address, uint32_t ui32Count)
|
|
{
|
|
uint32_t ui32Status;
|
|
|
|
//
|
|
// Check parameters in a debug build.
|
|
//
|
|
ASSERT(pui32Data);
|
|
ASSERT(ui32Address < SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
ASSERT((ui32Address + ui32Count) <=
|
|
SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
ASSERT((ui32Address & 3) == 0);
|
|
ASSERT((ui32Count & 3) == 0);
|
|
|
|
//
|
|
// Make sure the EEPROM is idle before we start.
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Read the status.
|
|
//
|
|
ui32Status = HWREG(EEPROM_EEDONE);
|
|
}
|
|
while(ui32Status & EEPROM_EEDONE_WORKING);
|
|
|
|
//
|
|
// Set the block and offset appropriately to program the first word.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = EEPROMBlockFromAddr(ui32Address);
|
|
HWREG(EEPROM_EEOFFSET) = OFFSET_FROM_ADDR(ui32Address);
|
|
|
|
//
|
|
// Convert the byte count to a word count.
|
|
//
|
|
ui32Count /= 4;
|
|
|
|
//
|
|
// Write each word in turn.
|
|
//
|
|
while(ui32Count)
|
|
{
|
|
//
|
|
// This is a workaround for a silicon problem on Blizzard rev A. We
|
|
// need to do this before every word write to ensure that we don't
|
|
// have problems in multi-word writes that span multiple flash sectors.
|
|
//
|
|
if(CLASS_IS_TM4C123 && REVISION_IS_A0)
|
|
{
|
|
_EEPROMSectorMaskSet(ui32Address);
|
|
}
|
|
|
|
//
|
|
// Write the next word through the autoincrementing register.
|
|
//
|
|
HWREG(EEPROM_EERDWRINC) = *pui32Data;
|
|
|
|
//
|
|
// Wait a few cycles. In some cases, the WRBUSY bit is not set
|
|
// immediately and this prevents us from dropping through the polling
|
|
// loop before the bit is set.
|
|
//
|
|
SysCtlDelay(10);
|
|
|
|
//
|
|
// Wait for the write to complete.
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Read the status.
|
|
//
|
|
ui32Status = HWREG(EEPROM_EEDONE);
|
|
}
|
|
while(ui32Status & EEPROM_EEDONE_WORKING);
|
|
|
|
//
|
|
// Make sure we completed the write without errors. Note that we
|
|
// must check this per-word because write permission can be set per
|
|
// block resulting in only a section of the write not being performed.
|
|
//
|
|
if(ui32Status & EEPROM_EEDONE_NOPERM)
|
|
{
|
|
//
|
|
// An error was reported that would prevent the values from
|
|
// being written correctly.
|
|
//
|
|
if(CLASS_IS_TM4C123 && REVISION_IS_A0)
|
|
{
|
|
_EEPROMSectorMaskClear();
|
|
}
|
|
return(ui32Status);
|
|
}
|
|
|
|
//
|
|
// Move on to the next word.
|
|
//
|
|
pui32Data++;
|
|
ui32Count--;
|
|
|
|
//
|
|
// Do we need to move to the next block? This is the case if the
|
|
// offset register has just wrapped back to 0. Note that we only
|
|
// write the block register if we have more data to read. If this
|
|
// register is written, the hardware expects a read or write operation
|
|
// next. If a mass erase is requested instead, the mass erase will
|
|
// fail.
|
|
//
|
|
if(ui32Count && (HWREG(EEPROM_EEOFFSET) == 0))
|
|
{
|
|
HWREG(EEPROM_EEBLOCK) += 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clear the sector protection bits to prevent possible problems when
|
|
// programming the main flash array later.
|
|
//
|
|
if(CLASS_IS_TM4C123 && REVISION_IS_A0)
|
|
{
|
|
_EEPROMSectorMaskClear();
|
|
}
|
|
|
|
//
|
|
// Return the current status to the caller.
|
|
//
|
|
return(HWREG(EEPROM_EEDONE));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Writes a word to the EEPROM.
|
|
//!
|
|
//! \param ui32Data is the word to write to the EEPROM.
|
|
//! \param ui32Address defines the byte address within the EEPROM to which the
|
|
//! data is to be written. This value must be a multiple of 4.
|
|
//!
|
|
//! This function is intended to allow EEPROM programming under interrupt
|
|
//! control. It may be called to start the process of writing a single word of
|
|
//! data into the EEPROM at a given word-aligned address. The call is
|
|
//! asynchronous and returns immediately without waiting for the write to
|
|
//! complete. Completion of the operation is signaled by means of an
|
|
//! interrupt from the EEPROM module. The EEPROM peripheral shares a single
|
|
//! interrupt vector with the flash memory subsystem, \b INT_FLASH.
|
|
//!
|
|
//! \return Returns status and error information in the form of a logical OR
|
|
//! combinations of \b EEPROM_RC_WRBUSY, \b EEPROM_RC_NOPERM,
|
|
//! \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE and \b EEPROM_RC_WORKING. Flags
|
|
//! \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and \b EEPROM_RC_WORKING are
|
|
//! expected in normal operation and do not indicate an error.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMProgramNonBlocking(uint32_t ui32Data, uint32_t ui32Address)
|
|
{
|
|
//
|
|
// Check parameters in a debug build.
|
|
//
|
|
ASSERT(ui32Address < SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
ASSERT((ui32Address & 3) == 0);
|
|
|
|
//
|
|
// This is a workaround for a silicon problem on Blizzard rev A.
|
|
//
|
|
if(CLASS_IS_TM4C123 && REVISION_IS_A0)
|
|
{
|
|
_EEPROMSectorMaskSet(ui32Address);
|
|
}
|
|
|
|
//
|
|
// Set the block and offset appropriately to program the desired word.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = EEPROMBlockFromAddr(ui32Address);
|
|
HWREG(EEPROM_EEOFFSET) = OFFSET_FROM_ADDR(ui32Address);
|
|
|
|
//
|
|
// Write the new word using the auto-incrementing register just in case
|
|
// the caller wants to write follow-on words using direct register access
|
|
//
|
|
HWREG(EEPROM_EERDWRINC) = ui32Data;
|
|
|
|
//
|
|
// Return the current status to the caller.
|
|
//
|
|
return(HWREG(EEPROM_EEDONE));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Erases the EEPROM and returns it to the factory default condition.
|
|
//!
|
|
//! This function completely erases the EEPROM and removes any and
|
|
//! all access protection on its blocks, leaving the device in the factory
|
|
//! default condition. After this operation, all EEPROM words contain the
|
|
//! value 0xFFFFFFFF and all blocks are accessible for both read and write
|
|
//! operations in all CPU modes. No passwords are active.
|
|
//!
|
|
//! The function is synchronous and does not return until the erase operation
|
|
//! has completed.
|
|
//!
|
|
//! \return Returns 0 on success or non-zero values on failure. Failure codes
|
|
//! are logical OR combinations of \b EEPROM_RC_WRBUSY, \b EEPROM_RC_NOPERM,
|
|
//! \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and \b EEPROM_RC_WORKING.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMMassErase(void)
|
|
{
|
|
//
|
|
// This is a workaround for a silicon problem on Blizzard rev A.
|
|
//
|
|
if(CLASS_IS_TM4C123 && REVISION_IS_A0)
|
|
{
|
|
_EEPROMSectorMaskClear();
|
|
}
|
|
|
|
//
|
|
// Start the mass erase processing
|
|
//
|
|
HWREG(EEPROM_EEDBGME) = EEPROM_MASS_ERASE_KEY | EEPROM_EEDBGME_ME;
|
|
|
|
//
|
|
// Wait for completion.
|
|
//
|
|
_EEPROMWaitForDone();
|
|
|
|
//
|
|
// Reset the peripheral. This is required so that all protection
|
|
// mechanisms and passwords are reset now that the EEPROM data has been
|
|
// scrubbed.
|
|
//
|
|
SysCtlPeripheralReset(SYSCTL_PERIPH_EEPROM0);
|
|
|
|
//
|
|
// Wait for completion again.
|
|
//
|
|
SysCtlDelay(2);
|
|
_EEPROMWaitForDone();
|
|
|
|
//
|
|
// Pass any error codes back to the caller.
|
|
//
|
|
return(HWREG(EEPROM_EEDONE));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Returns the current protection level for an EEPROM block.
|
|
//!
|
|
//! \param ui32Block is the block number for which the protection level is to
|
|
//! be queried.
|
|
//!
|
|
//! This function returns the current protection settings for a given
|
|
//! EEPROM block. If block 0 is currently locked, it must be unlocked prior
|
|
//! to calling this function to query the protection setting for other blocks.
|
|
//!
|
|
//! \return Returns one of \b EEPROM_PROT_RW_LRO_URW, \b EEPROM_PROT_NA_LNA_URW
|
|
//! or \b EEPROM_PROT_RO_LNA_URO optionally OR-ed with
|
|
//! \b EEPROM_PROT_SUPERVISOR_ONLY.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMBlockProtectGet(uint32_t ui32Block)
|
|
{
|
|
//
|
|
// Parameter validity check.
|
|
//
|
|
ASSERT(ui32Block < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
|
|
//
|
|
// Set the current block.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = ui32Block;
|
|
|
|
//
|
|
// Return the protection flags for this block.
|
|
//
|
|
return(HWREG(EEPROM_EEPROT));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Set the current protection options for an EEPROM block.
|
|
//!
|
|
//! \param ui32Block is the block number for which the protection options are
|
|
//! to be set.
|
|
//! \param ui32Protect consists of one of the values \b EEPROM_PROT_RW_LRO_URW,
|
|
//! \b EEPROM_PROT_NA_LNA_URW or \b EEPROM_PROT_RO_LNA_URO optionally ORed with
|
|
//! \b EEPROM_PROT_SUPERVISOR_ONLY.
|
|
//!
|
|
//! This function sets the protection settings for a given EEPROM block
|
|
//! assuming no protection settings have previously been written. Note that
|
|
//! protection settings applied to block 0 have special meaning and control
|
|
//! access to the EEPROM peripheral as a whole. Protection settings applied to
|
|
//! blocks numbered 1 and above are layered above any protection set on block 0
|
|
//! such that the effective protection on each block is the logical OR of the
|
|
//! protection flags set for block 0 and for the target block. This protocol
|
|
//! allows global protection options to be set for the whole device via block
|
|
//! 0 and more restrictive protection settings to be set on a block-by-block
|
|
//! basis.
|
|
//!
|
|
//! The protection flags indicate access permissions as follow:
|
|
//!
|
|
//! \b EEPROM_PROT_SUPERVISOR_ONLY restricts access to the block to threads
|
|
//! running in supervisor mode. If clear, both user and supervisor threads
|
|
//! can access the block.
|
|
//!
|
|
//! \b EEPROM_PROT_RW_LRO_URW provides read/write access to the block if no
|
|
//! password is set or if a password is set and the block is unlocked. If the
|
|
//! block is locked, only read access is permitted.
|
|
//!
|
|
//! \b EEPROM_PROT_NA_LNA_URW provides neither read nor write access unless
|
|
//! a password is set and the block is unlocked. If the block is unlocked,
|
|
//! both read and write access are permitted.
|
|
//!
|
|
//! \b EEPROM_PROT_RO_LNA_URO provides read access to the block if no password
|
|
//! is set or if a password is set and the block is unlocked. If the block is
|
|
//! password protected and locked, neither read nor write access is permitted.
|
|
//!
|
|
//! \return Returns a logical OR combination of \b EEPROM_RC_WRBUSY, \b
|
|
//! EEPROM_RC_NOPERM, \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and \b
|
|
//! EEPROM_RC_WORKING to indicate status and error conditions.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMBlockProtectSet(uint32_t ui32Block, uint32_t ui32Protect)
|
|
{
|
|
//
|
|
// Parameter validity check.
|
|
//
|
|
ASSERT(ui32Block < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
|
|
//
|
|
// Set the current block.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = ui32Block;
|
|
|
|
//
|
|
// Set the protection options for this block.
|
|
//
|
|
HWREG(EEPROM_EEPROT) = ui32Protect;
|
|
|
|
//
|
|
// Wait for the write to complete.
|
|
//
|
|
while(HWREG(EEPROM_EEDONE) & EEPROM_EEDONE_WORKING)
|
|
{
|
|
//
|
|
// Still working.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Pass any error codes back to the caller.
|
|
//
|
|
return(HWREG(EEPROM_EEDONE));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Sets the password used to protect an EEPROM block.
|
|
//!
|
|
//! \param ui32Block is the EEPROM block number for which the password is to be
|
|
//! set.
|
|
//! \param pui32Password points to an array of uint32_t values comprising
|
|
//! the password to set. Each element may be any 32-bit value other than
|
|
//! 0xFFFFFFFF. This array must contain the number of elements given by the
|
|
//! \e ui32Count parameter.
|
|
//! \param ui32Count provides the number of uint32_ts in the \e ui32Password.
|
|
//! Valid values are 1, 2 and 3.
|
|
//!
|
|
//! This function allows the password used to unlock an EEPROM block to be
|
|
//! set. Valid passwords may be either 32, 64 or 96 bits comprising words
|
|
//! with any value other than 0xFFFFFFFF. The password may only be set once.
|
|
//! Any further attempts to set the password result in an error. Once the
|
|
//! password is set, the block remains unlocked until EEPROMBlockLock() is
|
|
//! called for that block or block 0, or a reset occurs.
|
|
//!
|
|
//! If a password is set on block 0, this affects locking of the peripheral as
|
|
//! a whole. When block 0 is locked, all other EEPROM blocks are inaccessible
|
|
//! until block 0 is unlocked. Once block 0 is unlocked, other blocks
|
|
//! become accessible according to any passwords set on those blocks and the
|
|
//! protection set for that block via a call to EEPROMBlockProtectSet().
|
|
//!
|
|
//! \return Returns a logical OR combination of \b EEPROM_RC_WRBUSY, \b
|
|
//! EEPROM_RC_NOPERM, \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and \b
|
|
//! EEPROM_RC_WORKING to indicate status and error conditions.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMBlockPasswordSet(uint32_t ui32Block, uint32_t *pui32Password,
|
|
uint32_t ui32Count)
|
|
{
|
|
uint32_t ui32Reg;
|
|
|
|
//
|
|
// Check parameters in a debug build.
|
|
//
|
|
ASSERT(pui32Password);
|
|
ASSERT(ui32Block < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
ASSERT(ui32Count <= 3);
|
|
|
|
//
|
|
// Set the block number whose password we are about to write.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = ui32Block;
|
|
|
|
//
|
|
// Start with the first password word.
|
|
//
|
|
ui32Reg = EEPROM_EEPASS0;
|
|
|
|
//
|
|
// Write the password.
|
|
//
|
|
while(ui32Count)
|
|
{
|
|
//
|
|
// Start the process of writing the password.
|
|
//
|
|
HWREG(ui32Reg) = *pui32Password;
|
|
|
|
//
|
|
// Update values in preparation for writing the next word.
|
|
//
|
|
pui32Password++;
|
|
ui32Reg += 4;
|
|
ui32Count--;
|
|
|
|
//
|
|
// Wait for the last word write to complete or an error to be reported.
|
|
//
|
|
while(HWREG(EEPROM_EEDONE) & EEPROM_EEDONE_WORKING)
|
|
{
|
|
//
|
|
// Still working.
|
|
//
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return the final write status.
|
|
//
|
|
return(HWREG(EEPROM_EEDONE));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Locks a password-protected EEPROM block.
|
|
//!
|
|
//! \param ui32Block is the EEPROM block number which is to be locked.
|
|
//!
|
|
//! This function locks an EEPROM block that has previously been protected by
|
|
//! writing a password. Access to the block once it is locked is determined
|
|
//! by the protection settings applied via a previous call to the
|
|
//! EEPROMBlockProtectSet() function. If no password has previously been set
|
|
//! for the block, this function has no effect.
|
|
//!
|
|
//! Locking block 0 has the effect of making all other blocks in the EEPROM
|
|
//! inaccessible.
|
|
//!
|
|
//! \return Returns the lock state for the block on exit, 1 if unlocked (as
|
|
//! would be the case if no password was set) or 0 if locked.
|
|
//!
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMBlockLock(uint32_t ui32Block)
|
|
{
|
|
//
|
|
// Check parameters in a debug build.
|
|
//
|
|
ASSERT(ui32Block < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
|
|
//
|
|
// Select the block we are going to lock.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = ui32Block;
|
|
|
|
//
|
|
// Lock the block.
|
|
//
|
|
HWREG(EEPROM_EEUNLOCK) = 0xFFFFFFFF;
|
|
|
|
//
|
|
// Return the current lock state.
|
|
//
|
|
return(HWREG(EEPROM_EEUNLOCK));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Unlocks a password-protected EEPROM block.
|
|
//!
|
|
//! \param ui32Block is the EEPROM block number which is to be unlocked.
|
|
//! \param pui32Password points to an array of uint32_t values containing
|
|
//! the password for the block. Each element must match the password
|
|
//! originally set via a call to EEPROMBlockPasswordSet().
|
|
//! \param ui32Count provides the number of elements in the \e pui32Password
|
|
//! array and must match the value originally passed to
|
|
//! EEPROMBlockPasswordSet(). Valid values are 1, 2 and 3.
|
|
//!
|
|
//! This function unlocks an EEPROM block that has previously been protected by
|
|
//! writing a password. Access to the block once it is unlocked is determined
|
|
//! by the protection settings applied via a previous call to the
|
|
//! EEPROMBlockProtectSet() function.
|
|
//!
|
|
//! To successfully unlock an EEPROM block, the password provided must match
|
|
//! the password provided on the original call to EEPROMBlockPasswordSet(). If
|
|
//! an incorrect password is provided, the block remains locked.
|
|
//!
|
|
//! Unlocking block 0 has the effect of making all other blocks in the device
|
|
//! accessible according to their own access protection settings. When block
|
|
//! 0 is locked, all other EEPROM blocks are inaccessible.
|
|
//!
|
|
//! \return Returns the lock state for the block on exit, 1 if unlocked or 0 if
|
|
//! locked.
|
|
//!
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMBlockUnlock(uint32_t ui32Block, uint32_t *pui32Password,
|
|
uint32_t ui32Count)
|
|
{
|
|
//
|
|
// Check parameters in a debug build.
|
|
//
|
|
ASSERT(pui32Password);
|
|
ASSERT(ui32Block < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
ASSERT(ui32Count <= 3);
|
|
|
|
//
|
|
// Set the block that we are trying to unlock.
|
|
//
|
|
HWREG(EEPROM_EEBLOCK) = ui32Block;
|
|
|
|
//
|
|
// Write the unlock register with 0xFFFFFFFF to reset the unlock
|
|
// sequence just in case a short password was previously used to try to
|
|
// unlock the block.
|
|
//
|
|
HWREG(EEPROM_EEUNLOCK) = 0xFFFFFFFF;
|
|
|
|
//
|
|
// We need to write the password words in the opposite order when unlocking
|
|
// compared to locking so start at the end of the array.
|
|
//
|
|
pui32Password += (ui32Count - 1);
|
|
|
|
//
|
|
// Write the supplied password to unlock the block.
|
|
//
|
|
while(ui32Count)
|
|
{
|
|
HWREG(EEPROM_EEUNLOCK) = *pui32Password--;
|
|
ui32Count--;
|
|
}
|
|
|
|
//
|
|
// Let the caller know if their password worked.
|
|
//
|
|
return(HWREG(EEPROM_EEUNLOCK));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Hides an EEPROM block until the next reset.
|
|
//!
|
|
//! \param ui32Block is the EEPROM block number which is to be hidden.
|
|
//!
|
|
//! This function hides an EEPROM block other than block 0. Once hidden, a
|
|
//! block is completely inaccessible until the next reset. This mechanism
|
|
//! allows initialization code to have access to data which is to be hidden
|
|
//! from the rest of the application. Unlike applications using passwords, an
|
|
//! application making using of block hiding need not contain any embedded
|
|
//! passwords which could be found through disassembly.
|
|
//!
|
|
//! \return None.
|
|
//!
|
|
//*****************************************************************************
|
|
void
|
|
EEPROMBlockHide(uint32_t ui32Block)
|
|
{
|
|
//
|
|
// Check parameters in a debug build.
|
|
//
|
|
ASSERT(!ui32Block);
|
|
ASSERT(ui32Block < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
|
|
|
|
//
|
|
// Hide the requested block.
|
|
//
|
|
HWREG(EEPROM_EEHIDE) = (1 << ui32Block);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Enables the EEPROM interrupt.
|
|
//!
|
|
//! \param ui32IntFlags indicates which EEPROM interrupt source to enable.
|
|
//! This must be \b EEPROM_INT_PROGRAM currently.
|
|
//!
|
|
//! This function enables the EEPROM interrupt. When enabled, an interrupt
|
|
//! is generated when any EEPROM write or erase operation completes. The
|
|
//! EEPROM peripheral shares a single interrupt vector with the flash memory
|
|
//! subsystem, \b INT_FLASH. This function is provided as a convenience but
|
|
//! the EEPROM interrupt can also be enabled using a call to FlashIntEnable()
|
|
//! passing FLASH_INT_EEPROM in the \e ui32IntFlags parameter.
|
|
//!
|
|
//! \return None.
|
|
//!
|
|
//*****************************************************************************
|
|
void
|
|
EEPROMIntEnable(uint32_t ui32IntFlags)
|
|
{
|
|
//
|
|
// Look for valid interrupt sources.
|
|
//
|
|
ASSERT(ui32IntFlags == EEPROM_INT_PROGRAM);
|
|
|
|
//
|
|
// Enable interrupts from the EEPROM module.
|
|
//
|
|
HWREG(EEPROM_EEINT) |= EEPROM_EEINT_INT;
|
|
|
|
//
|
|
// Enable the EEPROM interrupt in the flash controller module.
|
|
//
|
|
HWREG(FLASH_FCIM) |= FLASH_FCRIS_ERIS;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Disables the EEPROM interrupt.
|
|
//!
|
|
//! \param ui32IntFlags indicates which EEPROM interrupt source to disable.
|
|
//! This must be \b EEPROM_INT_PROGRAM currently.
|
|
//!
|
|
//! This function disables the EEPROM interrupt and prevents calls to the
|
|
//! interrupt vector when any EEPROM write or erase operation completes. The
|
|
//! EEPROM peripheral shares a single interrupt vector with the flash memory
|
|
//! subsystem, \b INT_FLASH. This function is provided as a convenience but
|
|
//! the EEPROM interrupt can also be disabled using a call to FlashIntDisable()
|
|
//! passing FLASH_INT_EEPROM in the \e ui32IntFlags parameter.
|
|
//!
|
|
//! \return None.
|
|
//!
|
|
//*****************************************************************************
|
|
void
|
|
EEPROMIntDisable(uint32_t ui32IntFlags)
|
|
{
|
|
//
|
|
// Look for valid interrupt sources.
|
|
//
|
|
ASSERT(ui32IntFlags == EEPROM_INT_PROGRAM);
|
|
|
|
//
|
|
// Disable the EEPROM interrupt in the flash controller module.
|
|
//
|
|
HWREG(FLASH_FCIM) &= ~FLASH_FCIM_EMASK;
|
|
|
|
//
|
|
// Disable interrupts from the EEPROM module.
|
|
//
|
|
HWREG(EEPROM_EEINT) &= ~EEPROM_EEINT_INT;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Reports the state of the EEPROM interrupt.
|
|
//!
|
|
//! \param bMasked determines whether the masked or unmasked state of the
|
|
//! interrupt is to be returned. If bMasked is \b true, the masked state is
|
|
//! returned, otherwise the unmasked state is returned.
|
|
//!
|
|
//! This function allows an application to query the state of the EEPROM
|
|
//! interrupt. If active, the interrupt may be cleared by calling
|
|
//! EEPROMIntClear().
|
|
//!
|
|
//! \return Returns \b EEPROM_INT_PROGRAM if an interrupt is being signaled or
|
|
//! 0 otherwise.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMIntStatus(bool bMasked)
|
|
{
|
|
if(bMasked)
|
|
{
|
|
//
|
|
// If asked for the masked interrupt status, we check to see if the
|
|
// relevant interrupt is pending in the flash controller then return
|
|
// the appropriate EEPROM flag if it is.
|
|
//
|
|
return((HWREG(FLASH_FCMISC) & FLASH_FCMISC_EMISC) ?
|
|
EEPROM_INT_PROGRAM : 0);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If asked for the unmasked interrupt status, infer that an interrupt
|
|
// is pending if the WORKING bit of the EEDONE register is clear. The
|
|
// actual interrupt fires on the high to low transition of this bit
|
|
// but we don't have access to an unmasked interrupt status for the
|
|
// EEPROM because it's handled via the flash controller so we have to
|
|
// make do with this instead.
|
|
//
|
|
return((HWREG(EEPROM_EEDONE) & EEPROM_EEDONE_WORKING) ?
|
|
0 : EEPROM_INT_PROGRAM);
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Clears the EEPROM interrupt.
|
|
//!
|
|
//! \param ui32IntFlags indicates which interrupt sources to clear. Currently,
|
|
//! the only valid value is \b EEPROM_INT_PROGRAM.
|
|
//!
|
|
//! This function allows an application to clear the EEPROM interrupt.
|
|
//!
|
|
//! \note Because there is a write buffer in the Cortex-M processor, it may
|
|
//! take several clock cycles before the interrupt source is actually cleared.
|
|
//! Therefore, it is recommended that the interrupt source be cleared early in
|
|
//! the interrupt handler (as opposed to the very last action) to avoid
|
|
//! returning from the interrupt handler before the interrupt source is
|
|
//! actually cleared. Failure to do so may result in the interrupt handler
|
|
//! being immediately reentered (because the interrupt controller still sees
|
|
//! the interrupt source asserted).
|
|
//!
|
|
//! \return None.
|
|
//!
|
|
//*****************************************************************************
|
|
void
|
|
EEPROMIntClear(uint32_t ui32IntFlags)
|
|
{
|
|
//
|
|
// Clear the flash interrupt.
|
|
//
|
|
HWREG(FLASH_FCMISC) = FLASH_FCMISC_EMISC;
|
|
|
|
//
|
|
// Clear the sector protection bits to prevent possible problems when
|
|
// programming the main flash array later.
|
|
//
|
|
if(CLASS_IS_TM4C123 && REVISION_IS_A0)
|
|
{
|
|
_EEPROMSectorMaskClear();
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! Returns status on the last EEPROM program or erase operation.
|
|
//!
|
|
//! This function returns the current status of the last program or erase
|
|
//! operation performed by the EEPROM. It is intended to provide error
|
|
//! information to applications programming or setting EEPROM protection
|
|
//! options under interrupt control.
|
|
//!
|
|
//! \return Returns 0 if the last program or erase operation completed without
|
|
//! any errors. If an operation is ongoing or an error occurred, the return
|
|
//! value is a logical OR combination of \b EEPROM_RC_WRBUSY, \b
|
|
//! EEPROM_RC_NOPERM, \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and \b
|
|
//! EEPROM_RC_WORKING.
|
|
//!
|
|
//*****************************************************************************
|
|
uint32_t
|
|
EEPROMStatusGet(void)
|
|
{
|
|
return(HWREG(EEPROM_EEDONE));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
// Close the Doxygen group.
|
|
//! @}
|
|
//
|
|
//*****************************************************************************
|