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時,默認編譯會少一些插件或庫,會彈出一些錯誤信息。
該提示信息表明編譯需要git包,執行如下指令安裝:
sudo apt-get install git
該提示表明標準的C++庫沒有安裝,執行如下指令安裝:
sudo apt-get install lib32stdc++-4.9-dev
該提示表明缺少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」,點擊「驅動安裝」,提示安裝驅動成功即可。


注意事項:
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文件,如下圖所示。

工具配置好後,插上開發板的TypeC線、串口線以及5V DC電源線,按下RECOVERY(VOL+)鍵不放的同時,長按POWER鍵開機,在串口終端會有如下列印:

當uboot檢測到RECOVERY鍵按下時,會有「rockusb key pressed」的列印提示,這時,在燒錄工具界面會提示發現一個LOADER設備,然後點擊升級,即可開始升級過程(註:如果提示發現一個ADB設備,點擊切換按鈕切換成LOADER設備即可)。

點擊升級,稍等片刻,燒寫成功界面如下:

多設備升級固件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即可同時升級第二台、第三台設備,升級成功或者失敗的設備會在兩邊的列表中列出,移除成功或者失敗的設備後可以繼續連接需要升級的設備。

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(設備號)選擇設備:
選擇設備後彈出工具使用菜單如下圖,左側是功能描述,右側是命令語法,升級相關操作都在upgrade command列表下,忘記命令語法可以輸入H進行查看,清屏輸入CS,退出按Q。
- 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
備註:也可通過配置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即可。
該工具也支持命令行,使用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,進入配置界面:
進入Target options菜單,
在Target Architecture中選擇ARM(little endian),在Target Binary Format中選擇ELF,退回上一級,進入Toolchain目錄,按下圖配置:
退回上一級,進入System configuration目錄,作如下配置:
退回上一級,進入Target packages目錄,再進入Graphic libraries and applications (graphic/text)目錄,選擇Qt5,如下圖所示:
注意不要選Qt,它對應QT4.8版本。進入Qt5菜單,按下圖配置:
退回menuconfig的開始界面,進入Filesystem images菜單,作如下配置:
到此,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程序),如下圖所示:
進入gui/rasterwindow目錄,執行rasterwindow文件,指令如下:
./ rasterwindow &
這時,在開發板上可以看到一個標註有QWindow的圖案被繪製出來,如下圖所示:
進入qpa/windows目錄,執行windows文件,指令如下:
./windows &
這時,在開發板上可以看到有三幅圖案被繪製出來,如下圖所示:
進入sql/drilldown目錄,執行如下指令:
./drilldown &
這時,在開發板上可以看到有四個QT畫面被繪製出來,如下圖所示:
進入sql/books目錄,執行如下指令:
./books &
這時,在開發板上可以看到有一個對話框被繪製出來,如下圖所示:
進入sql/masterdetail目錄,執行如下指令:
./masterdetail &
這時,在開發板上可以看到有一個對話框繪製出來,如下圖所示:
默認buildroot編譯出了很多示例,這裡不帶一一列舉,有興趣的讀者可以自行嘗試。
安裝QT Creator
通常我們使用QT Creator創建基於QT的工程。在QT官網下載最新的QT安裝包,下載地址如下:
http://download.qt.io/official_releases/qt/
打開連結頁面如下:
點擊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也會被列出來,如下圖所示:
點擊QT圖標,QT Creator將會運行,如下圖所示:
默認QT的配置是針對X86架構的,這時編譯出來的示例只能在PC機上運行。我們打開Image Composition Example示例,它是一個圖片疊加顯示的示例,找到該示例,單擊即可。打開後的界面如下:
點擊左下腳綠色的三腳箭頭,開始編譯工程。在Compile Output欄會顯示編譯的整個過程。編譯完成後,提示如下:
編譯完成後,編譯出來的映像會自動運行,一個疊加的蝴蝶圖像界面顯示出來了,界面如下:
下面我們將該示例編譯到開發板上運行。使用QT Creator打開上面的示例工程,如下圖所示:
選擇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 & Run,在後邊選擇Qt Versions,默認Manual為空,Auto-detected選擇的QT5.1默認的qmake,它將運行在X86平台的linux系統上,因此我們要手動添加在ARM平台上運行的qmake。
在buildroot編譯文件系統時,我們選中QT5後,將會在buildroot的output/host/usr/bin目錄生成支持ARM平台的qmake,點擊Add,指向該路徑的qmake:
點擊Open,即在Manual中添加了支持ARM平台的qmake。再選擇Compilers一欄,如下圖所示:
默認Manual為空,Auto-detected為支持X86 32位和64位的GCC,這將直接導致編譯出來只能在PC機上運行。點擊Add,選擇GCC,如下圖所示:
在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,如下圖所示:
注意,這時默認Manual仍然為空,點擊Add,會彈出一個有很多選項的對話框,我們按如下方式配置:
這裡的Name,我們可以點擊Qt Versions,選擇Manual中的qmake,下面就會有名稱出來,將它拷貝過來即可,如下圖所示:
在框圖一中,點擊設置編譯環境的下拉箭頭,如下圖所示:
選擇Change Kit->Qt5.1.1(System),更改後的界面如下:
在框圖2中選擇release,更改後的界面如下:
到此,配置完畢,點擊框圖5中的編譯按鈕,在Compile Output中可以看到編譯信息如下:
這時,在框圖2中指定的目錄中已經生成了能夠在ARM平台運行的映像了,如下圖所示:
將該文件拷貝到x3399開發板上運行,可以看到美麗的蝴蝶圖案顯示出來了。
qttest測試程序
使用QT_demo測試LED燈
點擊上面的四盞燈可以看到開發板led的燈的亮和滅。
使用QT_demo測試蜂鳴器
進入QT5.6.1系統後,默認會運行我們自主編寫的測試demo,測試界面如下:
使用QT_demo調節背光
測試界面如下:
滑動圓形滑輪,可對開發板背光進行亮暗調節。
使用QT_demo測試按鍵
測試界面如下:
按下開發板任一獨立按鍵,圖中界面即會顯示相應鍵值,同時,按下時提示[keydown],抬起時提示[keyup]。
使用QT_demo測試音頻
將喇叭或耳機接到開發板的對應接口,點擊下圖中的Play Sound按鈕,會播放測試歌曲:
使用QT_demo測試觸控螢幕
進入如下界面:
單擊黃色矩形框,界面會進入全屏模式,這時我們可以任意書寫來測試觸控螢幕了,測試示例圖片如下:
使用QT_demo測試網絡
將網線連接開發板的有線乙太網接口,點擊界面中的Network Test按鈕,如果網絡已經連通,則會添加DNS,如果沒有連通,則會提示相應錯誤,如下圖所示:
連接網線後測試時,會有如下提示:
使用QT_demo測試TF卡
將SD卡插入開發板的SD卡槽,點擊Tfcard Test,界面上會列出SD卡中的內容。
使用QT_demo測試重啟
點擊Reboot按鈕,開發板將重啟。
使用QT_demo測試關機
點擊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卡插到開發板的任意卡槽,串口終端會有如下提示:

這時在文件系統的/dev目錄將會自動生成一個名叫mmcblk1p1的塊設備文件。它就是對應的TF卡的設備文件,使用如下命令掛載TF卡到/sdcard目錄:
mkdir /sdcard
mount /dev/mmcblk1p1 /sdcard
查看/scard目錄下的內容,即是我們TF卡中的內容,如下圖所示:
掛載U盤
進入QT圖形界面後,在命令終端會有控制台出現,這時可以通過控制台查看文件系統的內容。插入U盤後,串口終端會有如下提示:

這時在文件系統的/dev目錄將會自動生成一個名叫sda4的塊設備文件。它就是對應的U盤設備文件,使用如下命令掛載U盤到/udisk目錄:
mkdir /udisk
mount /dev/sda4 /udisk
查看/udisk目錄下的內容,即是我們U盤中的內容,如下圖所示:

保存系統時鐘
Linux可以使用date指令更改時間日期。例如:
date -s 201607211433 设置为2016年7月21日14:33分
hwclock -w 把刚设置的时间存入RTC寄存器
hwclock -s 恢复linux系统时钟为RTC寄存器值,一般将该指令放在rcS中开机自动执行。
掉電保存數據到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大小信息:

在進入文件系統後,可以通過cat命令查詢Linux系統分配到的SDRAM大小。執行如下命令:
cat /proc/meminfo

linux應用開發示例
本手冊給出的所有應用程式全部在九鼎創展x3399開發板上運行,這裡僅給出了一些比較基礎,常用的應用程式,旨在為用戶打開Linux世界奇妙的大門,用戶定能舉一反三,編寫出屬於自己的更加豐富完美的程序。
聲明:以下所有應用程式全部為九鼎創展科技有限公司原創作品,所有內容全經我們嚴格測試,建議用戶按照下面步驟動手編譯一遍,以增強自己的理解,不推薦直接使用我們提供好的文件。另外,敬請商業人士勿侵犯版權。
Hello World
第一步:生成可執行文件
在x3399_marshmallow目錄新建app-ex目錄,在app-ex目錄新建hello目錄,然後在hello目錄下新建hello.c和makefile兩個文件:
vim hello.c

這是一個最基礎的應用程式,如果我們聲明了交叉編譯工具(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體系文件:
第二步:將可執行文件下載到開發板運行
比較常用的方式有以下四種:
- 通過串口和sz/rz工具
- 複製到存儲媒介,如SD卡,U盤等
- 通過NFS掛載文件系統,這時不用將可執行文件拷備到開發板了,推薦調試使用這種方式!
- 通過ftp傳輸
這裡介紹第二種方法,以TF卡為例,其他方法請讀者自行嘗試。
將生成的hello文件拷備到TF卡,再將TF卡插入開發板的TF卡接口,將TF卡mount到/mnt目錄:
cd /
mount /dev/mmcblk1p1 /mnt
進入mnt目錄,可以看到剛才拷貝的hello文件了:
運行hello:
./hello
列印信息如下:

表明,程序已經成功運行。
前面編譯文件我們需要通過手敲命令執行,我們可以通過編寫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下載到開發板上運行,如下圖所示:
多線程編程示例
建立程序編譯路徑:
<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下載到開發板上運行,如下圖所示:

多進程編程示例
在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編譯,將生成的可執行文件下載到開發板運行,仔細觀察串口監控信息:

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,如下圖所示:
保存退出,在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文件:
下載libtool-2.2.6a.tar.gz,解壓編譯獲得libtool工具。
再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等其他格式。