?? rawnandflash.c
字號:
unsigned short destPage)
{
unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw));
unsigned int sourceRow = sourceBlock * numPages + sourcePage;
unsigned int destRow = destBlock * numPages + destPage;
unsigned char error = 0;
ASSERT((sourcePage & 1) == (destPage & 1),
"CopyPage: Source and destination page must have the same parity.\n\r");
trace_LOG(DEBUG, "CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r",
sourceBlock, sourcePage, destBlock, destPage);
// Use the copy-back facility if available
if (NandFlashModel_SupportsCopyBack(MODEL(raw))) {
// Start operation
ENABLE_CE(raw);
// Start copy-back read
WRITE_COMMAND(raw, COMMAND_COPYBACK_READ_1);
WriteColumnAddress(raw, 0);
WriteRowAddress(raw, sourceRow);
WRITE_COMMAND(raw, COMMAND_COPYBACK_READ_2);
WaitReady(raw);
// Start copy-back write
WRITE_COMMAND(raw, COMMAND_COPYBACK_PROGRAM_1);
WriteColumnAddress(raw, 0);
WriteRowAddress(raw, destRow);
WRITE_COMMAND(raw, COMMAND_COPYBACK_PROGRAM_2);
WaitReady(raw);
// Check status
if (!IsOperationComplete(raw)) {
trace_LOG(trace_ERROR, "CopyPage: Failed to copy page.\n\r");
error = NandCommon_ERROR_CANNOTCOPY;
}
// Finish operation
DISABLE_CE(raw);
}
else {
// Software copy
unsigned char data[NandCommon_MAXPAGEDATASIZE];
unsigned char spare[NandCommon_MAXPAGESPARESIZE];
if (RawNandFlash_ReadPage(raw, sourceBlock, sourcePage, data, spare)) {
trace_LOG(trace_ERROR, "CopyPage: Failed to read page to copy\n\r");
error = NandCommon_ERROR_CANNOTREAD;
}
else if (RawNandFlash_WritePage(raw, destBlock, destPage, data, spare)) {
trace_LOG(trace_ERROR, "CopyPage: Failed to write dest. page\n\r");
error = NandCommon_ERROR_CANNOTWRITE;
}
}
return error;
}
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Initializes a RawNandFlash instance based on the given model and physical
/// interface. If no model is provided, then the function tries to autodetect
/// it.
/// Returns 0 if initialization is successful; otherwise returns
/// NandCommon_ERROR_UNKNOWNMODEL.
/// \param raw Pointer to a RawNandFlash 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 RawNandFlash_Initialize(
struct RawNandFlash *raw,
const struct NandFlashModel *model,
unsigned int commandAddress,
unsigned int addressAddress,
unsigned int dataAddress,
const Pin pinChipEnable,
const Pin pinReadyBusy)
{
trace_LOG(DEBUG, "RawNandFlash_Initialize()\r\n");
// Initialize fields
raw->commandAddress = commandAddress;
raw->addressAddress = addressAddress;
raw->dataAddress = dataAddress;
raw->pinChipEnable = pinChipEnable;
raw->pinReadyBusy = pinReadyBusy;
// Reset
RawNandFlash_Reset(raw);
// If model is not provided, autodetect it
if (!model) {
trace_LOG(DEBUG, "No model provided, trying autodetection ...\n\r");
if (NandFlashModel_Find(nandFlashModelList,
NandFlashModelList_SIZE,
RawNandFlash_ReadId(raw),
&(raw->model))) {
trace_LOG(trace_ERROR,
"RawNandFlash_Initialize: Could not autodetect chip.\n\r");
return NandCommon_ERROR_UNKNOWNMODEL;
}
}
else {
// Copy provided model
raw->model = *model;
}
return 0;
}
//------------------------------------------------------------------------------
/// Resets a NandFlash device.
/// \param raw Pointer to a RawNandFlash instance.
//------------------------------------------------------------------------------
void RawNandFlash_Reset(const struct RawNandFlash *raw)
{
trace_LOG(DEBUG, "RawNandFlash_Reset()\n\r");
ENABLE_CE(raw);
WRITE_COMMAND(raw, COMMAND_RESET);
WaitReady(raw);
DISABLE_CE(raw);
}
//------------------------------------------------------------------------------
/// Reads and returns the identifiers of a NandFlash chip.
/// \param raw Pointer to a RawNandFlash instance.
/// \return id1|(id2<<8)|(id3<<16)|(id4<<24)
//------------------------------------------------------------------------------
unsigned int RawNandFlash_ReadId(const struct RawNandFlash *raw)
{
unsigned int chipId;
trace_LOG(DEBUG, "RawNandFlash_ReadId()\n\r");
ENABLE_CE(raw);
WRITE_COMMAND(raw, COMMAND_READID);
WRITE_ADDRESS(raw, 0);
chipId = READ_DATA8(raw);
chipId |= READ_DATA8(raw) << 8;
chipId |= READ_DATA8(raw) << 16;
chipId |= READ_DATA8(raw) << 24;
DISABLE_CE(raw);
return chipId;
}
//------------------------------------------------------------------------------
/// Erases the specified block of the device, retrying several time if it fails.
/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK.
/// \param raw Pointer to a RawNandFlash instance.
/// \param block Number of the physical block to erase.
//------------------------------------------------------------------------------
unsigned char RawNandFlash_EraseBlock(
const struct RawNandFlash *raw,
unsigned short block)
{
unsigned char numTries = NUMERASETRIES;
trace_LOG(DEBUG, "RawNandFlash_EraseBlock(B#%d)\n\r", block);
while (numTries > 0) {
if (!EraseBlock(raw, block)) {
return 0;
}
numTries--;
}
trace_LOG(trace_ERROR, "RawNandFlash_EraseBlock: Failed to erase block after %d tries\n\r", NUMERASETRIES);
return NandCommon_ERROR_BADBLOCK;
}
//------------------------------------------------------------------------------
/// Reads the data and/or the spare areas of a page of a NandFlash into the
/// provided buffers. If a buffer pointer is 0, the corresponding area is not
/// read.
/// Returns 0 if the operation has been successful; otherwise returns 1.
/// \param raw Pointer to a RawNandFlash instance.
/// \param block Number of the block where the page to read resides.
/// \param page Number of the page to read inside the given block.
/// \param data Buffer where the data area will be stored.
/// \param spare Buffer where the spare area will be stored.
//------------------------------------------------------------------------------
unsigned char RawNandFlash_ReadPage(
const struct RawNandFlash *raw,
unsigned short block,
unsigned short page,
void *data,
void *spare)
{
unsigned char hasSmallBlocks = NandFlashModel_HasSmallBlocks(MODEL(raw));
unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
unsigned int pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(raw));
unsigned int rowAddress;
ASSERT(data || spare, "RawNandFlash_ReadPage: At least one area must be read\n\r");
trace_LOG(DEBUG, "RawNandFlash_ReadPage(B#%d:P#%d)\r\n", block, page);
// Calculate actual address of the page
rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page;
// Start operation
ENABLE_CE(raw);
// Use either small blocks or large blocks data area read
if (hasSmallBlocks) {
WRITE_COMMAND(raw, COMMAND_READ_A);
WriteColumnAddress(raw, 0);
WriteRowAddress(raw, rowAddress);
}
else {
WRITE_COMMAND(raw, COMMAND_READ_1);
WriteColumnAddress(raw, 0);
WriteRowAddress(raw, rowAddress);
WRITE_COMMAND(raw, COMMAND_READ_2);
}
// Wait for the nand to be ready
WaitReady(raw);
// Read data area if needed
if (data) {
WRITE_COMMAND(raw, COMMAND_READ_1);
ReadData(raw, (unsigned char *) data, pageDataSize);
}
// Use either small/large blocks spare area read
if (hasSmallBlocks) {
WRITE_COMMAND(raw, COMMAND_READ_C);
WriteColumnAddress(raw, 0);
WriteRowAddress(raw, rowAddress);
WaitReady(raw);
}
else {
WRITE_COMMAND(raw, COMMAND_RANDOM_OUT);
WriteColumnAddress(raw, pageDataSize);
WRITE_COMMAND(raw, COMMAND_RANDOM_OUT_2);
}
WaitReady(raw);
// Read spare area if needed
if (spare) {
WRITE_COMMAND(raw, COMMAND_READ_1);
ReadData(raw, (unsigned char *) spare, pageSpareSize);
}
// Disable CE
DISABLE_CE(raw);
return 0;
}
//------------------------------------------------------------------------------
/// Writes the data and/or the spare area of a page on a NandFlash chip. If one
/// of the buffer pointer is 0, the corresponding area is not written. Retries
/// several time if there is an error.
/// Returns 0 if the write operation is successful; otherwise returns
/// NandCommon_ERROR_BADBLOCK.
/// \param raw Pointer to a RawNandFlash instance.
/// \param block Number of the block where the page to write resides.
/// \param page Number of the page to write inside the given block.
/// \param data Buffer containing the data area.
/// \param spare Buffer containing the spare area.
//------------------------------------------------------------------------------
unsigned char RawNandFlash_WritePage(
const struct RawNandFlash *raw,
unsigned short block,
unsigned short page,
void *data,
void *spare)
{
unsigned char numTries = NUMWRITETRIES;
trace_LOG(DEBUG, "RawNandFlash_WritePage(B#%d:P#%d)\r\n", block, page);
while (numTries > 0) {
if (!WritePage(raw, block, page, data, spare)) {
return 0;
}
numTries--;
}
trace_LOG(trace_ERROR, "RawNandFlash_WritePage: Failed to write page after %d tries\n\r", NUMWRITETRIES);
return NandCommon_ERROR_BADBLOCK;
}
//------------------------------------------------------------------------------
/// Copy the data in a page of the NandFlash device to an other page on that
/// same chip. Both pages must have be even or odd; it is not possible to copy
/// and even page to an odd page and vice-versa. Several retries are attempted
/// if errors are encountered.
/// Returns 0 if the operation is successful; otherwise returns
/// NandCommon_ERROR_BADBLOCK indicating that the destination block is bad.
/// \param raw Pointer to a RawNandFlash instance.
/// \param sourceBlock Source block number.
/// \param sourcePage Source page number inside the source block.
/// \param destBlock Destination block number.
/// \param destPage Destination page number inside the destination block.
//------------------------------------------------------------------------------
unsigned char RawNandFlash_CopyPage(
const struct RawNandFlash *raw,
unsigned short sourceBlock,
unsigned short sourcePage,
unsigned short destBlock,
unsigned short destPage)
{
unsigned char numTries = NUMCOPYTRIES;
trace_LOG(DEBUG, "RawNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r",
sourceBlock, sourcePage, destBlock, destPage);
while (numTries) {
if (!CopyPage(raw, sourceBlock, sourcePage, destBlock, destPage)) {
return 0;
}
numTries--;
}
trace_LOG(trace_ERROR, "RawNandFlash_CopyPage: Failed to copy page after %d tries\n\r", NUMCOPYTRIES);
return NandCommon_ERROR_BADBLOCK;
}
//------------------------------------------------------------------------------
/// Copies the data of one whole block of a NandFlash device to another block.
/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK.
/// \param raw Pointer to a RawNandFlash instance.
/// \param sourceBlock Source block number.
/// \param destBlock Destination block number.
//------------------------------------------------------------------------------
unsigned char RawNandFlash_CopyBlock(
const struct RawNandFlash *raw,
unsigned short sourceBlock,
unsigned short destBlock)
{
unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw));
unsigned int i;
ASSERT(sourceBlock != destBlock,
"RawNandFlash_CopyBlock: Source block must be different from dest block\n\r");
trace_LOG(DEBUG, "RawNandFlash_CopyBlock(B#%d->B#%d)\n\r",
sourceBlock, destBlock);
// Copy all pages
for (i=0; i < numPages; i++) {
if (RawNandFlash_CopyPage(raw, sourceBlock, i, destBlock, i)) {
trace_LOG(trace_ERROR,
"RawNandFlash_CopyBlock: Failed to copy page %d\n\r",
i);
return NandCommon_ERROR_BADBLOCK;
}
}
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -