//***************************************************************************** | |
// | |
// flash.c - Driver for programming the on-chip flash. | |
// | |
// Copyright (c) 2005,2006 Luminary Micro, Inc. All rights reserved. | |
// | |
// Software License Agreement | |
// | |
// Luminary Micro, Inc. (LMI) is supplying this software for use solely and | |
// exclusively on LMI's Stellaris Family of microcontroller products. | |
// | |
// The software is owned by LMI and/or its suppliers, and is protected under | |
// applicable copyright laws. All rights are reserved. Any use in violation | |
// of the foregoing restrictions may subject the user to criminal sanctions | |
// under applicable laws, as well as to civil liability for the breach of the | |
// terms and conditions of this license. | |
// | |
// THIS SOFTWARE IS PROVIDED "AS IS". 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. | |
// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR | |
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. | |
// | |
// This is part of revision 991 of the Stellaris Driver Library. | |
// | |
//***************************************************************************** | |
//***************************************************************************** | |
// | |
//! \addtogroup flash_api | |
//! @{ | |
// | |
//***************************************************************************** | |
#include "../hw_flash.h" | |
#include "../hw_ints.h" | |
#include "../hw_memmap.h" | |
#include "../hw_sysctl.h" | |
#include "../hw_types.h" | |
#include "debug.h" | |
#include "flash.h" | |
#include "interrupt.h" | |
//***************************************************************************** | |
// | |
//! Gets the number of processor clocks per micro-second. | |
//! | |
//! This function returns the number of clocks per micro-second, as presently | |
//! known by the flash controller. | |
//! | |
//! \return Returns the number of processor clocks per micro-second. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_usecget) || defined(BUILD_ALL) || defined(DOXYGEN) | |
unsigned long | |
FlashUsecGet(void) | |
{ | |
// | |
// Return the number of clocks per micro-second. | |
// | |
return(HWREG(FLASH_USECRL) + 1); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Sets the number of processor clocks per micro-second. | |
//! | |
//! \param ulClocks is the number of processor clocks per micro-second. | |
//! | |
//! This function is used to tell the flash controller the number of processor | |
//! clocks per micro-second. This value must be programmed correctly or the | |
//! flash most likely will not program correctly; it has no affect on reading | |
//! flash. | |
//! | |
//! \return None. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_usecset) || defined(BUILD_ALL) || defined(DOXYGEN) | |
void | |
FlashUsecSet(unsigned long ulClocks) | |
{ | |
// | |
// Set the number of clocks per micro-second. | |
// | |
HWREG(FLASH_USECRL) = ulClocks - 1; | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Erases a block of flash. | |
//! | |
//! \param ulAddress is the start address of the flash block to be erased. | |
//! | |
//! This function will erase a 1 kB block of the on-chip flash. After erasing, | |
//! the block will be filled with 0xFF bytes. Read-only and execute-only | |
//! blocks cannot be erased. | |
//! | |
//! This function will not return until the block has been erased. | |
//! | |
//! \return Returns 0 on success, or -1 if an invalid block address was | |
//! specified or the block is write-protected. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_erase) || defined(BUILD_ALL) || defined(DOXYGEN) | |
long | |
FlashErase(unsigned long ulAddress) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(!(ulAddress & (FLASH_ERASE_SIZE - 1))); | |
// | |
// Clear the flash access interrupt. | |
// | |
HWREG(FLASH_FCMISC) = FLASH_FCMISC_ACCESS; | |
// | |
// Erase the block. | |
// | |
HWREG(FLASH_FMA) = ulAddress; | |
HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_ERASE; | |
// | |
// Wait until the word has been programmed. | |
// | |
while(HWREG(FLASH_FMC) & FLASH_FMC_ERASE) | |
{ | |
} | |
// | |
// Return an error if an access violation occurred. | |
// | |
if(HWREG(FLASH_FCRIS) & FLASH_FCRIS_ACCESS) | |
{ | |
return(-1); | |
} | |
// | |
// Success. | |
// | |
return(0); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Programs flash. | |
//! | |
//! \param pulData is a pointer to the data to be programmed. | |
//! \param ulAddress is the starting address in flash to be programmed. Must | |
//! be a multiple of four. | |
//! \param ulCount is the number of bytes to be programmed. Must be a multiple | |
//! of four. | |
//! | |
//! This function will program a sequence of words into the on-chip flash. | |
//! Programming each location consists of the result of an AND operation | |
//! of the new data and the existing data; in other words bits that contain | |
//! 1 can remain 1 or be changed to 0, but bits that are 0 cannot be changed | |
//! to 1. Therefore, a word can be programmed multiple times as long as these | |
//! rules are followed; if a program operation attempts to change a 0 bit to | |
//! a 1 bit, that bit will not have its value changed. | |
//! | |
//! Since the flash is programmed one word at a time, the starting address and | |
//! byte count must both be multiples of four. It is up to the caller to | |
//! verify the programmed contents, if such verification is required. | |
//! | |
//! This function will not return until the data has been programmed. | |
//! | |
//! \return Returns 0 on success, or -1 if a programming error is encountered. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_program) || defined(BUILD_ALL) || defined(DOXYGEN) | |
long | |
FlashProgram(unsigned long *pulData, unsigned long ulAddress, | |
unsigned long ulCount) | |
{ | |
// | |
// Check the arguments. | |
// | |
ASSERT(!(ulAddress & 3)); | |
ASSERT(!(ulCount & 3)); | |
// | |
// Clear the flash access interrupt. | |
// | |
HWREG(FLASH_FCMISC) = FLASH_FCMISC_ACCESS; | |
// | |
// Loop over the words to be programmed. | |
// | |
while(ulCount) | |
{ | |
// | |
// Program the next word. | |
// | |
HWREG(FLASH_FMA) = ulAddress; | |
HWREG(FLASH_FMD) = *pulData; | |
HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_WRITE; | |
// | |
// Wait until the word has been programmed. | |
// | |
while(HWREG(FLASH_FMC) & FLASH_FMC_WRITE) | |
{ | |
} | |
// | |
// Increment to the next word. | |
// | |
pulData++; | |
ulAddress += 4; | |
ulCount -= 4; | |
} | |
// | |
// Return an error if an access violation occurred. | |
// | |
if(HWREG(FLASH_FCRIS) & FLASH_FCRIS_ACCESS) | |
{ | |
return(-1); | |
} | |
// | |
// Success. | |
// | |
return(0); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Gets the protection setting for a block of flash. | |
//! | |
//! \param ulAddress is the start address of the flash block to be queried. | |
//! | |
//! This function will get the current protection for the specified 2 kB block | |
//! of flash. Each block can be read/write, read-only, or execute-only. | |
//! Read/write blocks can be read, executed, erased, and programmed. Read-only | |
//! blocks can be read and executed. Execute-only blocks can only be executed; | |
//! processor and debugger data reads are not allowed. | |
//! | |
//! \return Returns the protection setting for this block. See | |
//! FlashProtectSet() for possible values. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_protectget) || defined(BUILD_ALL) || defined(DOXYGEN) | |
tFlashProtection | |
FlashProtectGet(unsigned long ulAddress) | |
{ | |
unsigned long ulFMPRE, ulFMPPE; | |
// | |
// Check the argument. | |
// | |
ASSERT(!(ulAddress & (FLASH_PROTECT_SIZE - 1))); | |
// | |
// Read the flash protection register and get the bits that apply to the | |
// specified block. | |
// | |
ulFMPRE = HWREG(FLASH_FMPRE); | |
ulFMPPE = HWREG(FLASH_FMPPE); | |
switch((((ulFMPRE >> (ulAddress / FLASH_PROTECT_SIZE)) & | |
FLASH_FMP_BLOCK_0) << 1) | | |
((ulFMPPE >> (ulAddress / FLASH_PROTECT_SIZE)) & FLASH_FMP_BLOCK_0)) | |
{ | |
// | |
// This block is marked as execute only (i.e. it can not be erased or | |
// programmed, and the only reads allowed are via the instruction fecth | |
// interface). | |
// | |
case 0: | |
case 1: | |
{ | |
return(FlashExecuteOnly); | |
} | |
// | |
// This block is marked as read only (i.e. it can not be erased or | |
// programmed). | |
// | |
case 2: | |
{ | |
return(FlashReadOnly); | |
} | |
// | |
// This block is read/write; it can be read, erased, and programmed. | |
// | |
case 3: | |
default: | |
{ | |
return(FlashReadWrite); | |
} | |
} | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Sets the protection setting for a block of flash. | |
//! | |
//! \param ulAddress is the start address of the flash block to be protected. | |
//! \param eProtect is the protection to be applied to the block. Can be one | |
//! of \b FlashReadWrite, \b FlashReadOnly, or \b FlashExecuteOnly. | |
//! | |
//! This function will set the protection for the specified 2 kB block of | |
//! flash. Blocks which are read/write can be made read-only or execute-only. | |
//! Blocks which are read-only can be made execute-only. Blocks which are | |
//! execute-only cannot have their protection modified. Attempts to make the | |
//! block protection less stringent (i.e. read-only to read/write) will result | |
//! in a failure (and be prevented by the hardware). | |
//! | |
//! Changes to the flash protection are maintained only until the next reset. | |
//! This allows the application to be executed in the desired flash protection | |
//! environment to check for inappropriate flash access (via the flash | |
//! interrupt). To make the flash protection permanent, use the | |
//! FlashProtectSave() function. | |
//! | |
//! \return Returns 0 on success, or -1 if an invalid address or an invalid | |
//! protection was specified. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_protectset) || defined(BUILD_ALL) || defined(DOXYGEN) | |
long | |
FlashProtectSet(unsigned long ulAddress, tFlashProtection eProtect) | |
{ | |
unsigned long ulProtectRE, ulProtectPE; | |
// | |
// Check the argument. | |
// | |
ASSERT(!(ulAddress & (FLASH_PROTECT_SIZE - 1))); | |
ASSERT((eProtect == FlashReadWrite) || (eProtect == FlashReadOnly) || | |
(eProtect == FlashExecuteOnly)); | |
// | |
// Convert the address into a block number. | |
// | |
ulAddress /= FLASH_PROTECT_SIZE; | |
// | |
// Get the current protection. | |
// | |
ulProtectRE = HWREG(FLASH_FMPRE); | |
ulProtectPE = HWREG(FLASH_FMPPE); | |
// | |
// Set the protection based on the requested proection. | |
// | |
switch(eProtect) | |
{ | |
// | |
// Make this block execute only. | |
// | |
case FlashExecuteOnly: | |
{ | |
// | |
// Turn off the read and program bits for this block. | |
// | |
ulProtectRE &= ~(FLASH_FMP_BLOCK_0 << ulAddress); | |
ulProtectPE &= ~(FLASH_FMP_BLOCK_0 << ulAddress); | |
// | |
// We're done handling this protection. | |
// | |
break; | |
} | |
// | |
// Make this block read only. | |
// | |
case FlashReadOnly: | |
{ | |
// | |
// The block can not be made read only if it is execute only. | |
// | |
if(((ulProtectRE >> ulAddress) & FLASH_FMP_BLOCK_0) != | |
FLASH_FMP_BLOCK_0) | |
{ | |
return(-1); | |
} | |
// | |
// Make this block read only. | |
// | |
ulProtectPE &= ~(FLASH_FMP_BLOCK_0 << ulAddress); | |
// | |
// We're done handling this protection. | |
// | |
break; | |
} | |
// | |
// Make this block read/write. | |
// | |
case FlashReadWrite: | |
default: | |
{ | |
// | |
// The block can not be made read/write if it is not already | |
// read/write. | |
// | |
if((((ulProtectRE >> ulAddress) & FLASH_FMP_BLOCK_0) != | |
FLASH_FMP_BLOCK_0) || | |
(((ulProtectPE >> ulAddress) & FLASH_FMP_BLOCK_0) != | |
FLASH_FMP_BLOCK_0)) | |
{ | |
return(-1); | |
} | |
// | |
// The block is already read/write, so there is nothing to do. | |
// | |
return(0); | |
} | |
} | |
// | |
// Set the new protection. | |
// | |
HWREG(FLASH_FMPRE) = ulProtectRE; | |
HWREG(FLASH_FMPPE) = ulProtectPE; | |
// | |
// Success. | |
// | |
return(0); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Saves the flash protection settings. | |
//! | |
//! This function will make the currently programmed flash protection settings | |
//! permanent. This is a non-reversible operation; a chip reset or power cycle | |
//! will not change the flash protection. | |
//! | |
//! This function will not return until the protection has been saved. | |
//! | |
//! \return Returns 0 on success, or -1 if a hardware error is encountered. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_protectsave) || defined(BUILD_ALL) || defined(DOXYGEN) | |
long | |
FlashProtectSave(void) | |
{ | |
// | |
// Tell the flash controller to write the flash read protection register. | |
// | |
HWREG(FLASH_FMA) = 0; | |
HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_COMT; | |
// | |
// Wait until the write has completed. | |
// | |
while(HWREG(FLASH_FMC) & FLASH_FMC_COMT) | |
{ | |
} | |
// | |
// Tell the flash controller to write the flash program protection | |
// register. | |
// | |
HWREG(FLASH_FMA) = 1; | |
HWREG(FLASH_FMC) = FLASH_FMC_WRKEY | FLASH_FMC_COMT; | |
// | |
// Wait until the write has completed. | |
// | |
while(HWREG(FLASH_FMC) & FLASH_FMC_COMT) | |
{ | |
} | |
// | |
// Success. | |
// | |
return(0); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Registers an interrupt handler for the flash interrupt. | |
//! | |
//! \param pfnHandler is a pointer to the function to be called when the flash | |
//! interrupt occurs. | |
//! | |
//! This sets the handler to be called when the flash interrupt occurs. The | |
//! flash controller can generate an interrupt when an invalid flash access | |
//! occurs, such as trying to program or erase a read-only block, or trying to | |
//! read from an execute-only block. It can also generate an interrupt when a | |
//! program or erase operation has completed. The interrupt will be | |
//! automatically enabled when the handler is registered. | |
//! | |
//! \sa IntRegister() for important information about registering interrupt | |
//! handlers. | |
//! | |
//! \return None. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_intregister) || defined(BUILD_ALL) || defined(DOXYGEN) | |
void | |
FlashIntRegister(void (*pfnHandler)(void)) | |
{ | |
// | |
// Register the interrupt handler, returning an error if an error occurs. | |
// | |
IntRegister(INT_FLASH, pfnHandler); | |
// | |
// Enable the flash interrupt. | |
// | |
IntEnable(INT_FLASH); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Unregisters the interrupt handler for the flash interrupt. | |
//! | |
//! This function will clear the handler to be called when the flash interrupt | |
//! occurs. This will also mask off the interrupt in the interrupt controller | |
//! so that the interrupt handler is no longer called. | |
//! | |
//! \sa IntRegister() for important information about registering interrupt | |
//! handlers. | |
//! | |
//! \return None. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_intunregister) || defined(BUILD_ALL) || defined(DOXYGEN) | |
void | |
FlashIntUnregister(void) | |
{ | |
// | |
// Disable the interrupt. | |
// | |
IntDisable(INT_FLASH); | |
// | |
// Unregister the interrupt handler. | |
// | |
IntUnregister(INT_FLASH); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Enables individual flash controller interrupt sources. | |
//! | |
//! \param ulIntFlags is a bit mask of the interrupt sources to be enabled. | |
//! Can be any of the \b FLASH_FCIM_PROGRAM or \b FLASH_FCIM_ACCESS values. | |
//! | |
//! Enables the indicated flash controller interrupt sources. Only the sources | |
//! that are enabled can be reflected to the processor interrupt; disabled | |
//! sources have no effect on the processor. | |
//! | |
//! \return None. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_intenable) || defined(BUILD_ALL) || defined(DOXYGEN) | |
void | |
FlashIntEnable(unsigned long ulIntFlags) | |
{ | |
// | |
// Enable the specified interrupts. | |
// | |
HWREG(FLASH_FCIM) |= ulIntFlags; | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Disables individual flash controller interrupt sources. | |
//! | |
//! \param ulIntFlags is a bit mask of the interrupt sources to be disabled. | |
//! Can be any of the \b FLASH_FCIM_PROGRAM or \b FLASH_FCIM_ACCESS values. | |
//! | |
//! Disables the indicated flash controller interrupt sources. Only the | |
//! sources that are enabled can be reflected to the processor interrupt; | |
//! disabled sources have no effect on the processor. | |
//! | |
//! \return None. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_intdisable) || defined(BUILD_ALL) || defined(DOXYGEN) | |
void | |
FlashIntDisable(unsigned long ulIntFlags) | |
{ | |
// | |
// Disable the specified interrupts. | |
// | |
HWREG(FLASH_FCIM) &= ~(ulIntFlags); | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Gets the current interrupt status. | |
//! | |
//! \param bMasked is false if the raw interrupt status is required and true if | |
//! the masked interrupt status is required. | |
//! | |
//! This returns the interrupt status for the flash controller. Either the raw | |
//! interrupt status or the status of interrupts that are allowed to reflect to | |
//! the processor can be returned. | |
//! | |
//! \return The current interrupt status, enumerated as a bit field of | |
//! \b FLASH_FCMISC_PROGRAM and \b FLASH_FCMISC_ACCESS. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_intgetstatus) || defined(BUILD_ALL) || defined(DOXYGEN) | |
unsigned long | |
FlashIntGetStatus(tBoolean bMasked) | |
{ | |
// | |
// Return either the interrupt status or the raw interrupt status as | |
// requested. | |
// | |
if(bMasked) | |
{ | |
return(HWREG(FLASH_FCMISC)); | |
} | |
else | |
{ | |
return(HWREG(FLASH_FCRIS)); | |
} | |
} | |
#endif | |
//***************************************************************************** | |
// | |
//! Clears flash controller interrupt sources. | |
//! | |
//! \param ulIntFlags is the bit mask of the interrupt sources to be cleared. | |
//! Can be any of the \b FLASH_FCMISC_PROGRAM or \b FLASH_FCMISC_ACCESS | |
//! values. | |
//! | |
//! The specified flash controller interrupt sources are cleared, so that they | |
//! no longer assert. This must be done in the interrupt handler to keep it | |
//! from being called again immediately upon exit. | |
//! | |
//! \return None. | |
// | |
//***************************************************************************** | |
#if defined(GROUP_intclear) || defined(BUILD_ALL) || defined(DOXYGEN) | |
void | |
FlashIntClear(unsigned long ulIntFlags) | |
{ | |
// | |
// Clear the flash interrupt. | |
// | |
HWREG(FLASH_FCMISC) = ulIntFlags; | |
} | |
#endif | |
//***************************************************************************** | |
// | |
// Close the Doxygen group. | |
//! @} | |
// | |
//***************************************************************************** |