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

📄 nandflash.c

📁 AT91SAM7SE系列IAR编程中外扩NAND的源码。
💻 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 + -