跳转至: 导航, 搜索

RK3399 Linux Manual

目录

编译Linux+QT

安装依赖包

使用如下命令安装所需的软件包:

sudo apt-get update
sudo apt-get install git-core gnupg flex bison gperf libsdl1.2-dev libwxgtk3.0-dev build-essential zip curl zlib1g-dev gcc-multilib g++-multilib genromfs libc6-dev-i386 libncurses5-dev x11proto-core-dev libx11-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip gperf lsb-core lib32z1-dev lib32ncurses5-dev lzop

编译uboot

说明:QT系统使用的uboot与内核与安卓完全相同,如果编译过android的uboot和内核,则本小节步骤可以省略。

在android源码目录下执行如下命令编译uboot,编译完成后映像文件RK3399MiniLoaderAll_V1.05.bin(因版本不同,名称不一定相同)以及uboot.img会释放到out/release目录。

./mk.sh     -u

编译android内核

说明:QT系统使用的uboot与内核与安卓完全相同,如果编译过android的uboot和内核,则本小节步骤可以省略。

在android源码目录下执行如下命令编译linux内核,编译完成后映像文件kernel.img、resource.img会释放到out/release目录。

./mk.sh     -k

编译文件系统

在android源码目录下执行如下命令编译linux映像文件,编译完成后linux映像文件linux-rootfs.img会释放到out/release目录。

./mk.sh     -b

在执行./mk.sh -b编译buildroot时,默认编译会少一些插件或库,会弹出一些错误信息。

Rk3288-buildroot-git.png

该提示信息表明编译需要git包,执行如下指令安装:

sudo  apt-get  install  git

Rk3288-buildroot-libc++.png

该提示表明标准的C++库没有安装,执行如下指令安装:

sudo apt-get install lib32stdc++-4.9-dev

Rk3288-buildroot-libz.png

该提示表明缺少libz库,执行如下指令安装:

sudo apt-get install lib32z1

再执行./mk.sh -b指令即可正常编译了。编译完成后,最终打包好的文件系统linux-rootfs.img存放在out/release目录下。它包含了QT5.6的标准库,以及一些常用的QT示例。

生成update-linux.img文件系统

在android源码目录下执行如下命令生成单一android映像文件update-linux.img:

./mk.sh     -U

update-linux.img为整个QT系统升级文件的单一映像,包括了uboot,内核,文件系统等。注意,生成update-linux.img的先决条件是已经成功编译了uboot,内核和linux文件系统,缺一不可。


烧写linux QT映像

Windows下烧写映像文件

驱动安装

解压光盘tools\x3399烧写工具\windows目录下的DriverAssitant_v4.5.zip文件,打开“DriverInstall.exe”,点击“驱动安装”,提示安装驱动成功即可。

399 × 192px
533 × 257px

注意事项:

1.目前支持的操作系统包括:XP,Win7_32,Win7_64,Win8_32,Win8_64。

2.XP系统在驱动安装完后,若还提示“发现新设备”, 安装驱动时选择“自动安装”。

3.若之前已经安装过老版本驱动,请先点击“驱动卸载”后再进行“驱动安装”。

生成统一固件update-linux.img

我们已经在mk脚本中集成了生成统一固件的方法,在编译linux文件系统时(./mk.sh -b -U),会自动生成update-android.img,并释放到out/release目录。

烧录固件update-linux.img

解压光盘tools\x3399烧写工具\windows目录下的AndroidTool_Release_v2.38.zip文件,得到AndroidTool_Release_v2.38文件夹,打开AndroidTool.exe,选择“升级固件”选项卡,点击“固件”,在弹出窗口中选择已经生成的update-linux.img文件,如下图所示。

905 × 456px

工具配置好后,插上开发板的TypeC线、串口线以及5V DC电源线,按下RECOVERY(VOL+)键不放的同时,长按POWER键开机,在串口终端会有如下打印:

1,075 × 706px

当uboot检测到RECOVERY键按下时,会有“rockusb key pressed”的打印提示,这时,在烧录工具界面会提示发现一个LOADER设备,然后点击升级,即可开始升级过程(注:如果提示发现一个ADB设备,点击切换按钮切换成LOADER设备即可)。

905 × 456px

点击升级,稍等片刻,烧写成功界面如下:

905 × 456px

多设备升级固件update-linux.img

该工具适合用户批量刷机,可以同时给多台设备烧录固件。

解压光盘tools\x3399烧写工具\windows目录下的FactoryTool-v1.42e.rar文件,打开FactoryTool.exe,点击“固件”选择update-android.img,勾选“升级”,点击“启动”,如下图所示:

步骤1 点击固件,选择需要使用的update-linux.img;

步骤2 点击启动(选择升级按钮);

步骤3 连接开发板USB、DC电源,按下recovery键(对应VOL+键),对应USB口发现设备,并实现自动升级;然后重复步骤3即可同时升级第二台、第三台设备,升级成功或者失败的设备会在两边的列表中列出,移除成功或者失败的设备后可以继续连接需要升级的设备。

998 × 753px

linux下烧写映像文件

生成固件update-linux.img

我们已经在mk脚本中集成了生成统一固件的方法,在编译android文件系统时(./mk.sh -s),会自动生成update-linux.img,并释放到out/release目录。

烧录固件update-linux.img

工具路径:tools\x3399烧写工具\linux\ Linux_Upgrade_Tool_v1.24.zip

在升级之前将update-linux.img拷贝到upgrade_tool相同目录下,运行upgrade_tool(需要sudo)

work@ubuntu:~/3288/Linux_Upgrade_Tool_v1.2/cp rockdev/update.img .
work@ubuntu:~/3288/Linux_Upgrade_Tool_v1.2$ sudo ./upgrade_tool 

执行结果如下图,发现设备列表,输入要升级的DevNo(设备号)选择设备: DevNo.png

选择设备后弹出工具使用菜单如下图,左侧是功能描述,右侧是命令语法,升级相关操作都在upgrade command列表下,忘记命令语法可以输入H进行查看,清屏输入CS,退出按Q。

DevNo1.png

  • CD 命令: 选择设备, 当执行的命令有包含设备重启操作时, 需重新选择设备,当改变操作设备时需重新选择
  • SD 命令:msc 切换到 rockusb 升级模式。 当切换执行成功后, 需要重新选择设备
  • UF 命令:升级完整 update.img 固件,当执行成功后需要重新选择设备
  • UL 命令:升级 loader 功能,当执行成功后需要重新选择设备
  • DI 命令:下载单独 image 镜像到指定扇区,例如升级 kernel.img 或者 system.img 都可以

直接使用此功能.例如下载 kernel.img: DI -k kernel.img parameter //如果之前通过 DI 下 载过 parameter,则再下载 kernel.img 时就可以不用指定最后的 parameter 参数

  • DB 命令:下载 boot,在 maskrom状态下,可以通过此功能, 让 maskrom设备进行 Rockusb协议通讯
  • EF 命令:擦除整个 nandflash
  • LF 命令:低格保留块后面区域,只有在 loader 模式下使用

执行uf update-linux.img开始更新固件,下图为更新过程截图:

Rockusb>uf update-linux.img

DevNo2.png


备注:也可通过配置config.ini文件配置升级映像文件,只需输入UF即可升级,请用户自行尝试。

使用upgrade_tool指令烧写映像

上一节我们介绍了通过upgrade_tool烧写统一固件update-linux.img的方法,熟悉三星平台的开发者会发现,这种方法并不是很高效,真正操作起来,它远没有fastboot工具来的迅速。其实,upgrade_tool工具同样支持类似于fastboot的烧写方式。

为了烧写方便,可以在mk脚本中,默认在编译系统时,将烧写工具upgrade_tool拷贝到out/release目录。

第一步:打开串口终端,并打开minicom,用于适时监控串口调试信息;

第二步:按住RECOVERY键,连接USB OTG线和电源线,这时uboot打印信息将会提示已经进入USB下载模式。如果接通电源后没来得及按住RECOVERY键,在按住RECOVERY键的同时,再按下复位键即可。

第二步:打开第二个串口终端,进入out/release目录;

第三步:在out/release目录下敲击如下指令,烧写相应的映像。

 sudo upgrade_tool  di  –k  <nowiki>kernel.img(烧写内核)

 sudo upgrade_tool  di  –s  system.img(烧写文件系统)

 sudo upgrade_tool  di  resource  resource.img(烧写资源文件)

 sudo upgrade_tool  di  –r recovery.img(烧写急救文件)

 sudo upgrade_tool  ul  RK3399MiniLoaderAll_V1.05.bin (烧写bootloader)

 sudo upgrade_tool  di  uboot  uboot.img  parameter.txt(烧写uboot,必须指定parameter.txt)

 sudo upgrade_tool  di  trust   trust.img   parameter.txt(烧写trust,必须指定parameter.txt)

 sudo upgrade_tool  uf  update-linux.img(烧写统一固件)
 

Rkflashkit

rkflashkit 有图形界面,后加了命令行支持,更是好用。

work@ubuntu~/rktool$ sudo apt-get install build-essential fakeroot

work@ubuntu~/rktool$ git clone <nowiki>https//github.com/linuxerwang/rkflashkit

work@ubuntu~/rktool$ cd rkflashkit

work@ubuntu~/rktool$ ./waf debian

work@ubuntu~/rktool$ sudo apt-get install python-gtk2

work@ubuntu~/rktool$ sudo dpkg -i rkflashkit_0.1.4_all.deb
 

注意:rkflashkit_0.1.4_all.deb会因版本更新,版本数字可能会有所变化,如果执行失败,执行ls命令查看下即可。

work@ubuntu~/rktool/$ sudo rkflashkit

如下是图形界面,在Devices下选择设备,选择要烧写的分区和对应的映像文件,点击Flash image即可。

947 × 684px

该工具也支持命令行,使用help命令查看使用方法

 work@ubuntu~/rktool/rkflashkit$ rkflashkit --help

 Usage<cmd<nowiki>> [args] [<cmd> [args]...]



 part                              List partition

 flash @<PARTITION> <IMAGE FILE>   Flash partition with image file

 cmp @<PARTITION> <IMAGE FILE>     Compare partition with image file

 backup @<PARTITION> <IMAGE FILE>  Backup partition to image file

 erase  @<PARTITION>               Erase partition

 reboot                            Reboot device



 For example, flash device with boot.img and kernel.img, then reboot



  sudo rkflashkit flash @boot boot.img @kernel.img kernel.img reboot

 work@ubuntu~/rktool/rkflashkit$ 

QT文件系统的搭建

前面章节的介绍,都是九鼎创展工程师已经移植的文件系统包,如果换一个平台,一切从零开始,我们如何构建linux QT文件系统呢?本章节将会带您一步步搭建linux文件系统。

下载buildroot

在buildroot官网下载最新的buildroot包,下载地址如下:

[http//buildroot.uclibc.org/download.html http//buildroot.uclibc.org/download.html]

本文使用的是buildroot 2016.02,用户下载最新版本与本文介绍版本配置可能略有不同,根据下文配置适当修改即可。

配置buildroot

将下载的buildroot包拷贝到ubuntu系统用户目录并解压,得到buildroot目录,通过命令终端进入buildroot目录,执行make menuconfig,进入配置界面:

1,456 × 938px

进入Target options菜单,

1,456 × 938px

在Target Architecture中选择ARM(little endian),在Target Binary Format中选择ELF,退回上一级,进入Toolchain目录,按下图配置:

1,456 × 938px

退回上一级,进入System configuration目录,作如下配置:

1,456 × 938px

退回上一级,进入Target packages目录,再进入Graphic libraries and applications (graphic/text)目录,选择Qt5,如下图所示:

1,456 × 938px

注意不要选Qt,它对应QT4.8版本。进入Qt5菜单,按下图配置:

1,456 × 938px

1,456 × 938px

退回menuconfig的开始界面,进入Filesystem images菜单,作如下配置:

1,456 × 938px

到此,buildroot配置完成。默认配置保存在buildroot根目录的.config中,我们可以备份该配置文件,以防后续配置出错。执行如下指令备份配置文件:

   cp  .config  x3399_defconfig

编译buildroot

配置完成后,执行make指令即可编译buildroot了。编译buildroot会会依赖一些第三方插件和库,在第一章的编译文件系统小节中,已经给出了需要安装的包,在编译之前需要提前安装,否则会报错。 编译完成后,文件系统映像rootfs.ext2会生成到output/images目录。

测试QT5.1默认示例

将uboot,内核,文件系统烧写进开发板,进入linux文件系统后,可以进入/usr/lib/qt/examples目录测试QT示例。

进入gui/analogclock目录,执行analogclock文件,指令如下:

./analogclock &

这时,在开发板上可以看到有一个时钟图案被绘制出来(会覆盖默认的QTTEST程序),如下图所示:

QT5.1-default.png

进入gui/rasterwindow目录,执行rasterwindow文件,指令如下:

./ rasterwindow &

这时,在开发板上可以看到一个标注有QWindow的图案被绘制出来,如下图所示:

QT5.1-default1.png

进入qpa/windows目录,执行windows文件,指令如下:

./windows &

这时,在开发板上可以看到有三幅图案被绘制出来,如下图所示:

QT5.1-default2.png

进入sql/drilldown目录,执行如下指令:

./drilldown &

这时,在开发板上可以看到有四个QT画面被绘制出来,如下图所示:

QT5.1-default3.png

进入sql/books目录,执行如下指令:

./books &

这时,在开发板上可以看到有一个对话框被绘制出来,如下图所示:

QT5.1-default4.png

进入sql/masterdetail目录,执行如下指令:

./masterdetail &

这时,在开发板上可以看到有一个对话框绘制出来,如下图所示:

QT5.1-default5.png

默认buildroot编译出了很多示例,这里不带一一列举,有兴趣的读者可以自行尝试。

安装QT Creator

通常我们使用QT Creator创建基于QT的工程。在QT官网下载最新的QT安装包,下载地址如下:

http://download.qt.io/official_releases/qt/

打开链接页面如下:

QT-Creator-install.png

点击5.1,下载最新的安装包,得到名为qt-linux-opensource-5.1.1-x86-offline.run的文件,将它拷贝到ubuntu的用户目录,使用如下指令安装:

./ qt-linux-opensource-5.1.1-x86-offline.run

安装完成后,QT Creator也就安装完成了。

编译QT Creator默认示例

点击ubuntu图标,输入qt,将会查找含有qt的文件,同时,安装好的QT Creator也会被列出来,如下图所示:

Build-QT-Creator-default.png

点击QT图标,QT Creator将会运行,如下图所示:

Build-QT-Creator-default1.png

默认QT的配置是针对X86架构的,这时编译出来的示例只能在PC机上运行。我们打开Image Composition Example示例,它是一个图片叠加显示的示例,找到该示例,单击即可。打开后的界面如下:

Build-QT-Creator-default2.png

点击左下脚绿色的三脚箭头,开始编译工程。在Compile Output栏会显示编译的整个过程。编译完成后,提示如下:

Build-QT-Creator-default3.png

编译完成后,编译出来的映像会自动运行,一个叠加的蝴蝶图像界面显示出来了,界面如下:


Build-QT-Creator-default4.png

下面我们将该示例编译到开发板上运行。使用QT Creator打开上面的示例工程,如下图所示:

Build-QT-Creator-default5.png

选择Projects一栏,可以看到最顶端的框图1,显示Desktop Qt 5.1.1 GCC 64bit,表明它通过64位的GCC编译,框图2表明在debug模式下编译,相对release模式,debug模式下含有大量调试信息,编译出来的映像会比较大。通常发布映像时,我们选择release模式。框图3指定了编译的路径。框图4指定了qmake和交叉编译工具。框图5为调试按键,第一个用于选择编译模式为debug或release,第二个为运行按钮,第三个为单步调试按钮,第四个为编译按钮。框图6为一些输出信息,如Compile Output,会给出整个编译的信息。

在框图1中,点击Tools->Options,如下图:

Build-QT-Creator-default6.png

在左测对话框中选择Build & Run,在后边选择Qt Versions,默认Manual为空,Auto-detected选择的QT5.1默认的qmake,它将运行在X86平台的linux系统上,因此我们要手动添加在ARM平台上运行的qmake。

在buildroot编译文件系统时,我们选中QT5后,将会在buildroot的output/host/usr/bin目录生成支持ARM平台的qmake,点击Add,指向该路径的qmake:

Build-QT-Creator-default7.png

点击Open,即在Manual中添加了支持ARM平台的qmake。再选择Compilers一栏,如下图所示:

Build-QT-Creator-default8.png

默认Manual为空,Auto-detected为支持X86 32位和64位的GCC,这将直接导致编译出来只能在PC机上运行。点击Add,选择GCC,如下图所示:

Build-QT-Creator-default9.png

在Name中重命名,以区别ARM和PC平台,如我们命名为GCC-ARM-LINUX,它将会直接显示在前面QT工程界面的框图1中,到时我们编译QT工程时,能够一目了然,编译出来的到底是PC平台还是ARM平台。在Compiler path中指定交叉编译工具,在buildroot中默认已经自动下载并安装了交叉编译工具,我们指定到如下路径即可:

buildroot/output/host/opt/ext-toolchain/bin/arm-linux-gnueabihf-g++

设置完成后,点击OK,完成设置。

再回到QT的工程界面,我们发现框图1中的配置仍然针对PC机,点击框图1中的Manage Kits,如下图所示:

Build-QT-Creator-default10.png

注意,这时默认Manual仍然为空,点击Add,会弹出一个有很多选项的对话框,我们按如下方式配置:

Build-QT-Creator-default11.png

这里的Name,我们可以点击Qt Versions,选择Manual中的qmake,下面就会有名称出来,将它拷贝过来即可,如下图所示:

Build-QT-Creator-default12.png

在框图一中,点击设置编译环境的下拉箭头,如下图所示:

Build-QT-Creator-default13.png

选择Change Kit->Qt5.1.1(System),更改后的界面如下:

Build-QT-Creator-default14.png

在框图2中选择release,更改后的界面如下:

Build-QT-Creator-default15.png

到此,配置完毕,点击框图5中的编译按钮,在Compile Output中可以看到编译信息如下:

Build-QT-Creator-default16.png

这时,在框图2中指定的目录中已经生成了能够在ARM平台运行的映像了,如下图所示:

Build-QT-Creator-default17.png

将该文件拷贝到x3399开发板上运行,可以看到美丽的蝴蝶图案显示出来了。

Build-QT-Creator-default18.png

qttest测试程序

使用QT_demo测试LED灯

led

点击上面的四盏灯可以看到开发板led的灯的亮和灭。

使用QT_demo测试蜂鸣器

进入QT5.6.1系统后,默认会运行我们自主编写的测试demo,测试界面如下:

1,024 × 600px 按住Beep键时,蜂鸣器鸣叫,松开时,蜂鸣器停止鸣叫。

使用QT_demo调节背光

测试界面如下:

1,024 × 600px

滑动圆形滑轮,可对开发板背光进行亮暗调节。

使用QT_demo测试按键

测试界面如下:

1,024 × 600px

按下开发板任一独立按键,图中界面即会显示相应键值,同时,按下时提示[keydown],抬起时提示[keyup]。

使用QT_demo测试音频

将喇叭或耳机接到开发板的对应接口,点击下图中的Play Sound按钮,会播放测试歌曲:

QTtest-demo5-audio.png

使用QT_demo测试触摸屏

进入如下界面:

ts

单击黄色矩形框,界面会进入全屏模式,这时我们可以任意书写来测试触摸屏了,测试示例图片如下:

ts1

使用QT_demo测试网络

将网线连接开发板的有线以太网接口,点击界面中的Network Test按钮,如果网络已经连通,则会添加DNS,如果没有连通,则会提示相应错误,如下图所示:

1,024 × 600px

连接网线后测试时,会有如下提示:

1,024 × 600px

使用QT_demo测试TF卡

tf

tf 将SD卡插入开发板的SD卡槽,点击Tfcard Test,界面上会列出SD卡中的内容。

tf1

使用QT_demo测试重启

点击Reboot按钮,开发板将重启。

reboot

使用QT_demo测试关机

点击Poweroff按钮,开发板将会关机。

poweroff



linux底层开发示例

播放mp3

注:linux系统缺省登录账户为root,密码:123456

将存放有mp3文件的TF卡插到开发板的任意卡槽,使用如下命令挂载TF卡:

<nowiki>
 cd  /

 mkdir  sdcard

 mount  /dev/mmcblk1p1  /sdcard

 cd  sdcard

使用如下命令播放:

./mplayer  *.avi
./mplayer  *.mp3

连接串口后,可以通过PC键盘的0或9调节音量。也可以使用madplayer播放音乐。

在后台运行程序

在上一节中给出了播放音乐的示例,但是这时候mplayer已经占据了终端控制台,在音乐播放完之前,我们无法再使用终端控制台了。又比如我们开发一款产品时,就需要在启动文件系统后运行一个应用程序,如果运行了一个程序,终端控制台就被占用了,那将极大的限制我们的功能。为止,我们可以将程序放在后台运行。使用方法很简单,我们只需在执行的指令后面添加一个”&”即可。如播放音乐时使用如下命令:

./mplayer  *.mp3  &

中止程序的运行

中止程序的运行有多种方式,最直接的方式就是直接按ctrl+c。如前面我们正在播放一段音频文件,我们可以按ctrl+c退出程序。但是如果程序在后台运行,那么我们按ctrl+c就不管用了。这时我们可以使用kill命令。

kill+===PID===
kill+===文件名===

屏幕抓图

本文档中的各个图片,都是采用gsnap这个工具进行抓图的。进入QT图形界面后,我们能在LCD上看到丰富多彩的人机交互界面。通过gsnap可以抓取到图形界面精彩的瞬间。在控制台终端输入如下命令:

gsnap  test_pic.jpg  /dev/fb0

这时在当前目录将会保存test_pic.jpg图像文件。详细的gsnap移植步骤在后面会有详细描述。

挂载TF卡

进入QT图形界面后,在命令终端会有控制台出现,这时可以通过控制台查看文件系统的内容。将TF卡插到开发板的任意卡槽,串口终端会有如下提示:

1,899 × 299px

这时在文件系统的/dev目录将会自动生成一个名叫mmcblk1p1的块设备文件。它就是对应的TF卡的设备文件,使用如下命令挂载TF卡到/sdcard目录:

mkdir  /sdcard
mount  /dev/mmcblk1p1  /sdcard

查看/scard目录下的内容,即是我们TF卡中的内容,如下图所示:

1,905 × 378px

挂载U盘

进入QT图形界面后,在命令终端会有控制台出现,这时可以通过控制台查看文件系统的内容。插入U盘后,串口终端会有如下提示:

1,882 × 304px

这时在文件系统的/dev目录将会自动生成一个名叫sda4的块设备文件。它就是对应的U盘设备文件,使用如下命令挂载U盘到/udisk目录:

mkdir  /udisk
mount  /dev/sda4  /udisk

查看/udisk目录下的内容,即是我们U盘中的内容,如下图所示:

1,873 × 241px

保存系统时钟

Linux可以使用date指令更改时间日期。例如:

date  -s  201607211433  设置为2016年7月21日14:33分
hwclock  -w  把刚设置的时间存入RTC寄存器
hwclock  -s   恢复linux系统时钟为RTC寄存器值,一般将该指令放在rcS中开机自动执行。

1,123 × 139px

掉电保存数据到flash

由于本系统采用了ext4文件系统,因此可以很方便的保存数据,确保掉电后数据不丢失。如我们从U盘中拷备一首歌曲到/root目录:

cp /udisk/muyangqu.mp3 /

重启开发板,我们发现在root目录仍然存在刚才拷备的这首歌曲,说明掉电后数据并没有丢失。

设置开机自动运行程序

借助启动脚本可以设置各种程序开机后自动运行,这点很类似于WINDOWS的Autobat自动批处理文件。启动脚本位于/etc/init.d/rcS中,我们可以将自己想要开机运行的程序或是开机执行的指令放在rcS里面。比如我们想制作一个简单的开机音乐,我们就完全可以在rcS中添加如下语句:

./mplayer  start.mp3  &

这时,开机后就会播放名叫start.mp3的音乐了。注意start.mp3需要在当前执行指令所在目录。

查看开发板内存信息

X3399开发板默认配置2GB LPDDR3 SDRAM,在uboot启动时,打印信息上会给出RAM大小信息:

1,096 × 570px

在进入文件系统后,可以通过cat命令查询Linux系统分配到的SDRAM大小。执行如下命令:

cat  /proc/meminfo
1,106 × 525px

linux应用开发示例

本手册给出的所有应用程序全部在九鼎创展x3399开发板上运行,这里仅给出了一些比较基础,常用的应用程序,旨在为用户打开Linux世界奇妙的大门,用户定能举一反三,编写出属于自己的更加丰富完美的程序。

声明:以下所有应用程序全部为九鼎创展科技有限公司原创作品,所有内容全经我们严格测试,建议用户按照下面步骤动手编译一遍,以增强自己的理解,不推荐直接使用我们提供好的文件。另外,敬请商业人士勿侵犯版权。

Hello World

第一步:生成可执行文件

在x3399_marshmallow目录新建app-ex目录,在app-ex目录新建hello目录,然后在hello目录下新建hello.c和makefile两个文件:

vim  hello.c
307 × 109px

这是一个最基础的应用程序,如果我们声明了交叉编译工具(export PATH=/home/lixu/projects/3399/x3399_marshmallow/buildroot/output/host/opt/ext-toolchain/bin$PATH)(这里我们用到buildroot中的交叉编译工具),可以直接敲入命令进行编译(由于开发板环境缺少c库,编译时需要加上-static静态编译):

arm-linux-gcc-4.4.3 -o hello hello.c -static

说明:由于开发板文件系统缺少标准函数库,编译时加上-static选项;使用的编译器为aarch64-linux-gnu-gcc。

编译完成后,在当前目录会生成hello可执行文件,我们可以使用file命令查询执行文件是否为ARM体系文件:

1,123 × 74px

第二步:将可执行文件下载到开发板运行

比较常用的方式有以下四种:

  • 通过串口和sz/rz工具
  • 复制到存储媒介,如SD卡,U盘等
  • 通过NFS挂载文件系统,这时不用将可执行文件拷备到开发板了,推荐调试使用这种方式!
  • 通过ftp传输

这里介绍第二种方法,以TF卡为例,其他方法请读者自行尝试。

将生成的hello文件拷备到TF卡,再将TF卡插入开发板的TF卡接口,将TF卡mount到/mnt目录:

cd  /
mount  /dev/mmcblk1p1  /mnt

进入mnt目录,可以看到刚才拷贝的hello文件了:

948 × 85px

运行hello:

./hello

打印信息如下:

967 × 135px

表明,程序已经成功运行。

前面编译文件我们需要通过手敲命令执行,我们可以通过编写makefile来代替手敲的动作。

在hello目录下新建makefile文件:vim makefile

hello
   aarch64-linux-gnu-gcc –o hello hello.c –static
clean
   rm –f hello *.o

直接在hello目录下敲make就可以生成hello文件。运行的效果和前面的完全相同。

数学函数库调用

建立程序编译路径:

<nowiki>
 mkdir  math

 cd  math

 vim  math.c

编辑如下内容:

 <nowiki>include <stdio.h>

 include <stdlib.h>

 include <math.h>


int main(void)

{

    double a=9.0;

    printf("sqrt(%f)=%f\n",a,sqrt(a));



    return 0;

}

编辑makefile文件,内容如下:

<nowiki>
OBJS=math.o

LDFLAGS = -lm -static

CC = yourtoolchainpath/bin/aarch64-linux-gnu-gcc



math${OBJS}

    ${CC} -o $@ $^ $(LDFLAGS) 



clean

    rm -f math *.o

执行make,将生成的可执行文件math下载到开发板上运行,如下图所示:

958 × 99px

多线程编程示例

建立程序编译路径:

<nowiki>
 mkdir  thread

 cd  thread

 vim  thread.c

编辑如下内容:

<nowiki>include<stddef.h>

include<stdio.h>

include<unistd.h>

include"pthread.h"

void function1(void);

void function2(void);

int func_flag=0;

pthread_mutex_t mutex;



main()

{

    pthread_t reader;

    pthread_mutex_init(&mutex,NULL);

    pthread_create(&reader,NULL,(void*)&function1,NULL);

    function2();

}



void function2(void)

{

    while(1)

    {

        pthread_mutex_lock(&mutex);

        if(func_flag==0)

        {

            printf("excute function2.\n");

            func_flag=1;

        }

        pthread_mutex_unlock(&mutex);

    }

}



void function1(void)

{

    while(1)

    {

        pthread_mutex_lock(&mutex);

        if(func_flag==1)

        {

            printf("excute function1.\n");

            func_flag=0;

        }

        pthread_mutex_unlock(&mutex);

    }

}

编辑makefile文件,内容如下:

<nowiki>
OBJS=thread.o

LDFLAGS = -lpthread -static

CC = yourtoolchainpath/bin/aarch64-linux-gnu-gcc



thread${OBJS}

    ${CC} -o $@ $^ $(LDFLAGS) 



clean

    rm -f thread *.o

执行make,将生成的可执行文件thread下载到开发板上运行,如下图所示:

821 × 125px

多进程编程示例

在Linux下通用调用fork函数创建新的进程。调用fork时,系统将产生一个与当前进程相同的进程。它与原有的进程具有相同的数据,连接关系和在程序同一处执行时的连续性。通常将原有的进程叫父进程,新创建的进程叫子进程。

fork调用将分两次返回,从父子进程返回。进程创建语法如下:

 <nowiki>include <unistd.h>

 pid_t  pid;

 pid = fork();

如果pid返回0,表示说明从子进程返回,否则从父进程返回,此时返回的是进程的ID号。我们可以通过getpid()函数来获得进程的ID号。

首先建立程序编译目录:

<nowiki>
 mkdir  process

 cd  process

 vim  process.c

编辑如下内容:

<nowiki>include<stdio.h>

include<unistd.h>

include<sys/types.h>



main()

{

    pid_t pid;

    pid=fork();

    if (pid<0)

    {

        printf("fork is error!\n");

        return 1;

    }

    else if (pid == 0)

    {

        while (1)

        {

            printf("the child process is running now.pid=%d\n",getpid());

            sleep(1);//linux延时函数,延时1秒

        }

    }

    else

    {

        while (1)

        {

            printf("the perent process is running now.pid=%d\n",getpid());

            sleep(1);

        }

    }

    return 0;

}

编辑makefile文件,内容如下:

<nowiki>
OBJS=process.o

LDFLAGS = -lpthread -static

CC = yourtoolchainpath/bin/aarch64-linux-gnu-gcc



process${OBJS}

    ${CC} -o $@ $^ $(LDFLAGS)



clean

    rm -f process *.o

执行make编译,将生成的可执行文件下载到开发板运行,仔细观察串口监控信息:

967 × 210px

makefile编程示例

在上面的很多测试程序实例中,我们都编写了一些简单的makefile文件。下面我们介绍makefile的基本的语法。

makefile就好比批处理文件,里面写了一系列集合,当运行make编译时,便会按makefile提供的命令及顺序完成编译。

这里我们给出三个文件:main.c,func.c,func.h。主程序在main.c中,在main.c中程序会调用func.c中的函数,func.c中的函数又会用到func.h中定义的变量。

main.c文件内容如下:

<nowiki>include "func.h"



extern int fd;



int main(int argc,char **argv)

{    

    fd = open(DEVICE_NAME,0);//打开设备

    if(fd == -1)

    {

        printf("open device %s error \n",DEVICE_NAME);

        return 0;

    }

    else

    {

        printf("open device %s ok! \n",DEVICE_NAME);

    }

    

    while(1)

    {

        glint_led();

    }

    close(fd);

    return 0;

}

该文件会调用glint_led ()函数,这个函数在func.c中。func.c的内容如下:

<nowiki>include "func.h"



void glint_led(void)

{

    ioctl(fd,LED_ON);

    sleep(1);

    ioctl(fd,LED_OFF);

    sleep(1);

}

这里仅仅是一个读取按键的函数,供main函数调用。该函数需要用到了一些变量,另外还需要一些头文件支持,这些都存放在func.h中,其内容如下:

<nowiki>include <stdio.h>

include <stdlib.h>

include <unistd.h>

include <sys/ioctl.h>



define DEVICE_NAME    "/dev/vib"

define LED_ON 0x11

define LED_OFF 0x22



int fd;

很明显,这是基于LED测试程序,人为的分成的三个文件。我们的目的不在于分离代码,而在于学习makefile的编写方法。

当不使用makefile时,我们使用如下指令编译:

aarch64-linux-gnu-gcc-gcc -o mkfile main.c func.c

编译完成后,将会生成可执行文件mkfile。将它下载到开发板上运行,和前面的按键测试完全相同。现在我们尝试编写第一个属于自己的makefile

<nowiki>
mkfilemain.o func.o

    aarch64-linux-gnu-gcc -o mkfilemain.o func.o

main.omain.c

    aarch64-linux-gnu-gcc -c main.c -o main.o

func.ofunc.c func.h

    aarch64-linux-gnu-gcc -c func.c -o func.o

    

clean

    rm -f mkfile *.o

执行make后,编译器会依次编译main.c和func.c文件,生成main.o和func.o文件,最后将这两个.o文件打包到可执行文件mkfile中。这时将mkfile文件下载到开发板运行,效果和前面的是一样的。我们可以执行make clean指令清除生成的.o文件和可执行文件。

makefile具有很强大的推理功能,我们完全可以简化上面的代码。优化后的代码如下:

<nowiki>
OBJS=main.o func.o

CC= aarch64-linux-gnu-gcc



mkfile${OBJS}

    ${CC} -o $@ $^

main.o

func.ofunc.h



clean

    rm -f mkfile *.o

可见,这次比上面的完整版要简化多了。前面通过变量OBJS定义了要编译的源文件,变量CC给出了交叉编译工具。$@ 表示目标文件的全称,即mkfile,$^表示所有被依赖的文件,并以空格分开,即main.o func.o。后面的clean为清除指令,执行make clean后会执行 clean后面的指令。需要注意的是,rm指令后面千万不要使用$@符号来表征我们要删除的目标文件,因为这时候$@已经不再表示mkfile了,而表示clean。同样,使用make指令编译,一样能够生成我们需要的目录文件mkfile。

上面的makefile使用了变量以及预定义变量。第一句即定义了变量OBJS,将它赋值为main.o func.o,第二句定义了变量CC,将它赋值为一个交叉编译工具定义。引用变量时,通过${*}表示,这里*表示前面定义的变量。

上面使用了$@和$^两个预定义变量,GNU make主要有以下七种预定义变量:

$*

不包含扩展名的目标文件名称

$+

所有的依赖文件,以空格分开,以出现的先后为序,可能包含重复的依赖文件

$<

第一个依赖文件的名称

$?

所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚

$@

目标的完整名称

$^

所有的依赖文件,以空格分开,不包含重复的依赖文件

$%

如果目标是归档成员,则该变量表示目标的归档成员名称。例如,如果目标名称为mytarget.so(image.o),则$@ 为mytarget.so,而$% 为image.o。

对比以上几种编译方式,我们不然发现,其实最简的还是第一种,因为它就一句话就搞定了。那么在makefile中,我们是否也可以精简到只有一句话呢?答案是肯定的。我们继续利用makefile强大的推理功能进行简化,得到如下makefile代码:

<nowiki>
OBJS=main.o func.o

CC= aarch64-linux-gnu-gcc



mkfile${OBJS}

    ===${CC} -o $@ $^===



clean

    rm -f mkfile *.o

这次,makefile真正编译的代码,就只有上面红色部分一条指令了。和前面比较,不难发现,单独对main.c和func.c两个文件编译的指令已经去掉了。前面我们提到,makefile具有强大的推理功能,我们在生成目标文件mkfile时,makefile会推理出它需要main.c和func.c两个文件,因此它首先就会去编译这两个文件,最后再执行目标文件的生成。因此我们完全可以将它们省去。

这里只是makefile的一点基础,读者可以借助于其他书籍对makefile作更深一层的了解。

mplayer移植

有两种移植mplayer,第一种方法就是直接下载mplayer源码包,手动配置编译环境,再通过交叉编译环境编译。该方法比较传统,我们有更方便的方法,直接在buildroot中选中mplayer,再make即可,buildroot会自动下载mplayer源码包,自动配置编译环境并编译。

在buildroot的menuconfig配置选项中,进入Target packages-> Audio and video applications选项,选中mplayer,如下图所示:

1,366 × 768px

保存退出,在buildroot下直接make,生成文件系统后更新到开发板,mplayer就打包进文件系统了。

madplayer移植

madplayer的移植方法和mplayer的移植方法完全雷同,直接在buildroot中选中madplayer的选项,再make即可。

屏幕抓图工具gsnap移植

屏幕抓图的方法有多种,有不少爱好者自己动手写抓图小程序。这里我们使用JPEG库来处理。具体用到了jpegsrc.v6b.tar.gz和gsnap.tar.gz两个源码包(这2个压缩包请读者自己到网络上面下载)。

一:安装libjpeg

解压jpeg库源码包,进入根目录:

tar     zxf     jpegsrc.v6b.tar.gz
cd  jpeg-6b

二:配置编译环境:

<nowiki>
./configure --prefix=/home/lixu/projects/3399/x3399_marshmallow/buildroot/output/host/opt/ext-toolchain --exec-prefix=/home/lixu/projects/3399/x3399_marshmallow/buildroot/output/host/opt/ext-toolchain --target=arm-linux --enable-shared --enable-static



CC=/home/lixu/projects/3399/x3399_marshmallow/buildroot/output/host/opt/ext-toolchain/bin/aarch64-linux-gnu-gcc

AR=/home/lixu/projects/3399/x3399_marshmallow/buildroot/output/host/opt/ext-toolchain/bin/aarch64-linux-gnu-ar rc

AR2=/home/lixu/projects/3399/x3399_marshmallow/buildroot/output/host/opt/ext-toolchain/bin/aarch64-linux-gnu-ranlib

三:配置好之后,make编译,如果提示缺少libtool文件:

1,292 × 76px

下载libtool-2.2.6a.tar.gz,解压编译获得libtool工具。

1,122 × 47px

再make clean,重复之前的第二步:配置编译环境。

四:在x3399_marshmallow/buildroot/output/host/opt/ext-toolchain下建立man/man1目录:

cd  x3399_marshmallow/buildroot/output/host/opt/ext-toolchain
mkdir  -p  man/man1

五:编译,安装

make
make  install

这时,在x3399_marshmallow/buildroot/output/host/opt/ext-toolchain/man/man1目录下将会生成以下文件:

cjpeg.1  djpeg.1  jpegtran.1  rdjpgcom.1  wrjpgcom.1

在x3399_marshmallow/buildroot/output/host/opt/ext-toolchain/lib目录下生成以下文件:

libjpeg.a  libjpeg.la  libjpeg.so  libjpeg.so.62  libjpeg.so.62.0.0

六:解压gsnap

tar  zxf  gsnap.tar.gz
cd  gsnap

七:修改makefile

<nowiki>
all

    /home/lixu/projects/3399/x3399_marshmallow/buildroot/output/host/opt/ext-toolchain/bin/aarch64-linux-gnu-gcc -g gsnap.c -ljpeg -o gsnap –static

clean

    rm -f gsnap

八:编译,得到可执行文件gsnap

make

九:将jpeg库文件复制到文件系统的lib目录,注意保持文件的链接属性

cp  -a  libjpeg.s*  “文件系统路径”/lib

十:将可执行文件gsnap复制到文件系统的sbin目录

cp  gsnap  “文件系统路径”/sbin

十一:重新制作文件系统,下载到开发板上,使用如下命令即可截获图形界面:

gsnap  1.jpg  /dev/fb0

同样可以将图片保持为bmp,png等其他格式。