微控制器制造商的开发板, 以及他们与开发板一起提供的软件项目例程, 在工程师着手一个新设计时可以提供很大帮助. 但在设计项目完成其早期阶段后, 进一步设计时, 制造商提供的软件也可能会导致一些问题.
微控制器制造商的开发板, 以及他们与开发板一起提供的软件项目例程, 在工程师着手一个新设计时可以提供很大帮助. 但在设计项目完成其早期阶段后, 进一步设计时, 制造商提供的软件也可能会导致一些问题.
使用实时操作系统作为应用程序代码平台的设计还面临着许多挑战, 比如如何将功能分配给不同的并行任务, 如何设计高可靠的进程间通信, 以及如何在硬件上测试整个软件包等问题.
越来越多的 OEM 厂商发现, 避免上述两个问题的最好方式, 是使用基于开源, 经过验证, 可扩展, 可运行在不同硬件平台的操作系统 Linux 开始新的设计. 就已经被移植到各种计算机硬件平台的操作系统的数量来说, Linux 首屈一指. Linux 的衍生版本已运行在非常广泛的嵌入式系统中, 包括: 网络路由器, 移动电话, 建筑自动化控制, 电视机和视频游戏控制台.
虽然 Linux 被成功使用, 但并不意味着它很容易使用. Linux 包含的代码超过一百万行, 其运作带有鲜明的 Linux 方法论味道, 初学者可能难以迅速掌握.
因此, 本文的主旨是为使用 Linux 的嵌入式操作系统版本 --μClinux, 开始一个新的设计项目, 该指南共分为五个步骤. 为了说明该指南, 本文介绍了在意法半导体的 STM32F429 微控制器 (ARM Cortex-M4 内核, 最高 180MHz) 上的一个μClinux 项目实现, 使用了 Emcraft 的 STM32F429 Discovery Linux 板支持包(BSP).
步骤 1:Linux 工具和项目布局
每个嵌入式软件设计都从选择合适的工具开始.
工具链是一组连接 (或链接) 在一起的软件开发工具, 它包含诸如 GNU 编译器集合 (GCC),binutils(一组包括连接器, 汇编器和其它用于目标文件和档案工具的开发工具) 和 glibc(提供系统调用和基本函数的 C 函数库)等组件; 在某些情况下, 还可能包括编译器和调试器等其它工具.
用于嵌入式开发的工具链是一个交叉工具链, 更常见的叫法是交叉编译器.
GNU Binutils 是嵌入式 Linux 工具链的第一个组件. GNU Binutils 包含两款重要工具:
"as", 汇编器, 将汇编代码 (GCC 所生成) 转换成二进制代码
"ld", 连接器, 将离散目标代码段连接到库或形成可执行文件
编译器是工具链的第二个重要组成部分. 在嵌入式 Linux, 它被称为 GCC, 支持许多种微控制器和处理器架构.
接下来是 C 函数库. 它实现 Linux 的传统 POSIX 应用编程接口(API), 该 API 可被用来开发用户空间应用. 它通过系统调用与内核对接, 并提供高阶服务.
工程师有几种 C 函数库选择:
glibc 是开源 GNU 项目提供的可用 C 函数库. 该库是全功能, 可移植的, 它符合 Linux 标准.
嵌入式 GLIBC(EGLIBC)是一款针对嵌入式系统优化的衍生版. 其代码是精简的, 支持交叉编译和交叉测试, 其源代码和二进制代码与 GLIBC 的兼容.
uClibc 是另一款 C 函数库, 可在闪存空间有限, 和 / 或内存占用必须最小的情况下使用.
调试器通常也是工具链的一部分, 因为在目标机上调试应用程序运行时, 需要一个交叉调试器. 在嵌入式 Linux 领域, GDB 是常用调试器.
上述工具是如此地不可或缺, 但当它们各自为战时, 会花太长时间来编译 Linux 源代码并将其整合成最终映像 (image). 幸运的是, Buildroot(自动生成交叉编译工具的工具) 会自动完成构建一个完整嵌入式系统的过程, 并通过产生下述任一或所有任务, 简化了交叉编译:
交叉编译工具链
根文件系统
内核映像
引导映像
对嵌入式系统设计师来说, 还可以方便地使用一种工具 (utility) 聚合工具, 如 BusyBox, 这种工具将通常最需要的工具整合在一起. 根据 BusyBox 的信息页面介绍,"它将许多常用 UNIX 工具的微型版本整合成一个小的可执行文件. 它提供了对大多数你通常会在 GNU fileutils 和 shellutils 等工具中看到的工具的替代. BusyBox 里的工具通常比其全功能 GNU 对应版本的选择少; 但所包含选项所提供的预期功能和行为则与对应的 GNU 所提供的几无差别. 对任何小或嵌入式系统来说, BusyBox 提供的环境都是相当完整的."
最后一个重要工具是一款 BSP, 是为搭载了项目目标 MCU 或处理器的主板专门做的.
BSP 包括预先配置的工具, 以及将操作系统加载到主板的引导加载程序. 它还为内核和器件驱动器提供源代码(见图 1).
图 1: 用于 STM32F429 Discovery 板的 Emcraft BSP 的主要部件.
步骤 2: 引导序列, 时钟系统, 存储器和串行接口
典型的嵌入式 Linux 启动顺序执行如下:
1)引导加载程序固件 (示例项目里的 U-Boot) 运行于目标 MCU 内置闪存 (无需外部存储器), 并在上电 / 复位后, 执行所有必需的初始化工作, 包括设置串口和用于外部存储器(RAM) 访问的存储器控制器.
2)U-Boot 可将 Linux 映像从外部 Flash 转移到外部 RAM, 并将控制交接到 RAM 中的内核入口点. 可压缩 Linux 映像以节省闪存空间, 代价是在启动时要付出解压缩时间.
3)Linux 进行引导并安装基于 RAM 的文件系统 (initramfs) 作为根文件系统. 在项目构建时, Initramfs 被填充以所需的文件和目录, 然后被简单地链接到内核.
4)在 Linux 内核下, 执行 / sbin/init./sbin/init 程序按照 / etc/inittab 中配置文件的描述对系统进行初始化.
5)一旦初始化进程完成运行级执行和 / sbin/init 里的命令, 它会启动一个登录进程.
6)壳初始化文件 / etc/profile 的执行, 标志着启动过程的完成.
通过使能就地执行 (Execute In Place--XIP) 可以显著缩短启动时间, 提升整体性能, XIP 是从闪存执行代码的方法. 通常, Linux 代码是从闪存加载到外部存储器, 然后从外部存储器执行. 通过从闪存执行, 因不再需复制这步, 从而只需较少的存储器, 且只读存储器不再占程序空间.
本文的示例项目基于 STM32F429 MCU. 事实上, 用户可能会发现, 开始时, STM32F4 系列 MCU 的外设初始化不容易掌握. 幸运的是, 意法半导体开发了一些工具来帮助解决这一问题. STM32CubeMX 初始化代码生成器 (部件编号 UM1718) 属于最新的. 该工具包括外设初始化的每一个细节, 在配置外设时, 会显示警告和错误, 并警告硬件冲突.
对小型嵌入式 Linux 项目来说, STM32F429 MCU 内部闪存足够用. 重要的是要记住: 嵌入式 Linux 项目中使用多个二进制映像(引导加载程序, Linux 内核和根文件系统): 这些都需要闪存扇区边界对齐. 这就避免了在装载一个图像时, 另一图像被部分删除或损坏的风险.
步骤 3: 在主机上安装 Linux
要构建一个嵌入式 Linux 项目, 一台 Linux 主机是必需的. 对于 Windows PC, 最好是安装 Oracle VirtualBox, 以创建 "一台"512Mbyte RAM 和 16Gbyte 硬盘的新虚拟机.
有许多 Linux 版本可用; 据笔者的经验, Debian 就是与 VirtualBox 环境相匹配的一款. 这款 Linux 主机必须能够访问互联网, 以便下载针对这款 ARM Cortex-M 目标 MCU 的 GNU 交叉编译工具. 设计师将创建一个类似于图 1 所示的树形结构, 并将交叉构建工具提存到 / tools 文件夹.
在这点上, 有必要建立一个 ACTIVATE.sh 脚本. 只需使用下列代码就可实现.(<......>是提取到的 GNU 工具文件夹路径):
- export INSTALL_ROOT=<.......>
- export PATH=$INSTALL_ROOT/bin:$PATH
- export CROSS_COMPILE=arm-uclinuxeabiexport
- CROSS_COMPILE_APPS=arm-uclinuxeabiexport
- MCU=STMDISCO
- export ARCH=arm
在干净的 Linux 系统中安装 GNU 工具, 但其使用并非自给自足, 实际上还需要其它系统的配合. 其运行实际上依赖于若干其它系统组件(如主机 C/C++ 编译器, 标准 C 函数库头文件, 以及一些系统工具). 获得这些必要组件的一种方法是安装用于 C 的 Eclipse 集成开发环境(IDE). 除解决这个迫在眉睫的问题外, Eclipse IDE 还可在开发过程中的许多其它方面提供帮助, 当然, 详述 Eclipse IDE 的特性不是本文目的.
现在, 是时候启用 Linux 终端工具了: 点击 "应用程序(Applications)", 然后 "附件(Accessories)" 和 "终端(Terminal)"(见图 2).
图 2:Linux 包含的 "终端(Terminal)" 工具和 "文件(Files)", 一种类似 Windows 资源管理器的图形化工具.
终端是用于配置 Linux 主机和构建嵌入式 Linux 应用程序的主要工具. 键入以下命令来安装 Eclipse 和其它所需工具:
su [输入根用户密码]
- apt-get install eclipse-cdt
- apt-get install genromfs
- apt-get install libncurses5-dev
- apt-get install git
- apt-get install mc
准备该 Linux 项目的最后一步是下载 STM32F429 Discovery Buildroot, 并解压到 / uclinux 文件夹.
步骤 4: 用 Buildroot 构建μClinux
现在有必要关闭先前使用根用户配置文件的终端, 并启动一个新终端. 在命令行中输入 "mc", 并使用导航器导航到 "Documents", 然后输入 "uClinux" 命令. 按 Ctrl+O 并激活 Linux ARM Cortex-M 开发部分, 并运行 ".ACTIVATE.sh" 命令. 再次按下 Ctrl+O 并进入 "stm32f429-linux-builder-master" 文件夹.
用户现在有两个选择. 如果使用 VirtualBox 中的示例项目, 请遵循 "make clean" 和 "make all" 命令序列. 如果准备一个全新环境, 使用 "make" 命令. 约 30 分钟后, 新的μClinux 映像将可用, 如下所示:
- out\uboot\u-boot.bin
- out\kernel\arch\arm\boot\ xipuImage.bin
- out\romfs.bin
将这些新映像写入闪存. 如果使用 Windows 和 ST-LINK 工具, 下面的代码将工作:
ST-LINK_CLI.exe -ME
ST-LINK_CLI.exe -P "u-boot.bin" 0x08000000
ST-LINK_CLI.exe -P "xipuImage.bin" 0x08020000
ST-LINK_CLI.exe -P "romfs.bin" 0x08120000
将串行调试器 (serial console) 连接到目标电路板(外部 RX=>PC10, 外部 TX=>PC11,115200bits/s,8 个数据位, 无奇偶校验, 1 个停止位模式), 然后按下复位按钮, 该μClinux 项目将启动运行. 开机输出将显示在串行调试器上, 显示屏将出现 Linux 的企鹅标识.
步骤 5: 创建 "你好, 世界" 应用
现在, 按照代码示例和下面的说明, 将一个用户应用添加到μClinux 项目中.
创建:"stm32f429-linux-builder-master/user/src/hello.c" 文件:
- #include
- int main() {
- printf("Hello, world\n");
- return 0;
- }
必要时使用 Tab 键, 创建:"stm32f429-linux-builder-master/user/Makefile" 文件:
- CC = $(CROSS_COMPILE)gcc
- LDFLAGS ?=$(CFLAGS)
- target_out ?= out
- all: checkdirs
- [Tab] $(CC) $(LDFLAGS) src/hello/hello.c -o $(target_out)/bin/
- hello $(LDLIBS)
- [Tab] -rm -rf $(target_out)/bin/*.gdb
- checkdirs:
- [Tab] mkdir -p $(target_out)/bin
- clean:
- [Tab] -rm -rf $(target_out)
通过 activate.sh 脚本, 在不激活交叉编译环境下, 在主机测试 "Hello, world" 这个应用.
在 / user 文件夹下, 输入:
- make all
- ./out/bin/hello
为将 hello.c 嵌入到 Linux Buildroot 里的脚本, 修改 mk/rootf.mak 文件, 必要时, 使用 Tab 键.(粗体字表示新行开始处):
- . . .
- user_hello:
- [Tab] make -C $(user_dir) CROSS_COMPILE=$(CROSS_
- COMPILE) CFLAGS=$(ROOTFS_CFLAGS) target_
- out=$(target_out_user)
- $(rootfs_target): $(rootfs_dir) $(target_out_busybox)/.config
- user_hello
- [Tab] cp -af $(rootfs_dir)/* $(target_out_romfs)
- [Tab] cp -f $(target_out_kernel)/fs/ext2/ext2.ko $(target_out_romfs)/lib/modules
- [Tab] cp -f $(target_out_kernel)/fs/mbcache.ko $(target_out_romfs)/lib/modules
- [Tab] cp -f $(target_out_user)/bin/* $(target_out_romfs)/usr/bin
- ...
需对 mk/defs.mak 文件做最后修改. 加入以下几行:
- . . .
- user_dir := $(root_dir)/user
- target_out_user := $(target_out)/user
- user_dir := $(root_dir)/user
- target_out_user := $(target_out)/user
一旦在目标 MCU 上建成, 下载并运行映像, 就可在 / usr/bin 目录中找到该应用程序以及其它已有的应用程序. 在连接到 Discovery 板的终端上键入 "hello[回车]", 可对该应用进行测试.
来源: http://os.51cto.com/art/201805/571965.htm