TQ2440开发板学习纪实(8)--- 从NAND Flash读取数据,把代码搬
因为依赖于S3C2440的开机自动从Nandflash复制数据到片内SRAM执行,目前我们的可执行程序体积仍然不能大于4KB的限制。而我们的程序目前已经非常接近这个限制大小了,为了能够继续开发,必须突破这个限制。为此需要实现代码搬运功能,把程序从Nandflash搬运到SDRAM中去,并跳转到SDRAM执行。 本文为啥不实现NandFlash写? 因为对于我们的实现目前尚未需求。更重要的是,写操作涉及到擦除,更涉及到NandFlash寿命。为了减少写次数,延长NandFlash寿命,一般会在软件层实现写缓存。这就涉及到大量的代码,会偏离我们实验的主题--代码搬运。等以后确实需要保存数据到NandFlash时,再实现写功能不迟。 1 NAND Flash基础知识1.1 TQ2440板载Nandflash芯片基本情况NAND Flash作为一种存储芯片,其读写操作需要特定的时序和规范。实际上也存在相关的工业标准,用来标准化Nandflash的读写等操作。 其接口非常简单,其中
1.2 Nand flash基本术语
1.3 S3C2440片内NandFlash控制器(1)硬件读取 2 利用S3C2440片内NandFlash控制器读取NandFlash数据2.1 相关寄存器
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 || i>=start+count ) {
c = rNFDATA8;
}else {
*p++ = rNFDATA8;
}
}
nand_chip_disable();
return count;
}
2.4 全范围任意读基于页内任意读,我们进而可以实现全范围任意读。原理如下: /* 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,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,(size-n)); /* last page */
return n;
}
3 代码搬运3.1 需求分析(1)程序的前4KB,要完成的基本功能:CPU时钟初始化,SDRAM初始化,NandFlash初始化,UART0初始化。然后把NandFlash中的程序整体复制到SDRAM中,最后使能中断,跳转到Main函数执行。 3.2 关键技术3.2.1 位置无关代码程序的前4KB首先是被硬件自动复制到SRAM中执行,然后是被自己搬运到SDRAM中运行,这就需要这部分代是地址无关代码。具体来说:
3.2.2 绝对地址跳转这个正好与相对地址跳转相反,绝对地址跳转指令如 BX,或者给PC直接赋值的指令如 mov pc,Rn, add pc,rn,rm等等。它们都是直接给PC强制赋值,从而时间4GB范围的跳转。 SRAM地址空间为[0x00000000,0x00001000),而SDRAM的地址范围是[0x30000000,0x34000000),显然两者最小距离也远远超过了相对跳转的范围。 目前需要绝对地址跳转的地方有:
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 源码导读基本的流程是: 4 完整源码完整源码下载,V0.9。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |