韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别

NOR Flash编程实现识别

  • 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
  • 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
  • 参考资料:《嵌入式Linux应用开发完全手册》韦东山,开发版原理图,MX29LV160DBTI-70G(NOR FLASH) datasheet,MX29LV800BBTC datasheet
  • 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-1

目录

  • NOR Flash编程实现识别
    • 一、实现功能
    • 二、编程原理
      • 1、构建并封装两个函数,使其实现对指定地址写入数据与读出指定地址信息。
      • 2、打印设备ID、厂家ID
      • 3、进入CFI模式。
      • 4、打印NOR Flash容量
      • 5、打印各个扇区起始地址
      • 6、退出CFI模式
    • 三、编程文件
      • 1、新建一个nor flash.c文件
      • 2、修改main.c文件
      • 3、修改Makefile文件
    • 四、运行结果


一、实现功能

功能:识别nor flash,打印厂家ID、设备ID 、容量和各个扇区起始地址。

二、编程原理

1、构建并封装两个函数,使其实现对指定地址写入数据与读出指定地址信息。

写入数据函数:

/* 构建一个函数,功能:往地址里面写数据 */
#define  NOR_FLASH_BASE 0  //nor--cs0,base addr :0

void nor_write_addr(unsigned int base,unsigned int offset,unsigned int val )
{
	volatile unsigned short *p = (volatile unsigned short *)(base + (offset<<1));
	*p = val;
}
/* 封装nor_write_addr */
void nor_cmd(unsigned int offset,unsigned int cmd)
{
	nor_write_addr(NOR_FLASH_BASE,offset,cmd);
}

读出信息函数:

/* 构建一个函数,功能:读取地址中的信息 */
#define  NOR_FLASH_BASE 0  //nor--cs0,base addr :0

unsigned int nor_read_addr(unsigned int base,unsigned int offset)
{
	volatile unsigned short *p = (volatile unsigned short *)(base + (offset<<1));
	return *p;
}
/* 封装nor_read_addr */
unsigned int nor_data(unsigned int offset)
{
	return nor_read_addr(NOR_FLASH_BASE,offset);
}

2、打印设备ID、厂家ID

打印设备ID、厂家ID在上节讲过这里就不详细讲,直接贴出代码:

	int vendor,device;
/* 打印设备ID 
	 * 1、先解锁
	 * 2、后根据信息输入对应的nor_cmd指令
	 * 3、读取数据后要reset
	 */
	nor_cmd(0x555,0xaa);
	nor_cmd(0x2aa,0x55);
	nor_cmd(0x555,0x90);
	
	vendor = nor_data(0);
	device = nor_data(1);

	nor_cmd(0,0xf0);

3、进入CFI模式。

进入CFI模式才可查询容量和各个扇区的信息
查MX29LV800BT/BB datasheet第10页可知:

韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别_第1张图片

图2.1
	char str[4];

	nor_cmd(0x55,0x98);  //进入cfi模式
	str[0] = nor_data(0x10);
	str[1] = nor_data(0x11);
	str[2] = nor_data(0x12);
	str[3] = '\0';
	printf("str = %s\n\r",str);

4、打印NOR Flash容量

查MX29LV160DBTI-70G datasheet第27页可知:

在这里插入图片描述

图3.1
	/* 打印容量 */
	int device_size;
	device_size = 1<<nor_data(0x27);   //代表2的nor_data(0x27)次方	    
	printf("device_size = %x  ,%dM",device_size,(device_size/(1024*1024)));

5、打印各个扇区起始地址

首先:画图解释erase block regions

韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别_第2张图片

图4.1

分析:
①、对于一个NOR Flash,其中含有若干个region(s)每个region含有若干个block(s)

其次:查询MX29LV800BT/BB datasheetd第9页

韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别_第3张图片

图4.2

分析:
①、读出地址0x2C可以知道一共有几个regions,手册可知一共有4个
②、每个region的信息可以通过读取4个地址的信息组成。

然后:参考CFI publication 100第九页找到

韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别_第4张图片

图4.3

最后:查MX29LV160DBTI-70G(NOR FLASH)第27页可知

韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别_第5张图片

图4.4

结合图4.2和图4.3分析:
①、读取region1中的block信息,需要读取地址0x2D、0x2E、 0x2F、 0x30,每个地址的数据只需要关心其低8位,即低1个字节
②、每个地址对应低8位的数据,按地址大小顺序重新组合成一个32位的数据;如用[0xXX]表示该地址中存储的数据,即region1中的block信息,可表示为[30,2F,2E,2D]。
③、[30,2F] ✖ 256(高16位 ✖ 256)表示:该region中每个block的大小
④、[2E,2D] + 1(低16位 + 1)表示:相同大小的block的数量

由图4.1可知NOR Flash中有region(s),region中有block(s)。
所以在编写程序时采用两个for循环,
第一个循环读取每个region中的blocks数据
第二个循环负责打印每个block的起始地址
/* 打印各个扇区的起始地址 */
	/* 名词解释:
	 *    erase block region : 里面含有1个或多个block, 它们的大小一样
	 * 一个nor flash含有1个或多个region
	 * 一个region含有1个或多个block(扇区)

	 * Erase block region information:
	 *    前2字节+1    : 表示该region有多少个block 
	 *    后2字节*256  : 表示block的大小
	 */
	regions = nor_data(0x2C);
	regions_info_base = 0x2d;
	block_addr = 0;
	flag = 0;
	printf("Block/Sector Start Address:\n\r");

	for(i = 0;i<regions;i++)
	{
		
		blocks = nor_data(regions_info_base)+(nor_data(regions_info_base+1)<<8)+1;     //计算该region中blocks的个数
		block_size = 256*(nor_data(regions_info_base+2)+(nor_data(regions_info_base+3)<<8));	  //计算每个block的大小
		regions_info_base +=4;   //使得进入下次循环时地址为下一个region的信息地址
		
		for(j=0;j<blocks;j++)
		{
		
		   /* 打印每个block的起始地址 */
			printHex(block_addr);
			putchar(' ');
			flag++;
			block_addr +=block_size;
			if (flag % 5 == 0)
				printf("\n\r");
			
		}
	}
	printf("\n\r");

6、退出CFI模式

	nor_cmd(0, 0xf0);

三、编程文件

1、新建一个nor flash.c文件

#include "my_printf.h"
#include "string_utils.h"

#define  NOR_FLASH_BASE 0  //nor--cs0,base addr :0
/* 构建一个函数,功能:往地址里面写东西 */
void nor_write_addr(unsigned int base,unsigned int offset,unsigned int val )
{
	volatile unsigned short *p = (volatile unsigned short *)(base + (offset<<1));
	*p = val;
}
/* 封装nor_write_addr */
void nor_cmd(unsigned int offset,unsigned int cmd)
{
	nor_write_addr(NOR_FLASH_BASE,offset,cmd);
}

/* 构建一个函数,功能:读取地址中的信息 */
unsigned int nor_read_addr(unsigned int base,unsigned int offset)
{
	volatile unsigned short *p = (volatile unsigned short *)(base + (offset<<1));
	return *p;
}

/* 封装nor_read_addr */
unsigned int nor_data(unsigned int offset)
{
	return nor_read_addr(NOR_FLASH_BASE,offset);
}

/* 识别nor flash */
void do_scan_nor_flash(void)
{
	/* 各变量对应含义
	 * 用到的标志位
	 * 设备容量大小
	 * 厂家ID,设备ID
	 * region的数量、第一个region的信息地址
	 * blocks的数量、block的地址、block的大小
	 */
	char str[4];  
	int i,j,flag;
	int device_size;
	int vendor,device;
	int regions,regions_info_base;
	int blocks,block_addr,block_size;

	/* 打印设备ID 
	 * 1、先解锁
	 * 2、后根据信息输入对应的nor_cmd指令
	 * 3、读取数据后要reset
	 */
	nor_cmd(0x555,0xaa);
	nor_cmd(0x2aa,0x55);
	nor_cmd(0x555,0x90);
	
	vendor = nor_data(0);
	device = nor_data(1);

	nor_cmd(0,0xf0);
	
	/* 
	 * 1、首先进入cfi模式
	 * 2、对获取信息的不同,执行nor_cmd进行写操作
	 * 3、执行nor_data,读出对应地址的信息
	 */
	nor_cmd(0x55,0x98);
	str[0] = nor_data(0x10);
	str[1] = nor_data(0x11);
	str[2] = nor_data(0x12);
	str[3] = '\0';
	printf("\n\r");
	printf("str = %s\n\r",str);
		
	/* 打印容量 */
	device_size = 1<<(nor_data(0x27));    //2的nor_data(0x27)次方
	printf("Vendor ID = 0x%x, Device ID = 0x%x, Nor Flash Size = 0x%x, %dM\n\r", vendor, device, device_size, (device_size/(1024*1024)));

	/* 打印各个扇区的起始地址 */
	/* 名词解释:
	 *    erase block region : 里面含有1个或多个block, 它们的大小一样
	 * 一个nor flash含有1个或多个region
	 * 一个region含有1个或多个block(扇区)

	 * Erase block region information:
	 *    前2字节+1    : 表示该region有多少个block 
	 *    后2字节*256  : 表示block的大小
	 */
	regions = nor_data(0x2C);
	regions_info_base = 0x2d;
	block_addr = 0;
	flag = 0;
	printf("\n\r");
	printf("Block/Sector Start Address:\n\r");

	for(i = 0;i<regions;i++)
	{
		
		blocks = nor_data(regions_info_base)+(nor_data(regions_info_base+1)<<8)+1;     //计算该region中blocks的个数
		block_size = 256*(nor_data(regions_info_base+2)+(nor_data(regions_info_base+3)<<8));	  //计算每个block的大小
		regions_info_base +=4;   //使得进入下次循环时地址为下一个region的信息地址
		
		for(j=0;j<blocks;j++)
		{		
		   /* 打印每个block的起始地址 */
			printHex(block_addr);
			putchar(' ');
			flag++;
			block_addr +=block_size;
			if (flag % 5 == 0)
				printf("\n\r");		
		}
	}
	printf("\n\r");
	/* 退出CFI模式 */
	nor_cmd(0, 0xf0);
}
/* 擦除nor flash某个扇区 */
void do_erase_nor_flash(void)
{}

/* 编写某个地址 */
void do_write_nor_flash(void)
{}

/* 读某个地址 */
void do_read_nor_flash(void)
{}

void nor_flash_test(void)
{
	char c;
	while(1)
	{
		/* 打印菜单,供选择测试内容 */
		printf("[S] Scan nor flash\n\r");
		printf("[E] Erase nor flash\n\r");
		printf("[W] Write nor flash\n\r");
		printf("[R] Read nor flash\n\r");
		printf("[Q] Quit nor flash\n\r");
		printf("Enter Selection: ");

		c = getchar();
		printf("%c\n\r",c);
		
		/* 测试内容:
		 * 1、识别nor flash
		 * 2、擦除nor flash某个扇区
		 * 3、编写某个地址
		 * 4、读某个地址
		 */

		switch (c)
		{
			case 'Q':
			case 'q':
				return;
				break;
			case 'S':
			case 's':
				do_scan_nor_flash();
				break;
			case 'W':
			case 'w':
				do_write_nor_flash();
				break;
			case 'R':
			case 'r':
				do_read_nor_flash();
				break;
			case 'E':
			case 'e':
				do_erase_nor_flash();
				break;
			default:
				break;
		}
	}
}

2、修改main.c文件

添加nor_flash_test()函数以及屏蔽timer_init()函数

#include "s3c2440_soc.h"
#include "uart.h"
#include "sdram_init.h"

char g_Char = 'A';
char g_Char2 = 'a';
char i ='0';

int main(void)
{
	unsigned char c;
	int flag;

	//interrupt_init();
	key_eint_int();
//	timer0_init();
	uart0_init();
	//sdram_init();

	nor_flash_test();
		
	puts("uart0 init success!\n\r''");
	putchar(i);
	
	while(1)
	{
		putchar(g_Char); 
		g_Char++;
		delay(1000000);
		putchar(g_Char2); 
		g_Char2++;
		delay(1000000);
	}	
	return 0;
}




3、修改Makefile文件

添加本节使用到的…o文件指令以及修改依赖指令:添加-march=armv4

all: start.o led.o uart.o sdram_init.o main.o exception.o eint.o timer.o nor_flash.o my_printf.o string_utils.o lib1funcs.o
	
	arm-linux-ld -T sdram.lds $^ -o sdram.elf
	arm-linux-objcopy -O binary -S sdram.elf sdram.bin
	arm-linux-objdump -D sdram.elf > sdram.dis
clean:
	rm *.bin *.o *.elf *.dis
	
%.o : %.c
	arm-linux-gcc -march=armv4 -c -o $@ $<

%.o : %.S
	arm-linux-gcc -march=armv4 -c -o $@ $<	

四、运行结果

程序运行截图:韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别_第6张图片
实际Nor Flash信息:韦东山嵌入式Linux学习——014 NOR Flash(2)-NOR Flash编程实现识别_第7张图片

  通过观察可知,二图的厂家ID、设备ID 、容量和各个扇区起始地址对一样,所以功能可正确运行。

你可能感兴趣的:(韦东山嵌入式Linux第一阶段)