Example #1
0
void DataFlash_SITL::ChipErase()
{
	for (int i=0; i<DF_NUM_PAGES; i++) {
		PageErase(i);
        hal.scheduler->delay(1);
	}
}
Example #2
0
//*****************************************************************************
//
//! 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);
}
Example #3
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);
}
Example #4
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);
}
Example #5
0
void DataFlash_APM1::ChipErase ()
{
	for (int i=0; DF_NUM_PAGES; i++) {
		PageErase(i);
	}
}