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.
Keywords:S3C2440 Nandflash
Reference address:S3C2440-Nandflash
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. 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 is 64 pages, and the entire device includes 2048 blocks. This makes a total of 2112M bits of capacity. 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 takes 5 cycles to achieve this. The address accessed in the first cycle is A0"A7; the address accessed in the second cycle is A8"A11, which acts on IO0"IO3, and IO4"IO7 must be low at this time; the address accessed in the third cycle is A12"A19; the address accessed in the fourth cycle is A20"A27; the address accessed in the fifth cycle is 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, it can be seen 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.
#include "2440addr.h"
#define CMD_READ1 0x00
#define CMD_READ2 0x30
#define CMD_READID 0x90
#define CMD_RESET 0xFF
#define CMD_WRITE1 0x80
#define CMD_WRITE2 0x10
#define CMD_BLOCKERASE1 0x60
#define CMD_BLOCKERASE2 0xD0
#define CMD_RANDOMWRITE 0x85
#define CMD_RANDOMREAD1 0x05
#define CMD_RANDOMREAD2 0xE0
#define CMD_READSTATE 0x70
#define NF_CMMD(cmd) rNFCMD = cmd
#define NF_ADDR(addr) rNFADDR = addr
#define NF_WRDATA(data) rNFDATA = data
#define NF_WRDATA8(data) rNFDATA8 = data
#define NF_RDDATA() rNFDATA
#define NF_RDDATA8() rNFDATA8
#define NF_CE_L() rNFCONT &= "(0x1<<1)
#define NF_CE_H() rNFCONT |= 0x1<<1
#define NF_MECC_LOCK() rNFCONT |= 0x1<<5
#define NF_MECC_ULOCK() rNFCONT &= "(0x1<<5)
#define NF_SECC_LOCK() rNFCONT |= 0x1<<6
#define NF_SECC_ULOCK() rNFCONT &= "(0x1<<6)
#define NF_RESETECC() rNFCONT |= 0x1<<4
#define NF_WAITRB() while(!(rNFSTAT&0x1))
#define NF_CLEARRB() rNFSTAT |= 0x1<<2
#define NF_DETECT() while(!(rNFSTAT&0x1<<2))
#define TACLS 1
#define TWRPH0 1
#define TWRPH1 1
#define U32 unsigned int
#define U8 unsigned char
U8 buffer[2048], Ecc[6];
U8 cmd, data, command;
U32 block, add, pagenumber, count;
U8 NF_BlockErase(U32 block){ //Erase in blocks
U8 state;
NF_CE_L(); //Open nandflash chip select
NF_CLEARRB(); //Wait for R/nB signal to be ready
NF_CMMD(CMD_BLOCKERASE1);
NF_ADDR((block<<6)&0xff);
NF_ADDR((block>>2)&0xff);
NF_ADDR((block>>10)&0xff);
NF_CMMD(CMD_BLOCKERASE2);
NF_WAITRB();
NF_CMMD(CMD_READSTATE);
do{
state = NF_RDDATA8();
}while(!(state&0x40));
if(state&0x1){
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x40;
return 0x40; //0x40 block erase failed
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x60;
return 0x60; //0x60 block erased successfully
}
}
U8 NF_PageWrite(U32 pagenumber){
U32 i, mecc, secc;
U8 state;
NF_CE_L();
NF_RESETECC(); //Reset ECC
NF_CLEARRB();
NF_CMMD(CMD_WRITE1);
NF_ADDR(0x00);
NF_ADDR(0x00);
NF_ADDR(pagenumber&0xff);
NF_ADDR((pagenumber>>8)&0xff);
NF_ADDR((pagenumber>>16)&0xff);
//First unlock the main area, then read and write in the main area, generate the main area ECC check, and then lock the ECC, so that the ECC is written to rNFMECC0/1 by the hardware, and we read it to spare
//The area should store the checksum position 2048"2051. When reading and writing the spare area, the ECC of the spare area is generated, and the hardware automatically writes it into rNFSECC, which will generate a spare area
//Checksum, two bytes, written to 2052"2053. When reading, we read the ECC of the main area and the ECC of the spare area and put them into rNFMECCD0/1 and rNFSECC.
//The hardware completes the verification of rNFMECC0/1, rNFSECC and rNFMECCD0/1, rNFSECCD.
NF_MECC_ULOCK(); //Unlock the ECC of the main area
for(i = 0; i < 2048; i++){
NF_WRDATA8((char)(i+1)); //ECC is generated in this process
}
NF_MECC_LOCK(); //Lock main area ECC
mecc = rNFMECC0; //Read the main area ECC
Ecc[0] = (U8)(mecc&0xff);
Ecc[1] = (U8)((mecc>>8)&0xff);
Ecc[2] = (U8)((mecc>>16)&0xff);
Ecc[3] = (U8)((mecc>>24)&0xff);
NF_SECC_ULOCK(); //Unlock the ECC of the main area
for(i = 0; i < 4; i++){
NF_WRDATA8(Ecc[i]); //Write the ECC of maina area into the first 4 bytes of spare area. This process generates the ECC of spare area.
}
NF_SECC_LOCK(); //Lock the ECC of spare area
secc = rNFSECC; //Read ECC of spare area
Ecc[4] = (secc)&0xff;
Ecc[5] = (secc>>8)&0xff;
for(i = 4; i < 6; i++){
NF_WRDATA8(Ecc[ i]); //Write the ECC of the spare area into the spare area
}
NF_CMMD(CMD_WRITE2);
NF_DETECT(); //Wait for the R/nB signal to become high, i.e. not busy
NF_CMMD(CMD_READSTATE); //Send read status command, 0x70
do{
state = NF_RDDATA8(); //Check the status I/O bit 0 is 0 for write success 1 is failure, I/O bit 6 is 0 for busy 1 is ready
}while(!(state&0x40));
if(state&0x1){
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x43;
return 0x43; //0x43 random write failed
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x63;
return 0x63; //0x63 random write success
}
}
U8 NF_PageRead(U32 pagenumber){
U32 i, mecc, secc;
NF_CE_L();
NF_RESETECC();
NF_CLEARRB();
NF_CMMD(CMD_READ1);
NF_ADDR(0x00);
NF_ADDR(0x00);
NF_ADDR(pagenumber&0xff);
NF_ADDR((pagenumber>>8)&0xff);
NF_ADDR((pagenumber>>16)&0xff);
NF_CMMD(CMD_READ2);
NF_WAITRB();
NF_MECC_ULOCK();
for(i = 0; i < 2048; i++){
buffer[i] = NF_RDDATA8();
}
NF_MECC_LOCK();
NF_SECC_ULOCK();
mecc = NF_RDDATA();
NF_SECC_LOCK();
rNFMECCD0 = ((mecc&0xff00)<<8) | (mecc&0xff); //Read the ECC just now and compare rNFMECCD0/1, rNFSECCD with rNFMECC0/1, RNFSECC to see if an error occurs
rNFMECCD1 = ((mecc&0xff000000)>>8) | ((mecc&0xff0000)>>16); //The check is because nandflash is prone to bit reversal and bad blocks
secc = NF_RDDATA();
rNFSECCD = ((secc&0xff00)<<8)|(secc&0xff);
NF_CE_H();
if((rNFESTAT0 & 0x0f) == 0x0){ //If the lower 4 bits are all 0, it means there is no error
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x66;
for(i = 0; i < 8; i++){
while(!(rUTRSTAT0&0x4));
rUTXH0 = buffer[i];
}
return 0x66;
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x44;
return 0x44;
}
} [page]
void NF_Init(){
//GPA 17~22 connected to nandflash
rGPACON = rGPACON & ("(0x3f<<17)) | (0x3f<<17);
//TACLS is the duration from CLE/ALE valid to nWE valid, TWRPH0 is the duration from nWE valid, TWRPH1 is the duration from nWE invalid to CLE/ALE invalid, these times are in HCLK units (HCLK=100MHz in this program)
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)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0) ;
}
void NF_Reset(){
NF_CE_L();
NF_WAITRB();
NF_CMMD(CMD_RESET);
NF_DETECT();
NF_CE_H();
}
void NF_ReadID(){
char MID, DID, cyc3, cyc4, cyc5;
NF_CE_L();
NF_CLEARRB();
NF_CMMD(CMD_READID);
NF_ADDR(0x00);
MID = NF_RDDATA8(); //Manufacturer ID
while(!(rUTRSTAT0&0x4));
rUTXH0 = MID;
DID = NF_RDDATA8(); //Device ID
while(!(rUTRSTAT0&0x4));
rUTXH0 = DID;
cyc3 = NF_RDDATA8(); //Other information
while(!(rUTRSTAT0&0x4));
rUTXH0 = cyc3;
cyc4 = NF_RDDATA8();
while(!(rUTRSTAT0&0x4));
rUTXH0 = cyc4;
cyc5 = NF_RDDATA8();
while(!(rUTRSTAT0&0x4));
rUTXH0 = cyc5;
NF_CE_H();
}
U8 NF_RandomWrite(U32 pagenumber, U32 add, U8 data){ //Just follow the timing
U8 state;
NF_CE_L();
NF_CMMD(CMD_WRITE1);
NF_ADDR(0x00);
NF_ADDR(0x00);
NF_ADDR(pagenumber&0xff);
NF_ADDR((pagenumber>>8)&0xff);
NF_ADDR((pagenumber>>16)&0xff);
NF_CMMD(CMD_RANDOMWRITE);
NF_ADDR(add&0xff); //Determine the address within the page
NF_ADDR((add>>8)&0xff);
NF_WRDATA8(data); //Write data
NF_CMMD(CMD_WRITE2);
NF_WAITRB();
NF_CMMD(CMD_READSTATE);
do{
state = NF_RDDATA8();
}while(!(state&0x40));
if(state&0x1){
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x44;
return 0x44; //0x44 random write failed
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x66;
return 0x66; //0x66 random write success
}
}
U8 NF_RandomRead(U32 pagenumber, U32 add){ //Just follow the timing
char ch;
NF_CE_L();
NF_CMMD(CMD_READ1);
NF_ADDR(0x00);
NF_ADDR(0x00);
NF_ADDR(pagenumber&0xff);
NF_ADDR((pagenumber>>8)&0xff);
NF_ADDR((pagenumber>>16)&0xff);
NF_CMMD(CMD_READ2);
NF_WAITRB();
NF_CMMD(CMD_RANDOMREAD1);
NF_ADDR(add&0xff);
NF_ADDR((add>>8)&0xff);
NF_CMMD(CMD_RANDOMREAD2);
ch = NF_RDDATA8(); //Read data
while(!(rUTRSTAT0&0x4));
rUTXH0 = ch;
NF_CE_H();
return ch;
}
U8 NF_IsBadBlock(U32 block){
U8 result;
result = NF_RandomRead(block*64, 2054); //0"2047 is the main area data, 2048"2051 is the ECC check of the main area, 2052"2053 is the ECC check of the spare area
if(result == 0x33){
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x62;
return 0x62; //0x62 is a bad block
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x42;
return 0x42; //0x42 is not a bad block
}
}
U8 NF_MarkBadblock(U32 block){
U8 result;
result = NF_RandomWrite(block*64, 2054, 0x33); //0x33 marks the bad block. block*64 gets the address of the first page of the block.
if(result == 0x66){
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x61;
return 0x61; //0x61 marks the bad block successfully
}
else{
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0x41;
return 0x41; //0x41 failed to mark bad block
}
}
void __irq UART0_ISR(void){
U8 ch;
rSRCPND |= (0x1<<28);
rINTPND |= (0x1<<28);
rSUBSRCPND |= 0x1<<0;
if(rUTRSTAT0 & 0x1){
ch = rURXH0;
while(!(rUTRSTAT0&0x4));
rUTXH0 = ch;
cmd = ch;
}
}
int Main(){
count = 0;
rULCON0 = 0x3;
rUCON0 = (1<<11)|(1<<2)|(1<<0);
rUBRDIV0 = 26;
rSRCPND = 0x1<<28;
rINTPND = 0x1<<28;
rSUBSRCPND = 0x1<<0;
rINTMSK &= "(0x1<<28);
rINTSUBMSK &= "(0x1<<0);
pISR_UART0 = (U32)UART0_ISR;
NF_Init();
while(1){
switch(cmd){
case 0x11:
NF_Reset();
break;
case 0x22:
NF_ReadID();
break;
case 0x33:
NF_RandomRead(2001*64,0x3);
break;
case 0x44:
NF_RandomWrite(2001*64,2052,0xbc);
break;
case 0x55:
NF_PageRead(2001*64);
break;
case 0x66:
while(!(rUTRSTAT0&0x4));
rUTXH0 = 0xba;
NF_PageWrite(2001*64);
break;
case 0x77:
NF_BlockErase(2001);
break;
case 0x88:
NF_IsBadBlock(2001);
break;
case 0x99:
NF_MarkBadblock(2001);
break;
}
cmd = 0;
}
return 0;
}
Previous article:S3C2440-IIC
Next article:S3C2440-IIC
- Popular Resources
- Popular amplifiers
Latest Microcontroller Articles
He Limin Column
Microcontroller and Embedded Systems Bible
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
MoreSelected Circuit Diagrams
MorePopular Articles
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
MoreDaily News
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
Guess you like
- 8 Common Uses of Diodes
- TMS320C6655 Fixed and Floating Point Digital Signal Processor
- [Digi-Key KOL Lecture] Common Techniques for Designing Low-Power DC-DC Converters
- Problems encountered in B-U585I-IOT02A test
- [FS-IR02 + D1CS-D54] - 4: Linking with MCU (FS-IR02)
- [Atria Development Board AT32F421 Review] TEST06 CFFT related tests
- EasyARM-RT1052 Review] + Basic IoT transmission framework (final post)
- TCP/IP Detailed Explanation (Layer 7/Layer 4 Protocol)
- FPGA Selection Strategy.pdf
- How to connect esp8266 and pyboard using UART