——————————————————————————————————————————
- /*
- @func BOOL | FMD_WriteSector | Writes the specified data to the specified NAND flash sector/page.
- @rdesc TRUE = Success, FALSE = Failure.
- @comm
- @xref
- */
- BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
- {
- BYTE Status;
- ULONG SectorAddr = (ULONG)startSectorAddr+START_PAGE;//这里确定起始地址
- ULONG MECC;
- if (!pSectorBuff && !pSectorInfoBuff)
- return(FALSE);
- BOOL bLastMode = SetKMode(TRUE);
- NF_nFCE_L(); // Select the flash chip.
- NF_WAITRB(); // Wait for flash to complete command.
- NF_CMD(CMD_RESET); // Send reset command.
- NF_WAITRB(); // Wait for flash to complete command.
- while (dwNumSectors--)
- {//安全确定地址所在位置
- ULONG blockPage = (((SectorAddr / NAND_PAGE_CNT) * NAND_PAGE_CNT) | (SectorAddr % NAND_PAGE_CNT));
- if (!pSectorBuff)
- {
- // If we are asked just to write the SectorInfo, we will do that separately
- NF_CMD(CMD_READ2); // Send read command.
- NF_WAITRB(); // Wait for flash to complete command.
- NF_CMD(CMD_WRITE); // Send write command.
- NF_ADDR(0); // Column = 0.
- NF_ADDR(blockPage & 0xff); // Page address.
- NF_ADDR((blockPage >> 8) & 0xff);
- if (NEED_EXT_ADDR)
- NF_ADDR((blockPage >> 16) & 0xff);
- NF_WAITRB(); // Wait for flash to complete command.
- WrPageInfo((PBYTE)pSectorInfoBuff);//使用汇编实现的
- NF_CMD(CMD_WRITE2); // Send write confirm command.
- NF_WAITRB(); // Wait for flash to complete command.
- do
- {
- NF_CMD(CMD_STATUS);
- Status = NF_RDDATA(); // Read command status.
- }while(!(Status & STATUS_READY));
- if (Status & STATUS_ERROR)
- {
- NF_nFCE_H(); // Deselect the flash chip.
- SetKMode (bLastMode);
- return(FALSE);
- }
- pSectorInfoBuff++;
- }
- else
- {
- NF_CMD(CMD_READ); // Send read command.
- NF_WAITRB(); // Wait for flash to complete command.
- NF_CMD(CMD_WRITE); // Send write command.
- NF_ADDR(0); // Column = 0.
- NF_ADDR(blockPage & 0xff); // Page address.
- NF_ADDR((blockPage >> 8) & 0xff);
- if (NEED_EXT_ADDR)
- NF_ADDR((blockPage >> 16) & 0xff);
- NF_WAITRB(); // Wait for flash to complete command.
- // Special case to handle un-aligned buffer pointer.
- NF_RSTECC();
- NF_MECC_UnLock();
- if( ((DWORD) pSectorBuff) & 0x3) //这个所谓的非对齐是什么意思?
- {
- WrPage512Unalign (pSectorBuff);//汇编里面已经包含了循环
- }
- else
- {
- WrPage512(pSectorBuff); // Write page/sector data.
- }
- NF_MECC_Lock();//generate ecc
- // Write the SectorInfo data to the media.
- //
- if(pSectorInfoBuff)
- {
- WrPageInfo((PBYTE)pSectorInfoBuff);
- pSectorInfoBuff++;
- }
- // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)
- else
- {
- BYTE TempInfo[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
- WrPageInfo(TempInfo);
- }
- //read ECC
- MECC = NF_RDMECC0();
- NF_WRDATA((UCHAR)((MECC ) & 0xff));
- NF_WRDATA((UCHAR)((MECC >> 8) & 0xff));
- NF_WRDATA((UCHAR)((MECC >> 16) & 0xff));
- NF_WRDATA((UCHAR)((MECC >> 24) & 0xff));
- //write ecc to spare area
- NF_CMD(CMD_WRITE2); // Send write confirm command.
- NF_WAITRB(); // Wait for flash to complete command.
- do
- {
- NF_CMD(CMD_STATUS);
- Status = NF_RDDATA(); // Read command status.
- }while(!(Status & STATUS_READY));
- if (Status & STATUS_ERROR)
- {
- NF_nFCE_H(); // Deselect the flash chip.
- SetKMode (bLastMode);
- return(FALSE);
- }
- pSectorBuff += NAND_PAGE_SIZE;
- }
- ++SectorAddr;
- }
- NF_nFCE_H(); // Deselect the flash chip.
- SetKMode (bLastMode);
- return(TRUE);
- }
读flash 扇区(页)函数和写 flash 扇区(页)函数有点类似,把读和写的ECC比较,看是否正确。
- /*这个函数用于读nandflash的一个扇区
- startSectorAddr: nandflash物理扇区的起始地址,对于nandflash来说,就是nandflash中从哪个page开始。
- pSectorBuff:扇区数据buffer,从nandflash中读出的每一个扇区的数据都存放在这个buffer中。
- pSectorInfoBuff:扇区信息buffer,一般每个扇区的信息会被保存在nandflash的带外数据中,针对小page,带外数据有16 bytes,大page有64 bytes。从nandflash的带外数据将该扇区的相关信息读出来,存放在这个buffer中。
- dwNumSectors:读取多少个扇区,对于nandflash来说相当于读取多少个page。
- @func BOOL | FMD_ReadSector | Reads the specified sector(s) from NAND flash.
- @rdesc TRUE = Success, FALSE = Failure.
- @comm
- @xref
- */
- BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
- {
- ULONG SectorAddr = (ULONG)startSectorAddr +START_PAGE;
- ULONG MECC;
- if (!pSectorBuff && !pSectorInfoBuff)
- return(FALSE);
- BOOL bLastMode = SetKMode(TRUE);
- NF_nFCE_L(); // Select the flash chip.
- NF_WAITRB(); // Wait for flash to complete command.
- NF_CMD(CMD_RESET); // Send reset command.
- NF_WAITRB(); // Wait for flash to complete command.
- while (dwNumSectors--)
- { //为什么还要计算blockPage?
- //为什么要这么计算?
- //我明白了,这个SectorAddr所在地方已经超过了一个block,加上后面
- //是为了算上超过一个page的部分,这样做是为了安全
- ULONG blockPage = (((SectorAddr / NAND_PAGE_CNT) * NAND_PAGE_CNT) | (SectorAddr % NAND_PAGE_CNT));
- // read spare area
- if (!pSectorBuff)
- {
- //read spare area cmd
- NF_CMD(CMD_READ2); // Send read confirm command.
- NF_WAITRB(); // Wait for command to complete.
- NF_ADDR(0); // Column = 0.
- NF_ADDR(blockPage & 0xff); // Page address.
- NF_ADDR((blockPage >> 8) & 0xff);
- if (NEED_EXT_ADDR)
- NF_ADDR((blockPage >> 16) & 0xff);
- NF_WAITRB(); // Wait for command to complete.
- RdPageInfo((PBYTE)pSectorInfoBuff); // Read page/sector information.
- pSectorInfoBuff++;
- }
- // read data area
- else
- {
- NF_CMD(CMD_READ); // Send read command.
- NF_WAITRB(); // Wait for command to complete.
- NF_ADDR(0); // Column = 0.
- NF_ADDR(blockPage & 0xff); // Page address.
- NF_ADDR((blockPage >> 8) & 0xff);
- if (NEED_EXT_ADDR)
- NF_ADDR((blockPage >> 16) & 0xff);
- NF_WAITRB(); // Wait for command to complete.
- // Handle unaligned buffer pointer
- // 下面两个函数的控制看手册220page
- NF_RSTECC();
- NF_MECC_UnLock();
- if( ((DWORD) pSectorBuff) & 0x3) //这个用来干什么?
- {
- RdPage512Unalign (pSectorBuff);
- }
- else
- {
- RdPage512(pSectorBuff); // Read page/sector data.
- }
- NF_MECC_Lock();//针对主数据区的校验
- //RdPage512Unalign RdPage512 RdPageInfo这几个都是nand.s的汇编函数
- if (pSectorInfoBuff)
- {
- RdPageInfo((PBYTE)pSectorInfoBuff); // Read page/sector information.
- pSectorInfoBuff ++;
- }
- else
- {
- BYTE TempInfo[8];
- RdPageInfo(TempInfo); // Read page/sector information.
- }
- MECC = NF_RDDATA() << 0;
- MECC |= NF_RDDATA() << 8;
- MECC |= NF_RDDATA() << 16;
- MECC |= NF_RDDATA() << 24;
- //see datasheet page220
- NF_WRMECCD0( ((MECC&0xff00)<<8)|(MECC&0xff) );
- NF_WRMECCD1( ((MECC&0xff000000)>>8)|((MECC&0xff0000)>>16) );
- if (NF_RDESTST0 & 0x3)// if ECC fail ------main area /spare area bit error
- {
- RETAILMSG(1,(TEXT("ecc error %x %x /r/n"),NF_RDMECC0(),MECC));
- NF_nFCE_H(); // Deselect the flash chip.
- SetKMode (bLastMode);
- return FALSE;
- }
- pSectorBuff += NAND_PAGE_SIZE;
- }
- ++SectorAddr;
- }
- NF_nFCE_H(); // Deselect the flash chip.
- SetKMode (bLastMode);
- return(TRUE);
- }
——————现在再来看在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
——————————————————————————————————————————
地址对齐是ARM驱动工程师最应该注意的问题。这个真的要小心谨慎。
也欢迎大家来发表意见。
__________________________________________________________-
转载请标明:作者wogoyixikexie@gliet.桂林电子科技大学一系科协,原文地址:http://blog.youkuaiyun.com/gooogleman——如有错误,希望能够留言指出;如果你有更加好的方法,也请在博客后面留言,我会感激你的批评和分享。