S3C2440裸机------Nor Flash编程_识别

发布者:满足的36号最新更新时间:2021-10-12 来源: eefocus关键字:Nor  Flash编程  识别 手机看文章 扫描二维码
随时随地手机看文章

1.编写菜单程序

首先我们编写一个测试菜单程序,用来获取norFlash信息以及对NorFlash进行读写操作,代码如下:


void nor_flash_test(void)

{

char c;

 

while (1)

{

/* 打印菜单, 供我们选择测试内容 */

printf("[s] Scan nor flashnr");

printf("[e] Erase nor flashnr");

printf("[w] Write nor flashnr");

printf("[r] Read nor flashnr");

printf("[q] quitnr");

printf("Enter selection: ");

 

c = getchar();

printf("%cnr", 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 'e':

case 'E':

do_erase_nor_flash();

break;

 

case 'w':

case 'W':

do_write_nor_flash();

break;

 

case 'r':

case 'R':

do_read_nor_flash();

break;

default:

break;

}

}

}


2.获取容量信息

要想获取容量信息,我们首先需要进入cfi模式,往55H这个地址写入98可以进入cfi模式。

然后我们实现一个函数,用来往某个地址写入某个数据。


#define NOR_FLASH_BASE  0  /* jz2440, nor-->cs0, base addr = 0 */

 

 

/* 比如:   55H 98 

 * 本意是: 往(0 + (0x55)<<1)写入0x98

 */

void nor_write_word(unsigned int base, unsigned int offset, unsigned int val)

{

volatile unsigned short *p = (volatile unsigned short *)(base + (offset << 1));

*p = val;

}


然后我们同样实现一个读取某个地址数据的函数。


unsigned int nor_read_word(unsigned int base, unsigned int offset)

{

volatile unsigned short *p = (volatile unsigned short *)(base + (offset << 1));

return *p;

}

 

unsigned int nor_dat(unsigned int offset)

{

return nor_read_word(NOR_FLASH_BASE, offset);

}

然后我们读取27这个地址就可以得到size,size是2的14次方。


nor_cmd(0x55, 0x98);  /* 进入cfi模式 */

 

/* 打印容量 */

size = 1<<(nor_dat(0x27));

printf("vendor id = 0x%x, device id = 0x%x, nor size = 0x%x, %dMnr", vendor, device, size, size/(1024*1024));


3.打印各个扇区的起始地址

从芯片手册里面我们可以看到有两个概念,block,region,我们一个norflash含有一个或多个region,然后一个region含有一个或多个block(扇区).一个region里面的所有block大小一样,但是不同region的扇区大小是不一样的,而且每个region含有的block数量也不一样。


然后每个region的信息是根据CFI publication 100规范,网上搜索:CFI publication 100,得到

我们可以看到从2D开始的四个字节中,低两个字节的值+1表示blocks的数量,高两个字节中的值乘以256就是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_dat(0x2c);

region_info_base = 0x2d;

block_addr = 0;

printf("Block/Sector start Address:nr");

cnt = 0;

for (i = 0; i < regions; i++)

{

blocks = 1 + nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8);

block_size = 256 * (nor_dat(region_info_base+2) + (nor_dat(region_info_base+3)<<8));

region_info_base += 4;

 

// printf("nrregion %d, blocks = %d, block_size = 0x%x, block_addr = 0x%xnr", i, blocks, block_size, block_addr);

 

for (j = 0; j < blocks; j++)

{

/* 打印每个block的起始地址 */

//printf("0x%08x ", block_addr);

printHex(block_addr);

putchar(' ');

cnt++;

block_addr += block_size;

if (cnt % 5 == 0)

printf("nr");

}

}

printf("nr");

/* 退出CFI模式 */

nor_cmd(0, 0xf0);


4.读取设备ID

我们在芯片手册的cfi模式下,没有看到跟设备ID相关的,那么我们只能在正常模式下去读设备ID。

/* 打印厂家ID、设备ID */

nor_cmd(0x555, 0xaa);    /* 解锁 */

nor_cmd(0x2aa, 0x55); 

nor_cmd(0x555, 0x90);    /* read id */

vendor = nor_dat(0);

device = nor_dat(1);

nor_cmd(0, 0xf0);        /* reset */

问题一:程序卡死

我们按照上面的方法去读取之后,发现连续读取会卡死,这是因为我们的main函数中有一个定时器中断函数,一旦发生定时器中断程序就会跳去中断子程序执行代码,这样就会破坏我们的读取设备ID的代码,因此要把main函数中的定时器中断代码注释掉。


问题二:ID读取错误

修改完上面程序卡死的问题之后,读取的ID仍然不正确,我们去看下反汇编文件。

我们的nor_write_word函数是想一次性的把一个16位的数写入,但是现在发现程序时一个字节一个字节的去写的,用的strb命令。


我们通过修改makefile,通过增加 -march=armv4配置来修改这个问题。修改后的makefile如下


all: start.o led.o uart.o init.o main.o exception.o interrupt.o timer.o nor_flash.o my_printf.o string_utils.o lib1funcs.o

#arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

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 $@ $<


重新编译之后,再来看反汇编文件:

这时发现,已经可以一次性操作两个字节了。


5.完整代码

完整的nor_flash.c如下:


#include "my_printf.h"

#include "string_utils.h"

 

 

#define NOR_FLASH_BASE  0  /* jz2440, nor-->cs0, base addr = 0 */

 

 

/* 比如:   55H 98 

 * 本意是: 往(0 + (0x55)<<1)写入0x98

 */

void nor_write_word(unsigned int base, unsigned int offset, unsigned int val)

{

volatile unsigned short *p = (volatile unsigned short *)(base + (offset << 1));

*p = val;

}

 

void nor_cmd(unsigned int offset, unsigned int cmd)

{

nor_write_word(NOR_FLASH_BASE, offset, cmd);

}

 

unsigned int nor_read_word(unsigned int base, unsigned int offset)

{

volatile unsigned short *p = (volatile unsigned short *)(base + (offset << 1));

return *p;

}

 

unsigned int nor_dat(unsigned int offset)

{

return nor_read_word(NOR_FLASH_BASE, offset);

}

 

 

/* 进入NOR FLASH的CFI模式

 * 读取各类信息

 */

void do_scan_nor_flash(void)

{

char str[4];

unsigned int size;

int regions, i;

int region_info_base;

int block_addr, blocks, block_size, j;

int cnt;

 

int vendor, device;

/* 打印厂家ID、设备ID */

nor_cmd(0x555, 0xaa);    /* 解锁 */

nor_cmd(0x2aa, 0x55); 

nor_cmd(0x555, 0x90);    /* read id */

vendor = nor_dat(0);

device = nor_dat(1);

nor_cmd(0, 0xf0);        /* reset */

nor_cmd(0x55, 0x98);  /* 进入cfi模式 */

 

str[0] = nor_dat(0x10);

str[1] = nor_dat(0x11);

str[2] = nor_dat(0x12);

str[3] = '';

printf("str = %snr", str);

 

/* 打印容量 */

size = 1<<(nor_dat(0x27));

printf("vendor id = 0x%x, device id = 0x%x, nor size = 0x%x, %dMnr", vendor, device, size, 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_dat(0x2c);

region_info_base = 0x2d;

block_addr = 0;

printf("Block/Sector start Address:nr");

cnt = 0;

for (i = 0; i < regions; i++)

{

blocks = 1 + nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8);

block_size = 256 * (nor_dat(region_info_base+2) + (nor_dat(region_info_base+3)<<8));

region_info_base += 4;

 

// printf("nrregion %d, blocks = %d, block_size = 0x%x, block_addr = 0x%xnr", i, blocks, block_size, block_addr);

 

for (j = 0; j < blocks; j++)

{

/* 打印每个block的起始地址 */

//printf("0x%08x ", block_addr);

printHex(block_addr);

putchar(' ');

cnt++;

block_addr += block_size;

if (cnt % 5 == 0)

printf("nr");

}

}

printf("nr");

/* 退出CFI模式 */

nor_cmd(0, 0xf0);

}

 

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 flashnr");

printf("[e] Erase nor flashnr");

printf("[w] Write nor flashnr");

printf("[r] Read nor flashnr");

printf("[q] quitnr");

printf("Enter selection: ");

 

c = getchar();

printf("%cnr", 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 'e':

case 'E':

do_erase_nor_flash();

break;

 

case 'w':

case 'W':

do_write_nor_flash();

break;

 

case 'r':

case 'R':

do_read_nor_flash();

break;

default:

break;

}

}

}

关键字:Nor  Flash编程  识别 引用地址:S3C2440裸机------Nor Flash编程_识别

上一篇:S3C2440裸机------Nor Flash编程_擦写读
下一篇:S3C2440裸机------Nor Flash原理及硬件操作

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved