void DataFlash_SITL::ChipErase() { for (int i=0; i<DF_NUM_PAGES; i++) { PageErase(i); hal.scheduler->delay(1); } }
//***************************************************************************** // //! Initializes the emulated EEPROM. //! //! This function initializes the EEPROM emulation area within the Flash. This //! function must be called prior to using any of the other functions in the //! API. It is expected that SysCtlClockSet() is called prior to calling this //! function due to SysCtlClockGet() being used by this function. //! //! \param ulStart is the start address for the EEPROM region. This address //! must be aligned on a 4K boundary. //! //! \param ulEnd is the end address for the EEPROM region. This address is //! not inclusive. That is, it is the first address just after the EEPROM //! emulation region. It must be aligned on a 4K boundary. It can be the first //! location after the end of the Flash array if the last Flash page is used //! for EEPROM emulation. //! //! \param ulSize is the size of each EEPROM page. This must be evenly //! divisible into the total EEPROM emulation region. The size must be //! specified such to allow for at least two EEMPROM emulation pages. //! //! \return A value of 0 indicates that the initialization was successful. A //! non-zero value indicates a failure. // //***************************************************************************** long SoftEEPROMInit(unsigned long ulStart, unsigned long ulEnd, unsigned long ulSize) { unsigned long ulActiveStatusCnt; unsigned char ucActivePgCnt; unsigned char* pucPageAddr; unsigned char* pucActivePg; tBoolean bFullPgFound; ASSERT(ulEnd > ulStart); ASSERT((ulStart % EEPROM_BOUNDARY) == 0); ASSERT((ulEnd % EEPROM_BOUNDARY) == 0); ASSERT((ulSize % FLASH_ERASE_SIZE) == 0); ASSERT(((ulEnd - ulStart) / ulSize) >= 2); // // Check that the EEPROM region is within the Flash. // if(ulEnd > SysCtlFlashSizeGet()) { // // Return the proper error. // return(ERR_RANGE); } // // Save the characteristics of the EEPROM Emulation area. Mask off the // lower bits of the addresses to ensure that they are 4K aligned. // g_pucEEPROMStart = (unsigned char *)(ulStart & ~(EEPROM_BOUNDARY - 1)); g_pucEEPROMEnd = (unsigned char *)(ulEnd & ~(EEPROM_BOUNDARY - 1)); g_ulEEPROMPgSize = ulSize; // // Set the number of clocks per microsecond to enable the Flash controller // to properly program the Flash. // FlashUsecSet(SysCtlClockGet() / 1000000); // // Get the active page count. // ucActivePgCnt = GetActivePageCount(); // // If there are no active pages, execute the following. This will be true // for a fresh start and can also be true if a reset or power-down occurs // during a clear operation. // if(ucActivePgCnt == 0) { // // If there are not any used pages, then this is a fresh start. // if(GetUsedPageCount() == 0) { // // Erase the first page. // if(PageErase(g_pucEEPROMStart)) { // // Return the proper error. // return(ERR_PG_ERASE); } // // The active status count will be 0. // ulActiveStatusCnt = 0; // // Mark the new page as active. Since this is a fresh start // start the counter at 0. // if(PageDataWrite(&ulActiveStatusCnt, g_pucEEPROMStart, 4)) { // // Return the proper error. // return(ERR_PG_WRITE); } // // Save the active page pointer. // g_pucActivePage = g_pucEEPROMStart; // // Save the next available entry. // g_pucNextAvailEntry = g_pucEEPROMStart + 8; } // // Else, a reset must have occurred before a clear operation could // complete. This is known since there are used pages but no active // pages. // else { // // Get the beginning address of the most recently used page. // pucPageAddr = GetMostRecentlyUsedPage(); // // Get the active status counter for the most recently used // page. Then add one to it for the next page. // ulActiveStatusCnt = *(unsigned long *)pucPageAddr + 1; // // Calculate the address of the page just after the most // recently used. // pucPageAddr = ((pucPageAddr + g_ulEEPROMPgSize) < g_pucEEPROMEnd) ? (pucPageAddr + g_ulEEPROMPgSize) : g_pucEEPROMStart; // // Erase this page. // if(PageErase(pucPageAddr)) { // // Return the proper error. // return(ERR_PG_ERASE); } // // Mark this page as active. // if(PageDataWrite(&ulActiveStatusCnt, pucPageAddr, 4)) { // // Return the proper error. // return(ERR_PG_WRITE); } // // Save the active page pointer. // g_pucActivePage = pucPageAddr; // // Save the next available entry. // g_pucNextAvailEntry = pucPageAddr + 8; } } // // Else, if there is 1 active page, execute the following. This will be // true for a normal start where the EEPROM has been previously // initialized and can also be true if a reset or power-down occurs during // a clear operation. // else if(ucActivePgCnt == 1) { // // Loop through the pages. // for(pucActivePg = g_pucEEPROMStart; pucActivePg < g_pucEEPROMEnd; pucActivePg += g_ulEEPROMPgSize) { // // Is this the active page? // if(PageIsActive(pucActivePg)) { // // Break out of the loop. // break; } } // // Now calculate the address of the page before the active page. // pucPageAddr = (pucActivePg == g_pucEEPROMStart) ? (g_pucEEPROMEnd - g_ulEEPROMPgSize) : (pucActivePg - g_ulEEPROMPgSize); // // Check to see if the page before has been used. // if(PageIsUsed(pucPageAddr)) { // // Check to see that the used page counter is one less than the // active page counter. // if(*(unsigned long*)pucPageAddr == (*(unsigned long*)pucActivePg - 1)) { // // This is a normal start. Save the active page pointer. // g_pucActivePage = pucActivePg; // // Save the next available entry. // g_pucNextAvailEntry = GetNextAvailEntry(); } // // Else, a reset must have occurred during the page erase or // programming the the active status counter of a // clear operation to leave the EEPROM in this state. // else { // // Erase the page that was marked active. It is incorrectly // marked active due to the counter being off. // if(PageErase(pucActivePg)) { // // Return the proper error. // return(ERR_PG_ERASE); } // // Get the active status counter for the most recently used // page. Then add one to it for the next page. // ulActiveStatusCnt = *(unsigned long *)pucPageAddr + 1; // // Mark this page as active. // if(PageDataWrite(&ulActiveStatusCnt, pucActivePg, 4)) { // // Return the proper error. // return(ERR_PG_WRITE); } // // Save the active page pointer. // g_pucActivePage = pucActivePg; // // Save the next available entry. // g_pucNextAvailEntry = pucActivePg + 8; } } // // Else, the page before the active one has not been used yet. // else { // // This is a normal start. Save the active page pointer. // g_pucActivePage = pucActivePg; // // Save the next available entry. // g_pucNextAvailEntry = GetNextAvailEntry(); } } // // Else, if there are 2 active pages, execute the following. This should // only occur if a reset or power-down occurs during a page swap operation. // In this case, one of the active pages must be full or else PageSwap() // would not have been called. // else if(ucActivePgCnt == 2) { // // Initially set bFullPgFound to false; // bFullPgFound = false; // // Loop through the pages. // for(pucActivePg = g_pucEEPROMStart; pucActivePg < g_pucEEPROMEnd; pucActivePg += g_ulEEPROMPgSize) { // // Is this the active page? // if(PageIsActive(pucActivePg)) { // // Is the page full? // if(*(unsigned long*)(pucActivePg + g_ulEEPROMPgSize - 4) != 0xFFFFFFFF) { // // Set the status to true // bFullPgFound = true; // // Then the page is full. Break out of the loop. // break; } } } // // Was a full page found? // if(bFullPgFound == true) { // // Now, the full page is pointed to by pucActivePg. Save this as // the active page. PageSwap() will be called again on the next // write. // g_pucActivePage = pucActivePg; // // Save the next available entry. It is the location just after // the end of the page since the page is full. This will cause // PageSwap() to be called on the next write. // g_pucNextAvailEntry = pucActivePg + g_ulEEPROMPgSize; } // // Else, this is not an expected case. Report the error. // else { // // Return the proper error. // return(ERR_TWO_ACTIVE_NO_FULL); } } // // Else there are more than 2 active pages. This should never happen. // else { // // Return the proper error. // return(ERR_ACTIVE_PG_CNT); } // // The EEPROM has been initialized. // g_bEEPROMInitialized = true; // // Return indicating that no error occurred. // return(0); }
//***************************************************************************** // //! Copies the most recent data from the full page to the new page. //! //! This function is called when an EEPROM page is full and is responsible for //! copying the most recent data for each ID to the next page. The global //! variables containing the beginning address of the active page and the next //! available entry are updated in this function. //! //! Order of operations: //! -# Erase the next page. //! -# Move the current data for each ID to the next page. //! -# Mark the next page as the active page (increment the counter). //! -# Mark the full page as used. //! //! It is possible that a power loss or reset could occur during the swap //! process. SoftEEPROMInit() is called upon the subsequent boot up and will //! attempt to detect and take the appropriate corrective actions if necessary. //! //! \param pucFullPageAddr is a pointer to beginning of the full page. //! //! \return A value of 0 indicates that the page swap was successful. A //! non-zero value indicates a failure. // //***************************************************************************** static long PageSwap(unsigned char* pucFullPageAddr) { unsigned short usCnt; unsigned short usSize; unsigned long ulEntry; unsigned char ucEntryID; unsigned char* pucNewEntry; unsigned char* pucUsedEntry; unsigned char* pucNewPageAddr; // // An array of bytes used as a bit vector to determine if the entry for the // given ID has already been copied over to the new page. // unsigned char ucIDSwapped[NUM_VECTOR_BYTES]; // // An array to store the entries to be moved to the next page. // Declared as static so that the memory is not allocated on the stack. // static unsigned long ulDataBuffer[32]; unsigned long ulNumWordsInBuffer; unsigned long ulByteCount; // // Initially set all the bits of the entire ucAddrSwapped array to 0. // for(usCnt = 0; usCnt < NUM_VECTOR_BYTES; usCnt++) { // // Set all bits of the bit vector to 0. // ucIDSwapped[usCnt] = 0; } // // Get the new page pointer. // pucNewPageAddr = ((pucFullPageAddr + g_ulEEPROMPgSize) < g_pucEEPROMEnd) ? (pucFullPageAddr + g_ulEEPROMPgSize) : g_pucEEPROMStart; // // Step 1) Erase the new page. // if(PageErase(pucNewPageAddr)) { // // Return error. // return(ERR_SWAP | ERR_PG_ERASE); } // // Initially set the used entry pointer to the last entry of the full page. // pucUsedEntry = pucFullPageAddr + g_ulEEPROMPgSize - 4; // // Initially set the new entry pointer to the first entry of the new page. // pucNewEntry = pucNewPageAddr + 8; // // Get the size of the variable array. The entries are 4 bytes each and the // first 2 words are used for status. // usSize = (g_ulEEPROMPgSize / 4) - 2; // // Calculate the number of bytes that can be written with the first // programming operation if using a part with Flash write buffers. // Initialize the number of words in the storage buffer. // ulByteCount = 32 - ((unsigned long)pucNewEntry & 0x7F); ulNumWordsInBuffer = 0; // // Step 2) Now copy the most recent data. Read from the end of the // currently active page first. Only copy the data for a given ID the // first time it is encountered since this is the most recent value for // that ID. // for(usCnt = 0;usCnt < usSize; usCnt++) { // // Read the entry. // ulEntry = *(unsigned long*)pucUsedEntry; // // Decrement the pointer to the entry in the full page. // pucUsedEntry -= 4; // // Get the ID for the entry. // ucEntryID = ulEntry >> 24; // // If this id has not been copied yet and the id is not equal to 0xFF // then copy it. Under normal conditions, we should never encounter // an entry with an id of 0xFF since PageSwap() should only be called // when the currently active page is full, but check just in case since // we don't want to copy empty entries. // if(((ucIDSwapped[ucEntryID / 8] & (0x1 << (ucEntryID % 8))) == 0) && (ucEntryID != 0xFF)) { // // Put the data in the buffer and increment the counter. // ulDataBuffer[ulNumWordsInBuffer++] = ulEntry; // // Set the appropriate bit in the bit vector to indicate that the ID // has already been copied. // ucIDSwapped[ucEntryID / 8] |= (0x1 << (ucEntryID % 8)); // // Decrement the ulByteCount remaining in the Flash write buffers. // ulByteCount -= 4; // // Check to see if all of the Flash write buffer space will be used // up in the next programming operation. // if(ulByteCount == 0) { // // Program the buffer to memory. // if(PageDataWrite(&ulDataBuffer[0], pucNewEntry, ulNumWordsInBuffer * 4)) { // // Return the error. // return(ERR_SWAP | ERR_PG_WRITE); } // // Increment the address to program the next entry in the new page. // pucNewEntry += (ulNumWordsInBuffer * 4); // // Reset the byte count remaining the write buffer space to the // equivalent of 32 words. Reset the number of words already in // the local buffer to 0. // ulByteCount = 32 * 4; ulNumWordsInBuffer = 0; } } } // // Are there any words remaining in the data buffer? // if(ulNumWordsInBuffer != 0) { // // Program the buffer to memory. // if(PageDataWrite(&ulDataBuffer[0], pucNewEntry, ulNumWordsInBuffer * 4)) { // // Return the error. // return(ERR_SWAP | ERR_PG_WRITE); } // // Increment the address to program the next entry in the new page. // pucNewEntry += (ulNumWordsInBuffer * 4); } // // Step 3) Mark the new page as active. Increment the active status // counter by 1 from the previous page. First just store in local buffer. // ulDataBuffer[0] = (*(unsigned long*)pucFullPageAddr) + 1; // // Now program the status word to Flash. // if(PageDataWrite(&ulDataBuffer[0], pucNewPageAddr, 4)) { // // Return the error. // return(ERR_SWAP | ERR_PG_WRITE); } // // Step 4) Mark the full page as used. This is indicated by marking the // second status word in the page. First just store in local buffer. // ulDataBuffer[0] = ~(ERASED_WORD); // // Now program the status word to Flash. // if(PageDataWrite(&ulDataBuffer[0], pucFullPageAddr + 4, 4)) { // // Return the error. // return(ERR_SWAP | ERR_PG_WRITE); } // // Now save the pointer to the beginning of the new active page and return. // g_pucActivePage = pucNewPageAddr; // // The next available entry location in the new page is pucNewEntry. // g_pucNextAvailEntry = pucNewEntry; // // Check that the next available entry is within the the new page. If a // page size of 1K is used (1024/4 - 2 = 254 entries) and all 255 IDs are // used (0-254) then it is possible to swap to a new page and not have // any available entries in the new page. This should be avoided by // the user by configuring the EEPROM appropriately for the given // application. // if(!(g_pucNextAvailEntry < (g_pucActivePage + g_ulEEPROMPgSize))) { // // Return the error. // return(ERR_SWAP | ERR_AVAIL_ENTRY); } // // Return success. // return(0); }
//***************************************************************************** // //! Clears the EEPROM contents. //! //! This function clears the EEPROM contents. //! Order of operations: //! -# Mark the current page as used. //! -# Erase the next page. //! -# Mark the erased page as the active page (increment the counter). //! //! It is possible that a power loss or reset could occur during the clear //! process. SoftEEPROMInit() is called upon the subsequent boot up and will //! attempt to detect and take the appropriate corrective actions if necessary. //! //! \return A value of 0 indicates that the clear operation was successful. A //! non-zero value indicates a failure. // //***************************************************************************** long SoftEEPROMClear(void) { unsigned long ulStatus; unsigned char* pucNewPageAddr; // // Has the EEPROM been initialized? If not, return the error. // if(!g_bEEPROMInitialized) { // // Return the proper error. // return(ERR_NOT_INIT); } // // Step 1) Mark the current page as used. // ulStatus = ~(ERASED_WORD); if(PageDataWrite(&ulStatus, g_pucActivePage + 4, 4)) { // // Return the proper error. // return(ERR_PG_WRITE); } // // Get new page pointer. // pucNewPageAddr = ((g_pucActivePage + g_ulEEPROMPgSize) < g_pucEEPROMEnd) ? (g_pucActivePage + g_ulEEPROMPgSize) : g_pucEEPROMStart; // // Step 2) Erase the new page. // if(PageErase(pucNewPageAddr)) { // // Return the proper error. // return(ERR_PG_ERASE); } // // Step 3) Mark the new page as active. Increment the active count by one // from the previous page. // ulStatus = (*(unsigned long*)g_pucActivePage) + 1; if(PageDataWrite(&ulStatus, pucNewPageAddr, 4)) { // // Return the proper error. // return(ERR_PG_WRITE); } // // Now save the pointer to the beginning of the new active page and return. // g_pucActivePage = pucNewPageAddr; // // The next available entry location is the first entry in the new page. // g_pucNextAvailEntry = pucNewPageAddr + 8; // // Return indicating that no error occurred. // return(0); }
void DataFlash_APM1::ChipErase () { for (int i=0; DF_NUM_PAGES; i++) { PageErase(i); } }