⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 media_flash.c

📁 This software package contains the USB framework core developped by ATMEL, as well as a Mass stora
💻 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 + -