Conceptos básicos de flash NAND.

El viaje de mil millas comienza con un solo paso cuando las cosas básicas son sólidas, ¿podemos hacer mejores cosas? Solo sobre esta base se pueden realizar mejoras e innovaciones, como dice el refrán: los cimientos son débiles y el terreno está sacudido. A continuación se presenta el conocimiento básico de nandflash: dado que NAND tiene las características de gran capacidad, precio económico, operación rápida (borrado y escritura) y pocos pines, cada vez más dispositivos usan NAND. El desarrollo de la tecnología moderna de procesos, así como tecnologías como la protección de bloques defectuosos y la corrección de errores (oob), básicamente se puede manejar bien.

La siguiente es una breve introducción al conocimiento del hardware NAND y al proceso de operación, así como a los puntos principales de la programación: los estudiantes que quieran saber más al respecto deben leer detenidamente el manual de datos oficial. El folleto de datos es siempre el mejor material de aprendizaje. La siguiente introducción se basa en el chip K9F2G08U0C.

Estructura de almacenamiento de datos NAND:

Se puede ver en la figura que la unidad de almacenamiento nand es una página, y el tamaño de cada página es de 2 KB. También se proporciona un OOB de 64 bytes (sin espacio en blanco). Oob se utiliza para almacenar el bloque defectuoso y el código de verificación de los datos 2K anteriores. oob es invisible para la CPU, y la CPU solo opera los primeros 2K de datos al leer y escribir datos. Ingrese la dirección de la columna (es decir, las primeras columnas de esta página) antes de ingresar la dirección de la fila (es decir, la dirección de la página, las primeras páginas).

Pines NAND y sus funciones:

NAND flash es un chip de memoria, por lo que lo más básico es usar la función de almacenamiento, leer los datos en la dirección A y escribir los datos C en la dirección B. Pero del diagrama esquemático, se encuentra que hay pocos pines NAND y ningún pin de dirección.

Pregunta: Solo hay 8 pines de datos, DATA0 ~ DATA7, ¿cómo transferir direcciones, datos y comandos?

Respuesta: Obviamente, esto es a través de la multiplexación de pines. DATA0 ~ DATA7 se puede utilizar para transferir direcciones, comandos y datos. Solo se puede transmitir un tipo al mismo tiempo. ¿Quién decide si la dirección o los datos y los comandos se transmiten en este momento? El chip puede controlarse mediante pines para que funcione de manera ordenada. Cuando ALE es alto, los datos transmitidos en DATA0 ~ DATA7 son la dirección (ALE: habilitación de LATCH de dirección). Es un comando (CLE: comando LATCH enable). Cuando CLE y ALE están bajos, los datos se transmiten en DATA0 ~ DATA7.

P: ¿Cuál es la función de CE en el chip?

Respuesta: CE es un pin de selección de chip. Cuando CE es bajo, puede seleccionar nand flash y luego puede operar este chip. ¿Por qué elegir un chip? Debido a que muchos chips están conectados a DATA0 ~ DATA7, es necesario que el SOC distinga qué chip funciona.

P: Después de escribir datos en flash, el chip no puede escribir datos de inmediato, lleva tiempo. ¿Cuándo puedo escribir o cuándo puedo leer datos?

Respuesta: El pin R / B (LISTO / OCUPADO) se usa para indicar el estado de nand. Si es alto, está listo, puede escribir datos en él.

Pregunta: ¿Cómo distinguir las operaciones de lectura y escritura realizadas por SOC en nand?

Respuesta: Se puede controlar con el pin RE / WE.

Entonces, cuando el procesador opera NAND (muchos procesadores integrarán el controlador NAND, siempre que el control de operación pueda controlar nand), solo necesita realizar los siguientes pasos:

  • Seleccione NAND configurando el pin de selección de chip.
  • Emitir instrucciones de operación (simultáneamente emitir pulsos de escritura).
  • Emita la dirección de la operación (emita simultáneamente el pulso de escritura).
  • Leer datos (o escribir datos)

Por ejemplo, lea los datos, consulte el diagrama de temporización y otras operaciones son las mismas, como borrar, escribir, leer ID y otras operaciones.

  • Seleccione esta opción configurando CE en nivel bajo.
  • Ajuste CLE a nivel alto, envíe 00 a nand (envíe pulso de escritura)
  • Establezca ALE en nivel alto y envíe la dirección (la dirección de la primera columna es la dirección de emisión) a nand (enviar escritura) en secuencia.
  • Establezca CLE alto, envíe 30 a nand (envíe algunos pulsos)
  • Controle si está ocupado, espere a que los datos estén listos, envíe un pulso de lectura para comenzar a leer los datos.
  • Salga del estado de lectura, establezca CLE en nivel alto, envíe 0xff a nand (debe enviar un pulso de escritura al enviar)

Si es problemático operar los pines uno por uno de acuerdo con la secuencia anterior, también es difícil garantizar que lo haga al mismo tiempo. Por lo tanto, muchos procesadores tienen controladores NAND integrados para ayudar a manejar estas engorrosas operaciones. Solo necesitamos operar los registros correspondientes para enviar comandos, enviar direcciones y enviar datos. La siguiente figura es el diagrama de flujo de operación del controlador s3c2440 NAND

  • La misma nand es la misma que ni. Cuando necesite salir del modo de lectura-escritura después de que se complete la operación, use restablecer para salir.
  • La característica del flash es que solo cambia de 1 a 0, pero no de 0 a 1. Por lo tanto, al escribir datos en la memoria flash, primero debe borrarse (es decir, todos están configurados en 0xff).

La programación de chips de memoria es básicamente similar, con operaciones como inicialización, identificación, lectura, escritura y borrado. El proceso de programación para NAND también es el mismo, como sigue:

  • Inicialice el controlador flash NAND del chip de control principal, establezca principalmente la sincronización NAND.
  • Lea la información del chip de identificación de identificación.
  • Para lograr la lectura, lea una página a la vez.
  • Para escribir, escriba una página a la vez (página).
  • Para lograr el borrado, borre un bloque a la vez.

El ajuste de sincronización de NAND está completamente determinado por un flash externo. La sincronización en S3C2440 es la siguiente:

  • TACLS indica cuánto tiempo después de que se envía la señal de bloqueo de dirección o comando, se puede enviar el pulso de escritura.
  • TWRPH0 indica la duración (período) de las señales de pulso de lectura y escritura
  • TWRPH1 indica cuánto tiempo después del final de la señal de lectura y escritura para liberar el comando de bloqueo o la señal de bloqueo de dirección.

Diagrama de tiempos en NAND:

Se puede ver en la figura: TACLS = Tcls-Twp = 0 TWRPH0 = Twp = 12 TWRPH1 = Tclh = 5.

El siguiente es el código de programación NAND en 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();
}

La lectura, escritura, borrado y lectura de la ID del chip en el código se refieren al manual de datos de nand y al capítulo del controlador de nand de s3c2440.

Publicado 35 artículos originales · Me gusta1 · Visitas 1870

Supongo que te gusta

Origin blog.csdn.net/lzj_linux188/article/details/101762378
Recomendado
Clasificación