diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2014-03-16 14:41:11 +0200 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2014-03-16 14:41:11 +0200 |
| commit | 990090a4cc9070837d31e66b58d40f0c3d038741 (patch) | |
| tree | cf1b905082c364e9b223e0c5058566103138dae5 /utils/flash_pb.c | |
| parent | 7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff) | |
Add usblib and utils
Diffstat (limited to 'utils/flash_pb.c')
| -rw-r--r-- | utils/flash_pb.c | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/utils/flash_pb.c b/utils/flash_pb.c new file mode 100644 index 0000000..ac85830 --- /dev/null +++ b/utils/flash_pb.c @@ -0,0 +1,493 @@ +//*****************************************************************************
+//
+// flash_pb.c - Flash parameter block functions.
+//
+// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_flash.h"
+#include "inc/hw_types.h"
+#include "inc/hw_sysctl.h"
+#include "driverlib/debug.h"
+#include "driverlib/flash.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "utils/flash_pb.h"
+
+//*****************************************************************************
+//
+//! \addtogroup flash_pb_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The address of the beginning of the flash used for storing parameter blocks;
+// this must be the start of an erase block in the flash.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBStart;
+
+//*****************************************************************************
+//
+// The address of the end of the flash used for storing parameter blocks; this
+// must be the start of an erase block in the flash, or the first location
+// after the end of the flash array if the last erase block is used for storing
+// parameters.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBEnd;
+
+//*****************************************************************************
+//
+// The size of the parameter block when stored in flash; this must be a power
+// of two less than or equal to the flash erase sector size such that a single
+// flash sector contains an integral number of parameter blocks.
+//
+//*****************************************************************************
+static uint32_t g_ui32FlashPBSize;
+
+//*****************************************************************************
+//
+// The address of the most recent parameter block in flash.
+//
+//*****************************************************************************
+static uint8_t *g_pui8FlashPBCurrent;
+
+//*****************************************************************************
+//
+// The erase sector size of the current flash.
+//
+//*****************************************************************************
+#define FLASH_SECTOR_SIZE MAP_SysCtlFlashSectorSizeGet()
+
+//*****************************************************************************
+//
+//! Determines if the parameter block at the given address is valid.
+//!
+//! \param pui8Offset is the address of the parameter block to check.
+//!
+//! This function will compute the checksum of a parameter block in flash to
+//! determine if it is valid.
+//!
+//! \return Returns one if the parameter block is valid and zero if it is not.
+//
+//*****************************************************************************
+static uint32_t
+FlashPBIsValid(uint8_t *pui8Offset)
+{
+ uint32_t ui32Idx, ui32Sum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pui8Offset != (void *)0);
+
+ //
+ // Loop through the bytes in the block, computing the checksum.
+ //
+ for(ui32Idx = 0, ui32Sum = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ ui32Sum += pui8Offset[ui32Idx];
+ }
+
+ //
+ // The checksum should be zero, so return a failure if it is not.
+ //
+ if((ui32Sum & 255) != 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the sum is equal to the size * 255, then the block is all ones and
+ // should not be considered valid.
+ //
+ if((g_ui32FlashPBSize * 255) == ui32Sum)
+ {
+ return(0);
+ }
+
+ //
+ // This is a valid parameter block.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the address of the most recent parameter block.
+//!
+//! This function returns the address of the most recent parameter block that
+//! is stored in flash.
+//!
+//! \return Returns the address of the most recent parameter block, or NULL if
+//! there are no valid parameter blocks in flash.
+//
+//*****************************************************************************
+uint8_t *
+FlashPBGet(void)
+{
+ //
+ // See if there is a valid parameter block.
+ //
+ if(g_pui8FlashPBCurrent)
+ {
+ //
+ // Return the address of the most recent parameter block.
+ //
+ return(g_pui8FlashPBCurrent);
+ }
+
+ //
+ // There are no valid parameter blocks in flash, so return NULL.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Writes a new parameter block to flash.
+//!
+//! \param pui8Buffer is the address of the parameter block to be written to
+//! flash.
+//!
+//! This function will write a parameter block to flash. Saving the new
+//! parameter blocks involves three steps:
+//!
+//! - Setting the sequence number such that it is one greater than the sequence
+//! number of the latest parameter block in flash.
+//! - Computing the checksum of the parameter block.
+//! - Writing the parameter block into the storage immediately following the
+//! latest parameter block in flash; if that storage is at the start of an
+//! erase block, that block is erased first.
+//!
+//! By this process, there is always a valid parameter block in flash. If
+//! power is lost while writing a new parameter block, the checksum will not
+//! match and the partially written parameter block will be ignored. This is
+//! what makes this fault-tolerant.
+//!
+//! Another benefit of this scheme is that it provides wear leveling on the
+//! flash. Since multiple parameter blocks fit into each erase block of flash,
+//! and multiple erase blocks are used for parameter block storage, it takes
+//! quite a few parameter block saves before flash is re-written.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBSave(uint8_t *pui8Buffer)
+{
+ uint8_t *pui8New;
+ uint32_t ui32Idx, ui32Sum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pui8Buffer != (void *)0);
+
+ //
+ // See if there is a valid parameter block in flash.
+ //
+ if(g_pui8FlashPBCurrent)
+ {
+ //
+ // Set the sequence number to one greater than the most recent
+ // parameter block.
+ //
+ pui8Buffer[0] = g_pui8FlashPBCurrent[0] + 1;
+
+ //
+ // Try to write the new parameter block immediately after the most
+ // recent parameter block.
+ //
+ pui8New = g_pui8FlashPBCurrent + g_ui32FlashPBSize;
+ if(pui8New == g_pui8FlashPBEnd)
+ {
+ pui8New = g_pui8FlashPBStart;
+ }
+ }
+ else
+ {
+ //
+ // There is not a valid parameter block in flash, so set the sequence
+ // number of this parameter block to zero.
+ //
+ pui8Buffer[0] = 0;
+
+ //
+ // Try to write the new parameter block at the beginning of the flash
+ // space for parameter blocks.
+ //
+ pui8New = g_pui8FlashPBStart;
+ }
+
+ //
+ // Compute the checksum of the parameter block to be written.
+ //
+ for(ui32Idx = 0, ui32Sum = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ ui32Sum -= pui8Buffer[ui32Idx];
+ }
+
+ //
+ // Store the checksum into the parameter block.
+ //
+ pui8Buffer[1] += ui32Sum;
+
+ //
+ // Look for a location to store this parameter block. This infinite loop
+ // will be explicitly broken out of when a valid location is found.
+ //
+ while(1)
+ {
+ //
+ // See if this location is at the start of an erase block.
+ //
+ if(((uint32_t)pui8New & (FLASH_SECTOR_SIZE - 1)) == 0)
+ {
+ //
+ // Erase this block of the flash. This does not assume that the
+ // erase succeeded in case this block of the flash has become bad
+ // through too much use. Given the extremely low frequency that
+ // the parameter blocks are written, this will likely never fail.
+ // But, that assumption is not made in order to be safe.
+ //
+ MAP_FlashErase((uint32_t)pui8New);
+ }
+
+ //
+ // Loop through this portion of flash to see if is all ones (in other
+ // words, it is an erased portion of flash).
+ //
+ for(ui32Idx = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ if(pui8New[ui32Idx] != 0xff)
+ {
+ break;
+ }
+ }
+
+ //
+ // If all bytes in this portion of flash are ones, then break out of
+ // the loop since this is a good location for storing the parameter
+ // block.
+ //
+ if(ui32Idx == g_ui32FlashPBSize)
+ {
+ break;
+ }
+
+ //
+ // Increment to the next parameter block location.
+ //
+ pui8New += g_ui32FlashPBSize;
+ if(pui8New == g_pui8FlashPBEnd)
+ {
+ pui8New = g_pui8FlashPBStart;
+ }
+
+ //
+ // If every possible location has been checked and none are valid, then
+ // it will not be possible to write this parameter block. Simply
+ // return without writing it.
+ //
+ if((g_pui8FlashPBCurrent && (pui8New == g_pui8FlashPBCurrent)) ||
+ (!g_pui8FlashPBCurrent && (pui8New == g_pui8FlashPBStart)))
+ {
+ return;
+ }
+ }
+
+ //
+ // Write this parameter block to flash.
+ //
+ MAP_FlashProgram((uint32_t *)pui8Buffer, (uint32_t)pui8New,
+ g_ui32FlashPBSize);
+
+ //
+ // Compare the parameter block data to the data that should now be in
+ // flash. Return if any of the data does not compare, leaving the previous
+ // parameter block in flash as the most recent (since the current parameter
+ // block failed to properly program).
+ //
+ for(ui32Idx = 0; ui32Idx < g_ui32FlashPBSize; ui32Idx++)
+ {
+ if(pui8New[ui32Idx] != pui8Buffer[ui32Idx])
+ {
+ return;
+ }
+ }
+
+ //
+ // The new parameter block becomes the most recent parameter block.
+ //
+ g_pui8FlashPBCurrent = pui8New;
+}
+
+//*****************************************************************************
+//
+//! Initializes the flash parameter block.
+//!
+//! \param ui32Start is the address of the flash memory to be used for storing
+//! flash parameter blocks; this must be the start of an erase block in the
+//! flash.
+//! \param ui32End is the address of the end of flash memory to be used for
+//! storing flash parameter blocks; this must be the start of an erase block in
+//! the flash (the first block that is NOT part of the flash memory to be
+//! used), or the address of the first word after the flash array if the last
+//! block of flash is to be used.
+//! \param ui32Size is the size of the parameter block when stored in flash;
+//! this must be a power of two less than or equal to the flash erase block
+//! size (typically 1024).
+//!
+//! This function initializes a fault-tolerant, persistent storage mechanism
+//! for a parameter block for an application. The last several erase blocks
+//! of flash (as specified by \e ui32Start and \e ui32End are used for the
+//! storage; more than one erase block is required in order to be
+//! fault-tolerant.
+//!
+//! A parameter block is an array of bytes that contain the persistent
+//! parameters for the application. The only special requirement for the
+//! parameter block is that the first byte is a sequence number (explained
+//! in FlashPBSave()) and the second byte is a checksum used to validate the
+//! correctness of the data (the checksum byte is the byte such that the sum of
+//! all bytes in the parameter block is zero).
+//!
+//! The portion of flash for parameter block storage is split into N
+//! equal-sized regions, where each region is the size of a parameter block
+//! (\e ui32Size). Each region is scanned to find the most recent valid
+//! parameter block. The region that has a valid checksum and has the highest
+//! sequence number (with special consideration given to wrapping back to zero)
+//! is considered to be the current parameter block.
+//!
+//! In order to make this efficient and effective, three conditions must be
+//! met. The first is \e ui32Start and \e ui32End must be specified such that
+//! at least two erase blocks of flash are dedicated to parameter block
+//! storage. If not, fault tolerance can not be guaranteed since an erase of a
+//! single block will leave a window where there are no valid parameter blocks
+//! in flash. The second condition is that the size (\e ui32Size) of the
+//! parameter block must be an integral divisor of the size of an erase block
+//! of flash. If not, a parameter block will end up spanning between two erase
+//! blocks of flash, making it more difficult to manage. The final condition
+//! is that the size of the flash dedicated to parameter blocks (\e ui32End -
+//! \e ui32Start) divided by the parameter block size (\e ui32Size) must be
+//! less than or equal to 128. If not, it will not be possible in all cases to
+//! determine which parameter block is the most recent (specifically when
+//! dealing with the sequence number wrapping back to zero).
+//!
+//! When the microcontroller is initially programmed, the flash blocks used for
+//! parameter block storage are left in an erased state.
+//!
+//! This function must be called before any other flash parameter block
+//! functions are called.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBInit(uint32_t ui32Start, uint32_t ui32End, uint32_t ui32Size)
+{
+ uint8_t *pui8Offset, *pui8Current;
+ uint8_t ui8One, ui8Two;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT((ui32Start % FLASH_SECTOR_SIZE) == 0);
+ ASSERT((ui32End % FLASH_SECTOR_SIZE) == 0);
+ ASSERT((FLASH_SECTOR_SIZE % ui32Size) == 0);
+
+ //
+ // Save the characteristics of the flash memory to be used for storing
+ // parameter blocks.
+ //
+ g_pui8FlashPBStart = (uint8_t *)ui32Start;
+ g_pui8FlashPBEnd = (uint8_t *)ui32End;
+ g_ui32FlashPBSize = ui32Size;
+
+ //
+ // Loop through the portion of flash memory used for storing parameter
+ // blocks.
+ //
+ for(pui8Offset = g_pui8FlashPBStart, pui8Current = 0;
+ pui8Offset < g_pui8FlashPBEnd; pui8Offset += g_ui32FlashPBSize)
+ {
+ //
+ // See if this is a valid parameter block (in other words, the checksum
+ // is correct).
+ //
+ if(FlashPBIsValid(pui8Offset))
+ {
+ //
+ // See if a valid parameter block has been previously found.
+ //
+ if(pui8Current != 0)
+ {
+ //
+ // Get the sequence numbers for the current and new parameter
+ // blocks.
+ //
+ ui8One = pui8Current[0];
+ ui8Two = pui8Offset[0];
+
+ //
+ // See if the sequence number for the new parameter block is
+ // greater than the current block. The comparison isn't
+ // straightforward since the one byte sequence number will wrap
+ // after 256 parameter blocks.
+ //
+ if(((ui8One > ui8Two) && ((ui8One - ui8Two) < 128)) ||
+ ((ui8Two > ui8One) && ((ui8Two - ui8One) > 128)))
+ {
+ //
+ // The new parameter block is older than the current
+ // parameter block, so skip the new parameter block and
+ // keep searching.
+ //
+ continue;
+ }
+ }
+
+ //
+ // The new parameter block is more recent than the current one, so
+ // make it the new current parameter block.
+ //
+ pui8Current = pui8Offset;
+ }
+ }
+
+ //
+ // Save the address of the most recent parameter block found. If no valid
+ // parameter blocks were found, this will be a NULL pointer.
+ //
+ g_pui8FlashPBCurrent = pui8Current;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
|
