历史上的今天
今天是:2024年10月11日(星期五)
2021年10月11日 | S3C2440裸机------NandFlash编程_数据读取
2021-10-11 来源:eefocus
1.NandFlash结构介绍
一个page是由2028的page data和64字节的OOB(out of bank)组成的,
位反转:NandFlash在读一页数据或者写一页数据的时候有可能会发生位反转,就是在读某一页数据的时候,里面有某一位可能是错误的,为了解决这个问题引入了oob区,写页数据的时候,把数据写进去,同时会生成一个校验码,把校验码写到oob区里面,读数据的时候,读出一页数据,使用oob里面的校验码对数据进行修正,oob的存在是为了解决NandFlash的缺点。
2.读数据

我们想读取NandFlash的时候,所谓的行地址是指在哪一个page上面,所谓的列地址是指在这个page上的哪一个地址(0-2047)。
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int i = 0;
int page = addr / 2048;
int col = addr & (2048 - 1);
nand_select();
while (i < len)
{
/* 发出00h命令 */
nand_cmd(00);
/* 发出地址 */
/* col addr */
nand_addr_byte(col & 0xff);
nand_addr_byte((col>>8) & 0xff);
/* row/page addr */
nand_addr_byte(page & 0xff);
nand_addr_byte((page>>8) & 0xff);
nand_addr_byte((page>>16) & 0xff);
/* 发出30h命令 */
nand_cmd(0x30);
/* 等待就绪 */
wait_ready();
/* 读数据 */
for (; (col < 2048) && (i < len); col++)
{
buf[i++] = nand_data();
}
if (i == len)
break;
col = 0;
page++;
}
nand_deselect();
}
这里的wait_ready()函数是根据S3C2440的这个寄存器写的

void wait_ready(void)
{
while (!(NFSTAT & 1));
}
3.支持NandFlash启动
下面修改程序,保证当我们的代码大于4K时也能从NandFlash启动,首先修改我们之前的copy2sdram函数,增加一个NandFlash分支。
int isBootFromNorFlash(void)
{
volatile unsigned int *p = (volatile unsigned int *)0;
unsigned int val = *p;
*p = 0x12345678;
if (*p == 0x12345678)
{
/* 写成功, 对应nand启动 */
*p = val;
return 0;
}
else
{
return 1;
}
}
void copy2sdram(void)
{
/* 要从lds文件中获得 __code_start, __bss_start
* 然后从0地址把数据复制到__code_start
*/
extern int __code_start, __bss_start;
volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
volatile unsigned int *src = (volatile unsigned int *)0;
int len;
len = ((int)&__bss_start) - ((int)&__code_start);
if (isBootFromNorFlash())
{
while (dest < end)
{
*dest++ = *src++;
}
}
else
{
nand_init();
nand_read(src, dest, len);
}
}
这里的isBootFromNorFlas函数是根据,假如是NorFalsh启动,那么0地址不能像内存一样去写。
4.完整代码
#include "s3c2440_soc.h"
#include "my_printf.h"
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/*设置NAND FLASH的时序*/
NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
/*使能NAND FLASH控制器,初始化ECC,禁止片选*/
NFCONT = (1<<4) | (1<<1) | (1<<0);
}
void nand_select(void)
{
/*使能片选*/
NFCONT &=~(1<<1);
}
void nand_deselect(void)
{
/*禁止片选*/
NFCONT |= (1<<1);
}
void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCCMD = cmd;
for(i=0; i<10; i++);
}
void nand_addr_byte(unsigned char addr)
{
volatile int i;
NFADDR = addr;
for(i=0; i<10; i++);
}
unsigned char nand_data(void)
{
return NFDATA;
}
void wait_ready(void)
{
while (!(NFSTAT & 1));
}
void nand_chip_id(void)
{
unsigned char buf[5]={0};
nand_select();
nand_cmd(0x90);
nand_addr_byte(0x00);
buf[0] = nand_data();
buf[1] = nand_data();
buf[2] = nand_data();
buf[3] = nand_data();
buf[4] = nand_data();
nand_deselect();
printf("maker id = 0x%xnr",buf[0]);
printf("device id = 0x%xnr",buf[1]);
printf("3rd byte = 0x%xnr",buf[2]);
printf("4th byte = 0x%xnr",buf[3]);
printf("page size = %d kbnr",1 << (buf[3] & 0x03));
printf("block size = %d kbnr",64 << ((buf[3] >> 4) & 0x03));
printf("5th byte = 0x%xnr",buf[4]);
}
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int i = 0;
int page = addr / 2048;
int col = addr & (2048 - 1);
nand_select();
while (i < len)
{
/* 发出00h命令 */
nand_cmd(00);
/* 发出地址 */
/* col addr */
nand_addr_byte(col & 0xff);
nand_addr_byte((col>>8) & 0xff);
/* row/page addr */
nand_addr_byte(page & 0xff);
nand_addr_byte((page>>8) & 0xff);
nand_addr_byte((page>>16) & 0xff);
/* 发出30h命令 */
nand_cmd(0x30);
/* 等待就绪 */
wait_ready();
/* 读数据 */
for (; (col < 2048) && (i < len); col++)
{
buf[i++] = nand_data();
}
if (i == len)
break;
col = 0;
page++;
}
nand_deselect();
}
void nand_flash_test(void)
{
char c;
while (1)
{
/* 打印菜单, 供我们选择测试内容 */
printf("[s] Scan nand flashnr");
printf("[e] Erase nand flashnr");
printf("[w] Write nand flashnr");
printf("[r] Read nand flashnr");
printf("[q] quitnr");
printf("Enter selection: ");
c = getchar();
printf("%cnr", c);
/* 测试内容:
* 1. 识别nand flash
* 2. 擦除nand flash某个扇区
* 3. 编写某个地址
* 4. 读某个地址
*/
switch (c)
{
case 'q':
case 'Q':
return;
break;
case 's':
case 'S':
nand_chip_id();
break;
case 'e':
case 'E':
break;
case 'w':
case 'W':
break;
case 'r':
case 'R':
break;
default:
break;
}
}
}
史海拾趣
|
:局限于技术条件,目前生产中在统计生产产品产量方面不少还是依靠人工进行统计。在实际操作过程中,往往出现产品严重丢失,投入的原料量和产出的成品量严重失衡,因此,有必要采用工厂产量监控查询系统对整个工厂的产品产量进行准确的计量,文章基 ...… 查看全部问答> |
|
我想用wifi控制小车,并在小车上装个摄像头,把视频传到PC端显示,看到网上很多成功的,但不知道具体的实现,有谁做过吗?比如小车上用什么操作系统?实时性怎么样?用arm直接控制马达还是单加一个单片机?越具体越好,谢谢大家了… 查看全部问答> |
|
【C2000 LaunchPad】单相交流电压+电流表__算法篇 目前,电力行业里面计算电量参数使用最多的是傅里叶算法(FFT)。网上有一篇非常经典的关于FFT的介绍文章“FFT结果的物理意义”,作者是网络名人“电脑圈圈”。我就不多说了。直接转载过来,给大家参考。 FFT是离散傅立叶变换的快 ...… 查看全部问答> |






