NAND flash basics.

The journey of a thousand miles begins with one step-only when the basic things are solid, can we make better things. Only on this basis can improvements and innovations be made, as the saying goes: the foundation is weak and the ground is shaken. The basic knowledge of nandflash is introduced below. Since NAND has the characteristics of large capacity, cheap price, fast operation (erasing and writing), and few pins, more and more devices use NAND now. The development of modern process technology, as well as technologies such as bad block protection and error correction (oob), can basically be handled well.

The following is a brief introduction to NAND hardware knowledge and operation process, as well as the main points of programming. Students who want to know more about it are better to read the official data manual carefully. The data booklet is always the best learning material. The following introduction is based on the K9F2G08U0C chip.

NAND data storage structure:

It can be seen from the figure that the nand storage unit is a page, and the size of each page is 2KB. A 64-byte OOB (out of blank) is also provided. Oob is used to store the bad block and the check code of the previous 2K data. oob is invisible to the CPU, and the CPU only operates the first 2K of data when reading and writing data. Enter the column address (that is, the first few columns in this page) before entering the row address (that is, the address of the page, the first few pages).

NAND pins and their functions:

NAND flash is a memory chip, so the most basic is to use the storage function, read the data at address A, and write data C to address B. But from the schematic diagram, it is found that there are few NAND pins and no address pins.

Question: There are only 8 data pins, DATA0 ~ DATA7, how to transfer address, data and command?

Answer: Obviously this is through the multiplexing of pins. DATA0 ~ DATA7 can be used to transfer both address and command and data. Only one type can be transmitted at the same time. Who decides whether the address or data and commands are transmitted at this time? The chip can be controlled by pins to make it work in an orderly manner. When ALE is high, the address transmitted on DATA0 ~ DATA7 is (ALE: address LATCH enable). When CLE is high, the transmission on DATA0 ~ DATA7 is It is a command (CLE: command LATCH enable). When both CLE and ALE are low, data is transmitted on DATA0 ~ DATA7.

Q: What is the function of CE on the chip?

Answer: CE is a chip select pin. When CE is low, you can select nand flash, and then you can operate this chip. Why choose a chip? Because many chips are connected to DATA0 ~ DATA7, it is necessary for the SOC to distinguish which chip is operated.

Q: After writing data to flash, the chip cannot write data immediately, it takes time. When can I write or when can I read data?

Answer: The R / B (READY / BUSY) pin is used to indicate the state of nand. If it is high, it is ready, you can write data into it.

Question: How to distinguish the read and write operations performed by SOC on nand?

Answer: It can be controlled by RE / WE pin.

So when the processor operates NAND (many processors will integrate NAND controller, as long as the operation control can control nand), only need to perform the following steps:

  • Select NAND by setting the chip select pin.
  • Issue operation instructions (simultaneously issue write pulses).
  • Issue the operation address (simultaneously issue the write pulse).
  • Read data (or write data)

For example, read data, refer to the timing diagram, and other operations are the same, such as erasing, writing, reading ID and other operations.

  • Select this nand by setting CE to low level.
  • Set CLE to high level, send 00 to nand (send write pulse)
  • Set ALE to high level and send the address (the first column address is the issue address) to nand (send write) in sequence.
  • Set CLE high, send 30 to nand (send some pulses)
  • Monitor whether it is busy, wait for the data to be ready, send a read pulse to start reading the data.
  • Exit the read state, set CLE to high level, send 0xff to nand (you need to send a write pulse when sending)

If it is troublesome to operate the pins one by one according to the above sequence, it is also difficult to guarantee to do it at the same time. Therefore, many processors have integrated NAND controllers to help deal with these cumbersome operations. We only need to operate the corresponding registers to send commands, send addresses, and send data. The following figure is the operation flowchart of s3c2440 NAND controller

  • The same nand is the same as nor. When you need to exit read-write mode after the operation is complete, use reset to exit.
  • The characteristic of flash is that it only changes from 1 to 0, but not from 0 to 1. Therefore, when writing data to the flash, it needs to be erased first (that is, all are set to 0xff).

The programming of memory chips is basically similar, with operations such as initialization, identification, read, write, and erase. The programming process for NAND is also the same, as follows:

  • Initialize the NAND flash controller of the main control chip, mainly set the NAND timing.
  • Read the information of the ID identification chip.
  • To achieve reading, read one page at a time.
  • To write, write one page at a time (page).
  • To achieve erasure, erase one block at a time.

The timing setting of NAND is completely determined by external flash. The timing in S3C2440 is as follows:

  • TACLS indicates how long after the address or command latch signal is sent, the write pulse can be sent.
  • TWRPH0 indicates the time length (period) of read and write pulse signals
  • TWRPH1 indicates how long after the end of the read and write signal to release the command latch or address latch signal.

Timing diagram in NAND:

It can be seen from the figure: TACLS = Tcls-Twp = 0 TWRPH0 = Twp = 12 TWRPH1 = Tclh = 5.

The following is the NAND programming code in S3C:



#define PAGE_SIZE	(0x800)
#define BLOCK_SIZE	(64*PAGE_SIZE)


unsigned char nand_read(void)
{
	volatile unsigned char *NFDATA = (volatile unsigned char *)0x4E000010;
	return *NFDATA&0xff;
}

/*发送指令函数,往寄存器中写入值,控制器会自动发出指令*/
void nand_cmd(unsigned char cmd)
{	
	volatile int i = 0;
	volatile unsigned char *NFCMMD = (volatile unsigned char *)0x4E000008;
	*NFCMMD = cmd;
	for(i = 0;i < 100;i++);
	
}
/*发送地址函数,往寄存器中写入值,控制器会自动发出地址*/
void nand_addr(unsigned char addr)
{
	volatile int i = 0;
	volatile unsigned char *NFADDR = (volatile unsigned char *)0x4E00000C;
	*NFADDR = addr;
	for(i = 0;i < 100;i++);

}
/*nand flash 片选*/
void nand_select(void)
{
	volatile unsigned int *NFCONT = (volatile unsigned int*)0x4E000004;
	*NFCONT &= ~(1<<1);
}
/*nand flash取消片选*/
void nand_disselect(void)
{
	volatile unsigned int *NFCONT = (volatile unsigned int*)0x4E000004;
	*NFCONT |= (1<<1);
}

void nand_init(void)
{
	#define TACLS 		0
	#define TWRPH0 		1
	#define TWRPH1		0
	volatile unsigned int *NFCONF = (volatile unsigned int*)0x4E000000;
	volatile unsigned int *NFCONT = (volatile unsigned int*)0x4E000004;

	/*设置NAND控制器的时序,参考手册时序图*/
	*NFCONF = (TACLS<<14) | (TWRPH0<<8) |(TWRPH1<<4);
	/*使能NAND控制器*/
	*NFCONT = (1<<0) | (1<<1) |(1<<4);
}

void nand_reset(void)
{
	nand_cmd(0xff);
}

void read_nand_id(void)
{
	unsigned int buffer[5] = {0};
	volatile int i;
	/*发送指令0x90*/
	nand_cmd(0x90);
	/*发送地址00*/
	nand_addr(0);
	/*读数据总线获取数据*/
	for(i =0 ;i <5;i++){
		buffer[i] = nand_read();
		putHex_(buffer[i]);
	}
	/*退出读取ID状态*/
	nand_cmd(0xff);
}

void nand_wait_ready(void)
{
	volatile unsigned int *NFSTAT = (volatile unsigned int *)0x4E000020;
	/*等待nand进入就绪状态*/
	while(!(*NFSTAT&1));
}

#if 0
void nand_read_dat(unsigned int addr,unsigned int length,char* buf)
{
	unsigned short offset;
	unsigned int page;
	int i;

	page = addr / PAGE_SIZE;
	offset = addr % PAGE_SIZE;

	nand_cmd(0x00);
	nand_addr(offset&0xff);
	nand_addr(offset>>8 &0xff);
	nand_addr(page&0xff);
	nand_addr(page>>8&0xff);
	nand_addr(page>>16&0xff);
	nand_cmd(0x30);

	nand_wait_ready();
		
	for(i = 0;i<length;i++){
		*buf++ =nand_read();
	}

	nand_cmd(0xff);
	
}
#endif

void nand_read_dat(unsigned int addr,unsigned int length,char*buf)
{
	/*参考nand flash芯片手册读时序图*/
	unsigned short col = addr % PAGE_SIZE;
	unsigned int page = addr / PAGE_SIZE;
	int i = 0;
	while(i <length){
		/*发出0x00命令*/
		nand_cmd(0x00);
		/*发出列地址column低8bit*/
		nand_addr(col&0xff);
		/*发出列地址column高8bit*/
		nand_addr(col>>8&0xff);
		/*发出行地址(page)低8bit*/
		nand_addr(page&0xff);
		/*发出行地址(page)第二字节*/
		nand_addr(page>>8&0xff);
		/*发出行地址(page)的第三个字节*/
		nand_addr(page>>16&0xff);
		/*发出0x30命令,开始读取数据*/
		nand_cmd(0x30);

		/*等待nand就绪*/
		nand_wait_ready();
		
		for(; ((col<PAGE_SIZE)&&(i<length));i++,col++){
			*buf++ = nand_read();		
		}
		if(i == length){break;}
		col = 0;
		page++;
		
	}
	nand_reset();
	
}

int erase_block(unsigned int addr,int len)
{
	
	//unsigned char val = 0; 
	/*参考nand flash芯片手册擦除时序图*/
	unsigned int page = addr / PAGE_SIZE;
	if(addr % BLOCK_SIZE){return -1;}
	
	while(1){
		/*发出命令0x60*/
		nand_cmd(0x60);
		/*发出行地址1*/
		nand_addr(page&0xff);
		/*发出行地址2*/
		nand_addr(page>>8&0xff);
		/*发出行(page)地址3*/
		nand_addr(page>>16&0xff);
		/*发出命令0xd0*/
		nand_cmd(0xD0);
		/*等待nand就绪*/

		nand_wait_ready();
		len -= BLOCK_SIZE;
		if(len<=0){break;}
		page += 64;

	}
#if 0	
	nand_read_dat(0x70,1,&val);
	putHex_(val);
	if(val & 1){
		puts_("erase error\n\r");
	}else{
		puts_("erase success\n\r");
	}
#endif
	nand_reset();
 	return 0;
}

void nand_program_dat(unsigned int addr,unsigned int length,unsigned char* buf)
{
	/*参考nand flash芯片page编程时序图*/
	unsigned int page = addr / PAGE_SIZE;
	unsigned short col = addr % PAGE_SIZE;
	volatile unsigned char* NFDATA = (volatile unsigned char*)0x4E000010;
	int i = 0;
	unsigned char val = 0;
	
	while(i<length){
		/*发送命令0x80*/
		nand_cmd(0x80);
		/*发送地址*/
		nand_addr(col&0xff);
		nand_addr(col>>8&0xff);
		nand_addr(page &0xff);
		nand_addr(page>>8&0xff);
		nand_addr(page>>16&0xff);
		/*发送数据*/
		for(; ((col <PAGE_SIZE) &&i<length); i++,col++){
			*NFDATA = *buf++;
		}
		/*发送命令0x10*/
		nand_cmd(0x10);
		/*等待芯片处于就绪状态*/
		nand_wait_ready();
		/*校验是否编程(写)成功*/
#if 0
		nand_read_dat(0x70,1,&val);
		putHex_(val);
		if(val & 1){
			puts_("program error\n\r");
		}else{
			puts_("program success\n\r");
		}
#endif		
		if(i ==length){break;}
		col = 0;
		page++;
		
	}
	nand_reset();
}

void nand_flash_test(void)
{
	char c;
	int i;
	char buffer[PAGE_SIZE];
	/*初始化NAND控制器*/
	nand_init();
	/*设置片选信号、选择nand*/
	nand_select();
	
	while(1){
		puts_("[s] Scan nand flash\n\r");
		puts_("[e] erase nand flash\n\r");
		puts_("[w] write nand flash\n\r");
		puts_("[r] read nand flash\n\r");
		puts_("[q] quit \n\r");
		puts_("please enter selection: ");
		c=getchar_();
		puts_("\n\r");

		switch(c){
			case 'S':
			case 's':
				read_nand_id();
				break;
			case 'e':
			case 'E':
				erase_block(0,BLOCK_SIZE);
				break;
			case 'w':
			case 'W':
				for(i = 0;i<PAGE_SIZE;i++){
					buffer[i] = i;
				}
				nand_program_dat(0, PAGE_SIZE, buffer);
				break;
			case 'r':
			case 'R':
				for(i = 0;i<PAGE_SIZE;i++)
				buffer[i] = 0;
				nand_read_dat(0,PAGE_SIZE,buffer);
				for(i = 0;i < PAGE_SIZE;i++){
					putHex_(buffer[i]);
				}
				break;
			case 'q':
			case 'Q':
				return;
				break;
			case 't':
			case 'T':
				//do_test_serial();
				break;
			default:
				puts_("please enter  the correct instruction\n\r");

		}

	}
		/*取消片选*/
	nand_disselect();
}

The reading, writing, erasing and reading the chip ID in the code refer to the nand data manual and the s3c2440 nand controller chapter.

Published 35 original articles · Like1 · Visits 1870

Guess you like

Origin blog.csdn.net/lzj_linux188/article/details/101762378