📄 nandflash.c
字号:
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : NandFlash.c
//* Object : NandFlash routine
//* Creation : WG 18/Dec/2006
//*----------------------------------------------------------------------------
#include "project.h"
#include "AT91SAM7SE-EK.h"
#include "NandFlash.h"
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Init
//* \brief Configure the SMC controller and EBI controller for Nand Flash support
//*----------------------------------------------------------------------------
void AT91F_NandFlash_Init (void)
{
AT91PS_SMC2 psmc = AT91C_BASE_SMC;
// Init the EBI for NAND FLASH Support
AT91C_BASE_EBI -> EBI_CSA |= AT91C_EBI_CS3A_SMC_NandFlash; // Chip Select is assigned to SMC controller
// Configure SMC Register
psmc->SMC2_CSR[3] =
AT91C_SMC2_NWS_2 | // 2 wait states required required by the NAND Flash device
AT91C_SMC2_WSEN_EN | // NWS register enabled
AT91C_SMC2_TDF_2_CYCLES | // 2 Data Float Time Cycles required by the NAND Flash device
AT91C_SMC2_BAT_8BIT | // 1 8-bit device connected over the bus
AT91C_SMC2_DBW_8 | // 8-bit Data Bus Width
AT91C_SMC2_DRP_STANDARD | // Standard Read protocol required by the NAND Flash device
AT91C_SMC2_ACSS_STANDARD | // Standard address to chip select
AT91C_SMC2_RWSETUP_0_CYCLE | // 0 Read/Write Setup time required by the Nand Flash Device
AT91C_SMC2_RWHOLD_1_CYCLE ; // 1 Read/Write Setup time required by the ECC controller
//Configure PIO for EBI CS3
AT91F_EBI_NandFlash_CfgPIO();
// Disable Pull ups on A21/NANDALE and A22/NANDCLE
AT91C_BASE_PIOC -> PIO_PPUDR = ((1 << 21) | (1 << 22));
//Send a DBGU message
AT91F_DBGU_Printk("NAND Flash Device Initialized \n\r");
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Reset
//* \brief Reset the Nand Flash device
//*----------------------------------------------------------------------------
void AT91F_NandFlash_Reset (void)
{
NAND_ENABLE_CE(); // Enable the NAND Flash device
WRITE_NAND_COMMAND(NAND_CMD_RESET);
NAND_WAIT_READY(); // Wait for Read/Busy Signal assertion
NAND_DISABLE_CE(); // Disable the NAND Flash device
}
//*----------------------------------------------------------------------------
//* \fn AT91F_EBI_NandFlash_CfgPIO
//* \brief Configure the PIO for NAND FLASH
//*----------------------------------------------------------------------------
void AT91F_EBI_NandFlash_CfgPIO(void)
{
// Activate PIOC clock
AT91F_PIOC_CfgPMC ();
// Configure PIO controllers to periph mode
AT91F_PIO_CfgPeriph(
AT91C_BASE_PIOC, // PIO controller base address
((unsigned int) AT91C_PC0_D0 ) |
((unsigned int) AT91C_PC1_D1 ) |
((unsigned int) AT91C_PC2_D2 ) |
((unsigned int) AT91C_PC3_D3 ) |
((unsigned int) AT91C_PC4_D4 ) |
((unsigned int) AT91C_PC5_D5 ) |
((unsigned int) AT91C_PC6_D6 ) |
((unsigned int) AT91C_PC7_D7 ) |
((unsigned int) AT91C_PC19_A21 ) |
((unsigned int) AT91C_PC20_A22 ) , // Peripheral A
// ((unsigned int) AT91C_PC15_NCS3_NANDCS) | // Only used with CE don't care NAND Flash Devices
((unsigned int) AT91C_PC17_NANDOE ) |
((unsigned int) AT91C_PC18_NANDWE )); // Peripheral B
// Activate PIOB clock
AT91F_PIOB_CfgPMC ();
// Configure Ready/Busy PIO Input signal
AT91F_PIO_CfgInput(AT91C_BASE_PIOB, AT91C_PIO_PB19);
// Configure /CE PIO signal
AT91F_PIO_CfgOutput(AT91C_BASE_PIOB, AT91C_PIO_PB18); // Only used if the EBI NCS3_NANDCS not assigned as CE signal
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Read_ID
//* \brief Read the device ID
//*----------------------------------------------------------------------------
void AT91F_NandFlash_Read_ID (PSNandInfo pNandInfo)
{
volatile unsigned char Maker_ID = 0;
volatile unsigned char Device_Code = 0;
volatile unsigned char Not_Used = 0 ;
volatile unsigned char ID_Data = 0;
NAND_ENABLE_CE(); // Enable the NAND Flash device
// Write the Read ID Command
WRITE_NAND_COMMAND(NAND_CMD_READID);
//Write the Address
WRITE_NAND_ADDRESS(0x00);
Maker_ID = READ_NAND();
Device_Code = READ_NAND();
Not_Used = READ_NAND();
ID_Data = READ_NAND();
NAND_DISABLE_CE(); // Disable the NAND Flash device
// Fill the NAND Structure parameters
pNandInfo -> Page_Size = 1024 << (ID_Data & 0x03);
pNandInfo -> Spare_Size = (8 << ((ID_Data & 0x04)>>2)) * (pNandInfo -> Page_Size / 512);
pNandInfo -> Block_Size = (64 * 1024) << ((ID_Data & 0x30)>>4);
if ((ID_Data & 0x40) == 0x00)
{
pNandInfo -> Bus_Width = 8;
}
else
{
pNandInfo -> Bus_Width = 16;
}
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Create_Bad_Block_Table
//* \brief Create a table identifying bad block(s)
//*----------------------------------------------------------------------------
short AT91F_NandFlash_Create_Bad_Block_Table (PSNandInfo pNandInfo,unsigned char* PBad_Block_Table)
{
volatile unsigned short i = 0;
volatile unsigned short j = 0;
volatile unsigned int Block_Address = 0x00000000;
volatile unsigned char Block_Offset = (pNandInfo -> Block_Size) / (pNandInfo -> Page_Size);
volatile unsigned short Number_Of_Bad_Blocks = 0;
for (j = 0; j < NB_OF_BLOCKS ; j++)
{
NAND_ENABLE_CE(); // Enable the NAND Flash device
WRITE_NAND_COMMAND(NAND_CMD_READ1); // Read Command 1
WRITE_NAND_ADDRESS(0x00000000); // Column address
WRITE_NAND_ADDRESS(0x00000000); // Column address
WRITE_NAND_ADDRESS(Block_Address); // Row address
WRITE_NAND_ADDRESS(Block_Address >> 8); // Row address
WRITE_NAND_ADDRESS(Block_Address >> 16); // Row address
WRITE_NAND_COMMAND(NAND_CMD_READ2); // Read Command 2
NAND_WAIT_READY(); // Wait for Read/Busy Signal assertion
// Jump to the ECC code location
WRITE_NAND_COMMAND(NAND_CMD_RDM_READ1); // Page Random Read Command 1
WRITE_NAND_ADDRESS(0x00); // Column address
WRITE_NAND_ADDRESS(0x08); // Column address
WRITE_NAND_COMMAND(NAND_CMD_RDM_READ2); // // Page Random Read Command 2
*PBad_Block_Table = READ_NAND();
if (*PBad_Block_Table != 0xFF)
{
Number_Of_Bad_Blocks++;
}
Block_Address = Block_Address + Block_Offset ;
PBad_Block_Table ++;
}
NAND_DISABLE_CE(); // Disable the NAND Flash device
return Number_Of_Bad_Blocks;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Block_Erase
//* \brief Erase a block
//*----------------------------------------------------------------------------
void AT91F_NandFlash_Block_Erase (PSNandInfo pNandInfo,unsigned char* PBad_Block_Table,unsigned short Block_Reference)
{
volatile unsigned short i;
volatile unsigned int Row_Address = (Block_Reference * 0x40);
PBad_Block_Table = PBad_Block_Table + Block_Reference;
if(*PBad_Block_Table != 0xFF)
{
AT91F_DBGU_Printk("Block corrupted, erase operation denied and aborted \n\r");
return;
}
NAND_ENABLE_CE(); // Enable the NAND Flash device
WRITE_NAND_COMMAND(NAND_CMD_ERASE1); // Erase Command 1
WRITE_NAND_ADDRESS(Row_Address); // Row address
WRITE_NAND_ADDRESS(Row_Address >> 8); // Row address
WRITE_NAND_ADDRESS(Row_Address >> 16); // Row address
WRITE_NAND_COMMAND(NAND_CMD_ERASE2); // Erase Command 2
NAND_WAIT_READY(); // Wait for Read/Busy Signal assertion
NAND_DISABLE_CE(); // Disable the NAND Flash device
if (AT91F_NandFlash_Status_Read() == 0)
{
AT91F_DBGU_Printk("Block erase operation successful \n\r");
}
else
{
AT91F_DBGU_Printk("Block erase operation unsuccessful \n\r");
*PBad_Block_Table = 0x00;
AT91F_DBGU_Printk("Bad block table has been updated\n\r");
// Please add code to declare the block as "bad" within the NAND Flash device
}
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Page_Read
//* \brief Read a page
//*----------------------------------------------------------------------------
void AT91F_NandFlash_Page_Read (PSNandInfo pNandInfo,unsigned char* PPage_Buffer,unsigned short Block_Reference, unsigned short Page_Reference)
{
volatile unsigned short i;
volatile unsigned int Row_Address = (Block_Reference * 0x40) + Page_Reference;
NAND_ENABLE_CE(); // Enable the NAND Flash device
WRITE_NAND_COMMAND(NAND_CMD_READ1); // Page Read Command 1
WRITE_NAND_ADDRESS(0x00); // Column address
WRITE_NAND_ADDRESS(0x00); // Column address
WRITE_NAND_ADDRESS(Row_Address); // Row address
WRITE_NAND_ADDRESS(Row_Address >> 8); // Row address
WRITE_NAND_ADDRESS(Row_Address >> 16); // Row address
WRITE_NAND_COMMAND(NAND_CMD_READ2); // Page Read Command 2
NAND_WAIT_READY(); // Wait for Read/Busy Signal assertion
for (i=0; i < (pNandInfo -> Page_Size ); i++)
{
*PPage_Buffer = READ_NAND(); // Fill the Page Buffer with main area data
PPage_Buffer++;
}
// Jump to the ECC code location
WRITE_NAND_COMMAND(NAND_CMD_RDM_READ1); // Page Random Read Command 1
WRITE_NAND_ADDRESS(ECC_LSB_OFFSET); // Column address
WRITE_NAND_ADDRESS(ECC_MSB_OFFSET); // Column address
WRITE_NAND_COMMAND(NAND_CMD_RDM_READ2); // Page Random Read Command 2
READ_NAND(); // Four Accesses Allowing the ECC controller to compare calculated and stored ECC codes
READ_NAND(); //
READ_NAND(); //
READ_NAND(); //
if (AT91C_BASE_HECC ->ECC_SR != 0x00) // Check the ECC Status Register
{
AT91F_DBGU_Printk("ECC Error !!\n\r"); // Send a DBGU message if an error detected
//return;
}
// Jump back to the spare zone first location
WRITE_NAND_COMMAND(NAND_CMD_RDM_READ1); // Page Random Read Command 1
WRITE_NAND_ADDRESS(SPARE_LSB_OFFSET); // Column address
WRITE_NAND_ADDRESS(SPARE_MSB_OFFSET); // Column address
WRITE_NAND_COMMAND(NAND_CMD_RDM_READ2); // Page Random Read Command 2
for (i=0; i < (pNandInfo -> Spare_Size); i++)
{
*PPage_Buffer = READ_NAND(); // Fill the Page Buffer with spare area data
PPage_Buffer++;
}
NAND_DISABLE_CE(); // Disable the NAND Flash device
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Page_Write
//* \brief Write a page
//*----------------------------------------------------------------------------
void AT91F_NandFlash_Page_Write (PSNandInfo pNandInfo,unsigned char* PBad_Block_Table,unsigned char* PPage_Buffer,unsigned short Block_Reference, unsigned short Page_Reference)
{
volatile unsigned short i;
volatile unsigned int Row_Address = (Block_Reference * 0x40) + Page_Reference;
volatile unsigned int Temp_Register;
PBad_Block_Table = PBad_Block_Table + Block_Reference;
if(*PBad_Block_Table != 0xFF) // Check the Bad Block Information byte
{
AT91F_DBGU_Printk("Block corrupted, write operation denied and aborted \n\r");
return;
}
NAND_ENABLE_CE(); // Enable the NAND Flash device
WRITE_NAND_COMMAND(NAND_CMD_PAGEPROG1); // Page Program Command 1
WRITE_NAND_ADDRESS(0x00); // Column address
WRITE_NAND_ADDRESS(0x00); // Column address
WRITE_NAND_ADDRESS(Row_Address); // Row address
WRITE_NAND_ADDRESS(Row_Address >> 8); // Row address
WRITE_NAND_ADDRESS(Row_Address >> 16); // Row address
for (i=0; i < (pNandInfo -> Page_Size); i++)
{
WRITE_NAND(*PPage_Buffer); // Write data in the main area
PPage_Buffer++;
}
// Jump to the ECC code location
WRITE_NAND_COMMAND(NAND_CMD_RDM_PAGEPROG);
WRITE_NAND_ADDRESS(ECC_LSB_OFFSET);
WRITE_NAND_ADDRESS(ECC_MSB_OFFSET);
// Write the computed ECC code
Temp_Register = (AT91C_BASE_HECC->ECC_PR) & 0xFF;
WRITE_NAND(Temp_Register);
Temp_Register = (AT91C_BASE_HECC->ECC_PR)>> 8 & 0xFF;
WRITE_NAND(Temp_Register);
Temp_Register = (AT91C_BASE_HECC->ECC_NPR) & 0xFF;
WRITE_NAND(Temp_Register);
Temp_Register = (AT91C_BASE_HECC->ECC_NPR)>> 8 & 0xFF;
WRITE_NAND(Temp_Register);
WRITE_NAND_COMMAND(NAND_CMD_PAGEPROG2); // Page Program Command 2
NAND_WAIT_READY(); // Wait for Read/Busy Signal assertion
NAND_DISABLE_CE(); // Disable the NAND Flash device
if (AT91F_NandFlash_Status_Read() == 0) // Check the write sequence operation
{
AT91F_DBGU_Printk("Page write operation successful \n\r");
}
else
{
AT91F_DBGU_Printk("Page write operation unsuccessful \n\r");
*PBad_Block_Table = 0x00;
AT91F_DBGU_Printk("Bad block table has been updated \n\r");
// Please add code to declare the block as "bad"
}
}
//*----------------------------------------------------------------------------
//* \fn AT91F_NandFlash_Status_Read
//* \brief Read Status
//*----------------------------------------------------------------------------
short AT91F_NandFlash_Status_Read(void)
{
unsigned short Status;
NAND_ENABLE_CE(); // Enable the NAND Flash device
WRITE_NAND_COMMAND(NAND_CMD_STATUS); // Status Command
Status = (READ_NAND() & 0x01); // Read the Status Byte
NAND_DISABLE_CE(); // Disable the NAND Flash device
return Status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -