s3c2440 operation on nandflash (K9F2G08)
Nandflash plays an important role in large-capacity data storage. Compared with norflash, it has some advantages, but one of its disadvantages is that it is easy to generate bad blocks. Therefore, when using nandflash, it is often necessary to use a verification algorithm to find bad blocks and mark them so that the bad blocks will not be used again in the future. Nandflash has no address or data bus. If it is an 8-bit nandflash, it only has 8 IO ports, which are used to transmit commands, addresses and data. Nandflash is mainly read and written in pages and erased in blocks. Each page is divided into a main area and a spare area. The main area is used to store normal data, and the spare area is used to store some additional information, such as the mark of whether the block is good or bad, the logical address of the block, and the ECC checksum of the data in the page.
Samsung is the main supplier of nand flash, so it is not surprising that it supports nand flash in all its processors. S3C2440 not only has nand flash interface, but also can use some mechanisms to start and run programs directly from nand flash. This article only introduces how to implement basic operations such as reading, writing and erasing nand flash, and does not involve the problem of nand flash startup program.
Here, we use K9F2G08U0A, which is an 8-bit nandflash. The operation of different types of nandflash will be different, but the hardware pins are basically the same, which brings convenience to product development and expansion. Because the PCB boards of different models are the same, nandflash of different capacities can be used by simply updating the software.
One page of K9F2G08U0A is (2K+64) bytes (the 2K before the plus sign indicates the capacity of the main area, and the 64 after the plus sign indicates the capacity of the spare area). One block of it is 64 pages, and the entire device includes 2048 blocks. This means a total capacity of 2112M bits. If only the main area capacity is counted, it is 256M bytes (i.e. 256M×8 bits). To achieve the use of 8 IO ports to access such a large capacity, K9F2G08U0A stipulates that it is implemented in 5 cycles. The first cycle accesses the address A0~A7; the second cycle accesses the address A8~A11, which acts on IO0~IO3, and IO4~IO7 must be low at this time; the third cycle accesses the address A12~A19; the fourth cycle accesses the address A20~A27; the fifth cycle accesses the address A28, which acts on IO0, and IO1~IO7 must be low at this time. The first two cycles transmit the column address, and the last three cycles transmit the row address. Through analysis, we can know that the column address is used to address the space within the page, and the row address is used to address the page. If you want to access the block directly, you need to start from address A18.
(2 to the 12th power is 4096, not 2048. Why? My personal understanding is that in order to be compatible with larger NAND in the future, the NAND address sequence can reserve the "column address length". Although A0-A7, A8-A11 are sent, the actual address is A0-A7, A8-A10; (intra-page address space))···········A total of 2048*64=131072 pages, 2 to the 17th power
Since all commands, addresses and data are transmitted from the 8-bit IO port, nandflash defines a command set to complete various operations. Some operations only require one command (i.e. one cycle), while some operations require two commands (i.e. two cycles) to implement. The following macros are commonly used commands for K9F2G08U0A:
#define CMD_READ1 0x00 //Page read command cycle 1
#define CMD_READ2 0x30 //Page read command cycle 2
#define CMD_READID 0x90 //Read ID command
#define CMD_WRITE1 0x80 //Page write command cycle 1
#define CMD_WRITE2 0x10 //Page write command cycle 2
#define CMD_ERASE1 0x60 //Block erase command cycle 1
#define CMD_ERASE2 0xd0 //Block erase command cycle 2
#define CMD_STATUS 0x70 //Read status command
#define CMD_RESET 0xff //Reset
#define CMD_RANDOMREAD1 0x05 //Random read command cycle 1
#define CMD_RANDOMREAD2 0xE0 //Random read command cycle 2
#define CMD_RANDOMWRITE 0x85 //Random write command
Here, the random read command and random write command can realize reading and writing at any address within a page. The read status command can realize reading the status register in the device. Through this command, it can be known whether the write operation or erase operation is completed (judgment bit 6) and whether it is completed successfully (judgment bit 0).
Pin Configuration:
OM[1:0] = 00: Enable NAND flash memory boot
NCON: NAND flash memory selection(Normal / Advance)
0: Normal NAND flash(256Words/512Bytes page size, 3/4 address cycle)
1: Advance NAND flash(1KWords /2KBytes page size, 4/5 address cycle)
GPG13: NAND flash memory page capacity selection
0: Page=256Words(NCON = 0) or Page=1KWords(NCON = 1)
1: Page=512Bytes(NCON = 0) or Page =2KBytes(NCON = 1)
GPG14: NAND flash memory address cycle selection
0: 3 address cycle(NCON = 0) or 4 address cycle(NCON = 1)
1: 4 address cycle(NCON = 0) or 5 address cycle(NCON = 1)
(Note: GPG13 GPG14 read only)
GPG15: NAND flash memory bus width selection
0: 8-bit bus width
1: 16-bit bus width
Hardware connection with s3c2440:
The following is an introduction to the nandflash controller of s3c2440. s3c2440 supports 8-bit or 16-bit nandflash with a page size of 256 words, 512 bytes, 1K words and 2K bytes. These configurations are achieved by the high and low levels of the corresponding pins after the system is powered on. s3c2440 can also generate ECC check codes in hardware, which makes it convenient to accurately and timely detect bad blocks of nandflash. The main registers of the nandflash controller are NFCONF (nandflash configuration register), NFCONT (nandflash control register), NFCMMD (nandflash command set register), NFADDR (nandflash address set register), NFDATA (nandflash data register), NFMECCD0/1 (nandflash main area ECC register), NFSECCD (nandflash spare area ECC register), NFSTAT (nandflash operation status register), NFESTAT0/1 (nandflash ECC status register), NFMECC0/1 (nandflash ECC register for data), and NFSECC (nandflash ECC register for IO).
NFCMMD, NFADDR and NFDATA are used to transmit commands, addresses and data respectively. For convenience, we can define some macro definitions to complete the above operations:
#define NF_CMD(data) {rNFCMD = (data); } //Transmission command
#define NF_ADDR(addr) {rNFADDR = (addr); } //Transmission address
#define NF_RDDATA() (rNFDATA) //Read 32-bit data
#define NF_RDDATA8() (rNFDATA8) //Read 8-bit data
#define NF_WRDATA(data) {rNFDATA = (data); } //Write 32-bit data
#define NF_WRDATA8(data) {rNFDATA8 = (data); } //Write 8-bit data
The definition of rNFDATA8 is (*(volatile unsigned char *)0x4E000010) //0x4E000010 is the address of the NFDATA register
NFCONF mainly uses TACLS, TWRPH0, and TWRPH1, which are used to configure the timing of nandflash. The data sheet of s3c2440 does not explain the specific meaning of these three variables in detail, but through the timing diagram it gives, we can see that TACLS is the duration between CLE/ALE valid to nWE valid, TWRPH0 is the valid duration of nWE, and TWRPH1 is the duration between nWE invalid to CLE/ALE invalid. These times are all in HCLK units (HCLK=100MHz in the program of this article). By consulting the data sheet of K9F2G08U0A, we can find and calculate the timing corresponding to the nandflash and s3c2440: tWP in K9F2G08U0A corresponds to TWRPH0, tCLH corresponds to TWRPH1, and (tCLS-tWP) corresponds to TACLS. K9F2G08U0A gives the minimum time, and s3c2440 only needs to meet its minimum time, so it is safer to take larger values for the three variables TACLS, TWRPH0, and TWRPH1. Here, these three values are 1, 2, and 0 respectively.
The 0th bit of NFCONF indicates whether the external nandflash is 8-bit IO or 16-bit IO. Of course, 8-bit IO should be selected here. The NFCONT register is another register that needs to be initialized in advance. Its 13th and 12th bits are used for lock configuration, 8th to 10th bits are used for nandflash interrupt, 4th to 6th bits are used for ECC configuration, 1st bit is used for nandflash chip selection, and 0th bit is used to enable the nandflash controller. In addition, in order to initialize nandflash, it is also necessary to configure the GPACON register so that its 17th to 22nd bits correspond to the control pins of the nandflash chip. The following program implements the initialization of the nandflash controller:
void NF_Init ( void )
{
rGPACON = (rGPACON &~(0x3f<<17)) | (0x3f<<17); //Configure chip pins
//TACLS=1, TWRPH0=2, TWRPH1=0, 8-bit IO,
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
//Unlock, shield nandflash interrupt, initialize ECC and lock main area and spare area ECC, enable nandflash chip select and controller
rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5) |(1<<4)|(1<<1)|(1<<0);
}
In order to better apply ECC and enable nandflash chip select, we also need some macro definitions:
#define NF_nFCE_L() {rNFCONT &= ~(1<<1); }
#define NF_CE_L() NF_nFCE_L() //Open nandflash chip select
#define NF_nFCE_H() {rNFCONT |= (1<<1); }
#define NF_CE_H() NF_nFCE_H() //Close nandflash chip select
#define NF_RSTECC() {rNFCONT |= (1<<4); } //Reset ECC
#define NF_MECC_UnLock() {rNFCONT &= ~(1<<5); } //Unlock main area ECC
#define NF_MECC_Lock() {rNFCONT |= (1<<5); } //Lock main area ECC
#define NF_SECC_UnLock() {rNFCONT &= ~(1<<6); } //Unlock spare area ECC
#define NF_SECC_Lock() {rNFCONT |= (1<<6); } //Lock spare area ECC
NFSTAT is another important register. Its bit 0 can be used to determine whether nandflash is busy, and bit 2 is used to detect the RnB pin signal:
#define NF_WAITRB() {while(!(rNFSTAT&(1<<0)));} //Wait until nandflash is not busy
#define NF_CLEAR_RB() {rNFSTAT |= (1<<2); } // Clear RnB signal
#define NF_DETECT_RB() {while(!(rNFSTAT&(1<<2)));} //Wait for RnB signal to become high, i.e. not busy
The following is a detailed introduction to the basic operations of K9F2G08U0A, including reset, read ID, page read, write data, random read, write data, block erase, etc.
The reset operation is the simplest, just write the reset command:
static void rNF_Reset()
{
NF_CE_L(); //Open nandflash chip select
NF_CLEAR_RB(); //Clear RnB signal
NF_CMD(CMD_RESET); //Write reset command
NF_DETECT_RB(); //Wait for RnB signal to become high, i.e. not busy
NF_CE_H(); //Close nandflash chip select
}
To read the K9F2G08U0A chip ID, you first need to write the read ID command, and then write the 0x00 address, you can read a total of five cycles of chip ID, the first cycle is the manufacturer ID, the second cycle is the device ID, the third cycle to the fifth cycle includes some specific chip information, which will not be introduced here:
static char rNF_ReadID()
{
char pMID;
char pDID;
char cyc3, cyc4, cyc5;
NF_nFCE_L(); //Open nandflash chip select
NF_CLEAR_RB(); //Clear RnB signal
NF_CMD(CMD_READID); //Read ID command
NF_ADDR(0x0); //Write 0x00 address
//Read five cycles of ID
pMID = NF_RDDATA8(); //Manufacturer ID: 0xEC
pDID = NF_RDDATA8(); //Device ID: 0xDA
cyc3 = NF_RDDATA8(); //0x10
cyc4 = NF_RDDATA8(); //0x95
cyc5 = NF_RDDATA8(); //0x44
NF_nFCE_H(); //Close nandflash chip select
return (pDID);
}
The following describes the read operation, which is performed in units of pages. If the ECC check is not performed during the data reading process, the read operation is relatively simple. The page address to be read is written between the two cycles of writing the read command, and then the data is read. If the data is to be read more accurately, the ECC check must be performed after the data is read to determine whether the read data is correct.
As we have introduced above, each page of nandflash has two areas: main area and spare area. The main area is used to store normal data, and the spare area is used to store other additional information, including ECC checksum. When we write data, we calculate the ECC checksum of this page of data, and then store the checksum in a specific position of the spare area. When reading this page of data next time, we also calculate the ECC checksum, and then compare it with the ECC checksum in the spare area. If it is consistent, it means that the read data is correct, if it is inconsistent, it is incorrect. The ECC algorithm is relatively complicated. Fortunately, s3c2440 can generate ECC checksums by hardware, which saves a lot of trouble. s3c2440 can generate ECC checksums for both the main area and the spare area. Because K9F2G08U0A is an 8-bit IO port, s3c2440 generates a total of 4 bytes of ECC code for the main area and 2 bytes of ECC code for the spare area. Here we stipulate that the main area ECC is stored in the 0th to 3rd addresses of the spare area of each page, and the spare area ECC is stored in the 4th and 5th addresses. The process of generating ECC check code is: before reading or writing data in a certain area, unlock the ECC of the area first to generate the ECC of the area. After reading or writing the data, lock the ECC of the area again, so that the system will save the generated ECC code to the corresponding register. The ECC of the main area is saved in NFMECC0/1 (because K9F2G08U0A is an 8-bit IO port, only NFMECC0 is used here), and the ECC of the spare area is saved in NFSECC. For the read operation, we still need to continue to read the corresponding address content of the spare area, and obtain the ECC of the main area and spare area stored in the last write operation, and put these data into the corresponding positions of NFMECCD0/1 and NFSECCD respectively. Finally, we can determine whether the read data is correct by reading the lower 4 bits of NFESTAT0/1 (because K9F2G08U0A is an 8-bit IO port, only NFESTAT0 is used here), where bits 0 and 1 indicate errors in the main area, and bits 2 and 3 indicate errors in the spare area.
Here is a specific page read operation procedure:
U8 rNF_ReadPage(U32 page_number)
{
U32 i, mecc0, secc;
NF_RSTECC(); //Reset ECC
NF_MECC_UnLock(); //Unlock main area ECC
NF_nFCE_L(); //Open nandflash chip select
NF_CLEAR_RB(); //Clear RnB signal
NF_CMD(CMD_READ1); //Page read command cycle 1
//Write 5 address cycles
NF_ADDR(0x00); //column address A0~A7
NF_ADDR(0x00); //column address A8~A11
NF_ADDR((page_number) & 0xff); //row address A12~A19
NF_ADDR((page_number >> 8) & 0xff); //row address A20~A27
NF_ADDR((page_number >> 16) & 0xff); //row address A28
NF_CMD(CMD_READ2); //Page read command cycle 2
NF_DETECT_RB(); //Wait for RnB signal to become high, i.e. not busy
//Read a page of data
for (i = 0; i < 2048; i++)
{
buffer[i] = NF_RDDATA8();
}
NF_MECC_Lock(); //Lock the ECC value of the main area
NF_SECC_UnLock(); //Unlock spare area ECC
mecc0=NF_RDDATA(); //Read the first 4 addresses of the spare area, that is, addresses 2048~2051. These 4 bytes are the ECC of the main area.
//Put the ECC check code of the main area read into the corresponding position of NFMECCD0/1
rNFMECCD0=((mecc0&0xff00)<<8)|(mecc0&0xff);
rNFMECCD1=((mecc0&0xff000000)>>8)|((mecc0&0xff0000)>>16);
NF_SECC_Lock(); //Lock the ECC value of the spare area
secc=NF_RDDATA(); //Continue to read the contents of the 4 addresses in the spare area, i.e., addresses 2052 to 2055, where the first 2 bytes are the ECC values of the spare area
//Put the ECC check code of the spare area read into the corresponding position of NFSECCD
rNFSECCD=((secc&0xff00)<<8)|(secc&0xff);
NF_nFCE_H(); //Close nandflash chip select
//Judge whether the data read is correct
if ((rNFESTAT0&0xf) == 0x0)
return 0x66; //Correct
else
return 0x44; //Error
}
This program is to read the content of a certain page into the global variable array buffer. The input parameter of this program is directly the page number of K9F2G08U0A. For example, if we want to read the content of page 128064, we can call this program as: rNF_ReadPage(128064);. Since page 128064 is page 0 in block 2001 (128064=2001×64+0), in order to more clearly express the relationship between pages and blocks, it can also be written as: rNF_ReadPage(2001*64);.
The general process of page write operation is: write the page address and data respectively between two write command cycles. Of course, in order to ensure the correctness of the data when reading it next time, the ECC value of the main area and the ECC value of the spare area need to be written into the spare area of the page. Then we also need to read the status register to determine whether the write operation is correct. The following is a specific page write operation program, in which the input parameter is also the page to which the data is to be written:
U8 rNF_WritePage(U32 page_number)
{
U32 i, mecc0, secc;
U8 stat, temp;
temp = rNF_IsBadBlock(page_number>>6); //Judge whether the block is a bad block
if(temp == 0x33)
return 0x42; //It is a bad block, return
NF_RSTECC(); //Reset ECC
NF_MECC_UnLock(); //Unlock the ECC of the main area
NF_nFCE_L(); //Open nandflash chip select
NF_CLEAR_RB(); //Clear RnB signal
NF_CMD(CMD_WRITE1); //Page write command cycle 1
//Write 5 address cycles
NF_ADDR(0x00); //column address A0~A7
NF_ADDR(0x00); //column address A8~A11
NF_ADDR((page_number) & 0xff); //row address A12~A19
NF_ADDR((page_number >> 8) & 0xff); //row address A20~A27
NF_ADDR((page_number >> 16) & 0xff); //row address A28
//Write a page of data
for (i = 0; i < 2048; i++)
{
NF_WRDATA8((char)(i+6));
}
NF_MECC_Lock(); //Lock the ECC value of the main area
mecc0=rNFMECC0; //Read the ECC check code of the main area
//Convert the ECC check code from font to byte type and save it to the global variable array ECCBuf
ECCBuf[0]=(U8)(mecc0&0xff);
ECCBuf[1]=(U8)((mecc0>>8) & 0xff);
ECCBuf[2]=(U8)((mecc0>>16) & 0xff);
ECCBuf[3]=(U8)((mecc0>>24) & 0xff);
NF_SECC_UnLock(); //Unlock the ECC of spare area
//Write the ECC value of the main area into the first 4 bytes of the spare area, i.e., addresses 2048 to 2051
for(i=0;i<4;i++)
{
NF_WRDATA8(ECCBuf[i]);
}
NF_SECC_Lock(); //Lock the ECC value of the spare area
secc=rNFSECC; //Read the ECC check code in the spare area
//Save the ECC check code to the global variable array ECCBuf
ECCBuf[4]=(U8)(secc&0xff);
ECCBuf[5]=(U8)((secc>>8) & 0xff);
//Continue to write the ECC value of the spare area into the 2052~2053th address of the spare area
for(i=4;i<6;i++)
{
NF_WRDATA8(ECCBuf[i]);
}
NF_CMD(CMD_WRITE2); //Page write command cycle 2
delay(1000); //Delay for a while to wait for the write operation to complete
NF_CMD(CMD_STATUS); //Read status command
// Check if the 6th bit of the status value is 1, that is, whether it is busy. This statement has the same effect as NF_DETECT_RB();
do{
stat = NF_RDDATA8();
}while(!(stat&0x40));
NF_nFCE_H(); //Close nandflash chip select
//Judge whether the 0th bit of the status value is 0. If it is 0, the write operation is correct, otherwise it is an error.
if (stat & 0x1)
{
temp = rNF_MarkBadBlock(page_number>>6); //Mark the block where this page is located as a bad block
if (temp == 0x21)
return 0x43 //Failed to mark bad blocks
else
return 0x44; //Write operation failed
}
else
return 0x66; //Write operation successful
}