S3C2440-Nandflash

Publisher:RainbowMelodyLatest update time:2015-04-08 Source: eechinaKeywords:S3C2440  Nandflash Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
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. 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;   
}
Keywords:S3C2440  Nandflash Reference address:S3C2440-Nandflash

Previous article:S3C2440-IIC
Next article:S3C2440-IIC

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号