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

📄 nand_if.c

📁 STM32实现读卡器功能,适用于STM32E-EVAL开发板
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name          : nand_if.c
* Author             : MCD Application Team
* Version            : V2.2.0
* Date               : 06/13/2008
* Description        : manage NAND operationx state machine
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
#include "platform_config.h"

#ifdef USE_STM3210E_EVAL
/* Includes ------------------------------------------------------------------*/
#include "nand_if.h"
#include "mass_mal.h"
#include "fsmc_nand.h"
#include "memory.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* extern variables-----------------------------------------------------------*/
extern u32 SCSI_LBA;
extern u32 SCSI_BlkLen;
/* Private variables ---------------------------------------------------------*/
u16 LUT[1024]; //Look Up Table Buffer
WRITE_STATE Write_State;
BLOCK_STATE Block_State;
NAND_ADDRESS wAddress, fAddress;
u16  phBlock, LogAddress, Initial_Page, CurrentZone = 0;
u16  Written_Pages = 0;

u16 LUT[1024]; //Look Up Table Buffer
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static u16 NAND_CleanLUT(u8 ZoneNbr);
static NAND_ADDRESS NAND_GetAddress(u32 Address);
static u16 NAND_GetFreeBlock(void);
static u16 NAND_Write_Cleanup(void);
SPARE_AREA ReadSpareArea(u32 address);
static u16 NAND_Copy(NAND_ADDRESS Address_Src, NAND_ADDRESS Address_Dest, u16 PageToCopy);
static NAND_ADDRESS NAND_ConvertPhyAddress(u32 Address);
static u16 NAND_BuildLUT(u8 ZoneNbr);

/*******************************************************************************
* Function Name  : NAND_Init
* Description    : Init NAND Interface
* Input          : None
* Output         : None
* Return         : Status
*******************************************************************************/
u16 NAND_Init(void)
{
  u16 Status = NAND_OK;

  FSMC_NAND_Init();
  Status = NAND_BuildLUT(0);
  Write_State = WRITE_IDLE;
  return Status;
}

/*******************************************************************************
* Function Name  : NAND_Write
* Description    : write one sector by once
* Input          : None
* Output         : None
* Return         : Status
*******************************************************************************/
u16 NAND_Write(u32 Memory_Offset, u32 *Writebuff, u16 Transfer_Length)
{
  /* check block status and calculate start and end addreses */
  wAddress    = NAND_GetAddress(Memory_Offset / 512);

  /*check Zone: if second zone is requested build second LUT*/
  if (wAddress.Zone != CurrentZone)
  {
    CurrentZone = wAddress.Zone;
    NAND_BuildLUT(CurrentZone);
  }

  phBlock     = LUT[wAddress.Block]; /* Block Index + flags */
  LogAddress  = wAddress.Block ; /* save logical block */

  /*  IDLE state  */
  /****************/
  if ( Write_State == WRITE_IDLE)
  {/* Idle state */

    if (phBlock & USED_BLOCK)
    { /* USED BLOCK */

      Block_State = OLD_BLOCK;
      /* Get a free Block for swap */
      fAddress.Block = NAND_GetFreeBlock();
      fAddress.Zone  = wAddress.Zone;
      Initial_Page = fAddress.Page  = wAddress.Page;

      /* write the new page */
      FSMC_NAND_WriteSmallPage((u8 *)Writebuff, fAddress, PAGE_TO_WRITE);
      Written_Pages++;

      /* get physical block */
      wAddress.Block = phBlock & 0x3FF;


      if (Written_Pages == SCSI_BlkLen)
      {
        NAND_Write_Cleanup();
        Written_Pages = 0;
        return NAND_OK;
      }
      else
      {
        if (wAddress.Page == (NAND_BLOCK_SIZE - 1))
        {
          NAND_Write_Cleanup();
          return NAND_OK;
        }
        Write_State = WRITE_ONGOING;
        return NAND_OK;
      }
    }
    else
    {/* UNUSED BLOCK */

      Block_State = UNUSED_BLOCK;
      /* write the new page */
      wAddress.Block = phBlock & 0x3FF;
      FSMC_NAND_WriteSmallPage( (u8 *)Writebuff , wAddress, PAGE_TO_WRITE);

      Written_Pages++;
      if (Written_Pages == SCSI_BlkLen)
      {
        Written_Pages = 0;
        NAND_Write_Cleanup();
        return NAND_OK;
      }
      else
      {
        Write_State = WRITE_ONGOING;
        return NAND_OK;
      }
    }
  }
  /* WRITE state */
  /***************/
  if ( Write_State == WRITE_ONGOING)
  {/* Idle state */
    if (phBlock & USED_BLOCK)
    { /* USED BLOCK */

      wAddress.Block = phBlock & 0x3FF;
      Block_State = OLD_BLOCK;
      fAddress.Page  = wAddress.Page;

      /* check if next pages are in next block */
      if (wAddress.Page == (NAND_BLOCK_SIZE - 1))
      {
        /* write Last page  */
        FSMC_NAND_WriteSmallPage( (u8 *)Writebuff , fAddress, PAGE_TO_WRITE);
        Written_Pages++;
        if (Written_Pages == SCSI_BlkLen)
        {
          Written_Pages = 0;
        }
        /* Clean up and Update the LUT */
        NAND_Write_Cleanup();
        Write_State = WRITE_IDLE;
        return NAND_OK;
      }

      /* write next page */
      FSMC_NAND_WriteSmallPage( (u8 *)Writebuff , fAddress, PAGE_TO_WRITE);
      Written_Pages++;
      if (Written_Pages == SCSI_BlkLen)
      {
        Write_State = WRITE_IDLE;
        NAND_Write_Cleanup();
        Written_Pages = 0;
      }

    }
    else
    {/* UNUSED BLOCK */
      wAddress.Block = phBlock & 0x3FF;
      /* check if it is the last page in prev block */
      if (wAddress.Page == (NAND_BLOCK_SIZE - 1))
      {
        /* write Last page  */
        FSMC_NAND_WriteSmallPage( (u8 *)Writebuff , wAddress, PAGE_TO_WRITE);
        Written_Pages++;
        if (Written_Pages == SCSI_BlkLen)
        {
          Written_Pages = 0;
        }

        /* Clean up and Update the LUT */
        NAND_Write_Cleanup();
        Write_State = WRITE_IDLE;



        return NAND_OK;
      }
      /* write next page in same block */
      FSMC_NAND_WriteSmallPage( (u8 *)Writebuff , wAddress, PAGE_TO_WRITE);
      Written_Pages++;
      if (Written_Pages == SCSI_BlkLen)
      {
        Write_State = WRITE_IDLE;
        NAND_Write_Cleanup();
        Written_Pages = 0;
      }
    }
  }
  return NAND_OK;
}

/*******************************************************************************
* Function Name  : NAND_Read
* Description    : Read sectors
* Input          : None
* Output         : None
* Return         : Status
*******************************************************************************/
u16 NAND_Read(u32 Memory_Offset, u32 *Readbuff, u16 Transfer_Length)
{
  NAND_ADDRESS phAddress;

  phAddress = NAND_GetAddress(Memory_Offset / 512);

  if (phAddress.Zone != CurrentZone)
  {
    CurrentZone = phAddress.Zone;
    NAND_BuildLUT(CurrentZone);
  }

  if (LUT [phAddress.Block] & BAD_BLOCK)
  {
    return NAND_FAIL;
  }
  else
  {
    phAddress.Block = LUT [phAddress.Block] & ~ (USED_BLOCK | VALID_BLOCK);
    FSMC_NAND_ReadSmallPage ( (u8 *)Readbuff , phAddress, Transfer_Length / 512);
  }
  return NAND_OK;
}

/*******************************************************************************
* Function Name  : NAND_CleanLUT
* Description    : Erase old blocks & rebuild the look up table
* Input          : None
* Output         : None
* Return         : Status
*******************************************************************************/
static u16 NAND_CleanLUT (u8 ZoneNbr)
{
#ifdef WEAR_LEVELLING_SUPPORT
  u16 BlockIdx, LUT_Item;
#endif
  /* Rebuild the LUT for the current zone */
  NAND_BuildLUT (ZoneNbr);

#ifdef WEAR_LEVELLING_SUPPORT
  /* Wear Leveling : circular use of free blocks */
  LUT_Item = LUT [BlockIdx]
             for (BlockIdx == MAX_LOG_BLOCKS_PER_ZONE ; BlockIdx < MAX_LOG_BLOCKS_PER_ZONE + WEAR_DEPTH ; BlockIdx++)
             {
               LUT [BlockIdx] = LUT [BlockIdx + 1];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -