历史上的今天
返回首页

历史上的今天

今天是:2024年09月15日(星期日)

2021年09月15日 | 从NAND Flash读取数据,把代码搬运到SDRAM运行

2021-09-15 来源:eefocus

因为依赖于S3C2440的开机自动从Nandflash复制数据到片内SRAM执行,目前我们的可执行程序体积仍然不能大于4KB的限制。而我们的程序目前已经非常接近这个限制大小了,为了能够继续开发,必须突破这个限制。为此需要实现代码搬运功能,把程序从Nandflash搬运到SDRAM中去,并跳转到SDRAM执行。


本文为啥不实现NandFlash写? 因为对于我们的实现目前尚未需求。更重要的是,写操作涉及到擦除,更涉及到NandFlash寿命。为了减少写次数,延长NandFlash寿命,一般会在软件层实现写缓存。这就涉及到大量的代码,会偏离我们实验的主题--代码搬运。等以后确实需要保存数据到NandFlash时,再实现写功能不迟。


1 NAND Flash基础知识

1.1 TQ2440板载Nandflash芯片基本情况

NAND Flash作为一种存储芯片,其读写操作需要特定的时序和规范。实际上也存在相关的工业标准,用来标准化Nandflash的读写等操作。

与RAM和ROM不同,NAND Flash的传送数据、地址、命令时共用同一组针脚,通过不同的时序加以区分。下图是TQ2440开发板上搭载的Nandflash接口图:

这里写图片描述

其接口非常简单,其中


IO0-IO7,8个针脚用于传送数据、地址、命令。

WP,写保护,直接接地。

WE,写使能

RE,读使能

CE,片选

ALE,地址锁存

RDY/B,忙闲状态

CLE,命令锁存

VSS,接地

VCC,电源


1.2 Nand flash基本术语

页(Page),NandFlash以页为单位进行读写,常见的页大小为512B,1KB,2KB等。

块(BLOCK),NandFlash在写入数据之前必须先擦除(写入1),而擦除的最小单元就是块,常见的块大小为64页。


擦除。NandFlash写入之前必须先擦除,也就是全部写入1。因为写的时候只能写0,不能写1。


数据带宽,也就是每次传送数据的位数(I/O针脚数),常见的有8,16。

地址周期,传送一个完整的地址,需要发送几次数据。


1.3 S3C2440片内NandFlash控制器

(1)硬件读取

S3C2440片内集成了NandFlash控制器,启动时,通过外部针脚的电平高低的硬件配置来获得页大小,数据宽度,地址周期等要素,从而可以在启动时能够完成读取Nandflash到SRAM。


(2)软件读取

S3C2440的片内NandFlash控制器同样对用户开放,允许用于以软件操纵它来读写NandFlash。


2 利用S3C2440片内NandFlash控制器读取NandFlash数据

2.1 相关寄存器

NFCONF 配置寄存器, 用于设置NandFlash时序

NFCONT 控制寄存器,用于控制片选等信号

GPACON 引脚复用,GPIO和NandFlash控制信号切换

NFCMD 命令寄存器,把命令写入时,自动发送

NFADDR 地址寄存器,把地址写入时,自动发送

NFDATA 数据寄存器,把数据写入时,自动发送。读取时,自动更新。

NFSTAT 状态寄存器,探测NANDFLASH是否忙


其他ECC相关寄存器,用于错误校验,暂时可以不用。

具体如何设置,请参考S3C2440的数据手册和Nandflash的数据手册。


2.2 初始化

void nand_init()

{

    rGPACON |= (0x3F << 17); /* GPIO */

    rNFCONF &= ~(3<<12 | 7<<8 | 7<<4); /* clock */

    rNFCONF |= (1<<12 | 4<<8 | 0<<4);


    rNFCONT |= 1;            /* enable NF controller */

    rNFCONT &= ~(1<<1);      /* Chip select */

    rNFCONT &= ~(1<<12);     /* disable soft lock */


    rNFSTAT |= 1<<2;         /* clear BUSY */

    nand_send_cmd(CMD_RESET);

    nand_wait();

}


2.3 页内任意读

NandFlash一般读取的最小单位为页。也有的NandFlash支持单字节读取,但是并不常用。我们可以通过先读一页,然后选择性的保存数据即可实现页内任意大小读取。


/* read [start,start+count) in a page */

int nand_read_page(unsigned char* buf, int iPage, int start, int count)

{

    nand_chip_enable();

    nand_send_cmd(CMD_PAGE_READ);

    nand_send_addr(0x00);

    nand_send_addr(0x00);

    nand_send_addr(iPage & 0xFF);

    nand_send_addr( (iPage >> 8) & 0xFF);

    nand_send_addr( (iPage >> 16) & 0x1);

    nand_send_cmd(CMD_PAGE_READ_CONFIRM);

    nand_wait();

    unsigned char * p = buf;


    int i;

    unsigned char c;

    for (i=0; i<2048; i++) {

        if ( i=start+count ) {

            c = rNFDATA8;

        }else {

            *p++ = rNFDATA8;

        }

    }

    nand_chip_disable();

    return count;

}


2.4 全范围任意读

基于页内任意读,我们进而可以实现全范围任意读。原理如下:

任何读操作涉及的范围无非有两种情况:

(1)所需数据正好全部属于同一个页。此时执行页内任意读即可。

(2)所需数据跨两个或多个页。此时对于每一页按顺序分别执行任意读即可。只是第一页和最后一页可能可能只需读部分数据,中间的页则是全页读取。

实现代码如下:


/* read size bytes starting from  addr */

int nand_read(unsigned char* buf, unsigned int addr, int size)

{

    int startPage = addr / 2048;

    int endPage = (addr+size-1) / 2048;

    int startByte = addr % 2048;

    /* if the range is in only one page */

    if (startPage == endPage) {

        return nand_read_page(buf, startPage, startByte, size);

    }


    /* if the range is across 2 or more pages */

    int n = nand_read_page(buf, startPage, startByte, 2048-startByte); /* the first page */

    int page = startPage+1;

    while (page < endPage) {                                           /* middle page(s) */

        n += nand_read_page(buf+n, page, 0, 2048);

        page ++;

    }

    n += nand_read_page(buf+n, endPage, 0, (size-n));                   /* last page */

    return n;


}


3 代码搬运

3.1 需求分析

(1)程序的前4KB,要完成的基本功能:CPU时钟初始化,SDRAM初始化,NandFlash初始化,UART0初始化。然后把NandFlash中的程序整体复制到SDRAM中,最后使能中断,跳转到Main函数执行。

(2)由于尚未启动MMU,所以异常向量入口位于绝对物理地址0开始处,也就是SRAM中。

(3)4KB之后的程序完成其他硬件初始化。


3.2 关键技术

3.2.1 位置无关代码

程序的前4KB首先是被硬件自动复制到SRAM中执行,然后是被自己搬运到SDRAM中运行,这就需要这部分代是地址无关代码。具体来说:


程序跳转需要使用相对跳转指令,如B,BL,它们都是相对于当前PC的值,增减适当偏移量来完成跳转。


C语言会自动根据跳转范围优先选用相对跳转指令,我们的程序跳转范围小于32MB,所以C编译器会自动生成位置无关代码。


3.2.2 绝对地址跳转

这个正好与相对地址跳转相反,绝对地址跳转指令如 BX,或者给PC直接赋值的指令如 mov pc, Rn, add pc, rn, rm等等。它们都是直接给PC强制赋值,从而时间4GB范围的跳转。


SRAM地址空间为[0x00000000, 0x00001000),而SDRAM的地址范围是[0x30000000,0x34000000),显然两者最小距离也远远超过了相对跳转的范围。


目前需要绝对地址跳转的地方有:


向Main()函数跳转

向异常处理程序跳转

3.2.3 链接过程的控制

搬运代码的功能需要位于可执行程序的前4KB,这可以通过链接脚本来控制。我们的链接脚本如下。


ENTRY(ResetEntry)

SECTIONS {

    . = 0x30000000;

    .text ALIGN(4): {

        init.o(.*)

        boot.o(.*)

        uart.o(.*)

        nand.o(.*)

        *(.text)

    }

    .data ALIGN(4): {

        *(.data)

        *(.rodata)

    }

    .bss ALIGN(4): {

        *(.bss)

    }

}


其中需要在SRAM中运行的文件是: init.s,boot.c,以及uart.c。


3.3 源码导读

基本的流程是:

(1)init.s 完成CPU时钟初始化,SDRAM初始化,各模式堆栈初始化,以及异常向量表的建立。

(2)然后调用boot.c里的boot()函数,此函数调用uart.c的函数完成串口初始化,调用nand.c里的函数完成代码搬运。

(3)跳转到main.c的Main()函数。

推荐阅读

史海拾趣

Custom LeatherCraft Manufacturing Co Inc公司的发展小趣事

在快速发展的同时,CLC也关注环保和可持续发展。他们采用环保材料和生产工艺,减少对环境的影响。同时,他们还积极推动循环利用和废物减量化措施,努力实现绿色生产。这些努力不仅提升了品牌形象,也为公司的长期发展奠定了基础。

Aptina (ON Semiconductor)公司的发展小趣事

随着市场竞争的加剧和行业发展的需要,Aptina最终被半导体巨头ON Semiconductor收购。这一收购使得Aptina得以借助ON Semiconductor的资源和平台,实现更快速的发展。ON Semiconductor对Aptina的收购也进一步提升了其在图像传感器领域的市场地位,为公司未来的发展注入了新的动力。

Electron Products Inc公司的发展小趣事

随着产品线的不断丰富和市场竞争的加剧,EPI开始积极拓展市场,寻求更广阔的发展空间。公司制定了国际化战略,通过参加国际展会、建立海外销售渠道等方式,成功将产品打入国际市场。同时,EPI还积极与海外企业合作,共同开发新产品,拓展业务领域。

ARMKEIL Microcontroller Tools公司的发展小趣事

ARMKEIL Microcontroller Tools公司的起点可以追溯到Keil公司的成立。1985年,Keil Elektronik GmbH(凯尔电子有限责任公司)在德国慕尼黑正式成立,由一群热衷于嵌入式系统开发的工程师创立。起初,公司的主要业务是开发和销售嵌入式系统的开发工具,这些工具为当时的电子工程师提供了强大的支持。随着业务的发展,Keil逐渐在嵌入式系统开发领域崭露头角。

Austek Microsystems公司的发展小趣事

面对行业技术的快速迭代,Austek Microsystems始终保持敏锐的洞察力。公司不断投入研发资金,引进先进的生产设备和技术人才,进行技术升级和产品迭代。通过不断地优化产品性能、提升生产效率,Austek Microsystems逐渐在市场中树立起了技术领先的形象。

上海国芯(Gcore)公司的发展小趣事
确保报警装置(如蜂鸣器、LED灯等)能够正常工作。

问答坊 | AI 解惑

SJA1000独立的CAN控制器应用指南

前面介绍了SJA1000独立的CAN控制器的工作原理和电路本文将介绍SJA1000独立的CAN控制器应用指南以变可以更好的运用SJA1000…

查看全部问答>

RF工程师的音:urgent:某著名半导体外企新出来的职位1_RF(内部推荐)

某著名外企新出来的RF 职位, 不过指明了公司名, 注意不符合请勿浪费资源,同时请注意工作地点有:上海,深圳,北京,成都,请在简历中注明申请去的地方。紧急招募,越开越好。请发中英文简历到 herofighter88@gmail.com 除Technical Hub Manager, ...…

查看全部问答>

各位大虾,帮忙看看下面是什么编译错误,怎么解决,多谢啦

在PPC下编译出现如下编译错误: 2140: Error: unsupported relocation type                                    &nb ...…

查看全部问答>

请问我Hook了ZwCreateFile后,为什么获取不到文件名呢?

我在我的HookZwCreateFile中 DbgPrint(\"HookZwCreateFile:%wZ\\n\",ObjectAttributes->ObjectName); 打印出来的全是目录,没有文件名?为啥? 谢谢各位驱动大牛。。。。…

查看全部问答>

问个问题?

用pc通过串口给单片机发送数据 用vb6.0编程 比如我要发送 0xFF  字节, 我用vb不知如何实现 试过: 用MScomm1.output=255    出错 用MScomm1.output=chr(255) 数据不准确 …

查看全部问答>

关于spi的问题

麻烦各位帮我看看程序 为什么我得不到uclk和mosi的波形呀 #include<msp430x14x.h> void main(void) { volatile unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop watchdog BCSCTL1&=~XT2OFF; ...…

查看全部问答>

ADI USB全速隔离芯片ADUM4160

ADI USB全速隔离芯片ADUM4160 ADuM4160是一款基于ADI公司iCoupler®技术的USB端口隔离器。它将高速CMOS工艺与单片空芯变压器技术相结合,可提供优异的工作性能,并且很容易与低速和全速USB兼容外设集成。许多微控制器实施的USB只向外部引脚提供 ...…

查看全部问答>

出mini6410开发板。。。。。。。。

RT,出mini6410,256RAM 1GB SLC FLASH 介绍淘宝搜 价格:420RMB。…

查看全部问答>

有关AD835的使用注意事项?

本帖最后由 paulhyde 于 2014-9-15 03:32 编辑 AD835在使用的过程中会影响结果的主要注意事项有哪些?谢谢!    …

查看全部问答>

28335 CCS3.3 上网下的例程 然后写程序写不上

28335 CCS3.3   上网下的例程  然后写程序写不上 提示 No sections were found that map to Flash …

查看全部问答>