nandflash相关的一些结构题和操作函数

1. Nand_Init()

int NandInit(void)
{       
  // -------------------------------
  // Configure GPIO9 in Alt Funct. A
  // -------------------------------
  *((uint32_t *) (GPIO0_REG_START_ADDR + 0x20)) |= 0x00000200;
        
  nand.addr.pBase       = (volatile uint16_t *) NAND_FLASH_CS0_START_ADDR;
  nand.addr.pCommand    = (volatile uint8_t *) NAND_FLASH_CS0_START_ADDR + 0x00810000;
  nand.addr.pCommonArea = (volatile uint8_t *) NAND_FLASH_CS0_START_ADDR + 0x01020000;
        
  // Map The Space for FSMC Registers
  nand.regs = (FSMCRegs *) 0x10100000;
        
  // --------------------------------------------------
  // Disable all the other CS that we do not use (NOR),
  // keeping high bit 7 for disabling WP.
  // This is a temporary solution to avoid conflicts
  // --------------------------------------------------
  // Bank NOR 0, 1, 2, 3 (to be removed when NOR comes)
  // --------------------------------------------------
  nand.regs->FSMC_BCR1 &= 0x00000080;
  nand.regs->FSMC_BCR2 &= 0x00000080;
  nand.regs->FSMC_BCR3 &= 0x00000080;

  // -----------------------------------------------
  // Set NAND Control Values depending on the CS
  // -----------------------------------------------
  // CONTROL REGISTER
  // -----------------------------------------------
  // address_low        : 0
  // page_length        : 512 (for ECC calculation)
  // ecc_logic          : 0   (enabled when required)
  // bus_width          : 16
  // mem_type           : 1       (NAND)
  // wait_feature       : 1   (linked to GPIO9 Alt. Func. "A")
  // pc_reset           : 0
  // -----------------------------------------------

  nand.regs->FSMC_PCR0 = FMSC_PCR_BUS_WIDTH_16 | FMSC_PCR_MEM_TYPE_NAND
      | FMSC_PCR_BANK_ENABLE | FMSC_PCR_WAIT_ENABLE;

  // ----------------------------------------------
  // Set NAND Timings Registers depending on the CS.
  // -----------------------------------------------
  // COMMON AREA
  // -----------------------------------------------
  // data_bus_hiz_phase         : 0x0D
  // addr_hold_phase            : 0x0D
  // wait_phase                         : 0x0D
  // addr_setup_phase           : 0x0D
  // -----------------------------------------------

  nand.regs->FSMC_PMEM0 = FMSC_PMEM_MEM0HIZ | FMSC_PMEM_MEM0HOLD
      | FMSC_PMEM_MEM0WAIT | FMSC_PMEM_MEM0SET;

  // -----------------------------------------
  // Reset the device and wait till it's ready
  // -----------------------------------------
  *(nand.addr.pCommand) = 0xff;

  // ---------------------------------------------
  // Write the specific command for reading the ID
  // ---------------------------------------------
  *(nand.addr.pCommand)    = 0x90;
  *(nand.addr.pCommonArea) = 0x00;

  // --------------------------------------------
  // Assign the Device ID and the Manifacturer ID
  // --------------------------------------------
  nand.id.uiManID    = (*(nand.addr.pBase) & 0xff);
  nand.id.uiDeviceID = (*(nand.addr.pBase) & 0xff);

  if (nand.id.uiManID != MAKER_ID || nand.id.uiDeviceID != DEVICE_ID)
          return -1;

  // -------------------------------------------------------------------
  // Let's assume that the ECC is implementation is supported by default
  // -------------------------------------------------------------------
  // We support BCH8 (8 correctable bits every 512 bytes of data)
  // -------------------------------------------------------------------

  return 0;
}
2.  FSMCRegs ---FSMC 是Nandflash controller 模块, FSMCRegs表示了该模块的寄存器情况
typedef volatile struct
{
        uint32_t FSMC_BCR0;   // 0x00
        uint32_t FSMC_BTR0;   // 0x04
        uint32_t FSMC_BCR1;   // 0x08
        uint32_t FSMC_BTR1;   // 0x0C
        uint32_t FSMC_BCR2;   // 0x10
        uint32_t FSMC_BTR2;   // 0x14
        uint32_t FSMC_BCR3;   // 0x18
        uint32_t FSMC_BTR3;   // 0x1C
        uint32_t UNUSED0[8];  // [0x18 - 0x40]
        uint32_t FSMC_PCR0;   // 0x40
        uint32_t FSMC_PISR0;  // 0x44
        uint32_t FSMC_PMEM0;  // 0x48
        uint32_t FSMC_PATT0;  // 0x4C
        uint32_t FSMC_PIO0;   // 0x50
        uint32_t FSMC_ECCR0;  // 0x54
        uint32_t FSMC_ECC2R0; // 0x58
        uint32_t FSMC_ECC3R0; // 0x5C
} FSMCRegs;
3.  Nand flash 模块的虚拟内存映射地址定义:

/* CF/CF+/NAND Flash chip-select 0 (SMPS0n LOW) */
#define NAND_FLASH_CS0_START_ADDR       0x40000000
#define NAND_FLASH_CS0_LENGTH           0x10000000
#define NAND_FLASH_CS0_END_ADDR         (NAND_FLASH_CS0_START_ADDR+NAND_FLASH_CS0_LENGTH-1)
  
/* CF/CF+/NAND Flash chip-select 1 (SMPS1n LOW) */
#define NAND_FLASH_CS1_START_ADDR       0x50000000
#define NAND_FLASH_CS1_LENGTH           0x10000000
#define NAND_FLASH_CS1_END_ADDR         (NAND_FLASH_CS1_START_ADDR+NAND_FLASH_CS1_LENGTH-1)

4. 一些nandflash相关的常量定义:

#define PAGE_SIZE                                       DATA_BYTES_PER_SECTOR
#define NAND_SECTOR_SIZE                        PAGE_SIZE               
#define NAND_SECTORS_PER_BLOCK          SECTORS_PER_BLOCK;
#define ECC_WORD_LIMIT                          256                             // 512 Byte data is the max length for ECC.
#define ECC_BYTES_PER_SUB_BLOCK         16                              // Effective number of ECC Byte per block.
#define ECC_WORD_PER_SUB_BLOCK          8                               // Number of ECC Word per block with padding.
#define SIZE_BYTE_SUB_BLOCK                     512                             // Size in Byte per ECC data block.
  
#define PAGE(x)                                         ((x + PAGE_SIZE - 1) / PAGE_SIZE)
  
  /* --------FSMC--PCR------ */
#define FMSC_PCR_BUS_WIDTH_8            (0x0)
#define FMSC_PCR_BUS_WIDTH_16           (0x10) 
#define FMSC_PCR_MEM_TYPE_NAND          (0x8)
#define FMSC_PCR_BANK_ENABLE            (0x4)
#define FMSC_PCR_WAIT_ENABLE            (0x2)
#define FMSC_PCR_PC_RESET                       (0x0)

/* --------FSMC--PMEM  0------ */
#define FMSC_PMEM_MEM0HIZ               (0x00<<24)
#define FMSC_PMEM_MEM0HOLD              (NAND_TIMING_1<<16)
#define FMSC_PMEM_MEM0WAIT              (NAND_TIMING_2<<8)
#define FMSC_PMEM_MEM0SET               (0x00)

#define ERROR_NAND_BAD_BLOCK                            -6

5.  这是初始化时候会校验的nandflash两个出厂值

typedef struct
{
        uint8_t uiManID;
        uint8_t uiDeviceID;
} NAND_Id;
6. Nandflash, 使用时的地址情况定义

typedef struct
{
        volatile uint8_t        *pCommand; // Pointer to command area
        volatile uint8_t        *pCommonArea;// Pointer to common area
        volatile uint8_t        *pAttributeArea;// Pointer to attribute area
        volatile uint16_t       *pBase;// Pointer to I/O area
} NAND_Address;
7. nand_system_context_t --- nand 模块上下文定义,几乎包括了nandflash所有的信息
typedef struct
{
        FSMCRegs                *regs;       // Virtual Address of the mapped register space (FSMC)
        NAND_Id                 id;           // Identity Card for the current device
        NAND_Address    addr;    // Logical Addresses associated to the current NAND device
} nand_system_context_t;
8. ReadNandPages() --- 读取nandflash中指定的从起始页到结束页的内容到buffer中

uint32_t ReadNandPages(uint32_t page, uint8_t *buf, int pageCount, int endPage)
{
  int err;

  seekBlock(page);

  while (pageCount && page <= endPage) {
      cacheNext();
          while (getBlockStatus()) {
          // --------------------------------------------------
          // Every time we meet a bad block, jump to next one
          // --------------------------------------------------
          page++;

          if (page > endPage) {
              puts("ERROR: Too many BAD BLOCKS for this image copy\r\n");
              cacheEnd();
              return 0;
          }

          cacheNext();
      }

      err = readPage((uint16_t *)buf);
      if (err)
        return 0;

      buf += PAGE_SIZE;
      pageCount--;
      page++;
  }

  cacheEnd();

  if (pageCount) {
      puts("ERROR: Partition too small for this image copy\r\n");
      return 0;
  }

  return page;
}
9. 一些nandflash 读写的辅助操作

static void cacheEnd(void)
{         
          *(nand.addr.pCommand) = 0x3f;
}         
          
static void cacheNext(void)
{         
          *(nand.addr.pCommand) = 0x31;
}             
//确定block地址              
static void seekBlock(uint32_t BlockAddress)
{
          *(nand.addr.pCommand) = 0x00;
          SET_BLOCK_ADDRESSING(nand.addr.pCommonArea, 0, BlockAddress);
          *(nand.addr.pCommand) = 0x30;
}     
10。 getBlockStatus() --- 获取block的状态,看是不是坏块。
static int getBlockStatus(void)
{
  uint32_t Data;
      
  // Position to OOB area
  *(nand.addr.pCommand) = 0x05;
  SET_BLOCK_OFFSET(nand.addr.pCommonArea, DATA_BYTES_PER_SECTOR);
  *(nand.addr.pCommand) = 0xE0;

  // Read the first word
  Data = (*nand.addr.pBase);
      
  // -----------------------------------------------------------------------------
  // Verify if the block is bad (return 1 in this case)
  // -----------------------------------------------------------------------------
  // The first byte of the first page spare area tells us if a block is bad (0x00)
  // -----------------------------------------------------------------------------
  return ((0xFF & Data) != 0xFF) ? ERROR_NAND_BAD_BLOCK : 0;
}
11 readPage() --- 读nandflash, 读写都是以page为单位,擦除是以block为单位。

static int readPage(uint16_t *buf)
{
#ifdef CONFIG_ECC
  uint32_t data_pos = 0;
  uint32_t ecc_pos = PAGE_SIZE + ECC_OOB_START;
  int ErrorCounter;
  int block, i, t;

  for (block = 0; block < ECC_BLOCKS_PER_PAGE; block++, buf += ECC_WORD_LIMIT) {

      // Position to read block
      *(nand.addr.pCommand) = 0x05;
      SET_BLOCK_OFFSET(nand.addr.pCommonArea, data_pos);
      *(nand.addr.pCommand) = 0xE0;
      data_pos += SIZE_BYTE_SUB_BLOCK;

      // reset ECC calculation
      nand.regs->FSMC_PCR0 &= ~0x00000040;
      nand.regs->FSMC_PCR0 |=  0x00000040;

      // ----------------------------------
      // Read 512 Bytes of data (128 WORDS)
      // ----------------------------------
      dma_copy16 (buf, (void *)nand.addr.pBase, ECC_WORD_LIMIT, DMA_CR_DSTI);

      // Position to ECC in the OOB area
      *(nand.addr.pCommand) = 0x05;
      SET_BLOCK_OFFSET(nand.addr.pCommonArea, ecc_pos);
      *(nand.addr.pCommand) = 0xE0;
      ecc_pos += ECC_BYTES_PER_SUB_BLOCK;

      // -------------------------------------------------
      // Read 16 Bytes of data (4 WORDS). 14 bytes are ecc
      // -------------------------------------------------
      for (i = 0; i < ECC_WORD_PER_SUB_BLOCK; i++)
        t = *(nand.addr.pBase);

      ErrorCounter = correctData((uint8_t *)buf);

      // -----------------------------
      // 0 or positive means we are OK
      // -----------------------------
      if (ErrorCounter < 0) {
          // ---------------------
          // Impossible to correct
          // ---------------------
          puts("RNP: IMPOSSIBLE TO CORRECT SECTOR SUB_BLOCK\r\n");
          return -1;
      }
  }
#else
  // Position to read block
  *(nand.addr.pCommand) = 0x05;
  SET_BLOCK_OFFSET(nand.addr.pCommonArea, 0);
  *(nand.addr.pCommand) = 0xE0;

  dma_copy16 (buf, (void *)nand.addr.pBase, ECC_WORD_LIMIT * ECC_BLOCKS_PER_PAGE, DMA_CR_DSTI);
#endif

  return 0;
}
12. correctData() --- 这个不知道干啥用的

#ifdef CONFIG_ECC
static int correctData(uint8_t *buf)
{
        const uint8_t flip[8] = {3, 2, 1, 0, 7, 6, 5, 4};
        const struct {
                uint32_t start;
                int shift;
        } pos13[8] = {
          {0, 0}, {1, 5}, {3, 2}, {4, 7},
          {6, 4}, {8, 1}, {9, 6}, {11, 3}
        };
        uint32_t val;
        int i;
        int error_count;
        uint16_t pos;
        uint16_t change;
        uint16_t invert;
        uint8_t ecc_code[14];

    // -----------------------------------------------------
    // Wait for the ECC to be ready
    // -----------------------------------------------------
    while (!(nand.regs->FSMC_PISR0 & 0x8000));

        val = nand.regs->FSMC_ECCR0;
        ecc_code[0] = (val >>  0) & 0xFF;
        ecc_code[1] = (val >>  8) & 0xFF;
        ecc_code[2] = (val >> 16) & 0xFF;
        ecc_code[3] = (val >> 24) & 0xFF;

        val = nand.regs->FSMC_ECC2R0;
        ecc_code[4] = (val >>  0) & 0xFF;
        ecc_code[5] = (val >>  8) & 0xFF;
        ecc_code[6] = (val >> 16) & 0xFF;
        ecc_code[7] = (val >> 24) & 0xFF;

        val = nand.regs->FSMC_ECC3R0;
        ecc_code[8]  = (val >>  0) & 0xFF;
        ecc_code[9]  = (val >>  8) & 0xFF;
        ecc_code[10] = (val >> 16) & 0xFF;
        ecc_code[11] = (val >> 24) & 0xFF;

        val = nand.regs->FSMC_PISR0;
        if (!(val & 0x4000)) {
                ecc_code[12] = (val >>  8) & 0xFF;
                ecc_code[13] = (val >> 16) & 0xFF;
        } else {
                ecc_code[12] = (val >> 16) & 0xFF;
                ecc_code[13] = 0xFF;
        }

    // --------------------------
    // Clear CodeReady status bit
    // --------------------------
    nand.regs->FSMC_PISR0 &= ~0x00008000;

    error_count = (ecc_code[3] & ERROR_COUNT_MASK) >> ERROR_COUNT_POS;

        /* If there are too many ECC errors, then we can't correct this block */
        if (error_count > ERROR_COUNT_MAX)
                return -1;

        for (i = 0; i < error_count; i++) {

                pos  = (ecc_code[pos13[i].start]   >> pos13[i].shift);
                pos |= (ecc_code[pos13[i].start+1] << (8 - pos13[i].shift));
                pos |= (ecc_code[pos13[i].start+2] << (16 - pos13[i].shift));
                pos &= 0x1fff;

                if (pos <= 4095) {

                        change = pos / 8;
                        invert = pos % 8;
                        if (buf[change] & 1<<flip[invert])
                                /* inversion 1->0 */
                                buf[change] = (buf[change] & ~(1<<flip[invert]));
                        else
                                /* inversion 0->1 */
                                buf[change] = (buf[change] | 1<<flip[invert]);
                }
        }

        return error_count;
}
#endif


 







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值