四极管:整理S3C6410制作SD启动卡以及简易SDbootloader的方法

 四极管要做一个2416的SD卡启动,并且引导镜像文件的bootloader方法,查看了资料,发现djyos兄在09年就研究过都江堰操作系统的移植,特整理如下:

应深圳友坚科技之邀,这几天要把djyos移植到他们的idea6410上。 
    现在发布的是si版本,是以单片机模式运行的,S3C6410这样强劲的cpu,运行si版本,就作为高速单片机用了,所有地址都是按照物理地址一一对应映射。cpu的状态也没有区分内核态和用户态。 
1、中断引擎最初的部分代码在IRQ态(还没决定是否使用FIQ)。 
2、中断引擎的大部分以及用户ISR运行在SVC态。 
3、所有其他代码运行在SYS态。 
    移植碰到的第一个问题就是烧录代码到flash的问题,由于廉价的jtag烧录器不支持arm11,我们不能要求用户必须拥有昂贵的仿真烧录工具才能够在idea6410上使用djyos,这样不利于用户使用。所以,移植的第一步,是要制作SD启动卡。 
    我的第一个目标,就是弄清楚怎么下载程序的问题,也就是把一个最简单的闪灯程序运行起来,写了几行代码,如下: 
    ldr     r0,=0x7f008820 
    ldr     r1,=0x1111 
    str     r1,[r0] 
    ldr     r0,=0x7f008824 
    ldr     r1,[r0] 
    bic     r2,r1,#3 
    orr     r2,r2,#0xc 
    bic     r3,r1,#0xc 
    orr     r3,r3,#3 
nn: 
    str     r2,[r0] 
    ldr     r4,=5000000 
delay1: 
    sub     r4,r4,#1 
    cmp     r4,#0 
    bne     delay1 
    str     r3,[r0] 
    ldr     r4,=5000000 
delay2: 
    sub     r4,r4,#1 
    cmp     r4,#0 
    bne     delay2 
    b       nn 

    6410的手册上说,可以从nandflash、onenand、SD卡启动,没有专用的烧录工具的情况下,只有SD卡启动是可以考虑的。手册上看到,SD卡启动,实际上是先执行片内IROM中的一段程序,该程序从SD卡中读取代码,写到stepping stone中,stepping stone是位于0x0c000000、size为8K的片内内存,代码写入stepping stone后,跳到0x0c000000处继续执行程序。那么,要实现从SD卡启动,就必须弄清楚: 
1、8K的代码保存在SD卡的什么位置。 
2、代码以什么格式存储。 
    为弄清楚上述问题,依例google一番,没找到有用的资料,上三星的网站,6410的资料没有公开,申请了一下,第二天得到了批准,也没有关于怎样从SD卡启动的资料。找三星代理,似乎不太爱搭理我,也是,我势单力薄一个人,他们怎看得上眼。难道就没有办法了? 
    山穷水尽疑无路,柳暗花明又一村,2450不是也可以从SD卡启动吗?找找2450的资料看有没有,谢天谢地,从网上找到一篇文档: 
896554S3C2450_IROM_ApplicationNote_Rev003.pdf 
我如获至宝,细细读之,虽然写得不太细,比如代码校验算法等都没有讲,总是可以试一下了。 
    依葫芦画瓢,把编译好的代码写入到最后芯片末尾偏移-9216字节处,插入SD卡座,把开关拨到SD0卡启动的位置,上电,哈哈,成功了,几个蓝色的LED欢快地闪烁起来。试了两个SD卡,16M的可以,2G的不行,不知何故,暂且放一边吧。 
    首战告捷,该歇歇了,待续。

 

上篇说道,用16M的SD卡启动可以,但用2G的卡却不行,反复试过,实在不知道怎么回事,也没有IROM中的加载程序的进一步资料,问题也就无从查起了,暂且先放一边,把后续的移植工作做完再说吧。 
    移植操作系统,跟开发裸奔程序是不一样的,裸奔程序可以从main开始写程序,在执行main之前,编译器产生了大量的代码用于初始化cpu、内存清零、初始化堆和栈、直到建立main的执行环境。而操作系统往往有自己的运行环境要求,C编译器完成的这些环境往往不能符合要求,需要自己写初始化文件,即initcpu.s文件。 
    初始化文件主要完成以下工作: 
1、从复位地址跳转到启动地址。 
2、设置cpu为特权模式,禁止看门狗和中断,禁止cache。 
3、设置时钟,有些cpu的时钟设置很复杂的,尤其是高速cpu,因为涉及到内核和外设匹配的问题,设置起来比较麻烦。 
4、设置内存总线,设置内存访问速度,要跟上一步的时钟设计配合,使cpu能正确读写内存和内存映射的外设。 
5、配置cache和mmu,然后使能cache和mmu。 
6、初始化栈,跳转到C代码。 
    根据拿来主义的原则,写cpu初始化代码千万不能自己从0开始写,而是要找一个现成的来参考,因为各个系统的cpu初始化工作是大同小异的。移植到2440的时候,因为2410和2440非常相似,用的是2410的initcpu.s直接改的,但看了一下6410的datasheet,发现6410与2440差别太大了,不能用2440的initcpu.s来改,必须另外找一个。一般来说,许多cpu厂商都会出example,会带一个文件名类似startup.s的文件,参考该文件来写即可。但是,三星不知从何年何月开始不公开其cpu的文档了,甚至连datasheet都要申请才给。当我千辛万苦找到三星提供的“6410_Test_Rev01”源代码包时,心都凉了,该代码包中虽然有start.s文件,但文件中只有几条指令,初始化过程都在"__rt_entry“函数中,而该函数在库中。对芯片应用资料的保密工作做得如此周密,不知三星所谋何事。 
    没办法,继续找,实在不行再自己一行行写。好在天无绝人之路,终于在友坚提供的wince的eboot代码中,找到了eboot的start.s文件,打开一看,果然是一个详细的启动文件,心中不禁狂喜! 
    接下来的工作,就是对照datasheet,看懂这个start.s,然后改造成适合djyos的。别看说的轻巧,这里面工作量还是很大的,6410的datasheet有1300多页,光时钟和总线配置相关的部分就有100多页,E文的,晕死。而且第一次用arm11,其mmu和cache配置和arm9有多大差别,还不可知。今天先写到这里,下回分解吧。

 

接续上回,开始啃start.s,跟所有的启动文件一样,开始部分是关闭cache、禁止中断等,没什么问题。这里稍稍解释一下为什么要做这些工作,禁止中断大家应该没什么异议,关键是为什么一定要禁止cache,原来,我们不知道程序为什么要重新启动,也不知道重新启动前cpu和cache处于什么状态,cache可能包含错误的信息,cpu可能会从中取得错误的指令,从而不能正常启动系统。eboot的start.s遗漏了一个很重要的过程,就是要重新把cpu设置成svc状态,因为就像我们不了解重启动前cache状态一样,cpu的状态也是未知的,须加上这几句确保cpu处于svc态: 
    mrs     r0,cpsr                 @取CPSR 
    bic     r0,r0,#MODEMASK         @清模式位 
    orr     r1,r0,#SVCMODE|NOINT    @设置为管理态,并禁止中断 
    msr     cpsr_cxsf,r1            @切换到管理态,可防止意外返回0地址时出错. 
    实际上,这几句仍然不够保险,因为如果程序是从user态直接跳转到0地址的话,mrs和msr指令是无效的。保险的做法是用swi指令强制修改,既然是个简易的bootloader程序,暂且偷懒一下。 
    依惯例,接下来是各种时钟初始化,S3C6410的时钟结构比较复杂,共有3个pll要设置,而且分频控制也较为复杂,虽然start.s有得抄,但还是要自己弄清楚,因为接下来的编程用得上。6410的时钟部分之所以如此复杂,完全是为了适应其内部丰富的外设,不同的外设需要不同的时钟。设置时钟,不外乎就是定义几个常用的主频,然后分别为这些主频定义锁相环(pll)的分频系数,再把这些分频系数填充到相应的寄存器中去,细节就不再赘述了,看代码吧。 
   初始化完时钟后,就轮到初始化内存总线了。依据用什么初始化什么的原则,这里只初始化了srom0和dram两个区域,这部分代码是用C语言实现的,参见memcfg.c文件,代码比较简单,不过是按照datasheet的要求,依次设置寄存器而已。 
    接下来,你一定会想到,该初始化mmu了,初始化mmu本来是一项复杂的工作,但si版本是为单片机准备的,即使6410再强劲,也只能委屈一下,当高速单片机了。mmu在这里并没有用来做地址变换,而是把4G内存空间全部映射到其物理地址上了。这种映射效果跟禁止mmu是一样的,但是arm的mmu和cache是绑定在一起的,禁止mmu的同时也就禁止了cache,故只能打开mmu。页表的地址在0x50000000,占用16Kbytes,故应用程序的起始地址是0x50004000。 
    又可以偷懒了,6410的核是arm11jzf-s的,2440的核是arm920T的,arm11jzf-s的mmu功能比arm920t的强很多,但都是arm公司的,做最简单映射的话,能否兼容呢?懒得读arm11的手册了,先试一下把2440版本的mmu初始化部分直接copy看行不行。事实证明是可行的,但我在这里绕了一个大大的圈子,浪费了许多时间。加入初始化mmu部分代码后,试了一下,发现灯不闪了,而把该段程序放到初始化页表的代码之前,则可以。仔细检查,发现是因为dram没有初始化,加上dram初始化后,先把闪灯程序放在dram初始化后面,发现可以了。这时候,不幸发生了,移动闪灯程序时,只copy了一半的代码,当然不闪了,可我没仔细检查代码,就怀疑是2440的mmu初始化代码不能用于6410的造成的(偷懒了,心虚),于是找来arm11jzf-s的手册猛啃,几百页的英文资料啊,费了好几天功夫,最后证明了一件事:原来的mmu初始化是正确的!! 
    到这里,基本硬件的初始化就算完成了,接下来要搞norflash和uart的driver了。待续……

 

之三讲到,cpu的初始化已经完成,下一步的工作便是初始化uart,使之能够跟PC连接上。
    初始化6410的uart,有两个时钟必须区分清楚,即uartclk和baudclk,前者由系统控制寄存器CLK_SRC和CLK_DIV2控制,手册并没有说明这个时钟的用途,我猜测是用于uart模块本身运行的;另一个时钟是baudclk,用来控制baud,产生串行移位时钟的,在uart模块的控制寄存器UCON中设置,然后用UBRDIV和UDIVSLOT0两个寄存器设置baud。uart的工作方式为:
baud=115200
接收和发送fifo:开
中断:关闭,以查询方式收发。
    接下来是norflash的驱动程序,也就是编写擦除和写入程序,根据am29lv160db的手册写就是了,没什么好说的。除了一些低级错误外,测试也几乎一次成功。
    至此,该轮到xmodem协议收发程序了,xmodem是一个简单的串口收发文件的协议,它把文件分成128字节的一个个小包传送,最后一包数据如果不满128字节,则以0x1a填充。该协议是有缺陷的,用来传送文本文件没问题,因为文本文件不会出现0x1a,但传送2进制文件的话,就不行了,因为接收方无法分辨最后的0x1a是文件本身的内容,还是填充物。不过没关系,作为代码,最后多一些垃圾并不碍事,无非就是多占几个字节而已。
    xmodem本来是有差错控制的,通过逐帧应答和校验和(或者CRC)来确保传输正确,不过这里偷了下懒,所有这些都省略了,传错了就再传一次。
    至此,移植到S3C6410的第一步,sdbootloader就制作完成了,接下来就是移植整个操作系统了

 

zhanglf08 :

楼主说2G的SD卡不行,应该是放的位置不对。我用的就是2G的SD卡,用友坚提供的bootloader工具烧写,对比发现,bootloader是从0x7537DC00这个地址开始写的,是一条跳转语句……我自己用RVDS写了个闪烁LED的汇编小程序,编译后,从这个位置开始写入,发现是可以用的,至于原因,还不清楚,估计与SD卡的结构有关

 

zhanglf08 :

16M的SD卡属于里面的SD/MMC Device,所以,从末地址,向前偏移9K(18个block),就行了

2G或者更大的的SD卡,属于SDHC Device,所以需要从末地址,向前偏移521K(1042个block)

 

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3472292&bbs_id=3065

 

 

 

转载请注明出处。作者:四极管。广西师范大学 电子工程学院大学生科技创新基地 邮箱: yangxingbo-0311@163.com

 

 

 




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值