2440 flash驱动的读写以及ECC的实现分析

作者:wogoyixikexie@gliet

 

——————————————————————————————————————————

写 flash 扇区(页)函数
  1. /*
  2.     @func   BOOL | FMD_WriteSector | Writes the specified data to the specified NAND flash sector/page.
  3.     @rdesc  TRUE = Success, FALSE = Failure.
  4.     @comm    
  5.     @xref   
  6. */
  7. BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
  8. {
  9.     BYTE Status;
  10.     ULONG SectorAddr = (ULONG)startSectorAddr+START_PAGE;//这里确定起始地址
  11.     ULONG MECC;
  12.     if (!pSectorBuff && !pSectorInfoBuff)
  13.         return(FALSE);
  14.         
  15.     BOOL bLastMode = SetKMode(TRUE);
  16.     NF_nFCE_L();                        // Select the flash chip.
  17.     NF_WAITRB();                // Wait for flash to complete command.
  18.     NF_CMD(CMD_RESET);          // Send reset command.
  19.     NF_WAITRB();                // Wait for flash to complete command.
  20.     while (dwNumSectors--)
  21.     {//安全确定地址所在位置
  22.         ULONG blockPage = (((SectorAddr / NAND_PAGE_CNT) * NAND_PAGE_CNT) | (SectorAddr % NAND_PAGE_CNT));
  23.         if (!pSectorBuff)
  24.         {
  25.      // If we are asked just to write the SectorInfo, we will do that separately
  26.             NF_CMD(CMD_READ2);                      // Send read command.
  27.             NF_WAITRB();                                // Wait for flash to complete command.
  28.             NF_CMD(CMD_WRITE);                    // Send write command.
  29.             NF_ADDR(0);                                 // Column = 0.
  30.             NF_ADDR(blockPage         & 0xff);          // Page address.
  31.             NF_ADDR((blockPage >>  8) & 0xff);
  32.             if (NEED_EXT_ADDR)
  33.                 NF_ADDR((blockPage >> 16) & 0xff);  
  34.             NF_WAITRB();   // Wait for flash to complete command.
  35.             WrPageInfo((PBYTE)pSectorInfoBuff);//使用汇编实现的
  36.             NF_CMD(CMD_WRITE2);     // Send write confirm command.
  37.             NF_WAITRB();                                // Wait for flash to complete command.
  38.             do
  39.             {
  40.                 NF_CMD(CMD_STATUS);
  41.                 Status = NF_RDDATA();                   // Read command status.
  42.             }while(!(Status & STATUS_READY));
  43.             if (Status & STATUS_ERROR)
  44.             {
  45.                 NF_nFCE_H();          // Deselect the flash chip.
  46.                 SetKMode (bLastMode);
  47.                 return(FALSE);
  48.             }
  49.             pSectorInfoBuff++;
  50.         }
  51.         else 
  52.         {
  53.             NF_CMD(CMD_READ);                     // Send read command.
  54.             NF_WAITRB();                                // Wait for flash to complete command.
  55.             NF_CMD(CMD_WRITE);                    // Send write command.
  56.             NF_ADDR(0);                                 // Column = 0.
  57.             NF_ADDR(blockPage         & 0xff);          // Page address.
  58.             NF_ADDR((blockPage >>  8) & 0xff);
  59.             if (NEED_EXT_ADDR)
  60.                 NF_ADDR((blockPage >> 16) & 0xff);  
  61.             NF_WAITRB();                                // Wait for flash to complete command.
  62.             //  Special case to handle un-aligned buffer pointer.
  63.             NF_RSTECC();
  64.             NF_MECC_UnLock();
  65.             if( ((DWORD) pSectorBuff) & 0x3) //这个所谓的非对齐是什么意思?
  66.             {
  67.                 WrPage512Unalign (pSectorBuff);//汇编里面已经包含了循环
  68.             }
  69.             else
  70.             {
  71.                 WrPage512(pSectorBuff);         // Write page/sector data.
  72.             }
  73.     NF_MECC_Lock();//generate ecc
  74.             
  75.             // Write the SectorInfo data to the media.
  76.             //
  77.             if(pSectorInfoBuff)
  78.             {
  79.                 WrPageInfo((PBYTE)pSectorInfoBuff);
  80.                 pSectorInfoBuff++;
  81.             }
  82. // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)
  83.             else                
  84.            {
  85.                 BYTE TempInfo[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  86.                 WrPageInfo(TempInfo);
  87.             }
  88.             //read ECC
  89.             MECC = NF_RDMECC0();
  90.             NF_WRDATA((UCHAR)((MECC      ) & 0xff));
  91.             NF_WRDATA((UCHAR)((MECC >>  8) & 0xff));
  92.             NF_WRDATA((UCHAR)((MECC >> 16) & 0xff));
  93.             NF_WRDATA((UCHAR)((MECC >> 24) & 0xff));
  94.             //write ecc to spare area
  95.             NF_CMD(CMD_WRITE2);           // Send write confirm command.
  96.             NF_WAITRB();                                // Wait for flash to complete command.
  97.             do
  98.             {
  99.             NF_CMD(CMD_STATUS);
  100.                 Status = NF_RDDATA();                   // Read command status.
  101.             }while(!(Status & STATUS_READY));
  102.             if (Status & STATUS_ERROR)
  103.             {
  104.         NF_nFCE_H();      // Deselect the flash chip.
  105.                 SetKMode (bLastMode);
  106.                 return(FALSE);
  107.             }
  108.             pSectorBuff += NAND_PAGE_SIZE;
  109.         }
  110.         ++SectorAddr;
  111.     }
  112.     NF_nFCE_H();                       // Deselect the flash chip.
  113.     SetKMode (bLastMode);
  114.     
  115.     return(TRUE);
  116. }

读flash 扇区(页)函数和写 flash 扇区(页)函数有点类似,把读和写的ECC比较,看是否正确。

  1. /*这个函数用于读nandflash的一个扇区
  2. startSectorAddr: nandflash物理扇区的起始地址,对于nandflash来说,就是nandflash中从哪个page开始。 
  3.     
  4. pSectorBuff:扇区数据buffer,从nandflash中读出的每一个扇区的数据都存放在这个buffer中。 
  5.     
  6. pSectorInfoBuff:扇区信息buffer,一般每个扇区的信息会被保存在nandflash的带外数据中,针对小page,带外数据有16 bytes,大page有64 bytes。从nandflash的带外数据将该扇区的相关信息读出来,存放在这个buffer中。 
  7.     
  8. dwNumSectors:读取多少个扇区,对于nandflash来说相当于读取多少个page。 
  9.     
  10.     @func   BOOL | FMD_ReadSector | Reads the specified sector(s) from NAND flash.
  11.     @rdesc  TRUE = Success, FALSE = Failure.
  12.     @comm    
  13.     @xref   
  14. */
  15. BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
  16. {
  17.     ULONG SectorAddr = (ULONG)startSectorAddr +START_PAGE;
  18.     ULONG MECC;
  19.     if (!pSectorBuff && !pSectorInfoBuff)
  20.         return(FALSE);
  21.     BOOL bLastMode = SetKMode(TRUE);
  22.     NF_nFCE_L();                        // Select the flash chip.
  23.     NF_WAITRB();                        // Wait for flash to complete command.
  24.     NF_CMD(CMD_RESET);                  // Send reset command.
  25.     NF_WAITRB();                        // Wait for flash to complete command.
  26.     
  27.     while (dwNumSectors--)
  28.     {   //为什么还要计算blockPage?
  29.         //为什么要这么计算?
  30.         //我明白了,这个SectorAddr所在地方已经超过了一个block,加上后面
  31.         //是为了算上超过一个page的部分,这样做是为了安全
  32.         ULONG blockPage = (((SectorAddr / NAND_PAGE_CNT) * NAND_PAGE_CNT) | (SectorAddr % NAND_PAGE_CNT));
  33.         // read spare area
  34.         if (!pSectorBuff)
  35.         {   
  36.         //read spare area cmd
  37.             NF_CMD(CMD_READ2);                          // Send read confirm command.
  38.             NF_WAITRB();                                // Wait for command to complete.
  39.             NF_ADDR(0);                                 // Column = 0.
  40.             NF_ADDR(blockPage         & 0xff);          // Page address.
  41.             NF_ADDR((blockPage >>  8) & 0xff);
  42.             if (NEED_EXT_ADDR)
  43.                 NF_ADDR((blockPage >> 16) & 0xff);  
  44.             NF_WAITRB();                                // Wait for command to complete.
  45.             RdPageInfo((PBYTE)pSectorInfoBuff);         // Read page/sector information. 
  46.             pSectorInfoBuff++;
  47.         }
  48.         
  49.         // read data area
  50.         else
  51.         {
  52.             NF_CMD(CMD_READ);                           // Send read command.
  53.             NF_WAITRB();                                // Wait for command to complete.
  54.             NF_ADDR(0);                                 // Column = 0.
  55.             NF_ADDR(blockPage         & 0xff);          // Page address.
  56.             NF_ADDR((blockPage >>  8) & 0xff);
  57.             if (NEED_EXT_ADDR)
  58.                 NF_ADDR((blockPage >> 16) & 0xff);  
  59.             NF_WAITRB();                                // Wait for command to complete.
  60.             //  Handle unaligned buffer pointer
  61.             // 下面两个函数的控制看手册220page
  62.             NF_RSTECC();
  63.             NF_MECC_UnLock();
  64.             if( ((DWORD) pSectorBuff) & 0x3) //这个用来干什么?
  65.             {
  66.                 RdPage512Unalign (pSectorBuff);
  67.             }
  68.             else 
  69.             {
  70.                 RdPage512(pSectorBuff);                 // Read page/sector data.
  71.             }
  72.             NF_MECC_Lock();//针对主数据区的校验
  73. //RdPage512Unalign RdPage512  RdPageInfo这几个都是nand.s的汇编函数
  74.             if (pSectorInfoBuff)
  75.             {
  76.                 RdPageInfo((PBYTE)pSectorInfoBuff);     // Read page/sector information.
  77.                 pSectorInfoBuff ++;
  78.             }
  79.             else
  80.             {
  81.                 BYTE TempInfo[8];
  82.                 RdPageInfo(TempInfo);                   // Read page/sector information.
  83.             }
  84.             MECC  = NF_RDDATA() << 0;
  85.             MECC |= NF_RDDATA() << 8;
  86.             MECC |= NF_RDDATA() << 16;
  87.             MECC |= NF_RDDATA() << 24;
  88.             
  89.             //see datasheet page220 
  90.             NF_WRMECCD0( ((MECC&0xff00)<<8)|(MECC&0xff) );
  91.             NF_WRMECCD1( ((MECC&0xff000000)>>8)|((MECC&0xff0000)>>16) );
  92.             
  93.             if (NF_RDESTST0 & 0x3)// if ECC  fail ------main area /spare area bit error
  94.             {
  95.                 RETAILMSG(1,(TEXT("ecc error %x %x /r/n"),NF_RDMECC0(),MECC));
  96.             
  97.                 NF_nFCE_H();                            // Deselect the flash chip.
  98.                 SetKMode (bLastMode);
  99.                 return FALSE;   
  100.             }            
  101.             pSectorBuff += NAND_PAGE_SIZE;
  102.         }
  103.         ++SectorAddr;
  104.     }
  105.     NF_nFCE_H();                        // Deselect the flash chip.
  106.     SetKMode (bLastMode);
  107.     return(TRUE);
  108. }

 

——————现在再来看在nand.s实现的汇编函数(注意对齐和非对齐的写法)

 if( ((DWORD) pSectorBuff) & 0x3) //这个所谓的非对齐是什么意思?
            {
                WrPage512Unalign (pSectorBuff);//汇编里面已经包含了循环
            }
----------------在汇编nand.s中实现了WrPage512Unalign 函数
LEAF_ENTRY    WrPage512Unalign
        stmfd    sp!,{r1 - r11}

        ldr    r1, =0xb0e00010  ;NFDATA
        mov    r2, #480

        ; Calculate number of unaligned bytes to read (r12 = 4 - (r0 & 3))
        and    r12, r0, #3
        rsb    r12, r12, #4
        mov    r3, r12
       
wr_unalign1
        ; Write unaligned bytes
        ldrb    r4, [r0]
        strb    r4, [r1]
        add    r0, r0, #1
        subs    r3, r3, #1
        bne    wr_unalign1

wr_main   
        ; Write 480 bytes (32 x 15)
        ldmia  r0!, {r4 - r11}

str r4, [r1]
str r5, [r1]
str r6, [r1]
str r7, [r1]
str r8, [r1]
str r9, [r1]
str r10,[r1]
str r11,[r1]

        subs    r2, r2, #32
        bne    wr_main

        ; Write 28 bytes
        ldmia  r0!, {r4 - r10}
str r4, [r1]这个flash是八位的,怎么使用32位的str指令呢?应该是strb才对啊
str r5, [r1]
str r6, [r1]
str r7, [r1]
str r8, [r1]
str r9, [r1]
str r10,[r1]

        ; Write trailing unaligned bytes
        rsbs    r12, r12, #4
        beq    wr_exit
       
wr_unalign2
        ldrb    r4, [r0]
        strb    r4, [r1]
        add    r0, r0, #1
        subs    r12, r12, #1
        bne    wr_unalign2     

wr_exit
        ldmfd    sp!, {r1 - r11}

        IF Interworking :LOR: Thumbing
          bx  lr
        ELSE
          mov  pc, lr          ; return
        ENDIF

——————————————————————————————————————————

2440的ECC支持2048大页,所以4byte

DATA寄存器很特殊,8位,16位和32位访问都可以,我猜测芯片是把32位访问拆成4个byte分别写4次

非对齐的时候就不能32位访问了,只好strb

——————————————————————————————————————————

引用 4 楼 gooogleman 的回复:
if( ((DWORD) pSectorBuff) & 0x3) //这个所谓的非对齐是什么意思?
            {
                WrPage512Unalign (pSectorBuff);//这个函数用汇编实现。汇编里面已经包含了循环
            }
——日,在这里也要考虑地址对齐问题。



地址对齐是ARM驱动工程师最应该注意的问题。这个真的要小心谨慎。
也欢迎大家来发表意见。

 

__________________________________________________________-

转载请标明:作者wogoyixikexie@gliet.桂林电子科技大学一系科协,原文地址:http://blog.csdn.net/gooogleman——如有错误,希望能够留言指出;如果你有更加好的方法,也请在博客后面留言,我会感激你的批评和分享。

你可能感兴趣的:(汇编,ext,cmd,Flash,buffer,byte)