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=1php