本文主要介紹三個部分的內(nèi)容:一、準(zhǔn)備sdk源碼 二、如何操作gpio 三、led設(shè)備驅(qū)動的實(shí)現(xiàn)。由于firefly官方一直在對源碼進(jìn)行更新,所以本文只以我正在用的版本介紹。此外,官方提供的下載工具版本不同需要準(zhǔn)備的鏡像文件(.img文件)也不同,因此,這里也只介紹我正在使用的版本。 sdk版本:firefly-sdk-20200629.7z 下載工具版本:androidtool v2.58 u-boot:2017.09 linux內(nèi)核:4.4.194 文件系統(tǒng):buildroot

鏡像文件如下,如上圖所示,只會下載勾選的鏡像。
代碼語言:JavaScript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
boot.img ==================> kernel/zboot.imgMiniLoaderALL.bin =========> /u-boot/rk3288_loader_v1.08.258.binparameter.txt =============> device/rockchip/rk3288/parameter-buildroot.txtrecovery.img ==============> buildroot/output/rockchip_rk3288_recovery/images/recovery.imgrootfs.img ================> buildroot/output/rockchip_rk3288/images/rootfs.ext2trust.img =================> u-boot/trust.imguboot.img =================> u-boot/uboot.img
一、準(zhǔn)備SDK源碼
實(shí)際上,firefly官網(wǎng)已經(jīng)有具體的步驟,但官網(wǎng)會經(jīng)常更新,所以這里再簡單的介紹一遍流程。
1.下載Linux-SDK源碼包
這里是官網(wǎng)鏈接

2.解壓Linux-SDK源碼包
將下載好的Linux-SDK源碼包拷貝至虛擬機(jī),虛擬機(jī)安裝好7z解壓縮工具和git工具。
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
7z x firefly-sdk-20200629.7z -r #遞歸解壓主和子目錄的內(nèi)容git reset --hard cd ~/proj/Firefly-RK3288#2. 下載遠(yuǎn)程 bundle 倉庫git clone https://github.com/FireflyTeam/bundle.git -b rk3288-Linux-bundle#3. 若 clone 失敗,可以前往 github 下載 bundle.zip:#4. 更新 SDK,并且后續(xù)更新不需要再次拉取遠(yuǎn)程倉庫,直接執(zhí)行以下命令即可./bundle/update rk3288-linux-bundle#5. 按照提示已經(jīng)更新內(nèi)容到 FETCH_HEAD,同步 FETCH_HEAD 到 firefly 分支git rebase FETCH_HEAD#6. 更新共用倉庫./bundle/update common-linux-bundlegit rebase FETCH_HEAD
最后需要注意本地分支是否是firefly,如果不是,切換之。

解壓后文件夾如下:

3.編譯Linux內(nèi)核源碼
這里是直接進(jìn)入Linux內(nèi)核源碼目錄下進(jìn)行編譯,也可以使用官方的build.sh腳本編譯,這個官網(wǎng)有教程,這里不再介紹。
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#交叉編譯器目錄firefly-sdk/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bincd /RK3288/firefly-sdk/kernel #進(jìn)入內(nèi)核源碼目錄export ARCH=armexport CROSS_COMPILE=arm-linux-gnueabihf- make firefly_linux_defconfig #使用內(nèi)核默認(rèn)配置make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig # 使用圖形化配置make -j8 rk3288-firefly.img #編譯 此過程包含設(shè)備樹、uImage、zImage的編譯以及image打包過程。最終生成需要的zboot.img文件
這里僅僅介紹了內(nèi)核鏡像文件的生成,對于開頭提到的其他文件,由于不是本文的重點(diǎn),這里也不再介紹,大家可以去查看官網(wǎng)教程。需要注意的是內(nèi)核一定要編譯通過,因為后面的驅(qū)動需要能夠編譯通過的內(nèi)核源碼。
二、應(yīng)用層操作GPIO
RK3288的GPIO號對應(yīng)的引腳可以通過如下文件查看:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
cat /sys/kernel/debug/pinctrl/pinctrl/pins
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
[root@rk3288:/sys/kernel/debug/pinctrl/pinctrl]# cat /sys/kernel/debug/pinctrl/pinctrl/pinsregistered pins: 264pin 0 (gpio0-0)pin 1 (gpio0-1)pin 2 (gpio0-2)pin 3 (gpio0-3)pin 4 (gpio0-4)pin 5 (gpio0-5)............
開發(fā)板上兩個LED對應(yīng)的引腳是:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
pin 249 (gpio8-1)=====> bluepin 250 (gpio8-2)=====> yellow
可以通過export GPIO的方式操作這兩個GPIO:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
[root@rk3288:/sys/class/gpio]# echo 250 > export[root@rk3288:/sys/class/gpio]# cd gpio250[root@rk3288:/sys/devices/platform/pinctrl/gpio/gpio250]# lsactive_low device direction edge power subsystem uevent value[root@rk3288:/sys/devices/platform/pinctrl/gpio/gpio250]#
direction:GPIO的方向,可以設(shè)置為in或者out value:0低電平 其他值高電平
開發(fā)板上兩個LED已經(jīng)應(yīng)用為LED子系統(tǒng)(gpio8-1,gpio8-2),需要取消這個應(yīng)用才可以使用sys文件操作GPIO,方法如下:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
Device Drivers > LED Support LED Support for GPIO connected LEDs
三、LED設(shè)備驅(qū)動
前面我們已經(jīng)準(zhǔn)備好了能夠編譯通過的linux內(nèi)核源碼,現(xiàn)在我們可以編寫Linux設(shè)備驅(qū)動了,由于我們使用的是帶設(shè)備樹的Linux內(nèi)核,所以驅(qū)動的編寫和不帶設(shè)備樹的內(nèi)核是有一點(diǎn)區(qū)別的,但總體流程不變。
1.firefly-rk3288 設(shè)備樹文件
firefly-rk3288 設(shè)備樹文件位于/firefly-sdk/kernel/arch/arm/boot/dts目錄下,對于led設(shè)備,我們需要打開rk3288-firefly.dtsi文件,找到led設(shè)備節(jié)點(diǎn):
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
leds {compatible = "gpio-leds";work {gpios = ;label = "firefly:blue:user";linux,default-trigger = "rc-feedback";pinctrl-names = "default";pinctrl-0 = ;};power {gpios = ;label = "firefly:green:power";linux,default-trigger = "default-on";pinctrl-names = "default";pinctrl-0 = ;};};
rk3288開發(fā)板共有兩個led,分別對應(yīng)GPIO8_A1和GPIO8_A2,但是我們在驅(qū)動程序中需要通過設(shè)備樹獲取到這兩個GPIO的值。所以下面介紹幾個常用設(shè)備樹操作函數(shù)(#include
a.通過絕對路徑,獲取設(shè)備節(jié)點(diǎn)
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
static inline struct device_node *of_find_node_by_path(const char *path)
b.通過父節(jié)點(diǎn)和名稱,獲取設(shè)備樹子節(jié)點(diǎn)
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
static inline struct device_node *of_get_child_by_name(const struct device_node *node,const char *name)
b.通過節(jié)點(diǎn)和名稱,獲取GPIO引腳號
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
static inline int of_get_named_gpio(struct device_node *np, const char *propname, int index)
2.firefly-rk3288 LED設(shè)備驅(qū)動編寫
帶設(shè)備樹的LED驅(qū)動與不帶設(shè)備樹的驅(qū)動區(qū)別在于,帶設(shè)備樹的LED驅(qū)動需要在程序中從設(shè)備樹中獲取需要的GPIO編號,然后就是字符設(shè)備驅(qū)動的那一套流程了。
驅(qū)動源碼文件如下:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#include <linux>//模塊加載卸載函數(shù)#include <linux>//內(nèi)核頭文件#include <linux>//數(shù)據(jù)類型定義#include <linux>//file_operations結(jié)構(gòu)體#include <linux>//class_create等函數(shù)#include <linux>#include <linux>/*包含printk等操作函數(shù)*/#include <linux>/*設(shè)備樹操作相關(guān)的函數(shù)*/#include <linux>/*gpio接口函數(shù)*/#include <linux>#include <linux>/*cdev_init cdev_add等函數(shù)*/#include <asm>/*gpio接口函數(shù)*/#include <asm>/*__copy_from_user 接口函數(shù)*/#define DEVICE_NAME "rk3288_led"typedef struct{ struct device_node *led_node;//設(shè)備樹節(jié)點(diǎn) int led_pin;//GPIO 引腳 struct cdev cdev;//定義一個cdev結(jié)構(gòu)體 struct class *class;//創(chuàng)建一個LED類 struct device *device;//創(chuàng)建一個LED設(shè)備 該設(shè)備是需要掛在LED類下面的 int major;//主設(shè)備號 dev_t dev_id;}led_typdef;static led_typdef ledx;//定義一個LED設(shè)備static int led_open(struct inode *inode, struct file *filp){ int ret = -1;retry:ret = gpio_request(ledx.led_pin, "led_yellow"); if(ret != 0) { printk("gpio %d req failed:%drn",ledx.led_pin,ret); gpio_free(ledx.led_pin);//引腳被占用(錯誤碼-16)釋放掉 goto retry;}gpio_direction_output(ledx.led_pin,0);return 0;}static int led_release(struct inode* inode ,struct file *filp){gpio_free(ledx.led_pin);return 0;}static int led_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){ int ret; unsigned char pbuf[1];ret = __copy_from_user(pbuf,buf, 1);if(ret <p>MakeFile文件如下:</p>代碼語言:javascript<i class="icon-code"></i>代碼運(yùn)行次數(shù):<!-- -->0<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewbox="0 0 16 16" fill="none"><path d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>運(yùn)行<svg width="16" height="16" viewbox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor"></path></svg>復(fù)制<pre class="prism-token token line-numbers javascript">obj-m:=led_driver.oPWD:=$(shell pwd)KDIR:=/RK3288/firefly-sdk/kernelall:$(MAKE) -C $(KDIR) M=$(PWD) clean:rm -rf *.ko *.order *.symvers *.cmd *.o *.mod.c *.tmp_versions .*.cmd .tmp_versions
驅(qū)動編譯成功后會生成一個.ko文件,將.ko文件拷貝到開發(fā)板上并加載,出現(xiàn)如下提示表明驅(qū)動加載成功。

接下來,我們還需要編寫一個測試APP,用于測試驅(qū)動是否正常工作,測試APP的源碼如下:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys>#include <sys>#include <fcntl.h>#include <termios.h>#include <errno.h>#include <limits.h>#include <asm>#include <time.h>#include <pthread.h>int main(void){ int fd = -1,i; char buf[1]={0}; fd = open("/dev/rk3288_led",O_RDWR); if(fd <p>將上述源碼用交叉編譯器編譯,即可生成可執(zhí)行文件,將該可執(zhí)行文件加上執(zhí)行權(quán)限拷貝到開發(fā)上并執(zhí)行,開發(fā)板的藍(lán)色LED燈應(yīng)該就開始閃爍起來了。</p></pthread.h></time.h></asm></limits.h></errno.h></termios.h></fcntl.h></sys></sys></unistd.h></stdlib.h></stdio.h>