本文主要介紹三個(gè)部分的內(nèi)容:一、準(zhǔn)備sdk源碼 二、如何操作gpio 三、led設(shè)備驅(qū)動(dòng)的實(shí)現(xiàn)。由于firefly官方一直在對(duì)源碼進(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

鏡像文件如下,如上圖所示,只會(huì)下載勾選的鏡像。
代碼語言: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)會(huì)經(jīng)常更新,所以這里再簡(jiǎn)單的介紹一遍流程。
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腳本編譯,這個(gè)官網(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)核鏡像文件的生成,對(duì)于開頭提到的其他文件,由于不是本文的重點(diǎn),這里也不再介紹,大家可以去查看官網(wǎng)教程。需要注意的是內(nèi)核一定要編譯通過,因?yàn)楹竺娴尿?qū)動(dòng)需要能夠編譯通過的內(nèi)核源碼。
二、應(yīng)用層操作GPIO
RK3288的GPIO號(hào)對(duì)應(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ā)板上兩個(gè)LED對(duì)應(yīng)的引腳是:
代碼語言:javascript代碼運(yùn)行次數(shù):0運(yùn)行復(fù)制
pin 249 (gpio8-1)=====> bluepin 250 (gpio8-2)=====> yellow
可以通過export GPIO的方式操作這兩個(gè)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ā)板上兩個(gè)LED已經(jīng)應(yīng)用為LED子系統(tǒng)(gpio8-1,gpio8-2),需要取消這個(gè)應(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ū)動(dòng)
前面我們已經(jīng)準(zhǔn)備好了能夠編譯通過的linux內(nèi)核源碼,現(xiàn)在我們可以編寫Linux設(shè)備驅(qū)動(dòng)了,由于我們使用的是帶設(shè)備樹的Linux內(nèi)核,所以驅(qū)動(dòng)的編寫和不帶設(shè)備樹的內(nèi)核是有一點(diǎn)區(qū)別的,但總體流程不變。
1.firefly-rk3288 設(shè)備樹文件
firefly-rk3288 設(shè)備樹文件位于/firefly-sdk/kernel/arch/arm/boot/dts目錄下,對(duì)于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ā)板共有兩個(gè)led,分別對(duì)應(yīng)GPIO8_A1和GPIO8_A2,但是我們?cè)隍?qū)動(dòng)程序中需要通過設(shè)備樹獲取到這兩個(gè)GPIO的值。所以下面介紹幾個(gè)常用設(shè)備樹操作函數(shù)(#include
a.通過絕對(duì)路徑,獲取設(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引腳號(hào)
代碼語言: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ū)動(dòng)編寫
帶設(shè)備樹的LED驅(qū)動(dòng)與不帶設(shè)備樹的驅(qū)動(dòng)區(qū)別在于,帶設(shè)備樹的LED驅(qū)動(dòng)需要在程序中從設(shè)備樹中獲取需要的GPIO編號(hào),然后就是字符設(shè)備驅(qū)動(dòng)的那一套流程了。
驅(qū)動(dòng)源碼文件如下:
代碼語言: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;//定義一個(gè)cdev結(jié)構(gòu)體 struct class *class;//創(chuàng)建一個(gè)LED類 struct device *device;//創(chuàng)建一個(gè)LED設(shè)備 該設(shè)備是需要掛在LED類下面的 int major;//主設(shè)備號(hào) dev_t dev_id;}led_typdef;static led_typdef ledx;//定義一個(gè)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);//引腳被占用(錯(cuò)誤碼-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ū)動(dòng)編譯成功后會(huì)生成一個(gè).ko文件,將.ko文件拷貝到開發(fā)板上并加載,出現(xiàn)如下提示表明驅(qū)動(dòng)加載成功。

接下來,我們還需要編寫一個(gè)測(cè)試APP,用于測(cè)試驅(qū)動(dòng)是否正常工作,測(cè)試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>