移植S3C44B0X嵌入式uClinux系统的参考
eeskill 2021-09-24

一、前言

ARM7TDMI是世界上广泛使用的32位嵌入式RISC处理器,是目前用于低端的ARM处理器核。它的高性能,低功耗,廉价和精简的程序代码一直是市场上的领先者。ARM公司研发了针对ARM图形化的编译器,连接器和调试器,这为整个嵌入式系统的开发调试提供了较好的环境。Samsung S3C44B0微处理器是三星公司提供的高性价比和高性能的微控制器解决方案,它使用ARM7TDMI核,从SamsungS3C4510B停产后,SamsungS3C44B0X更成为同类芯片的主流。

现今许多嵌入式系统要实现复杂的功能都需要操作系统支持,有了操作系统的支持,编写特定的应用程序就比较容易了。本文以uClinux最新源代码包为基础,修改代码以适合S3C44B0X的系统,包括启动程序bootloader,Linux内核源代码修改,根文件系统的定制。

二、硬件架构

一个最小的嵌入式系统包括以下几个部分:CPU、SDRAM、FLASH。但为了调试方便本文介绍的系统带了网口和串口,网口用于传输数据大批量数据,串口用于传输字符数据,这样就可以和主机通信了。硬件框图如图1所示。

系统实验板主要芯片(CPU,UART,FLASH(ROM),ETHERNETSDRAM),管脚连接如图2所示。

图2 S3C44B0X与SDRAM,Flash,以太网口,串口的连接图

三、软件架构

基于uClinux的嵌入式系统软件一般由三部分构成:启动程序(bootloader)、内核文件(kernel)、根文件系统(rootfs)。uClinux源代码包含程序库,Linux内核和根文件系统所需要的应用程序源代码,而启动程序要自己编写。

启动程序先初始化CPU,然后引导uClinux操作系统,操作系统引导起来后会加载根文件系统,加载根文件系统有几种方式,这里采用blockmemory技术(可以避免在启动时传递内核rootfs位置的参数)。根文件系统使用romfs文件系统,这种文件系统相对简单,很适合嵌入式系统的应用。这三部分在FLASH和内存的分配地址如图3和图4所示。

最难调试的部分应该是启动程序部分;对于以后的内核可以根据串口输出的错误信息来判断。笔者采用ARM公司的调试工具AXD来调试bootloader。

1.启动程序(bootloader)

bootloader有两大功能:初始化CPU和引导Linux内核(采用将压缩内核拷贝到内存解压方法,这样可以加快启动速度)。

(1)初始化CPU

1)中断向量

ARM要求中断向量表必须放置在从0地址开始,连续8×4字节的空间内。每当一个中断发生以后,ARM处理器便强制把PC指针置为向量表中对应中断类型的地址值。因为每个中断只占据向量表中1个字的存储空间,只能放置一条ARM指令,使程序跳转到存储器的其他地方,再执行中断处理。

所以0地址开始的地方,分配为flash的空间,在0地址开始处放中断向量,作为uClinux的启动代码,实现方式如下:

b reset

add pc,pc,#0x0c000000

add pc,pc,#0x0c000000

add pc,pc,#0x0c000000

add pc,pc,#0x0c000000

add pc,pc,#0x0c000000

add pc,pc,#0x0c000000

add pc,pc,#0x0c000000

0x0c000000为内存起始地址,uClinux将中断向量放入地址0x0c000008,因为cpu发生中断时仍然会跳转到0地址处的中断向量表中去,所以此处要修改中断向量表的地址,使程序能正确跳转到uClinux实现的中断向量处。由于ARM系统的三级流水线技术,当程序执行到x地址处,pc指针的值其实等于x+8。

在uClinux中相关代码如下:

#ifdef CONFIG_ARCH_S3C44B0

#undef vectors_base()

#define vectors_base() (0x0c000008)

#endif

add pc,pc,#0x0c000000这条语句将会有8的偏移量,当pc等于0时,这条指令的执行结果为pc=0x0c000008。

2)中断处理

这段reset代码放在flash中。这样系统每次复位后,会执行flash上的reset代码。

初始化存储器系统 初始化堆栈

在初始化堆栈时应该特别注意,堆栈指针地位置一定不能和其他程序的地址相冲突,否则程序很容易异常。 初始化有特殊要求的端口,设备 初始化用户程序执行环境 改变处理器模式 调用主应用程序

(2)引导Linux内核

主应用程序里放操作系统引导程序的代码,一般此处应该传递给Linux内核启动参数(如ramdisk的位置等),但程序加载内核使用blockmemory技术,所以不用传递参数来加载根文件系统rootfs。只要将Linux内核和rootfs从flash(如图1)拷贝到内存中相应位置(如图2)。拷贝完成后跳转到内核入口地址处执行。具体方法是用将压缩内核的地址转换成函数的指针,并传递处理器号ARCH_NUMBER。这在uClinux内核源代码的目录文件uClinux-dsit/linux2.4.x uClinux-dsit/linux2.4.x/arch/armnommu/tools/Match-types中定义:

s3c44b0 ARCH_S3C44B0 S3C44B0 178

2.uClinux系统内核

uClinux的官方网站发布的最新uClinux移植包是uclinux-dist-20040408,它包含了三星S3C4510B的源代码,可以将它移植到S3C44B0平台下。具体内核源代码的改动如下(其中出现的内存地址可以参考图4)。

(1)Linux内核编译配置选项

文件uClinux-distvendorsSamsungS3C44B0config.linux-2.4.x中:

#System Type

CONFIG_ARCH_MBA44B0=y

CONFIG_NO_PGT_CACHE=y

CONFIG_CPU_32=y

CONFIG_CPU_ARM710=y

CONFIG_CPU_WITH_CACHE=y

CONFIG_SERIAL_44B0=y

DRAM_BASE=0x0c000000#SDRAM起始地址

DRAM_SIZE=Ox01000000#SDRAM大小16M

FLASH_MEM_BASE=0x00000000#FLASH起始地址

FLASH_SIZE=0x00200000 #FLASH大小2M

以后的make都以CONFIG_ARCH_S3C44B0=y这选项来解决是编译和$3C4480相关的其他选项。

(2)处理器MAKEFILE文件

文件uClinux-dsit/linux2.4.x/arch/armnommu/Makefie中:

ifeq($(CONFIG_ARCH_S3C44B0),y)

TEXTADDR=0x0c008000

MACHINE=s3c44bO

endif

TEXTADDR=0x0c008000#表明未压缩的内核的位置

uClinux-dsit/linux2.4.x/arch/armnommu/boot/Makefie:

ifeq($(CONFIG_ARCH_S3C44B0),y)

ZRELADDR =0x0c008000

ZTEXTADDR =0x0c300000

endif

ZRELADDR=0x0c008000#表明未压缩的内核的位置

ZTEXTADDR=0x0c300000#表明压缩内核的位置

(3)中断向量地址

文件uClinux-dsit/linux2.4.x/include/asm-armnommu/proc-armv/system.h中

#ifdef CONFIG_ARCH_S3C44B0

#undef vectors_base()

#define vectors_base()(0x0c000008)

#endif

内存地址为0x0e000008的原因在启动程序一处已经提到过。

(4)处理器基本参数和类型

文件uClinux-dsit/linux2.4.x/arch/armnommu/machs3c44b0/arch.c中

MACHINE_START(MBA44B0,"S3C4480")

MAINTAINER("MacWang")

BOOT_MEM(0x0c000000,0x01c00000,0x01c00000)

BOOT_PARAMS(0x0c000100)

INITIRQ(genarch_init_irq)

MACHINE_END

其中MACHINE_START(MBA44B0,"S3C44B0")的"MBA4480"是在asm/mach-types.h里定义的平台类型

BOOT_MEM(0x0c000000,0x01c00000,0x01c00000)指定了启动的RAM地址0x0c000000,特殊功能寄存器地址0x01c00000,BOOT_PARAMS(0x0c000100)表示内核参数的传递地址。

文件uClinux-dsit/linux2.4.x/arch/armnommu/tools/Match-types中:

s3c44b0 ARCH_S3C44B0 S3C44B0 178

178是arch_number

在跳转到内核时,r0=0,r1=arch_number

(5)网络驱动

这里采用的芯片是RTL8019AS,数据宽度用的是8位,它和ne2000兼容,所以只要修改ne2000的源代码(I/O起始地址、中断向量号、数据宽度)就可以实现网口的驱动了。

文件uClinux-dsit/linux2.4.x/driver/net/ne.e中:

dev->base_addr=base_addr=NE2000_ADDR;

dev->irq=NE2000_IRQ_VECTOR;

NE2000_ADDR和NE2000IRQ_VECTOR分别是RTL8019AS的I/O起始地址和中断向量号,根据硬件连接改成相应的值。ne_probel函数中wordlength=2代表数据宽度为16位,改为wordlength=1代表数据宽度为8位。

(6)用blockmemory指定地址

对rootfs的加载一般有两种方式,用initrd技术和blockmemory。这里用blockmemory技术指定romfs的地址。(makemenuconfig时选定romfs和romdisksupport)

文件uClinux-dsit/linux2.4.x/driver/block/Blkmem.c中:

arena[]={

#ifdef CONFIG_ARCH_S3C44B0

{0,0x0CC00000,-1},

#endif

这样只要将mmfs加载到相应的地址0x0CC00000,内核就可以找到。

修改完成后,编译内核(make menconfig)时要选择支持ramdisk和blkmem。ne2000网卡驱动,romfs和ramfs文件系统,TCP/IP协议的项。

3.根文件系统(rootfs)

uClinux源代码包里有直接生成rootfs的工具,它所采用的是romfs格式的文件系统。

定制romfs时选择一些基本的shell命令,包括文件系统的一些命令,用户可根据需要选择自己需要的命令。笔者选择了telnet服务器程序(有利于从远程主机登录到系统上),ftp服务器和客户端命令等网络程序。

最后要结合自己的应用来编写一个uClinux操作系统下的应用程序。有了uClinux操作系统的支持,应用程序的编写就比较容易了。嵌入式uClinux系统下的应用程序和PC机上Linux系统下的编程相似,区别只是调用的库函数不一样。PC机上调试程序比较容易,可以先在PC机上调试代码,再从X86机移植程序到ARM处理器。在移植过程种应注意内存奇地址问题,在X86机上将4字节长的数据存放在一个内存奇地址上一般不会有问题,但在ARM处理器执行时就会产生异常。在Linux下有各种开源的代码,它们功能都比较完善,只要移植到uClinux下就可以了。这大大地增加了嵌入式系统地开发效率。

在uClinux-dist源代码包的usr目录下增加自己的程序文件夹,该文件夹内存放所需的程序和MAKEFILE文件。因为上一级目录的MAKEFILE会对子文件夹内的每个文件夹调用MAKE,所以在上层目录编译romfs时,就可以把这个程序放入根文件系统中。

最后把以上三个步骤生成的二进制文件用烧写FLASH工具分别烧写在如图3所示的flash地址处,就可以在嵌入式系统上运行一个带网络功能的uClinux操作系统了。

四、结语

本文根据笔者所用的嵌入式实验板为平台构建uClinux软件平台,在不同的S3C44B0X嵌入式系统中,根据硬件和应用的不同,可以更改相应的地方,以适合自己系统的需要。把移植过程中最关键的地方列出,其他细节(例如uClinux的编译)限于篇幅不再赘述,可以作为移植S3C44B0X嵌入式uClinux系统的参考。

声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
热门推荐
  • 相关技术文库
  • 单片机
  • 嵌入式
  • MCU
  • STM
  • ARM Cortex系列处理器知识点汇总

    最近因为要为芯片选定核,所以就在了解哪些核合适且性价比好,这是一个需要结合产品各类技术、市场分析的活,看似简单却还是需要一些储备的,今天选了一篇ARM Cortex系列的科普文章与大家分享。 众所周知,英国的ARM公司是嵌入式微处理器世界当中的佼佼者。AR

    05-11
  • 你的CPU属于哈佛结构还是冯诺依曼结构?

    现代的CPU基本上归为冯诺伊曼结构(也称普林斯顿结构)和哈佛结构。 冯洛伊曼结构就是我们所说的X86架构,而哈佛结构就是ARM架构。一个广泛用于桌面端(台式/笔记本/服务器/工作站等),一个雄踞移动领域,我们的手持设备(平板\手机用的大多就是他了)。 01

    05-10
  • 如何批量修改MCU封装管脚定义

    在做产品开发时,为了缩短研发周期,我们一般都是直接找来参考设计做参考。这些参考资料要么是来自原厂的,要么是来自方案商的。  接触过这么多的参考设计资料,发现大部分的资料都有一个通病,就是不少MCU的PIN脚定义都只是标出IO口的定义,其它复用​​​​功能

    05-08
  • MCU为什么要消抖动

    简单的说,进入了电子,不管是学纯模拟,还是学单片机,DSP、ARM等处理器,或者是我们的FPGA,一般没有不用到按键的地方。按键:人机交互控制,主要用于对系统的控制,信号的释放等。因此在这里,FPGA上应用的按键消抖动,也不得不讲! 一、为什么要消抖动 在

    05-07
  • 51单片机的ISP下载知识

    本文详细介绍了串口、51单片机的ISP下载等基础知识,已经学过单片机的也可以看看,加强一下对这方面的了解。 串口 串行接口简称串口,也称串行通信接口,是采用串行通信方式的扩展接口。 我们比较熟悉的USB接口,全名通用串行总线(Universal Serial BUS),就

    05-06
  • 硬件开发如何选择合适的MCU

    点击上方关注我们! 我在做硬件开发时,如果遇到的是一个新产品,新项目,之前没有做过的,没有任何的经验,在选MCU时,我一般是这样操作的。 首先,根据产品的需求,整理出一份硬件规格。比如,电源管理,传感器接口,人机交互接口等。 然后,整理出整个原理

    05-06
  • 单片机的功耗怎么算的?

    单片机的功耗是非常难算的,而且在高温下,单片机的功耗还是一个特别重要的参数。暂且把单片机的功耗按照下面的划分。 暂且把单片机的功耗按照下面的划分。 1.内部功耗(与频率有关) 2.数字输入输出口功耗 2.1输入口 2.2输出高 2.3输出低 3.模拟输入口功耗从

    05-07
  • 嵌入式工程师必备工具:I2C和SPI总线协议

    IIC vs SPI 现今,在低端数字通信应用领域,我们随处可见IIC (Inter-Integrated Circuit) 和 SPI (Serial Peripheral Interface)的身影。原因是这两种通信协议非常适合近距离低速芯片间通信。Philips(for IIC)和Motorola(for SPI) 出于不同背景和市场需求

    04-30
  • 嵌入式面试注意事项

    找工作也是一门技能,有的人很快就找到自己喜欢的工作,有的人找了很久也没找到合适的工作。 下面给大家分享几点找工作过程中存在的“潜规则”内容。 1、面试的本质不是考试,而是告诉面试官你会做什么 经验不够的小伙伴特别容易犯的一个错误,不清楚面试官到

    04-29
  • 为什么需要RTOS?

    很多单片机初学者都是从裸机开始的,裸机确实也能开发出好的产品,但作为一个嵌入式软件工程师,如果只能用裸机开发产品,那肯定是不够的。 要从裸机的思维转变到RTOS的思维,其实需要一个过程,而且开始的一段时间会很痛苦。但过一段时间理解了一些内容,能

    04-28
  • 使用RTOS的8个理由

    嵌入式系统中,有很多方式实现任务调度。功能有限的小系统中,无限循环足够实现系统功能。当软件设计变得庞大且复杂时,设计师应该考虑使用实时操作系统。 下面给大家分享使用RTOS的8个理由: 1.硬实时响应 基于优先级抢占的RTOS,根据任务的实时需求,执行优

    04-26
  • 单片机延时程序,Keil C编译器实现

    应用单片机的时候,经常会遇到需要短时间延时的情况。需要的延时时间很短,一般都是几十到几百微妙(us)。有时候还需要很高的精度,比如用单片机驱动 DS18B20的时候,误差容许的范围在十几us以内,不然很容易出错。这种情况下,用计时器往往有点小题大做。而

    04-26
下载排行榜
更多
EE直播间
更多
广告
X
广告