构建自己的embedded linux系统

[教程]使用buildroot完全自定义自己的embedded linux系统(nand)
http://www.eeboard.com/bbs/thread-38377-1-1.html

 

[教程] [教程]使用buildroot完全自定义自己的embedded linux系统(nand)

 

ubuntu, fedora, debian太过庞大了,你是否想完完全全的构建自己的embedded linux系统?本篇文章教你如何实现

编译环境:
ubuntu 12.04(x86_64)

目标环境:
1) linux-3.4内核
2) buildroot 2013-02
3)系统运行在nand上

固件制作步骤说明:
步骤一:创建自己的工作目录
$mkdir ~/mylinux
$cd ~/mylinux

步骤二:获取源代码
$git clone git://github.com/cubieboard/sunxi-tools.git tools
$git clone git://github.com/cubieboard/u-boot-sunxi.git u-boot
$git clone git://github.com/cubieboard/buildroot-sunxi.git buildroot
$git clone git://github.com/cubieboard/linux-sunxi.git linux-3.4

步骤三:切换到sunxi-3.4-cb分支
$cd tools
$git checkout -b sunxi-3.4-cb origin/sunxi-3.4-cb
$cd -
$cd u-boot
$git checkout -b sunxi-3.4-cb origin/sunxi-3.4-cb
$cd -
$cd buildroot
$git checkout -b sunxi-3.4-cb origin/sunxi-3.4-cb
$cd -
$cd linux-3.4
$git checkout -b sunxi-3.4-cb origin/sunxi-3.4-cb
$cd -

步骤四:编译并生成固件
$cd ~/mylinux
$tools/build.sh
漫长的编译完成后,在toosl/pack下面生成了一个100多M的固件

步骤五:
1)启动livesuit,并选中刚生成的固件
2)准备好一块cubieboard,按住micro USB口下面的烧写键,然后插入usb线,等3秒左右,松开按键,进入烧写模式

简易教程已经写完,后续里面各个部分如何定制,以及相关的原理会不断的补充上来,欢迎大家尝试并提出意见

教程二. 定制buildroot

$cd ~/mylinux/buildroot
$make cubieboard_defconfig
$make menuconfig

进入了如下的界面


通过上下左右,空格+返回选中要增加的软件包,定制完成后退出
把新的配置保存下来
$cp .config configs/cubieboard_defconfig

做完后就可以重新运行tools/build.sh重新生成固件了。有一点需要注意的,不要进到tools目录下运行build.sh脚本,必须在~/mylinux目录下,运行tools/build.sh

如果你还想进一步的定制你的文件系统,可以研究下board/cubieboard下面的skel以及scripts脚本,也可以上buildroot的官方网站查看他们的帮助文档

教程三 定制nand分区

1)当前分区情况说明
我们知道, cubieboard上的nandflash的容量是4GB。
当前nand的分区情况可以看~/mylinux/tools/pack/chips/sun4i/configs/linux/default/下面的sys_config.fex文件,如下面所示

[part_num]
num     = 4
[partition0]
    class_name  = DISK
    name        = bootloader
    size_hi     = 0
    size_lo     = 32768
    user_type   = 0
    ro          = 0
[partition1]
    class_name  = DISK
    name        = env
    size_hi     = 0
    size_lo     = 16384
    user_type   = 0
    ro          = 0
[partition2]
    class_name  = DISK
    name        = boot
    size_hi     = 0
    size_lo     = 16384
    user_type   = 0
    ro          = 0
[partition3]
    class_name  = DISK
    name        = rootfs
    size_hi     = 0
    size_lo     = 524288
    user_type   = 0
    ro          = 0


num= 4表示分为4个分区,每个分区的容量由size_lo指定,以1KB为单位。需要注意的是,如果4个分区的容量没有用完4GB(我们的nandflash 是4GB),则烧写的时候会自动添加一个分区,用完所有的nand容量。我们进入linux系统,看一下系统中的分区,如下:
[root@linux ~]# ls -l /dev/nand*
brw-------    1 root     root       93,   0 Jan  1  1970 /dev/nand
brw-------    1 root     root       93,   1 Jan  1  1970 /dev/nanda
brw-------    1 root     root       93,   2 Jan  1  1970 /dev/nandb
brw-------    1 root     root       93,   3 Jan  1  1970 /dev/nandc
brw-------    1 root     root       93,   4 Jan  1  1970 /dev/nandd
brw-------    1 root     root       93,   5 Jan  1  1970 /dev/nande


其中/dev/nand表示的是整个nand设备,容量是4GB,nanda,nandb,nandc,nandd是sys_config.fex中配置 的分区,nande是系统计算剩余容量自动创建的。在使用livesuit烧写的时候,每个用户分区要烧写的镜像也是在sys_config.fex中指 定的,如下

[down_num]
down_num    = 4

[download0]
part_name   = bootloader
pkt_name    = BOOTLOADER_00000
encrypt     = 0

[download1]
part_name   = env
pkt_name    = ENVIROMENT_00000
encrypt     = 0

[download2]
part_name   = boot
pkt_name    = KERNEL_000000000
encrypt     = 0

[download3]
part_name   = rootfs
pkt_name    = ROOTFS_000000000
encrypt     = 0


比如前面的bootloader分区,它的索引名是BOOTLOADER_00000,在相同目录下的image.cfg中找到下面一行
{filename = "bootloader.fex",   maintype = ITEM_ROOTFSFAT16,  subtype = "BOOTLOADER_00000",},

从上面我们可以发现,bootloader区下载的是bootloader.fex文件,我们可以仔细研究tools/pack/pack脚本,发现 bootloader.fex是fsbuild命令工具创建的一个fat16的文件镜像,它们内容来源于~/mylinux/tools/pack /chips/sun4i/wboot/bootfs。同理,其他的分区文件也可以这样分析。

2)修改指定分区容量大小
这里举个简单的例子,把nandd(也就是我们linux的根分区)容量从原来的512MB调整到2GB
,只需要在sys_config.fex的
[partition3]
    class_name  = DISK
    name        = rootfs
    size_hi     = 0
    size_lo     = 524288
    user_type   = 0
    ro          = 0

改为
[partition3]
    class_name  = DISK
    name        = rootfs
    size_hi     = 0
    size_lo = 2057152
    user_type   = 0
    ro          = 0


然后重修执行tools/build.sh,烧写完进入系统,nandd的容量就变成2GB了。

教程四 裁剪linux内核

其实同裁剪buildroot。命令如下

$cd ~/mylinux/linux-3.4
$cp arch/arm/configs/cubieboard_defconfig .config
$make ARCH=arm menuconfig (注意:不要漏了ARCH=arm)
执行完上面的命令后,则进入经典的NCURSE界面,选上自己喜欢的驱动后,退出,再把新的配置文件保存
$cp .config arch/arm/configs/cubieboard_defconfig


最后在回到mylinux目录,执行tools/build.sh即可。如果需要增加自己的驱动,建议加入到kernel的目录树中,可以参考 linux-3.4/Documentation/kbuild/kconfig-language.txt,有时间研究的话,可以学到很多东西。同时建 议新人好好看一看linux-3.4/Documentation/CodingStyle。

教程五 红外控制例子

在做好自己的系统后,下面我们写一个简单的红外控制计算机的例子(具体控制需要自己实现,这里是一个demo)
a)烧写完linux,上电
b)使用root(密码cubieboard)登录
c)连上以太网线
d)挂载开发机
$udhcpc  (自动配置ip)
$mount.cifs //192.168.1.2/share /mnt -o user=build (假设我的开发主机是192.168.1.2,并有一个共享目录share
e)写一段小代码,如下
//ir-demo.c,我直接放到share目录下
//arm-linux-gnueabihf-gcc -static -o ir-demo ir-demo.c
#include <stdio.h>
#include <stdint.h>
#include <linux/input.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <limits.h>
#include <sys/errno.h>

#ifndef EV_SYN
#define EV_SYN 0
#endif

#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x)  ((x)%BITS_PER_LONG)
#define BIT(x)  (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)

#define EVENT_SIZE  ( sizeof (struct inotify_event) )

int main (int argc, char **argv)
{
    int fd, rd, i;
    struct input_event ev[64];
    int version;
    unsigned short id[4];
    unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
    char name[256] = "Unknown";
    int abs[5];

    if (argc < 2) {
        printf("Usage: ir-runner /dev/input/eventX\n");
        return 1;
    }

    if ((fd = open(argv[argc - 1], O_RDONLY)) < 0) {
        perror("evtest");
        return 1;
    }

    ioctl(fd, EVIOCGNAME(sizeof(name)), name);
    printf("Input device name: \"%s\"\n", name);

    daemon(0, 1);

    while (1) {
        rd = read(fd, ev, sizeof(struct input_event) * 64);

        if (rd < (int) sizeof(struct input_event)) {
            perror("\nir: error reading");
            return 1;
        }

        for (i = 0; i < rd / sizeof(struct input_event); i++) {
            printf("code=%d, type=%d, value=%d\n", ev.code,
                   ev.type, ev.value); //可以在这里根据不同的code值执行不同的程序,可以用system系统调用
        }
    }

    close(fd);
    return 0;
}

f) 运行测试程序
#insmod /lib/modules/3.4.29+/kernel/drivers/input/keyboard/sun4i-ir.ko
此时打印提示是event1设备。
#/mnt/ir-demo /dev/input/event1
这个时候按遥控键就有反应了。如果配上LED灯或者GPIO就更佳了。


简化了下前面红外测试代码,并提交到github.com/cubieboard/buildroot-sunxi.git

commit 9d0aaa64c5bd034f1f53dd5889f7a77af0da40fd
Author: matson <matson@cubietech.com>
Date:   Sat Apr 27 11:20:55 2013 +0800

    cubieboard: add cb_tools package
    Add ir-daemon example program. This allow you to trigger some other program via IR module. The instructions to do this are:
    1. After system startup, insmod sunxi-ir.ko module
    2. run 'ir-daemon'
    3. Add a hook script or program, and the full name should be '/tools/ir-hook'
   
    when you push the IR key, ir-daemon will start '/tools/ir-hook', pass the keycode and value to '/tools/ir-hook'

diff --git a/configs/cubieboard_defconfig b/configs/cubieboard_defconfig
index 82deac0..68bcb41 100644
--- a/configs/cubieboard_defconfig
+++ b/configs/cubieboard_defconfig
@@ -1,6 +1,6 @@
#
# Automatically generated make config: don't edit
-# Buildroot 2013.02-dirty Configuration
+# Buildroot 2013.02-00001-g49408af-dirty Configuration
#
BR2_HAVE_DOT_CONFIG=y
BR2_HOSTARCH_NEEDS_IA32_LIBS=y
@@ -988,6 +988,7 @@ BR2_PACKAGE_UTIL_LINUX_LIBBLKID=y
# BR2_PACKAGE_UTIL_LINUX_LOGIN_UTILS is not set
# BR2_PACKAGE_UTIL_LINUX_WRITE is not set
# BR2_PACKAGE_DSP_TOOLS is not set
+BR2_PACKAGE_CB_TOOLS=y

#
# Text editors and viewers
diff --git a/package/Config.in b/package/Config.in
index faee5c3..6aba157 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -800,6 +800,7 @@ source "package/supervisor/Config.in"
source "package/systemd/Config.in"
source "package/util-linux/Config.in"
source "package/dsp-tools/Config.in"
+source "package/cb_tools/Config.in"
endmenu

menu "Text editors and viewers"
diff --git a/package/cb_tools/Config.in b/package/cb_tools/Config.in
new file mode 100644
index 0000000..67943e9
--- /dev/null
+++ b/package/cb_tools/Config.in
@@ -0,0 +1,5 @@
+config BR2_PACKAGE_CB_TOOLS
+        bool "cb_tools"
+        help
+          tools for cubieboard
+
diff --git a/package/cb_tools/cb_tools.mk b/package/cb_tools/cb_tools.mk
new file mode 100644
index 0000000..20a7ffe
--- /dev/null
+++ b/package/cb_tools/cb_tools.mk
@@ -0,0 +1,28 @@
+CB_TOOLS_DIR := $(BUILD_DIR)/cb_tools
+
+$(CB_TOOLS_DIR)/.source :
+        mkdir -pv $(CB_TOOLS_DIR)
+        cp -rf package/cb_tools/src/* $(CB_TOOLS_DIR)
+        touch $@
+
+$(CB_TOOLS_DIR)/.configured : $(CB_TOOLS_DIR)/.source
+        touch $@
+
+
+cb_tools-binary: $(CB_TOOLS_DIR)/.configured
+        $(MAKE) CC="$(TARGET_CC)" -C $(CB_TOOLS_DIR)
+
+
+cb_tools: cb_tools-binary
+        $(MAKE) DESTDIR="$(TARGET_DIR)" -C $(CB_TOOLS_DIR) install
+        rm -rf $(CB_TOOLS_DIR)/.source $(CB_TOOLS_DIR)/.configured
+
+
+##############################################################
+#
+# Add our target
+#
+#############################################################
+ifeq ($(BR2_PACKAGE_CB_TOOLS),y)
+TARGETS += cb_tools
+endif
diff --git a/package/cb_tools/src/Makefile b/package/cb_tools/src/Makefile
new file mode 100644
index 0000000..f70f181
--- /dev/null
+++ b/package/cb_tools/src/Makefile
@@ -0,0 +1,26 @@
+
+#CROSS_COMPILE?=arm-linux-gnueabihf-
+#CC=$(CROSS_COMPILE)gcc
+#LD=$(CROSS_COMPILE)ld
+
+#ifneq "CROSS_SYSROOT" ""
+#CROSS_SYSROOT=$(shell cd ../../../../out/br/staging; pwd)
+#endif
+
+#CFLAGS+=--sysroot=$(CROSS_SYSROOT)
+
+ir-daemon:ir-daemon.c
+        $(CC) $(CFLAGS) -o ir-daemon -lsysfs ir-daemon.c
+
+
+all: ir-daemon
+
+install:
+        install ir-daemon  $(DESTDIR)/bin
+
+clean:
+        rm -rf *.o ir-daemon
+
+.PHONY: all clean
+
+
diff --git a/package/cb_tools/src/ir-daemon.c b/package/cb_tools/src/ir-daemon.c
new file mode 100644
index 0000000..76a58c9
--- /dev/null
+++ b/package/cb_tools/src/ir-daemon.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <linux/input.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/inotify.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <sys/errno.h>
+#include <sysfs/dlist.h>
+#include <sysfs/libsysfs.h>
+
+#define SUNXI_IR_NAME "sun4i-ir"
+#define HOOK_PROGRAM "/tools/ir-hook"
+
+int get_sunxi_ir_device(char *buf_name, size_t buf_len)
+{
+        struct sysfs_class *input_class = NULL;
+        struct dlist *input_devices = NULL;
+        struct sysfs_class_device *cls_dev = NULL;
+        struct sysfs_device *tdev = NULL;
+        struct sysfs_attribute *tattr = NULL;
+        int ret = -1;
+
+        input_class = sysfs_open_class("input");
+        input_devices = sysfs_get_class_devices(input_class);
+
+        dlist_for_each_data(input_devices, cls_dev, struct sysfs_class_device) {
+                tdev = sysfs_get_classdev_device(cls_dev);
+                if (tdev != NULL) {
+                        tattr = sysfs_get_device_attr(tdev, "name");
+                        if (tattr == NULL)
+                                continue;
+                        if (tattr->value == NULL)
+                                continue;
+
+                        if (strncmp(tattr->value, SUNXI_IR_NAME, 8)) {
+                                continue;
+                        }
+                        memset(buf_name, buf_len, 0);
+                        strncpy(buf_name, cls_dev->name, buf_len - 1);
+                        ret = 0;
+
+                }
+        }
+
+        sysfs_close_class(input_class);
+        return ret;
+}
+
+
+int main (int argc, char **argv)
+{
+        int fd, rd, i, ret;
+        struct input_event ev[64];
+        char name_buf1[128];
+        char name_buf2[128];
+
+        ret = get_sunxi_ir_device(name_buf1, sizeof(name_buf1));
+        if (ret) {
+                printf("Please insmod sunxi-ir.ko\n");
+                return -1;
+        }
+
+        memset(name_buf2, sizeof(name_buf2), 0);
+        snprintf(name_buf2, sizeof(name_buf2), "/dev/input/%s", name_buf1);
+
+        printf("ir: %s\n", name_buf2);
+
+        if ((fd = open(name_buf2, O_RDONLY)) < 0) {
+                perror("evtest");
+                return 1;
+        }
+
+        daemon(0, 1);
+
+        while (1) {
+                rd = read(fd, ev, sizeof(struct input_event) * 64);
+
+                if (rd < (int) sizeof(struct input_event)) {
+                        perror("read");
+                        return 1;
+                }
+
+                for (i = 0; i < rd / sizeof(struct input_event); i++) {
+                        if (ev.type == 1) {
+                                if (ev.value == 1) {
+                                        printf("IR: %d DOWN\n", ev.code);
+                                } else {
+                                        printf("IR: %d UP\n", ev.code);
+                                }
+                                if (!access(HOOK_PROGRAM, X_OK)) {
+                                        memset(name_buf1, sizeof(name_buf1), 0);
+                                        snprintf(name_buf1, sizeof(name_buf1), "%s %d %d",
+                                                 HOOK_PROGRAM, ev.code, ev.value);
+                                        system(name_buf1);
+                                }
+                        }
+                }
+        }
+
+        close(fd);
+        return 0;
+}

编出固件后,在/tools/下面添加ir-hook程序或者脚本就可以了。ir-daemon在收到信号后,会启动/tools/ir-hook,并把code, value作为$1 $2参数传递给它。这样就可以通过红外控制各种东西了。


刚刚更新了linux-sunxi和tools-sunxi,把ir, leds默认编译进linux内核,gpio编译成模块。所以现在取最新的代码,然后添加下面的脚本,就可以红外控制灯了。理论上控制gpio也是一样 的,但记得要加载驱动,并且运行ir-daemon

cat /tools/ir-hook
#!/bin/bash

if [ "$2" -eq "1" ]; then
if cat /sys/class/leds/blue\:ph21\:led2/brightness|grep 1
then
echo 0 > /sys/class/leds/blue\:ph21\:led2/brightness
else
echo 1 > /sys/class/leds/blue\:ph21\:led2/brightness
fi

fi

使用红外控制gpio灯的例子。用了cubieboard的面包板

脚本如下
cat /tools/ir-hook
#!/bin/bash

if [ "$2" -eq "0" ]; then
        exit 0
fi

if ! ls /sys/class/gpio |grep gpio30
then
        echo "export 30, 31"
        echo 30 > /sys/class/gpio/export
        echo 31 > /sys/class/gpio/export
        echo out > /sys/class/gpio/gpio30_pd2/direction
        echo out > /sys/class/gpio/gpio31_pd1/direction
fi

if cat /sys/class/gpio/gpio31_pd1/value |grep 1
then
        echo 0 > /sys/class/gpio/gpio30_pd2/value
        echo 0 > /sys/class/gpio/gpio31_pd1/value
else
        echo 0 > /sys/class/gpio/gpio30_pd2/value
        echo 1 > /sys/class/gpio/gpio31_pd1/value
fi

gpio映射可以看:
1) http://linux-sunxi.org/Cubieboard
2)tools/pack/chips/sun4i/configs/linux/cubieboard/sys_config1.fex
  其中的gpio_para段
3)http://linux-sunxi.org/GPIO





原文作者:matson
原文链接:http://forum.cubietech.com/forum.php?mod=viewthread&tid=352&extra=&page=1

Chapter 1. Introduction Section 1.1. Why Linux? Section 1.2. Embedded Linux Today Section 1.3. Open Source and the GPL Section 1.4. Standards and Relevant Bodies Section 1.5. Chapter Summary Chapter 2. Your First Embedded Experience Section 2.1. Embedded or Not? Section 2.2. Anatomy of an Embedded System Section 2.3. Storage Considerations Section 2.4. Embedded Linux Distributions Section 2.5. Chapter Summary Chapter 3. Processor Basics Section 3.1. Stand-alone Processors Section 3.2. Integrated Processors: Systems on Chip Section 3.3. Hardware Platforms Section 3.4. Chapter Summary Chapter 4. The Linux KernelA Different Perspective Section 4.1. Background Section 4.2. Linux Kernel Construction Section 4.3. Kernel Build System Section 4.4. Obtaining a Linux Kernel Section 4.5. Chapter Summary Chapter 5. Kernel Initialization Section 5.1. Composite Kernel Image: Piggy and Friends Section 5.2. Initialization Flow of Control Section 5.3. Kernel Command Line Processing Section 5.4. Subsystem Initialization Section 5.5. The init Thread Section 5.6. Chapter Summary Chapter 6. System Initialization Section 6.1. Root File System Section 6.2. Kernel's Last Boot Steps Section 6.3. The Init Process Section 6.4. Initial RAM Disk Section 6.5. Using initramfs Section 6.6. Shutdown Section 6.7. Chapter Summary Chapter 7. Bootloaders Section 7.1. Role of a Bootloader Section 7.2. Bootloader Challenges Section 7.3. A Universal Bootloader: Das U-Boot Section 7.4. Porting U-Boot Section 7.5. Other Bootloaders Section 7.6. Chapter Summary Chapter 8. Device Driver Basics Section 8.1. Device Driver Concepts Section 8.2. Module Utilities Section 8.3. Driver Methods Section 8.4. Bringing It All Together Section 8.5. Device Drivers and the GPL Section 8.6. Chapter Summary Chapter 9. File Systems Section 9.1. Linux File System Concepts Section 9.2. ext2 Section 9.3. ext3 Section 9.4. ReiserFS Section 9.5. JFFS2 Section 9.6. cramfs Section 9.7. Network File System Section 9.8. Pseudo File Sys
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值