当前位置:首页 > 单片机 > 单片机
[导读]前 言随着计算机硬件技术的不断发展,功能强大、资源丰富的嵌入式芯片,成为研究人员开发专业应用领域产品的首选。三星公司生产的S3C44B0芯片,采用ARM7TDM I内核,具有功耗小、成本低的特点,是一款专门针对移动终

前 言

随着计算机硬件技术的不断发展,功能强大、资源丰富的嵌入式芯片,成为研究人员开发专业应用领域产品的首选。三星公司生产的S3C44B0芯片,采用ARM7TDM I内核,具有功耗小、成本低的特点,是一款专门针对移动终端及PDA手持设备市场的产品。近几年,源码开放的L inux系统迅速发展,很快成为跨平台操作系统中的佼佼者,并且出现了专门针对嵌入式系统的产品———uClinux。在S3C44B0芯片上移植 uClinux操作系统,能够充分发挥该芯片系统资源丰富(相对单片机而言)的特点,开发出功能强大的应用产品。

嵌入式系统的启动引导程序与硬件严格相关,对编写人员的要求较高,而在移植uClinux后又大大增加了引导程序的复杂程度,因此这部分代码往往是各个嵌入式产品开发厂商严格保密的部分。下面将以一款市场上成熟的基于S3C44B0芯片的嵌入式开发板为蓝本,对引导uClinux内核的过程进行分析。

系统引导过程分析

嵌入式系统中uClinux内核的系统引导过程通常可以分为3个阶段,即boot阶段、系统初始化阶段和uClinux内核引导阶段。通常情况下boot阶段和系统初始化阶段的工作由一段被称为bootloader的代码完成,而内核引导则是由事先编译好了的uClinux可执行镜像来实现。

系统内存组织

由于嵌入式系统的硬件环境千差万别,即使选用同一种型号的嵌入式芯片,其外围设备也大不相同,特别是存储设备的组织,将直接关系到引导程序的实现。对于 S3C44B0芯片,其生产厂家规定在系统加电自举后,从0x00000000处开始执行(其他芯片如ARM9系列可以通过地址映射改变该地址) ,故此处通常安排的是Flash 地址空间,用于保存bootloader启动代码以及uClinux映象。对于S3C44B0 芯片, RAM 地址被固定在0x0c000000到0x0fffffff的64兆,开发人员可以根据自己的需要再组织RAM,如本开发板存储器地址安排如下:

此外,考虑到Flash运行速度的问题,通常采取的做法是将系统初始化阶段的代码和uClinux内核镜像拷贝到RAM中执行。下面将分3个阶段分析系统引导过程。

boot阶段

boot阶段的主要工作是设置系统中断向量、完成对CPU内部寄存器的初始化、系统RAM初始化、为运行C程序组织堆栈、拷贝初始化阶段代码到RAM、跳转到C程序入口。该阶段代码直接在Flash中运行,为提高执行效率采用汇编语言编写。

(1) 设置中断向量。设置S3C44B0芯片的8种系统中断的中断向量地址(包括复位中断、未定义指令中断、软件中断、指令预取异常中断、数据异常中断、地址异常中断、IRQ 中断和F IQ 中断) ,该地址空间从系统RAM的起始地址开始安排。通常情况下,在Flash的起始部分,存放的就是针对各中断向量地址的无条件跳转指令。

__entry :

B ResetHandler

/* for reset vector */

LDR PC, = 0x0c00000c

/* 0x0c00000: 未定义指令中断向量地址*/

……

/* 中间省略类似跳转*/

LDR PC, = 0x0c000024

/* 0x0c000024: F IQ中断向量地址*/

(2) CPU内部寄存器初始化。通过配置CPU运行于SVC模式(采用改变CPSC寄存器中CPU运行模式位的方式来实现) ,并设置相关寄存器,以实现对基本硬件的初始化工作,包括关闭中断、初始化CPU通用端口和设置CPU频率等。进入SVC模式汇编代码如下:

MRS a1, CPSR /* 保存当前状态寄存器值*/

BICa1, a1, #MODE_MASK /* 清除运行模式位*/

ORR a1, a1, #SUP_MODE/* 设置为超级用户模式*/

ORR a1, a1, #LOCKOUT /* 关闭F IQ和IRQ */

MSR CPSR_cxsf, a1 /* 保存到当前状态寄存器*/

(3) 系统RAM初始化。初始化系统RAM的主要目的是为下面使用RAM空间的操作做好准备工作,如进行代码拷贝及堆栈初始化等。这部分工作可以分为两个步骤。首先,根据系统配置的存储器特性,初始化相关存储块控制寄存器的值, 在S3C44B0 中存储空间被分为BANK0到BANK7共8个块,分别由BANKCON0到BANKCON7控制各块存储器的读写时钟数和片选时钟数等信号参数,对于采取不同存储芯片的嵌入式系统,可以通过查阅芯片手册来获取该信息,并写入相关寄存器。

LDR r0, = rBANKCON0

LDR r1, = 0x700

STR r1, [ r0 ]

/* 中间省略BANK1到BANK6*/

LDR r0, = rBANKCON7

LDR r1, = 0x18000

STR r1, [ r0 ]

LDR r0, = rREFRESH

LDR r1, = 0xac03e1

STR r1, [ r0 ]

LDR r0, = rBANKSIZE

LDR r1, = 0x16

STR r1, [ r0 ]

然后,对存储器空间中需要清零的区域进行清零操作,该区域的范围往往是由开发人员通知编译器的,主要是用来存放C语言中全局变量等。

LDR a1, = Image_ZI_Base /* 获取清零区域基地址*/

MOV a3, #0 /* 清零a3寄存器*/

LDR a2, = Image_ZI_L imit /* 获取清零区域尾地址*/

CMP a1, a2

BEQ move_data

clear_loop: : /* 清零Image_ZI_Base到Image_ZI_Limit区域*/

STR a3, [ a1 ] , #4/* 清零4个字节,即一个字*/

CMP a1, a2 /* 判断是否到达清零区域尾部*/

BNE clear_loop /* 否则,继续清零循环*/

(4) 为运行C程序组织堆栈。由于在系统引导的下一阶段,通常会使用C语言来完成大部分(如建立主机通信、驱动外部端口的工作) ,故必须调整SP指针到堆栈顶,为C程序配置合适的堆栈环境。在具体实现过程中为避免堆栈数据被程序运行代码破坏,往往会把堆栈设置在RAM的高端地址,并把堆栈的生长方向设为向下生长,这样可以最大限度地利用RAM空间,同时可以避免上述问题发生。

(5)拷贝初始化阶段代码到RAM。由于在S3C44B0芯片中Flash和RAM是统一编址的,只需通过简单的循环来实现代码拷贝工作。

copy_code_to_ram :

LDR r3, = Flash_Sou/* Flash_Sou为Flash中代码首地址*/

LDR r2, =Ram_Dest /* Ram_Dest为Ram中代码首地址*/

LDR r1, = 0

next :

LDR r0, [ r1 ] , #4

STR r0, [ r2 ] , #4 /* 复制到ram*/

CMP r1, r3

BNE next

跳转到C程序入口:

LDR pc, =Main

系统初始化阶段

系统初始化阶段的主要工作是建立与主机间的通信、初始化定时器、检测内存映射、加载uClinux内核镜像和配置内核启动参数等。

与主机建立通讯

面向最终用户的嵌入式产品,其启动过程应该是不需要人工干预的,但对于大多数嵌入式开发平台而言,必须通过某种方式与主机间建立通讯联系,输出启动提示信息,以实现人工干预的系统启动过程,提供更加丰富的附加功能。一般情况下,最为廉价和简单的方式是通过串口实现嵌入式系统与主机间通讯( S3C44B0提供2个Uart口,建立通信前必须初始化至少一个),这种情况下就必须事先对串口进行初始化工作。

以本开发板为例,在系统初始化的初期,就进行了Uart口的初始化工作,并通过该端口与用户宿主机上的超级终端程序通信,从而提供了多种启动功能的选择,包括Demo程序下载、Flash重新编程等。Uart0口初始化过程可参看以下C代码,其中波特率因子的计算公式可以查阅S3C44B0芯片手册。

rULCON0 = 0x3;//设置Uart0 口线控寄存器,无奇偶效验, 8数据位, 0停止位

rUCON0 = 0x345;//设置Uart0控制寄存器

rUBRD IV0 = ( ( int) (mclk /16. /baud + 0.5) - 1 ) ;//设置波特率因子,其中mclk和baud为系统频率和波特率

初始化定时器

通过设置系统定时器相关的寄存器,实现为操作系统提供最基本的系统时钟支持。

检测内存映射

为防止发生内存映射错误,即系统映射到物理地址不存在的空间,必须对内存地址作读写一致性效验。通常做法是以内存页为单位,在每个页头进行读写操作,并比较读写结果。

加载uClinux内核镜像

加载uClinux内核工作实际上是完成将Flash中uClinux内核代码拷贝到RAM指定地址单元的工作,在拷贝前必须在第二阶段RAM启动代码和该部分代码之间预留一定的空间,用来存放uClinux的全局结构变量,如: 启动参数、内核页表、ARM的页目录等信息。全地址空间的分配情况可参看本开发板地址空间分配示意图1。


图1 地址空间分配示意图

配置内核启动参数

uClinux 内核启动过程中,支持参数传入。在嵌入式系统中,启动参数的传入主要靠bootloader程序向标记列表( tagged list)的相关域中填写对应的值来完成,常见的参数如有ATAG_CORE、ATAG_MEM、ATAG_CMDL INE、ATAG_RAMD ISK、ATAG_ IN ITRD等。

uClinux内核引导

在初始化阶段完成uClinux启动参数设置后,控制权交由uClinux内核接管,并调用解压内核函数( decomp ress_kernel) ,对拷贝到SDRAM的内核映像文件进行解压缩,然后跳转到内核调用函数( call_ kernel) ,该函数实际上是执行start_kernel ( ) ,其中包括了处理器结构的初始化、中断的初始化、进程相关的初始化以及内存初始化等重要工作。最后,将控制权交给解压后的uClinux系统,进而完成整个uClinux内核引导过程,参看以下伪码: If (启动参数配置正确)调用decomp ress_kernel ( )调用call_kernel ( )else提示启动失败decomp ress_kernel( ){解压内核镜像文件}call_kernel ( ){ start_kernel( ) ;}

小 结

对于嵌入式系统开发人员来说,针对某一特定的嵌入式硬件平台,移植开发基于uClinux操作系统的应用产品时,往往需要自己动手编写或修改已有的启动代码,而为uClinux内核启动准备合适的工作环境,占据了大部分工作量。至于uClinux引导,在设置好启动参数后则是由编译好的内核镜像自动完成,对于系统开发人员来说基本上是透明的。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭