功能:识别nor flash,打印厂家ID、设备ID 、容量和各个扇区起始地址。
写入数据函数:
/* 构建一个函数,功能:往地址里面写数据 */
#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);
}
打印设备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);
进入CFI模式才可查询容量和各个扇区的信息
查MX29LV800BT/BB datasheet第10页可知:
图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);
查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)));
首先:画图解释erase block regions
图4.1
分析:
①、对于一个NOR Flash,其中含有若干个region(s),每个region含有若干个block(s)。
其次:查询MX29LV800BT/BB datasheetd第9页
图4.2
分析:
①、读出地址0x2C可以知道一共有几个regions,手册可知一共有4个。
②、每个region的信息可以通过读取4个地址的信息组成。
然后:参考CFI publication 100第九页找到
图4.3
最后:查MX29LV160DBTI-70G(NOR FLASH)第27页可知
图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");
nor_cmd(0, 0xf0);
#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;
}
}
}
添加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;
}
添加本节使用到的…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 $@ $<
通过观察可知,二图的厂家ID、设备ID 、容量和各个扇区起始地址对一样,所以功能可正确运行。