本文将涵盖以下主题:F1C100s简介、Uboot、Linux内核裁剪定制,以及使用C或C++进行应用程序开发。我们还将提供两个示例:一个控制LED灯闪烁的简单示例,另一个创建带有按钮的GUI界面程序。
F1C100s 性能参数
F1C100s是一款低成本、低功耗的32位处理器,常用于嵌入式系统和物联网设备中。它具有ARM926EJ-S CPU架构、16KByte D-Cache、32KByte I-Cache和32MB DDR1 SIP内存。它支持H.264 1920x1080@30fps解码和MJPEG 1280x720@30fps编码。F1C100s是一款720P高清多媒体处理器。
F1C100s 参数如下:
USB OTG(USB On-The-Go)是一种规范,允许某些Android智能手机和平板电脑充当USB主机,以便您可以将其他USB外设(例如键盘或闪存驱动器)插入它们。USB OTG可以通过单个USB端口实现这种功能。USB连接通常从计算机(主机)开始并链接到另一个设备,通常是外围设备,例如打印机、鼠标、键盘或USB闪存驱动器。支持USB OTG的设备可以作为主机或外围设备。许多Android智能手机都支持USB OTG,包括较新的三星手机。有些安卓设备产品包装上是否有USB OTG标志,或者在设备设置中查找USB OTG信息。iOS设备不支持USB OTG,但有办法获得类似的功能并将USB设备连接到iPhone和iPad。
F1C100S处理器的框图如下:
F1C100s 对比全志自家其他芯片:
除内存参数外,F1C200s 与F1c100s 参数完全一样,但是 F1C200s 的内存是64M, F1C100s 是32M。
荔枝派(Lichee Pi) Nano 开发板的参数如下:
荔枝派 Nano 开发板引脚图如下:
荔枝派 Nano 长这样:
Linux 启动过程
一般的,嵌入式Linux 内核启动按先后顺序大概分为五部分:
ROM
SPL
U-Boot
Linux 内核
根文件系统
应用程序
1 ROM
第一阶段引导加载程序位于单片机的 ROM 中。ROM 代码是在器件启动时或上电复位 (POR) 后自动运行的第一个代码块。ROM 引导加载程序代码被硬编码到设备中,用户无法更改。
对于本文来说单片机就是指 F1C100s 这颗 SOC 芯片。
ROM代码有两个主要功能:
单片机的配置和主要外设的初始化,例如堆栈设置、配置看门狗定时器(有关详细信息,请参阅 TRM)以及 PLL 和系统时钟配置
通过检查下一阶段引导加载程序 (SPL) 的引导源以及将实际的下一阶段引导加载程序代码加载到内存中并启动它,为下一个引导加载程序做好准备
在设备上电之前,引导代码存放在两个地方之一。首先,ROM引导加载程序永久驻留在 CPU,无法修改。其次,引导镜像的所有其他部分(SPL和 U-boot 引导加载程序,以及Linux内核和文件系统)存储在非易失性存储器中(例如microSD卡或eMMC)。一旦设备上电,ROM引导加载程序将把第二阶段引导加载程序(即SPL)加载到CPU 内部存储器中。SPL将把第三阶段引导加载程序(即U-Boot的完整功能版本)加载到单片机内的DDR存储器中。最后,最后的引导加载程序阶段,即Linux内核,将被拉入DDR并执行。
2 SPL
第二阶段引导加载程序称为 SPL(辅助程序加载程序),但有时也称为 MLO(MMC 卡加载程序)。SPL 是 U-Boot 的第一阶段,必须从一个启动源加载到内部 RAM 中。SPL 的配置或用户交互非常有限,主要用于初始化外部 DDR 存储器并为下一个引导加载程序阶段:U-Boot 设置引导过程。
3 U-Boot
U-Boot允许通过串行终端对内核引导环境进行强大的基于命令的控制。用户可以控制诸如引导参数和内核引导命令等多个参数。此外,U-Boot环境变量也可以进行配置。这些环境变量存储在您的存储介质上的uEnv.txt文件中,或者如果配置了的话,直接存储在基于Flash的内存中。可以使用env print、env set和env save命令来查看、修改和保存这些环境变量。U-Boot还是一个非常有用的工具,可以编程和操作各种外部存储设备,同时也是在自定义板卡启动期间的有力辅助。
4 Linux kernel
zImage是压缩的内核镜像,包含描述内核的头部信息。此头部信息包括目标架构、操作系统、内核大小、入口点等。内核镜像的加载通常通过存储在U-Boot环境中的脚本来执行(所有脚本都以bootcmd ENV变量开头,在自动引导倒计时到期后执行,或者在U-Boot提示符处手动输入boot命令)
学历史不懂地理最多只能学会一半,学习 Linux 启动顺序也是一样,要知道各个模块的位置:
如何定制 U-Boot
U-Boot(Universal Bootloader)是嵌入式系统中常用的开源引导加载程序,定制 U-Boot 可以满足特定硬件需求,提高启动性能。以下是全志 F1C100s 上 U-Boot 定制的简单步骤,以及一个示例:
步骤 1:获取 U-Boot 源码
首先,从 U-Boot 官方仓库或全志官方资源中获取 F1C100s 对应版本的 U-Boot 源码。
git clone https://github.com/u-boot/u-boot.gitcd u-bootgit checkout -b f1c100s_branch origin/f1c100s_branch
步骤 2:配置交叉编译工具链
确保安装了适用于 F1C100s 的交叉编译工具链。根据您的需求,可以使用全志提供的或其他适用的工具链。
export CROSS_COMPILE=arm-linux-gnueabi-
步骤 3:配置 U-Boot
进入 U-Boot 源码目录,并使用 make 菜单配置工具。
make f1c100s_config
这将创建 .config
文件,其中包含了适用于 F1C100s 的默认配置。
步骤 4:定制配置
通过 make menuconfig
可以进一步配置 U-Boot,以满足您的特定需求。这个步骤允许您选择启用或禁用特定的功能和驱动,适应您的硬件环境。
make menuconfig
步骤 5:编译 U-Boot
使用 make 命令编译 U-Boot。
make
编译完成后,会生成 u-boot.bin
文件,这就是定制后的 U-Boot 可执行文件。
举个例子
作为示例,假设我们需要在 U-Boot 启动时输出一条自定义的欢迎消息。在 U-Boot 源码目录下的 include/configs/f1c100s.h
文件中添加如下定义:
#define CONFIG_SYS_EXTRA_OPTIONS "My custom welcome message!"
然后重新编译 U-Boot:
make
最后,将生成的 u-boot.bin
烧录到 F1C100s 目标设备中。
Linux 内核定制
Linux 内核是嵌入式系统中的核心组件,通过定制化可以适配特定的硬件需求和应用场景。以下是简单的 F1C100s Linux 内核定制步骤,以及一个示例:
步骤 1:获取 Linux 内核源码
从全志官方或其他适用的资源中获取 F1C100s 对应版本的 Linux 内核源码。
git clone https://github.com/linux-sunxi/linux-sunxi.gitcd linux-sunxigit checkout -b f1c100s_branch sunxi-4.14
步骤 2:配置交叉编译工具链
确保安装了适用于 F1C100s 的交叉编译工具链。这通常由全志或其他提供商提供。
export CROSS_COMPILE=arm-linux-gnueabi-
步骤 3:配置 Linux 内核
使用 make 菜单配置工具进行基本配置。
make sunxi_defconfig
这将创建 .config
文件,其中包含了适用于 F1C100s 的默认配置。
步骤 4:进一步定制配置
通过 make menuconfig
进一步配置 Linux 内核,以满足特定需求。
make menuconfig
步骤 5:编译 Linux 内核
使用 make 命令编译 Linux 内核。
make zImage
编译完成后,生成的 arch/arm/boot/zImage
文件即为编译好的内核镜像。
举个例子
作为示例,假设我们需要在 Linux 内核启动时输出一条自定义的欢迎消息。在 arch/arm/boot/dts/suniv-f1c100s.dts
文件中添加如下节点:
dtsCopy codechosen { bootargs-append = " my_custom_welcome_message";};
然后重新编译 Linux 内核:
make zImage
最后,将生成的内核镜像 zImage
烧录到 F1C100s 目标设备中。
点灯
接下来,让我们深入了解如何通过编写 C 语言程序来控制 LED 灯的闪烁。首先,我们需要了解如何初始化和控制 GPIO。
Linux 系统上层控制 GPIO 有很多种方法:
- shell 脚本
- Python 编程
- C 语言编程控制
以上只列出了常见三种还有其他的,Linux 山头多呀,不像 Windows 。
本文通过 C 语言进行编程控制。
以下是一个简单的例子,假设我们使用 GPIO0 引脚连接了一个 LED 灯:
#include <stdio.h>#include <wiringPi.h> // 使用 wiringPi 库来进行 GPIO 控制#define LED_PIN 0 // 假设 LED 连接到 GPIO0int main() { if (wiringPiSetup() == -1) { printf("Failed to initialize wiringPi.\n"); return 1; } pinMode(LED_PIN, OUTPUT); // 将 GPIO0 设置为输出模式 while (1) { digitalWrite(LED_PIN, HIGH); // 点亮 LED delay(1000); // 延迟1秒 digitalWrite(LED_PIN, LOW); // 关闭 LED delay(1000); // 延迟1秒 } return 0;}
这个简单的程序使用了 wiringPi 库,它是一个用于树莓派和其他嵌入式系统的 GPIO 控制库。在这个例子中,我们初始化了 wiringPi,并将 GPIO0 设置为输出模式。然后,我们使用一个无限循环来交替点亮和关闭 LED,每个状态维持1秒。
简单 GUI 界面应用举例
接下来,我们将介绍一个简单的 GUI 界面程序的例子,其中包含一个按钮,按下按钮后将弹出一个消息框,上面写着 "Hello World!"。
Linux GUI 应用开发需要使用 GUI 开发库,例如 GTK 或 Qt。由于篇幅有限,我们将使用 GTK 作为例子。还有一种新兴的开发 Linux GUI 应用的新方式:LVGL,本文不做介绍。
首先,确保你的系统中安装了 GTK 开发库。下面是一个简单的 GTK C 语言程序的示例代码:
#include <gtk/gtk.h>// 回调函数,用于处理按钮点击事件static void button_clicked(GtkWidget *widget, gpointer data) { GtkWidget *dialog; // 创建一个消息框 dialog = gtk_message_dialog_new(GTK_WINDOW(data), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Hello World!"); // 运行消息框并等待用户响应 gtk_dialog_run(GTK_DIALOG(dialog)); // 关闭消息框 gtk_widget_destroy(dialog);}int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *button; // 初始化 GTK gtk_init(&argc, &argv); // 创建主窗口 window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(window), "GTK Hello World"); gtk_container_set_border_width(GTK_CONTAINER(window), 10); // 创建按钮 button = gtk_button_new_with_label("Click Me!"); // 将按钮添加到主窗口 gtk_container_add(GTK_CONTAINER(window), button); // 连接按钮点击事件到回调函数 g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), (gpointer)window); // 显示所有窗口部件 gtk_widget_show_all(window); // 运行 GTK 主循环 gtk_main(); return 0;}
这个程序首先创建了一个主窗口,然后在窗口中添加了一个按钮。通过连接按钮的点击事件到回调函数 button_clicked
,我们实现了按钮点击后弹出消息框的效果。
总结
本文简要总结如下:
硬件参数介绍:
F1C100s 是一款基于 ARM926EJ-S 架构的单核处理器,主频可达 900MHz。
集成了多种外设接口,包括 GPIO、UART、SPI 等,适用于嵌入式系统和物联网应用。
U-Boot 和 Linux 内核裁剪定制:
- 使用 U-Boot 进行启动加载程序的裁剪,以适应特定硬件需求和提高启动性能。
- 利用 Linux 内核裁剪工具,如
make menuconfig
,选择性地启用或禁用内核功能和驱动,以减小内核体积和提高系统响应速度。
上层应用开发介绍:
- 使用 C 或 C++ 语言编写应用程序与裁剪后的 Linux 内核进行交互。
- 示例中演示了通过 GPIO 控制 LED 灯的闪烁,利用 wiringPi 库简化 GPIO 操作。
GUI 界面程序示例:
- 使用 GTK 开发库创建一个简单的 GUI 界面程序,包含一个按钮。
- 按钮点击时触发回调函数,弹出消息框显示 "Hello World!"。
以上例子涵盖了软硬件研发的多个方面,从底层的启动加载程序和内核裁剪,到上层的应用开发和图形界面设计。这些步骤为全志 F1C100s 的开发提供了一个基本的框架,仅为抛砖引玉之作,愿您在嵌入式 Linux 这条大道上向着诗和远方,一路狂奔!