胡建华 罗庆生
摘要 本文主要讲述了三个方面内容:第一,由于S3C44B0X没有地址重映射功能,本文讨论并设计了一个程序以实现这种伪“重映射”;第二,μC/OS-Ⅱ在移植到S3C44B0X嵌入式系统时,实现了时钟中断函数OSTickISR的C语言编写;第三,基于S3C44B0X的嵌入式系统设计过程中一些要点的总结。
关键词 ARM,S3C44B0X,Flash,SDRAM,μC/OS-Ⅱ
一、引言
S3C44B0X是一款高性能、低功耗的16/32位RISC架构的微处理器,其片上资源十分丰富,得到了广泛的应用,相应的研究书籍也非常多,但在这些参考书目中,很少提及到嵌入式系统设计过程中一些容易忽视的要点,这往往令初学者在设计过程中非常迷惑。uC/OS-Ⅱ是实时多任务内核,设计的主要任务就是操作系统的移植,现在网络上有很多可以移植的版本,但不能直接照搬,有些版本有些错误,而且不一定针对S3C44B0X处理器,由于这些接口是用汇编编写的,涉及到处理器本身,因此移植时必须了解bootloader和中断处理过程,才能实现uC/OS-Ⅱ真正意义上的移植,不会隐藏潜在的bug。
二、Flash中程序复制到SDRAM执行
相对于Flash来说,SDRAM的运行速度要快很多,现在有些处理器利用地址重映射功能,在程序运行的最初几条指令中,利用系统的存储器映射机构进行地址重映射,重新将SDRAM映射到地址0x0处,使得程序在SDRAM中执行,这样会使系统运行速度更快,同时使系统响应异常中断的速度更快。由于S3C44B0X没有地址重映射功能,就无法像前面所说的将SDRAM映射到地址0x0处执行。下面介绍一种方法,将位于NorFlash中的程序复制到SDRAM中去以获得更快的运行速度并正确执行,从而实现地址的伪“重映射”,此处以优龙科技S3C44B0X开发板中提供的bootloader为例分析,设计思路如下。
1.复制程序
由于程序要复制到SDRAM中去执行,因此复制最好在SDRAM初始化以后进行。一个程序编译完成后,生成的二进制文件中只有RO(code和data)和RW两个部分,ZI段在程序运行时初始化,这样复制过程就应该在初始化RW和ZI数据段函数InitRamData之前进行。
通过比较程序入口点(ResetEntry)和在ADS开发环境中设置的RO_base(在程序中有BaseOfROM DCD |Image$$RO$$Base| 这个定义,其他定义类同),其中ResetEntry是一个基于PC的标号,程序刚开始从Flash运行时,其值肯定为0x0,这样如果将RO_base设置为0x0,那么就无需复制,表明程序要在Flash中运行。如果将RO_base设置为SDRAM所处的地址空间,那么就需要将Flash中所有程序,即RO和RW两个部分复制到指定的SDRAM空间并SDRAM中执行程序。为了程序能够正确运行,要计算出复制程序空间的大小,这个大小由RO_Base、RW_base给出,程序复制到RO_base指向的空间,算法如下。
(1) 计算出RO程序段的大小
RO_size = TopOfROM - BaseOfROM
(2) 计算出RW数据段的大小
RW_size = BaseOfZero - BaseOfBSS
(3) 计算出Flash中整个程序段的大小
CODE_size = RO_size + RW_size
(4) 将CODE_size + BaseOfROM递减与BaseOfROM比较大小
如果前者大,就继续将代码从ResetEntry起始地址处复制至BaseOfROM起始地址空间,并将CODE_size + BaseOfROM递减,复制程序直至其与BaseOfROM相等,其中CODE_size + BaseOfROM = TopOfROM + RW_size,下面的程序设计中直接用了这个结果以简化程序编写。代码实现如下:
BL InitSystem ;进入InitSystem进行SDRAM,堆栈等初始化
ADR r0,ResetEntry
LDR r1,BaseOfROM
CMP r0,r1 ;比较ResetEntry与BaseOfROM,看是否要进行复制
LDREQ r0,TopOfROM
BEQ InitRamData ;如果ResetEntry与BaseOfROM相同,不复制
LDR r3, TopOfROM ;运行到这,说明要进行复制
LDR r4, BaseOfBSS
LDR r5, BaseOfZero
SUB r2, r5, r4
ADD r2, r3, r2 ;取得一个要进行比较的地址TopOfROM + RW_size
0
LDMIA r0!,{r4-r11} ;从ResetEntry开始取值,并将R0递增
STMIA r1!,{r4-r11} ;存入BaseOfROM开始的地址,并将R1递增
CMP r1, r2 ;比较R0与R1,判断是否继续复制
BCC %B0
这样程序就复制到了SDRAM中,起始地址由RO_base确定。
2.跳转运行
程序要正确运行,必须用一段指令找到位于SDRAM中的InitRamData标号,跳转到此处才能实现程序正确运行,跳转地址的计算方法是BaseOfROM + InitRamData标号。代码实现如下:
LDR r0,TopOfROM ;此指令为下面的InitRamData函数所准备。
LDR r1,BaseOfROM
LDR r2,=InitRamData
ADD r1,r1,r2
MOV pc,r1 ;程序跳转到SDRAM中InitRamData函数处运行
通过上面两个步骤,就实现了Flash中程序到SDRAM中的复制。此处要指出的是,在复制后,有些读者可能考虑到了绝对地址和相对地址的关系问题,比如在51系列单片机中可以用一条伪指令指定程序存放的绝对地址,但在此bootloader中,不用考虑绝对地址,指令前的标号都是基于PC的,编译时直接将其处理成一个基于PC的偏移;还有一些用EQU和MAP,FIELD等伪指令定义的标号,编译器会在Flash存储器中为这些标号分配一个地址空间(文字池)存放这些标号的表示的数值,这些标号也是基于当前PC的偏移,复制到SDRAM后也没有影响;程序之间的相对位置在编译时已经确定,因此将程序复制到SDRAM中不会影响程序的运行。
|