?? translatednandflash.c
字號:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, 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 disclaimer below.
*
* 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.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "TranslatedNandFlash.h"
#include <utility/trace.h>
#include <utility/assert.h>
#include <utility/math.h>
#include <string.h>
//------------------------------------------------------------------------------
// Internal definitions
//------------------------------------------------------------------------------
/// Custom trace levels for the current file.
#define DEBUG trace_DEBUG
#define INFO trace_INFO
#define IMPORTANT trace_FATAL
/// Casts
#define MAPPED(translated) ((struct MappedNandFlash *) translated)
#define MANAGED(translated) ((struct ManagedNandFlash *) translated)
#define ECC(translated) ((struct EccNandFlash *) translated)
#define RAW(translated) ((struct RawNandFlash *) translated)
#define MODEL(translated) ((struct NandFlashModel *) translated)
/// Minimum number of blocks that should be kept unallocated
#define MINNUMUNALLOCATEDBLOCKS 32
/// Maximum allowed erase count difference
#define MAXERASEDIFFERENCE 5
//------------------------------------------------------------------------------
// Internal functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Returns 1 if there are enough free blocks to perform a single block
/// allocation; otherwise returns 0.
/// \param translated Pointer to a TranslatedNandFlash instance.
//------------------------------------------------------------------------------
static unsigned char BlockCanBeAllocated(
const struct TranslatedNandFlash *translated)
{
unsigned short count;
// Count number of free and dirty blocks (unallocated blocks)
count = ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_DIRTY)
+ ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE);
// Check that count is greater than minimum number of unallocated blocks
if (count > MINNUMUNALLOCATEDBLOCKS) {
return 1;
}
else {
return 0;
}
}
//------------------------------------------------------------------------------
/// Returns 1 if the given page inside the currently written block is clean (has
/// not been written yet); otherwise returns 0.
/// \param translated Pointer to a TranslatedNandFlash instance.
/// \param page Page number.
//------------------------------------------------------------------------------
static unsigned char PageIsClean(
const struct TranslatedNandFlash *translated,
unsigned short page)
{
ASSERT(page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)),
"PageIsClean: Page out-of-bounds\n\r");
return ((translated->currentBlockPageStatuses[page / 8] >> (page % 8)) & 1) == 0;
}
//------------------------------------------------------------------------------
/// Marks the given page as being dirty (i.e. written).
/// \param translated Pointer to a TranslatedNandFlash instance.
/// \param page Page number.
//------------------------------------------------------------------------------
static void MarkPageDirty(
struct TranslatedNandFlash *translated,
unsigned short page)
{
ASSERT(page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)),
"PageIsClean: Page out-of-bounds\n\r");
translated->currentBlockPageStatuses[page / 8] |= 1 << (page % 8);
}
//------------------------------------------------------------------------------
/// Marks all pages as being clean.
/// \param translated Pointer to a TranslatedNandFlash instance.
//------------------------------------------------------------------------------
static void MarkAllPagesClean(struct TranslatedNandFlash *translated)
{
memset(translated->currentBlockPageStatuses, 0,
sizeof(translated->currentBlockPageStatuses));
}
//------------------------------------------------------------------------------
/// Allocates the best-fitting physical block for the given logical block.
/// Returns 0 if successful; otherwise returns NandCommon_ERROR_NOBLOCKFOUND if
/// there are no more free blocks, or a NandCommon_ERROR code.
/// \param translated Pointer to a TranslatedNandFlash instance.
/// \param block Logical block number.
//------------------------------------------------------------------------------
static unsigned char AllocateBlock(
struct TranslatedNandFlash *translated,
unsigned short block)
{
unsigned short freeBlock, liveBlock;
unsigned char error;
signed int eraseDifference;
trace_LOG(DEBUG, "Allocating a new block\n\r");
// Find youngest free block and youngest live block
if (ManagedNandFlash_FindYoungestBlock(MANAGED(translated),
NandBlockStatus_FREE,
&freeBlock)) {
trace_LOG(trace_ERROR, "AllocateBlock: Could not find a free block\n\r");
return NandCommon_ERROR_NOBLOCKFOUND;
}
// If this is the last free block, save the logical mapping in it and
// clean dirty blocks
trace_LOG(DEBUG, "Number of FREE blocks: %d\n\r",
ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE));
if (ManagedNandFlash_CountBlocks(MANAGED(translated),
NandBlockStatus_FREE) == 1) {
// Save mapping and clean dirty blocks
trace_LOG(DEBUG, "Last FREE block, cleaning up ...\n\r");
error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock);
if (error) {
trace_LOG(trace_ERROR, "AllocateBlock: Failed to save mapping\n\r");
return error;
}
error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated));
if (error) {
trace_LOG(trace_ERROR, "AllocatedBlock: Failed to erase dirty blocks\n\r");
return error;
}
// Allocate new block
return AllocateBlock(translated, block);
}
// Find youngest LIVE block to check the erase count difference
if (!ManagedNandFlash_FindYoungestBlock(MANAGED(translated),
NandBlockStatus_LIVE,
&liveBlock)) {
// Calculate erase count difference
trace_LOG(DEBUG, "Free block erase count = %d\n\r", MANAGED(translated)->blockStatuses[freeBlock].eraseCount);
trace_LOG(DEBUG, "Live block erase count = %d\n\r", MANAGED(translated)->blockStatuses[liveBlock].eraseCount);
eraseDifference = abs(MANAGED(translated)->blockStatuses[freeBlock].eraseCount
- MANAGED(translated)->blockStatuses[liveBlock].eraseCount);
// Check if it is too big
if (eraseDifference > MAXERASEDIFFERENCE) {
trace_LOG(IMPORTANT, "Erase difference too big, switching blocks\n\r");
MappedNandFlash_Map(
MAPPED(translated),
MappedNandFlash_PhysicalToLogical(
MAPPED(translated),
liveBlock),
freeBlock);
ManagedNandFlash_CopyBlock(MANAGED(translated),
liveBlock,
freeBlock);
// Allocate a new block
return AllocateBlock(translated, block);
}
}
// Map block
trace_LOG(DEBUG, "Allocating PB#%d for LB#%d\n\r", freeBlock, block);
MappedNandFlash_Map(MAPPED(translated), block, freeBlock);
return 0;
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Initializes a TranslatedNandFlash instance.
/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code.
/// \param translated Pointer to a TranslatedNandFlash instance.
/// \param model Pointer to the underlying nand chip model. Can be 0.
/// \param commandAddress Address at which commands are sent.
/// \param addressAddress Address at which addresses are sent.
/// \param dataAddress Address at which data is sent.
/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
//------------------------------------------------------------------------------
unsigned char TranslatedNandFlash_Initialize(
struct TranslatedNandFlash *translated,
const struct NandFlashModel *model,
unsigned int commandAddress,
unsigned int addressAddress,
unsigned int dataAddress,
const Pin pinChipEnable,
const Pin pinReadyBusy)
{
translated->currentLogicalBlock = -1;
translated->previousPhysicalBlock = -1;
MarkAllPagesClean(translated);
// Initialize MappedNandFlash
return MappedNandFlash_Initialize(MAPPED(translated),
model,
commandAddress,
addressAddress,
dataAddress,
pinChipEnable,
pinReadyBusy);
}
//------------------------------------------------------------------------------
/// Reads the data and/or the spare area of a page on a translated nandflash.
/// If the block is not currently mapped but could be (i.e. there are available
/// physical blocks), then the data/spare is filled with 0xFF.
/// Returns 0 if successful; otherwise returns NandCommon_ERROR_NOMOREBLOCKS
/// if no more block can be allocated, or a NandCommon_ERROR code.
/// \param translated Pointer to a TranslatedNandFlash instance.
/// \param block Logical block number.
/// \param page Number of page to read inside logical block.
/// \param data Data area buffer, can be 0.
/// \param spare Spare area buffer, can be 0.
//------------------------------------------------------------------------------
unsigned char TranslatedNandFlash_ReadPage(
const struct TranslatedNandFlash *translated,
unsigned short block,
unsigned short page,
void *data,
void *spare)
{
unsigned char error;
trace_LOG(INFO, "TranslatedNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);
// If the page to read is in the current block, there is a previous physical
// block and the page is clean -> read the page in the old block since the
// new one does not contain meaningful data
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -