📄 media_flash.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support - ROUSSET -
* ----------------------------------------------------------------------------
* Copyright (c) 2006, Atmel Corporation
* All rights reserved.
*
* 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 disclaiimer below.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the disclaimer below in the documentation and/or
* other materials provided with the distribution.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
* ----------------------------------------------------------------------------
*/
/*
$Id: media_flash.c 198 2006-10-30 10:01:09Z jjoannic $
*/
//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include "core/common.h"
#include "core/device.h"
#include "core/board.h"
#include "core/trace.h"
#include "media.h"
//------------------------------------------------------------------------------
// Internal Functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! \brief Returns a pointer to the physical flash interface
//! \param pMedia Pointer to a S_media instance
//! \return Pointer to the physical flash interface used by the media
//! \see S_media
//------------------------------------------------------------------------------
static AT91PS_FLASH FLA_GetInterface(S_media *pMedia)
{
return (AT91PS_FLASH) (pMedia->pInterface);
}
//------------------------------------------------------------------------------
//! \brief Writes one page of data on a flash memory
//! \param pMedia Pointer to a S_media instance
//! \see S_media
//------------------------------------------------------------------------------
void FLA_WritePage(S_media *pMedia)
{
unsigned int i;
unsigned int dOffset;
unsigned int dPage;
unsigned int dLength;
unsigned int dRemaining;
unsigned int *pSource;
unsigned int *pDest;
AT91PS_FLASH pFlash = FLA_GetInterface(pMedia);
// Compute function parameters
// Source address
pSource = (unsigned int *) pMedia->sTransfer.pData;
// Destination address
pDest = (unsigned int *) pMedia->sTransfer.dAddress;
// Page number and offset
dOffset = pMedia->sTransfer.dAddress - (unsigned int) AT91C_IFLASH;
dPage = dOffset / AT91C_IFLASH_PAGE_SIZE;
dOffset = dOffset%AT91C_IFLASH_PAGE_SIZE;
// Length of the data to write
dLength = min(pMedia->sTransfer.dLength,
AT91C_IFLASH_PAGE_SIZE - dOffset);
// Remaining bytes
dRemaining = AT91C_IFLASH_PAGE_SIZE - dOffset - dLength;
// Recopy the data which is not rewritten
i = 0;
while (i < dOffset) {
*pDest = *pDest;
pDest++;
i += 4;
}
// Copy the data to write
i = 0;
while (i < dLength) {
*pDest = *pSource;
pDest++;
pSource++;
i += 4;
}
// Recopy the data which is not rewritten
i = 0;
while (i < dRemaining) {
*pDest = *pDest;
pDest++;
i += 4;
}
// Update the transfer descriptor
pMedia->sTransfer.pData = pSource;
pMedia->sTransfer.dAddress = (unsigned int) pDest;
pMedia->sTransfer.dLength -= dLength;
// Perform the write operation
SET(pFlash->FLA_FCR,
AT91C_MC_CORRECT_KEY
| AT91C_MC_FCMD_START_PROG
| ((dPage << 8) & AT91C_MC_PAGEN));
// Enable interrupt on MC_FRDY (end of operation)
SET(pFlash->FLA_FMR, AT91C_MC_FRDY);
}
//------------------------------------------------------------------------------
//! \brief Interrupt handler for the internal flash
//!
//! Completes or continues a pending transfer
//! \param pMedia Pointer to a S_media instance
//! \see S_media
//------------------------------------------------------------------------------
void FLA_Handler(S_media *pMedia)
{
AT91PS_FLASH pFlash = FLA_GetInterface(pMedia);
// Disable the FRDY interrupt
CLEAR(pFlash->FLA_FMR, AT91C_MC_FRDY);
// Check if the transfer is finished or not
if (pMedia->sTransfer.dLength == 0) {
// End of transfer
// Put the media in Ready state
pMedia->bState = MED_STATE_READY;
// Invoke the callback if it exists
if (pMedia->sTransfer.fCallback != 0) {
pMedia->sTransfer.fCallback(
(unsigned int) pMedia->sTransfer.pArgument, 0, 0, 0);
}
}
else {
// Continue the transfer
FLA_WritePage(pMedia);
}
}
//------------------------------------------------------------------------------
//! \brief Reads a specified amount of data from a flash memory
//! \param pMedia Pointer to a S_media instance
//! \param dAddress Address of the data to read
//! \param pData Pointer to the buffer in which to store the retrieved
//! data
//! \param dLength Length of the buffer
//! \param fCallback Optional pointer to a callback function to invoke when
//! the operation is finished
//! \param pArgument Optional pointer to an argument for the callback
//! \return Operation result code
//------------------------------------------------------------------------------
unsigned char FLA_Read(S_media *pMedia,
unsigned int dAddress,
void *pData,
unsigned int dLength,
Callback_f fCallback,
void *pArgument)
{
unsigned char *pSource = (unsigned char *) dAddress;
unsigned char *pDest = (unsigned char *) pData;
// Check that the media is ready
if (pMedia->bState != MED_STATE_READY) {
TRACE_INFO("I: Media busy\n\r");
return MED_STATUS_BUSY;
}
// Check that the data to read is not too big
if ((dLength + dAddress) > (pMedia->dBaseAddress + pMedia->dSize)) {
TRACE_WARNING("W: FLA_Read: Data too big\n\r");
return MED_STATUS_ERROR;
}
// Enter Busy state
pMedia->bState = MED_STATE_BUSY;
// Read data
while (dLength > 0) {
*pDest = *pSource;
pDest++;
pSource++;
dLength--;
}
// Leave the Busy state
pMedia->bState = MED_STATE_READY;
// Invoke callback
if (fCallback != 0) {
fCallback((unsigned int) pArgument, MED_STATUS_SUCCESS, 0, 0);
}
return MED_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
//! \brief Writes data on a flash media
//! \param pMedia Pointer to a S_media instance
//! \param dAddress Address at which to write
//! \param pData Pointer to the data to write
//! \param dLength Size of the data buffer
//! \param fCallback Optional pointer to a callback function to invoke when
//! the write operation terminates
//! \param pArgument Optional argument for the callback function
//! \return Operation result code
//! \see S_media
//! \see Callback_f
//------------------------------------------------------------------------------
unsigned char FLA_Write(S_media *pMedia,
unsigned int dAddress,
void *pData,
unsigned int dLength,
Callback_f fCallback,
void *pArgument)
{
// Check that the media if ready
if (pMedia->bState != MED_STATE_READY) {
TRACE_WARNING("W: FLA_Write: Media is busy\n\r");
return MED_STATUS_BUSY;
}
// Check that dAddress is dword-aligned
if (dAddress%4 != 0) {
TRACE_WARNING("W: FLA_Write: Address must be dword-aligned\n\r");
return MED_STATUS_ERROR;
}
// Check that dLength is a multiple of 4
if (dLength%4 != 0) {
TRACE_WARNING("W: FLA_Write: Data length must be a multiple of 4 bytes\n\r");
return MED_STATUS_ERROR;
}
// Check that the data to write is not too big
if ((dLength + dAddress) > (pMedia->dBaseAddress + pMedia->dSize)) {
TRACE_WARNING("W: FLA_Write: Data too big\n\r");
return MED_STATUS_ERROR;
}
// Put the media in Busy state
pMedia->bState = MED_STATE_BUSY;
// Initialize the transfer descriptor
pMedia->sTransfer.pData = pData;
pMedia->sTransfer.dAddress = dAddress;
pMedia->sTransfer.dLength = dLength;
pMedia->sTransfer.fCallback = fCallback;
pMedia->sTransfer.pArgument = pArgument;
// Start the write operation
FLA_WritePage(pMedia);
return MED_STATUS_SUCCESS;
}
//------------------------------------------------------------------------------
//! \brief Indicates if the interrupt for the specified flash media is pending
//! \param pMedia Pointer to the S_media instance used
//! \return true if interrupt is pending, false otherwise
//------------------------------------------------------------------------------
static bool FLA_Pending(S_media *pMedia)
{
if (ISSET(AT91C_BASE_AIC->AIC_IPR, 1 << AT91C_ID_SYS)) {
return true;
}
else {
return false;
}
}
//------------------------------------------------------------------------------
// Exported Functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! \brief Initializes a S_media instance and the associated physical interface
//! \param pMedia Pointer to the S_media instance to initialize
//! \see S_media
//------------------------------------------------------------------------------
void FLA_Init(S_media *pMedia)
{
AT91PS_FLASH pFlash = AT91C_BASE_FLASH;
TRACE_INFO("I: Flash init\n\r");
// Initialize pMedia fields
pMedia->fWrite = FLA_Write;
pMedia->fRead = FLA_Read;
pMedia->fPending = FLA_Pending;
pMedia->fHandler = FLA_Handler;
pMedia->dBaseAddress = (unsigned int) AT91C_IFLASH;
pMedia->dSize = AT91C_IFLASH_SIZE;
pMedia->pInterface = pFlash;
pMedia->bState = MED_STATE_READY;
pMedia->sTransfer.pData = 0;
pMedia->sTransfer.dAddress = 0;
pMedia->sTransfer.dLength = 0;
pMedia->sTransfer.fCallback = 0;
pMedia->sTransfer.pArgument = 0;
// Initialize low-level interface
// Configure Flash Mode register
SET(pFlash->FLA_FMR, (AT91C_MASTER_CLOCK / 666666) << 16);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -