深入研究S3C2440 bootloader[原创]

肯请高手们批评指正,这里高手太多了,在这里给需要这东东的新手们分享下,老手们手下留情,多给点建议,谢谢了。

很久前就想移植2440的bootloader了,但是由于出身硬件职位有别,不能越殂代庖,因此此计划一度搁浅。但是扬创公司着实另人气愤,bootloader做得不好不说,还当自己代码如心肝宝贝,死活不肯开放,于是只能自己在业余时间移植了。

先来看看扬创的bootloader的实现方法:

首先:在汇编中初始化堆栈,中断向量表,MMU,时钟,串口等,然后跳到C语言的Main函数。这部分代码小于4K,放在block0。这个Main函数用来将第二段代码拷备到DRAM中并执行。

其次:进入第二段代码。第二段代码也是先在汇编中初始化堆栈,中断向量表等,然后跳到C语言的Main函数。这部分代码就不用有4K限制了,具体大小由第一段代码决定,因为它本身由第一段代码来搬运。这个Main函数用来显示开机图片以及进度条。然后视串口接收信息运行带有USB下载NK的Eboot或是读取NK映像,启动WINCE系统。

最后:进入第三段代码。这段代码用于通过USB将PC上的NK.nb0或NK.bin文件下载进NANDFLASH并运行。

可见,扬创公司光bootloader就分成了三个部分,即3个bin文件组成。然后分别将这三段二进制代码下载进分别从 block0,block2,block8(block12)开始的三块。具体烧写手段采用老掉牙的giveio烧写,就是曾经大名鼎鼎的SJF2440 了,相信不少嵌入式高手都用过,哈哈。如果不小心将bootloader弄丢了,再重烧一片,得等上好几分钟,足够你到外面跑上几千米再回来这么长了。尽管如此,我们的扬创公司仍然拿他们的代码当宝,死活不肯开源。要知道对于买你们板子的人,都是来学习的呀!学习嵌入式系统,bootloader是最基础也是进入嵌入式行业的敲门砖,没有了代码,无疑给学习添加了很大的麻烦,而扬创官方回答却是:用户开发产品用不着修改bootloader.我看扬创没开发过东西,不了解行情。

不说这么多废话了,说多了无益,让我们一起来揭开bootloader的神秘的面纱吧!

先说下我移植的bootloader的功能,以及烧录时间,和扬创的做下对比。

第一次下载bootloader到NANDFLASH的方法:

方法一:通过扬创的老掉牙的方法,先在ADS1.2里面生成bootloader.bin文件,然后用SJF2440烧写工具,配合giveio将BIN文件烧写进从block0开始的块。大概要花上十分钟左右的样子吧!BIN文件有点大。

方法二:在ADS1.2环境下,通过AXD将程序映像到DRAM的地址并运行,然后通过运行着的bootloader将本身bootloader的BIN 文件下载至NANDFLASH。很神奇吗?哈哈!本身bootloader运行的地方是ADS可配的,视文件大小可以选配在SRAM,SDRAM下运行,运行之后就可以拿程序本身来烧写代码至NAND了,弄懂原理了也就不足为奇了。这里暂时通过并口 + H-JTAG + WIGGLER的方式。

方法三:采用multiICE等仿真器下载BIN文件到NAND。

方法四:将ADS1.2的代码移植到MDK,通过ULINK2仿真,让程序运行在DRAM,然后通过bootloader程序将BIN文件烧写进NAND。

方法五:还有更多的方法留着你去做呢,哈哈.................

对比扬创的bootloader,至少有如下好处大家是看得到的吧:

其一:下载速度至少是扬创的50倍以上。大概以扬创下载整个文件需要3分钟计算,实际用USB下载bootloader仅需1秒,那就是180倍。

其二:如果手上没有USB的仿真器,那么也仅仅是用并口烧写过一次bootloader就不用了,除非NAND的bootloader被格掉了。如果手上有USB的仿真器,那就彻底不用并口了,这不正是广大笔记本开发者头痛之处么?

其三:整个bootloader文件只需一个工程文件,即只用一个BIN文件,而且是直接烧写至以block0开始的块。继续神奇?哈哈,2440手册上不是说第一段代码不能大于4K吗?这不是与手册冲突了?再觉得神奇就看代码吧!

先将整个bootloader的流程图放上来:



    		    深入研究S3C2440 bootloader[原创]
先从全局对整个工程有个大体的了解很重要,这样局部一条条的看更容易懂。

由于程序实在太长,这里分几个部分逐步说明。

一:串口配置。

整个bootloader的交互环境全部是通过串口显示的,那么怎么样才能准确无误的显示出想要的字符呢?

首先要知道的是:串口的CLK是挂在PCLK上的。波特率与PCLK有着密切的关系,因此正确设置PCLK,是和正确设置波特率有着千丝万缕的联系的。

S3C2440内置两个PLL电路,即MPLL和UPLL。MPLL给FCLK,HCLK,PCLK提供时钟,UPLL给USB提供时钟。

MPLL=FCLK=(2*m*Fin)/(p*2^s);

m=M+8;

p=P+2;

M,P由寄存器MPLLCON设置。

确定了FCLK后,HCLK和PCLK由寄存器CLKDIVN确定。

详细设置请参考S3C2440的SPEC。

这里设置mdiv=92,pdiv=1,s=1,计算得FCLK=400MHz.

相应的设置CLKDIVN,使得FCLK:HCLK:PCLK=1:4:8,

这样PCLK=400/8=50MHz.

再通过PCLK设置波特率为115200,这样串口配置就完成了。

二:TIMER4的设置

从上面的流程图可以看出,TIMER4用于倒计时,当在规定时间内没有响应键盘后,自动装载系统并运行。

TIMER4的时钟也是以PCLK为基准的。具体输入的时钟频率为:

Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}

其中prescaler value由寄存器rTCFG0确定,divider value由寄存器rTCFG1确定。

这里设置输入的频率Fin=PCLK/(3+1)/4=312500Hz.

然后设置定时器装载的初始值,由寄存器rTCNTB4确定。

这里设置rTCNTB4=3125.

由此可以算出,定时器产生一次中断所花的时间为:T=N/F=3125/312500=0.01S。

具体代码如下:

static void init_autorun_timer(int sec)
{
U32 val = (PCLK>>4)/100-1;

autorun_10ms = sec*100;

pISR_TIMER4 = (U32)autorun_proc;

rTCFG0 &= ~(0xff<<8);
rTCFG0 |= 3<<8; //prescaler 1 = 3+1 ,for Timer 2,3,4
rTCFG1 &= ~(0xf<<16);
rTCFG1 |= 1<<16; //mux = 1/4 ,for Timer 4

rTCNTB4 = val; //val = (PCLK>>4)/100-1
rTCON &= ~(0xf<<20);
rTCON |= 7<<20; //interval, inv-off, update TCNTB4&TCMPB4[占空比], start timer 4
rTCON &= ~(2<<20); //clear manual update bit
EnableIrq(BIT_TIMER4); //清0对应位,使能对应中断
}

static __irq void autorun_proc(void)
{
ClearPending(BIT_TIMER4);

if(autorun_ds) //自动运行标识位,为1时禁止自动运行;系统启动时有按键按下时为1
DisableIrq(BIT_TIMER4); //禁能对应中断

autorun_10ms--;
if(!autorun_10ms) //当中断一百次时执行下面的程序
{
DisableIrq(BIT_TIMER4);
//CLR_IF(); //in irq service routine, irq is disabled
//autorun_trig = 1; //masked by lqm!
//NandLoadRun();
//NandLoadRun_wince();//added by lqm,2008-06-29 ?????????不能加载?????????
EnRunWINCE=1;
}
}

中断程序中有个变量EnRunWINCE,默认为0.当autorun_10ms值减到0后,即定时的时间已到,

这时EnRunWINCE=1,后面的程序通过该变量判断时间到了,然后执行自动加载NK的代码。

具体代码如下:

if(EnRunWINCE)
{
NandLoadRun_wince();
}

三:LCD设置

bootloader运行时可以附加显示开机图片,这就需要对LCD控制器的相关寄存器进行设置。

由于寄存器较多,这里不一一列举,仅给LCD显示的函数如下:

void LCD_Play()
{
U32 i,j,k;
U32* palette;
Lcd_Init();
LcdBkLtSet( 70 ) ;//背光PWM设置
Lcd_PowerEnable(0, 1);
Lcd_EnvidOnOff(1); //turn on vedio
for(k=0,j=0;j for(i=0;i {
PutPixel(i,j,ackj[k++]);
}
}

四:USB,MMU,ISR,DMA等寄存器的设置

这里尤其是USB和DMA的寄存器设置,由于下载BIN文件是通过USB走的DMA下载的,因此设置这些寄存器至关重要。相关寄存器实在太多,这里不一一列举。

五:EBOOT

核心代码如下:

while(1)
{
if(menuUsed==1)Menu();
WaitDownload();
}

前面各寄存器初始化完成后,进入这个死循环,默认menuUsed=0,这时将执行函数WaitDownload()。

在WaitDownload()中,如果没有点击DNW的下载,这时没有检测到下载的BIN文件的大小,此时

downloadFileSize=0,这时执行下面的代码:

while(downloadFileSize==0)
{
//检测到USB连上后打印下面连接上的信息。
if(first==1 && isUsbdSetConfiguration!=0)
{
Uart_Printf("USB host is connected. Waiting a download.\n");//unmasked by lqm!
first=0;
}
//在没有按DNW下载时一个LED闪
if(j%0x100000==0)Led_Display(0x8);
if(j%0x100000==0x80000)Led_Display(0x0);
j++;

key=Uart_GetKey();
/*
if(autorun_trig) //Timer4倒计时到后autorun_trig置1,执行下面的函数。
AutoNandLoadRun(); //run it in svc mode
*/
/****************************************************
; 注意这里面的autorun_ds标识变量!
; 当系统启动后没有键按下时,autorun_ds=0;
; 此时timer4中断使能,通过中断自动运行系统;
; 如果按下键后,则运行Menu()函数,显示具体
; 的菜单供用户选择。
; 这时autorun_ds=1,timer4中断禁能;
; 系统不再自动加载。
****************************************************/
if(key!=0)
{
autorun_ds = 1;
//printf("disable autorun\n");
Menu();
first=1;
//To display the message,"USB host ...."
//在串口下载返回后downloadFileSize不为0,因此不能再执行USB下载!
}
//在这里添加自动加载NK的程序!added by lqm,2009-06-29
if(EnRunWINCE)
{
NandLoadRun_wince();
}
}
通过程序可以看到,此时LED会不停闪烁。

一旦通过DNW下载点击后,downloadFileSize将被赋值为下载的BIN文件或nb0文件的大小,不再为0,这个while循环将结束,程序继续往后运行,USB通过DMA将PC上的BIN或nb0文件下载到DRAM中。

在下载BIN或nb0文件时,开启定时器,用于计算下载整个文件所花的时间,并打印出来。

开始下载时,执行如下两个函数:

Timer_InitEx();
Timer_StartEx();

下载完后,执行如下函数:

time=Timer_StopEx();

下载一次所花的时间被保存在变量time中,并通过串口打印出来。

下载完后将执行数据校验,确保数据无误。

校验无误后,将根据前面是否选择下载并运行,如果下载时选择的下载并运行,这时将运行下载的程序。这里指下载到DRAM中才有这种功能。具体代码如下:

if(download_run==1)
{
register void(*run)(void); //使用寄存器变量以防止禁止DCACHE后数据不一致!!!
rINTMSK=BIT_ALLMSK;
run=(void (*)(void))downloadAddress; //使用DCACHE且RW区也在CACHE区间downloadAddress会在cache中
{
MMU_DisableDCache(); //download program must be in
MMU_DisableICache(); //non-cache area
MMU_InvalidateDCache(); //使所有DCACHE失效,本程序的MMU_Init中将会刷新DCACHE到存储器,
//为使应用此MMU_Init方式的程序能被正确运行必须先使DCACHE失效!!!
MMU_DisableMMU();
//call_linux(0, 193, downloadAddress); //或不用上面3个函数而直接使用call_linux
}
run();
}

如果选择的下载到NAND,bootloader先将下载的BIN文件下载进DRAM,再将DRAM的数据拷到NAND中。拷备完后,执行引导系统的程序。

具体程序如何拷到NAND,再如何引导系统,代码做了非常详尽的注释,这里不多说了。

bootloader生成的BIN文件:
[无法上传,sorry]
注:应该可以通过扬创提供的giveio烧到block0开始的块,之后就不用这么麻烦用giveio烧写了.
本贴视关注人数多少决定是否上传全部源代码。如果关注人太多则上传源代码并提供讲解,共同探讨。否则仅提供如上的BIN文件。------phosphor

本文系作者原创[phosphor],转载请注明出处->电子技术论坛:http://bbs.armeasy.com

附:详细源代码请进http://bbs.armeasy.com/thread-489-1-1.html

更多相关文章
  • [stephen原创]Ubuntu系统中GRUB的修复 如果你以前为ubuntu和windows多系统,当你重新安装windows,就会在MBR中只存在windows的起动选项,没有了ubuntu的grub,你可以用如下方法解决: 用ubuntu的LIVECD(即安装光盘)启动,进入终端,输入sud ...
  • 关于发布<计算机信息系统集成资质管理辦法(试行)>的通知 信部规[1999]1047号 各省.自治区.直辖市邮电管理局.电子厅局(公司).部属有关企.事业单位: 为加强计算机信息系统集成市场的规范化管理,促进计算机信息系统集成企.事业单位能力和水平的不断提高,确保各应用领域计算机信息系统 ...
  • 承接上文: 开源的悲哀--袁萌100天变身实录[1] 开源的悲哀--袁萌100天变身实录[2] 2008年3月末:虚伪的文档格式权威 进入2008年3月,一切都回到了起跑线.但袁萌老师已经回不到原来的地位上来,只能尴
  • 数组[0]和[firstobject]的区别   [0]:数组为空时回报错 [firstobject]:数组为空时回返回nil
  • 


    		    [轉]Ubuntu sudo aptget和dpkg命令
    转载:http://blog.163.com/andylauyy/blog/static/989416200810242540447/ 收藏之,学习中-- 1. APT(Ubuntu Linux软件包管理工具之一) apt-cache search # --(package 搜索包) apt-cac
  • [caffe]linux下安裝caffe(無cuda)以及python接口
    昨天在mac上折腾了一天都没有安装成功,晚上在mac上装了一个ParallelDesktop虚拟机,然后装了linux,十分钟就安装好了,我也是醉了=.= 主要过程稍微记录一下: 1.安装BLAS sudo apt-get install libatlas-base-dev 2.安装依赖项 sudo
  • [ufldl]Supervised Neural Networks
    要实现的部分为:forward prop, softmax函数的cost function,每一层的gradient,以及penalty cost和gradient. forwad prop forward prop是输入sample data,使sample data通过神经网络后得到神经网络输出
  • Ruby on Rails系列4、專題:Rails應用的國際化[i18n]
    1. 什么是internationalization(i18n)? 国际化,英文简称i18n,按照维基百科的定义:国际化是指在设计软件,将软件与特定语言及地区脱钩的过程.当软件被移植到不同的语言及地区时,软件本身不用做内部工程上的改变或修正. 当然,官方的定义总是十分高大上.实际上,今天我们要做的并
一周排行
  • Ganymede的新功能不再介绍,虽然官方网站上还没有提供正式版本的下载,但是一些镜像站点上已经可以下载到了 下载地址: [url]http://ftp.daum.net/eclipse/eclipse/downlo
  • java的AES加密算法: import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec
  • Uploading file local path: /Users/Rubert/Android/workspace/MyApplication/app/build/outputs/apk/app-debug.apk
  • 刚开始学,只会照着模板. 最长公共连续子串. #include <stdio.h> #include <string.h> #define maxn 202 int wa[maxn],wb[m ...
  • onvif規範的實現:使用gSOAP創建SOAP調用實例
    预备知识 ONVIF规范中设备管理和控制部分所定义的接口均以Web Services的形式 ...
  • AIX5.3 ORACLE10G RAC环境,新建LV时由于CHMOD.CHOWN未在两个节点同步,导致未设置权限的节点报ORA-01186\ORA-01157\ORA-01110错误,后对数据文件紧急下线过程中又出
  • 


    		    sms部署軟件系列之三,發布xp sp 3補丁
    利用部署的sms发布软件之三,发布xp sp3 补丁, 实验环境:此次试验用的虚拟机为,F
  • 很早就考虑考PMP了,但是做项目一般都是很难抽出时间来的.在老板的考核的要求下,也考虑自己的职业发展的情况下,开始了PMP之路. 虽然自己对PMBOK还是比较熟悉,但是真正面对考试还是不能忽视.毕竟自己的理解.经验与 ...
  • 生产环境中,可能会有各种各样的原因导致数据库不能提供服务,例如数据库库的硬件故障,操作系统故障或软件bug,人为的失误(例如rm -rf /)等,在这种情况下,dataguard显得尤为重要,当主库不可用的时候,可以
  • 最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下. 由于Java泛型的实现机制,使用了泛型的代码在 ...