media_flash.c

来自「最新版IAR FOR ARM(EWARM)5.11中的代码例子」· C语言 代码 · 共 416 行

C
416
字号
/* ----------------------------------------------------------------------------
 *         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,v 1.1.2.1 2006/12/05 08:33:25 danielru Exp $
*/

//------------------------------------------------------------------------------
//      Includes
//------------------------------------------------------------------------------

#include "intrinsics.h"
#include "core/common.h"
#include "core/device.h"
#include "core/board.h"
#include "core/trace.h"

#include "media.h"

#if defined(AT91SAM7A3EK)
#define AT91C_MC_FRDY AT91C_MC_EOP
#endif // defined(AT91SAM7A3EK)

void FLA_Handler(S_media *pMedia);

//------------------------------------------------------------------------------
//      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);
}

#if defined(AT91SAM7A3EK)
//------------------------------------------------------------------------------
//! \brief  Start write and wait until flash is ready
//------------------------------------------------------------------------------
__ramfunc void UnlockFlash(AT91PS_FLASH pFlash)
{
unsigned int Status;
  // Configure Flash Mode register
  SET(pFlash->FLA_FMR, ((AT91C_MASTER_CLOCK / 1000000)) << 16);
  Status = pFlash->FLA_FSR;

  for(int i = 0; i < AT91C_IFLASH_SIZE/(256*16);++i)
  {
    SET(pFlash->FLA_FCR,
        AT91C_MC_CORRECT_KEY
      | AT91C_MC_FCMD_UNLOCK
      | (AT91C_MC_PAGEN & (i << 8)));
    do
    {
      Status = pFlash->FLA_FSR;
    }
    while((Status & AT91C_MC_EOL) != AT91C_MC_EOL);
  }
}
#endif // defined(AT91SAM7A3EK)

//------------------------------------------------------------------------------
//! \brief  Start write and wait until flash is ready
//------------------------------------------------------------------------------
__ramfunc void FLA_WriteStating(S_media *pMedia, unsigned int dPage)
{
AT91PS_FLASH pFlash = pMedia->pInterface;
volatile unsigned int Status = pFlash->FLA_FSR;
    SET(pFlash->FLA_FCR,
        AT91C_MC_CORRECT_KEY
        | AT91C_MC_FCMD_START_PROG
        | ((dPage << 8) & AT91C_MC_PAGEN));
    while((pFlash->FLA_FSR & AT91C_MC_FRDY) != AT91C_MC_FRDY);
}

//------------------------------------------------------------------------------
//! \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);
*/
    unsigned int Save = __get_interrupt_state();
    __disable_interrupt();
    FLA_WriteStating(pMedia,dPage);
    __set_interrupt_state(Save);
    FLA_Handler(pMedia);

}

//------------------------------------------------------------------------------
//! \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

#if defined(AT91SAM7A3EK)
    unsigned int Save = __get_interrupt_state();
    __disable_interrupt();
    UnlockFlash(pFlash);
    __set_interrupt_state(Save);
#endif // defined(AT91SAM7A3EK)

    // Configure Flash Mode register
    SET(pFlash->FLA_FMR, ((AT91C_MASTER_CLOCK / 666666)) << 16);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?