diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2012-10-29 21:36:23 +0200 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2012-10-29 21:36:23 +0200 |
| commit | 44b979ac3dc53b29ee8176517b7d9a10935630c0 (patch) | |
| tree | 03c256e5e19ac2be9d19b3d4638cdf233b0ee4e9 /driverlib/eeprom.c | |
| parent | 8ced6b65a22e0c392bc31288b2eb3f713a0fc477 (diff) | |
Initial code
Diffstat (limited to 'driverlib/eeprom.c')
| -rw-r--r-- | driverlib/eeprom.c | 1140 |
1 files changed, 1140 insertions, 0 deletions
diff --git a/driverlib/eeprom.c b/driverlib/eeprom.c new file mode 100644 index 0000000..0cc31fb --- /dev/null +++ b/driverlib/eeprom.c @@ -0,0 +1,1140 @@ +//*****************************************************************************
+//
+// eeprom.c - Driver for programming the on-chip EEPROM.
+//
+// Copyright (c) 2010-2012 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 9453 of the Stellaris Peripheral Driver Library.
+//
+//*****************************************************************************
+
+#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 ((unsigned long)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
+EEPROMSetSectorMask(unsigned long ulAddress)
+{
+ unsigned long ulMask;
+
+ //
+ // 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).
+ //
+ ulMask = ~(1 << (ulAddress >> 7));
+
+ SysCtlDelay(10);
+ HWREG(0x400FD0FC) = 3;
+ SysCtlDelay(10);
+ HWREG(0x400AE2C0) = ulMask;
+ 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
+EEPROMClearSectorMask(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 must be called after SysCtlPeripheralEnable() and before
+//! the EEPROM is accessed to check for errors resulting from power failure
+//! during a previous write operation. The function detects these errors
+//! and performs as much recovery as possible before returning information to
+//! the caller on whether or not a previous data write was lost and must
+//! be retried.
+//!
+//! In cases where \b EEPROM_INIT_RETRY is returned, the application is
+//! responsible for determining which data write may have been lost and
+//! rewriting this data. If \b EEPROM_INIT_ERROR is returned, the EEPROM was
+//! unable to recover its state. This condition may or may not be resolved on
+//! future resets depending upon the cause of the fault. For example, if the
+//! supply voltage is unstable, retrying the operation once the voltage is
+//! stabilized may clear the error.
+//!
+//! Failure to call this function after a reset may lead to permanent data loss
+//! if the EEPROM is later written!
+//!
+//! \return Returns \b EEPROM_INIT_OK if no errors were detected,
+//! \b EEPROM_INIT_RETRY if a previous write operation may have been
+//! interrupted by a power or reset event or \b EEPROM_INIT_ERROR if the EEPROM
+//! peripheral cannot currently recover from an interrupted write or erase
+//! operation.
+//
+//*****************************************************************************
+unsigned long
+EEPROMInit(void)
+{
+ unsigned long ulStatus;
+
+ //
+ // 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 its reset processing.
+ //
+ EEPROMWaitForDone();
+
+ //
+ // Read the EESUPP register to see if any errors have been reported.
+ //
+ ulStatus = HWREG(EEPROM_EESUPP);
+
+ //
+ // Did an error of some sort occur during a previous attempt to write to
+ // the EEPROM?
+ //
+ if(ulStatus & (EEPROM_EESUPP_PRETRY | EEPROM_EESUPP_ERETRY))
+ {
+ //
+ // Perform a second reset to allow the EEPROM a chance to correct
+ // the errors.
+ //
+ SysCtlPeripheralReset(SYSCTL_PERIPH_EEPROM0);
+
+ //
+ // Wait for the EEPROM to complete it's reset processing once again.
+ //
+ SysCtlDelay(2);
+ EEPROMWaitForDone();
+
+ //
+ // Read EESUPP once again to determine if the error conditions are
+ // cleared.
+ //
+ ulStatus = HWREG(EEPROM_EESUPP);
+ if(ulStatus & (EEPROM_EESUPP_PRETRY | EEPROM_EESUPP_ERETRY))
+ {
+ return(EEPROM_INIT_ERROR);
+ }
+ else
+ {
+ return(EEPROM_INIT_RETRY);
+ }
+ }
+
+ //
+ // 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.
+//
+//*****************************************************************************
+unsigned long
+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 bytes in the device EEPROM.
+//
+//*****************************************************************************
+unsigned long
+EEPROMBlockCountGet(void)
+{
+ //
+ // Extract the number of blocks and return it to the caller.
+ //
+ return(BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+}
+
+//*****************************************************************************
+//
+//! Reads data from the EEPROM.
+//!
+//! \param pulData is a pointer to storage for the data read from the EEPROM.
+//! This pointer must point to at least \e ulCount bytes of available memory.
+//! \param ulAddress is the byte address within the EEPROM from which data is
+//! to be read. This value must be a multiple of 4.
+//! \param ulCount 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 pulData parameter.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+EEPROMRead(unsigned long *pulData, unsigned long ulAddress,
+ unsigned long ulCount)
+{
+ //
+ // Check parameters in a debug build.
+ //
+ ASSERT(pulData);
+ ASSERT(ulAddress < SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+ ASSERT((ulAddress + ulCount) <= SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+ ASSERT((ulAddress & 3) == 0);
+ ASSERT((ulCount & 3) == 0);
+
+ //
+ // Set the block and offset appropriately to read the first word.
+ //
+ HWREG(EEPROM_EEBLOCK) = EEPROMBlockFromAddr(ulAddress);
+ HWREG(EEPROM_EEOFFSET) = OFFSET_FROM_ADDR(ulAddress);
+
+ //
+ // Convert the byte count to a word count.
+ //
+ ulCount /= 4;
+
+ //
+ // Read each word in turn.
+ //
+ while(ulCount)
+ {
+ //
+ // Read the next word through the autoincrementing register.
+ //
+ *pulData = HWREG(EEPROM_EERDWRINC);
+
+ //
+ // Move on to the next word.
+ //
+ pulData++;
+ ulCount--;
+
+ //
+ // Do we need to move to the next block? This is the case if the
+ // offset register has just wrapped back to 0.
+ //
+ if(HWREG(EEPROM_EEOFFSET) == 0)
+ {
+ HWREG(EEPROM_EEBLOCK) += 1;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Writes data to the EEPROM.
+//!
+//! \param pulData points to the first word of data to write to the EEPROM.
+//! \param ulAddress defines the byte address within the EEPROM that the data
+//! is to be written to. This value must be a multiple of 4.
+//! \param ulCount 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_INVPL, \b EEPROM_RC_WRBUSY,
+//! \b EEPROM_RC_NOPERM, \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and
+//! \b EEPROM_RC_WORKING.
+//
+//*****************************************************************************
+unsigned long
+EEPROMProgram(unsigned long *pulData, unsigned long ulAddress,
+ unsigned long ulCount)
+{
+ unsigned long ulStatus;
+
+ //
+ // Check parameters in a debug build.
+ //
+ ASSERT(pulData);
+ ASSERT(ulAddress < SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+ ASSERT((ulAddress + ulCount) <= SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+ ASSERT((ulAddress & 3) == 0);
+ ASSERT((ulCount & 3) == 0);
+
+ //
+ // Make sure the EEPROM is idle before we start.
+ //
+ do
+ {
+ //
+ // Read the status.
+ //
+ ulStatus = HWREG(EEPROM_EEDONE);
+ }
+ while(ulStatus & EEPROM_EEDONE_WORKING);
+
+ //
+ // Set the block and offset appropriately to program the first word.
+ //
+ HWREG(EEPROM_EEBLOCK) = EEPROMBlockFromAddr(ulAddress);
+ HWREG(EEPROM_EEOFFSET) = OFFSET_FROM_ADDR(ulAddress);
+
+ //
+ // Convert the byte count to a word count.
+ //
+ ulCount /= 4;
+
+ //
+ // Write each word in turn.
+ //
+ while(ulCount)
+ {
+ //
+ // 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_BLIZZARD && REVISION_IS_A0)
+ {
+ EEPROMSetSectorMask(ulAddress);
+ ulAddress += 4;
+ }
+
+ //
+ // Write the next word through the autoincrementing register.
+ //
+ HWREG(EEPROM_EERDWRINC) = *pulData;
+
+ //
+ // Wait for the write to complete.
+ //
+ do
+ {
+ //
+ // Read the status.
+ //
+ ulStatus = HWREG(EEPROM_EEDONE);
+ }
+ while(ulStatus & 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(ulStatus & (EEPROM_EEDONE_NOPERM | EEPROM_EEDONE_INVPL))
+ {
+ //
+ // An error was reported that would prevent the values from
+ // being written correctly.
+ //
+ if(CLASS_IS_BLIZZARD && REVISION_IS_A0)
+ {
+ EEPROMClearSectorMask();
+ }
+ return(ulStatus);
+ }
+
+ //
+ // Move on to the next word.
+ //
+ pulData++;
+ ulCount--;
+
+ //
+ // Do we need to move to the next block? This is the case if the
+ // offset register has just wrapped back to 0.
+ //
+ if(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_BLIZZARD && REVISION_IS_A0)
+ {
+ EEPROMClearSectorMask();
+ }
+
+ //
+ // Return the current status to the caller.
+ //
+ return(HWREG(EEPROM_EEDONE));
+}
+
+//*****************************************************************************
+//
+//! Writes a word to the EEPROM.
+//!
+//! \param ulData is the word to write to the EEPROM.
+//! \param ulAddress 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 returna 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, \e INT_FLASH.
+//!
+//! \return Returns status and error information in the form of a logical OR
+//! combinations of \b EEPROM_RC_INVPL, \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.
+//
+//*****************************************************************************
+unsigned long
+EEPROMProgramNonBlocking(unsigned long ulData, unsigned long ulAddress)
+{
+ //
+ // Check parameters in a debug build.
+ //
+ ASSERT(ulAddress < SIZE_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+ ASSERT((ulAddress & 3) == 0);
+
+ //
+ // This is a workaround for a silicon problem on Blizzard rev A.
+ //
+ if(CLASS_IS_BLIZZARD && REVISION_IS_A0)
+ {
+ EEPROMSetSectorMask(ulAddress);
+ }
+
+ //
+ // Set the block and offset appropriately to program the desired word.
+ //
+ HWREG(EEPROM_EEBLOCK) = EEPROMBlockFromAddr(ulAddress);
+ HWREG(EEPROM_EEOFFSET) = OFFSET_FROM_ADDR(ulAddress);
+
+ //
+ // 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) = ulData;
+
+ //
+ // 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_INVPL, \b EEPROM_RC_WRBUSY,
+//! \b EEPROM_RC_NOPERM, \b EEPROM_RC_WKCOPY, \b EEPROM_RC_WKERASE, and
+//! \b EEPROM_RC_WORKING.
+//
+//*****************************************************************************
+unsigned long
+EEPROMMassErase(void)
+{
+ //
+ // This is a workaround for a silicon problem on Blizzard rev A.
+ //
+ if(CLASS_IS_BLIZZARD && REVISION_IS_A0)
+ {
+ EEPROMClearSectorMask();
+ }
+
+ //
+ // 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 ulBlock 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.
+//
+//*****************************************************************************
+unsigned long
+EEPROMBlockProtectGet(unsigned long ulBlock)
+{
+ //
+ // Parameter validity check.
+ //
+ ASSERT(ulBlock < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+
+ //
+ // Set the current block.
+ //
+ HWREG(EEPROM_EEBLOCK) = ulBlock;
+
+ //
+ // Return the protection flags for this block.
+ //
+ return(HWREG(EEPROM_EEPROT));
+}
+
+//*****************************************************************************
+//
+//! Set the current protection options for an EEPROM block.
+//!
+//! \param ulBlock is the block number for which the protection options are to
+//! be set.
+//! \param ulProtect 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_INVPL,
+//! \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.
+//
+//*****************************************************************************
+unsigned long
+EEPROMBlockProtectSet(unsigned long ulBlock, unsigned long ulProtect)
+{
+ //
+ // Parameter validity check.
+ //
+ ASSERT(ulBlock < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+
+ //
+ // Set the current block.
+ //
+ HWREG(EEPROM_EEBLOCK) = ulBlock;
+
+ //
+ // Set the protection options for this block.
+ //
+ HWREG(EEPROM_EEPROT) = ulProtect;
+
+ //
+ // 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 ulBlock is the EEPROM block number for which the password is to be
+//! set.
+//! \param pulPassword points to an array of unsigned long 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
+//! \b ulCount parameter.
+//! \param ulCount provides the number of unsigned longs in the \b ulPassword.
+//! 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_INVPL,
+//! \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.
+//
+//*****************************************************************************
+unsigned long
+EEPROMBlockPasswordSet(unsigned long ulBlock, unsigned long *pulPassword,
+ unsigned long ulCount)
+{
+ unsigned long ulReg;
+
+ //
+ // Check parameters in a debug build.
+ //
+ ASSERT(pulPassword);
+ ASSERT(ulBlock < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+ ASSERT(ulCount <= 3);
+
+ //
+ // Set the block number whose password we are about to write.
+ //
+ HWREG(EEPROM_EEBLOCK) = ulBlock;
+
+ //
+ // Start with the first password word.
+ //
+ ulReg = EEPROM_EEPASS0;
+
+ //
+ // Write the password.
+ //
+ while(ulCount)
+ {
+ //
+ // Start the process of writing the password.
+ //
+ HWREG(ulReg) = *pulPassword;
+
+ //
+ // Update values in preparation for writing the next word.
+ //
+ pulPassword++;
+ ulReg += 4;
+ ulCount--;
+
+ //
+ // 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 ulBlock 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.
+//!
+//*****************************************************************************
+unsigned long
+EEPROMBlockLock(unsigned long ulBlock)
+{
+ //
+ // Check parameters in a debug build.
+ //
+ ASSERT(ulBlock < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+
+ //
+ // Select the block we are going to lock.
+ //
+ HWREG(EEPROM_EEBLOCK) = ulBlock;
+
+ //
+ // Lock the block.
+ //
+ HWREG(EEPROM_EEUNLOCK) = 0xFFFFFFFF;
+
+ //
+ // Return the current lock state.
+ //
+ return(HWREG(EEPROM_EEUNLOCK));
+}
+
+//*****************************************************************************
+//
+//! Unlocks a password-protected EEPROM block.
+//!
+//! \param ulBlock is the EEPROM block number which is to be unlocked.
+//! \param pulPassword points to an array of unsigned long values containing
+//! the password for the blockt. Each element must match the password
+//! originally set via a call to EEPROMBlockPasswordSet().
+//! \param ulCount provides the number of unsigned longs in the \b pulPassword
+//! 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.
+//!
+//*****************************************************************************
+unsigned long
+EEPROMBlockUnlock(unsigned long ulBlock, unsigned long *pulPassword,
+ unsigned long ulCount)
+{
+ //
+ // Check parameters in a debug build.
+ //
+ ASSERT(pulPassword);
+ ASSERT(ulBlock < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+ ASSERT(ulCount <= 3);
+
+ //
+ // Set the block that we are trying to unlock.
+ //
+ HWREG(EEPROM_EEBLOCK) = ulBlock;
+
+ //
+ // 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.
+ //
+ pulPassword += (ulCount - 1);
+
+ //
+ // Write the supplied password to unlock the block.
+ //
+ while(ulCount)
+ {
+ HWREG(EEPROM_EEUNLOCK) = *pulPassword--;
+ ulCount--;
+ }
+
+ //
+ // Let the caller know if their password worked.
+ //
+ return(HWREG(EEPROM_EEUNLOCK));
+}
+
+//*****************************************************************************
+//
+//! Hides an EEPROM block until the next reset.
+//!
+//! \param ulBlock 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(unsigned long ulBlock)
+{
+ //
+ // Check parameters in a debug build.
+ //
+ ASSERT(!ulBlock);
+ ASSERT(ulBlock < BLOCKS_FROM_EESIZE(HWREG(EEPROM_EESIZE)));
+
+ //
+ // Hide the requested block.
+ //
+ HWREG(EEPROM_EEHIDE) = (1 << ulBlock);
+}
+
+//*****************************************************************************
+//
+//! Enables the EEPROM interrupt.
+//!
+//! \param ulIntFlags 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 \b ulIntFlags parameter.
+//!
+//! \return None.
+//!
+//*****************************************************************************
+void
+EEPROMIntEnable(unsigned long ulIntFlags)
+{
+ //
+ // Look for valid interrupt sources.
+ //
+ ASSERT(ulIntFlags == 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 ulIntFlags 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, \e 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 \b ulIntFlags parameter.
+//!
+//! \return None.
+//!
+//*****************************************************************************
+void
+EEPROMIntDisable(unsigned long ulIntFlags)
+{
+ //
+ // Look for valid interrupt sources.
+ //
+ ASSERT(ulIntFlags == 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 \e 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.
+//
+//*****************************************************************************
+unsigned long
+EEPROMIntStatus(tBoolean 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 ulIntFlags 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(unsigned long ulIntFlags)
+{
+ //
+ // 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_BLIZZARD && REVISION_IS_A0)
+ {
+ EEPROMClearSectorMask();
+ }
+}
+
+//*****************************************************************************
+//
+//! 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_INVPL,
+//! \b EEPROM_RC_WRBUSY, \b EEPROM_RC_NOPERM, \b EEPROM_RC_WKCOPY,
+//! \b EEPROM_RC_WKERASE, and \b EEPROM_RC_WORKING.
+//!
+//*****************************************************************************
+unsigned long
+EEPROMStatusGet(void)
+{
+ return(HWREG(EEPROM_EEDONE));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
|
