AIO-3399JD4 開發(fā)板上的 AD 接口有兩種,分別為:溫度傳感器 (Temperature Sensor)、逐次逼近ADC (Successive Approximation Register)。其中:
-
TS-ADC(Temperature Sensor):支持兩通道,時(shí)鐘頻率必須低于800KHZ
-
SAR-ADC(Successive Approximation Register):支持六通道單端10位的SAR-ADC,時(shí)鐘頻率必須小于13MHZ。
內(nèi)核采用工業(yè) I/O 子系統(tǒng)來(lái)控制 ADC,該子系統(tǒng)主要為 AD 轉(zhuǎn)換或者 DA 轉(zhuǎn)換的傳感器設(shè)計(jì)。
下面以SAR-ADC使用ADC風(fēng)扇為例子,介紹 ADC 的基本配置方法。
配置DTS節(jié)點(diǎn)
AIO-3399JD4 SAR-ADC 的 DTS 節(jié)點(diǎn)在 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi 文件中定義,如下所示:
用戶首先需在DTS文件中添加ADC的資源描述:
這里申請(qǐng)的是SARADC通道3,在 AIO-3399JD4 中是不提供給客戶外部使用的,而且也沒有風(fēng)扇接口,這里只是提供一個(gè)參考, 客戶可自行參考這個(gè)例子 運(yùn)用SARADC通道0 去做自己的一些開發(fā)。
在驅(qū)動(dòng)文件中匹配 DTS 節(jié)點(diǎn)
用戶驅(qū)動(dòng)可參考Firefly adc demo :kernel/drivers/adc/adc-firefly-demo.c,這是一個(gè)偵測(cè)Firefly-rk3399風(fēng)扇狀態(tài)的驅(qū)動(dòng)。 首先在驅(qū)動(dòng)文件中定義 of_device_id 結(jié)構(gòu)體數(shù)組:
然后將該結(jié)構(gòu)體數(shù)組填充到要使用 ADC 的 platform_driver 中:
接著在firefly_adc_probe中對(duì)DTS所添加的資源進(jìn)行解析:
獲取 AD 通道
注:iio_channel_get 通過(guò) probe 函數(shù)傳進(jìn)來(lái)的參數(shù) pdev 獲取 IIO 通道結(jié)構(gòu)體,probe 函數(shù)如下:
讀取 AD 采集到的原始數(shù)據(jù)
調(diào)用 iio_read_channel_raw 函數(shù)讀取 AD 采集的原始數(shù)據(jù)并存入 val 中。
使用標(biāo)準(zhǔn)電壓將 AD 轉(zhuǎn)換的值轉(zhuǎn)換為用戶所需要的電壓值。其計(jì)算公式如下:
注:
-
Vref 為標(biāo)準(zhǔn)電壓
-
n 為 AD 轉(zhuǎn)換的位數(shù)
-
Vresult 為用戶所需要的采集電壓
-
raw 為 AD 采集的原始數(shù)據(jù)
例如,標(biāo)準(zhǔn)電壓為 1.8V,AD 采集位數(shù)為 10 位,AD 采集到的原始數(shù)據(jù)為 568,則:
-
功能:獲取 iio 通道描述
-
參數(shù):
-
dev: 使用該通道的設(shè)備描述指針
-
consumer_channel: 該設(shè)備所使用的 IIO 通道描述指針
-
-
功能:釋放 iio_channel_get 函數(shù)獲取到的通道
-
參數(shù):
-
chan:要被釋放的通道描述指針
-
-
功能:讀取 chan 通道 AD 采集的原始數(shù)據(jù)。
-
參數(shù):
-
chan:要讀取的采集通道指針
-
val:存放讀取結(jié)果的指針
-
Demo程序使用
在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi中使能adc_demo,將”disabled” 改為 “okay”:
編譯內(nèi)核,燒錄內(nèi)核到Firefly-RK3399 開發(fā)板上,然后插拔風(fēng)扇時(shí),會(huì)打印內(nèi)核log信息如下:
獲取所有ADC值
有個(gè)便捷的方法可以查詢到每個(gè)SARADC的值:
為何按上面的步驟申請(qǐng)SARADC,會(huì)出現(xiàn)申請(qǐng)報(bào)錯(cuò)的情況?
驅(qū)動(dòng)需要獲取ADC通道來(lái)使用時(shí),需要對(duì)驅(qū)動(dòng)的加載時(shí)間進(jìn)行控制,必須要在saradc初始化之后。saradc是使用module_platform_driver()進(jìn)行平臺(tái)設(shè)備驅(qū)動(dòng)注冊(cè),最終調(diào)用的是module_init()。所以用戶的驅(qū)動(dòng)加載函數(shù)只需使用比module_init()優(yōu)先級(jí)低的,例如:late_initcall(),就能保證驅(qū)動(dòng)的加載的時(shí)間比saradc初始化時(shí)間晚,可避免出錯(cuò)。
GPIO, 全稱 General-Purpose Input/Output(通用輸入輸出),是一種軟件運(yùn)行期間能夠動(dòng)態(tài)配置和控制的通用引腳。 RK3399有5組GPIO bank:GPIO0~GPIO4,每組又以 A0~A7, B0~B7, C0~C7, D0~D7 作為編號(hào)區(qū)分(不是所有 bank 都有全部編號(hào),例如 GPIO4 就只有 C0~C7, D0~D2)。 所有的GPIO在上電后的初始狀態(tài)都是輸入模式,可以通過(guò)軟件設(shè)為上拉或下拉,也可以設(shè)置為中斷腳,驅(qū)動(dòng)強(qiáng)度都是可編程的。 每個(gè) GPIO 口除了通用輸入輸出功能外,還可能有其它復(fù)用功能,例如 GPIO2_A2,可以利用成以下功能:
-
GPIO2_A2
-
CIF_D2
每個(gè) GPIO 口的驅(qū)動(dòng)電流、上下拉和重置后的初始狀態(tài)都不盡相同,詳細(xì)情況請(qǐng)參考《RK3399 規(guī)格書》中的 “Chapter 10 GPIO” 一章。 RK3399 的 GPIO 驅(qū)動(dòng)是在以下 pinctrl 文件中實(shí)現(xiàn)的:
其核心是填充 GPIO bank 的方法和參數(shù),并調(diào)用 gpiochip_add 注冊(cè)到內(nèi)核中。
本文以TP_RST(GPIO0_B4)和LCD_RST(GPIO4_D5)這兩個(gè)通用GPIO口為例寫了一份簡(jiǎn)單操作GPIO口的驅(qū)動(dòng),在SDK的路徑為:
以下就以該驅(qū)動(dòng)為例介紹GPIO的操作。
首先在DTS文件中增加驅(qū)動(dòng)的資源描述:
這里定義了一個(gè)腳作為一般的輸出輸入口:
AIO-3399JD4 的dts對(duì)引腳的描述與Firefly-RK3288有所區(qū)別,GPIO0_B4被描述為:<&gpio0 12 GPIO_ACTIVE_HIGH>,這里的12來(lái)源于:8+4=12,其中8是因?yàn)镚PIO0_B4是屬于GPIO0的B組,如果是A組的話則為0,如果是C組則為16,如果是D組則為24,以此遞推,而4是因?yàn)锽4后面的4。 GPIO_ACTIVE_HIGH表示高電平有效,如果想要低電平有效,可以改為:GPIO_ACTIVE_LOW,這個(gè)屬性將被驅(qū)動(dòng)所讀取。
然后在probe函數(shù)中對(duì)DTS所添加的資源進(jìn)行解析,代碼如下:
of_get_named_gpio_flags 從設(shè)備樹中讀取 firefly-gpio 和 firefly-irq-gpio 的 GPIO 配置編號(hào)和標(biāo)志,gpio_is_valid 判斷該 GPIO 編號(hào)是否有效,gpio_request 則申請(qǐng)占用該 GPIO。如果初始化過(guò)程出錯(cuò),需要調(diào)用 gpio_free 來(lái)釋放之前申請(qǐng)過(guò)且成功的 GPIO 。 在驅(qū)動(dòng)中調(diào)用 gpio_direction_output 就可以設(shè)置輸出高還是低電平,這里默認(rèn)輸出從DTS獲取得到的有效電平GPIO_ACTIVE_HIGH,即為高電平,如果驅(qū)動(dòng)正常工作,可以用萬(wàn)用表測(cè)得對(duì)應(yīng)的引腳應(yīng)該為高電平。 實(shí)際中如果要讀出 GPIO,需要先設(shè)置成輸入模式,然后再讀取值:
下面是常用的 GPIO API 定義:
在Firefly的例子程序中還包含了一個(gè)中斷引腳,GPIO口的中斷使用與GPIO的輸入輸出類似,首先在DTS文件中增加驅(qū)動(dòng)的資源描述:
IRQ_TYPE_EDGE_RISING表示中斷由上升沿觸發(fā),當(dāng)該引腳接收到上升沿信號(hào)時(shí)可以觸發(fā)中斷函數(shù)。 這里還可以配置成如下:
然后在probe函數(shù)中對(duì)DTS所添加的資源進(jìn)行解析,再做中斷的注冊(cè)申請(qǐng),代碼如下:
調(diào)用gpio_to_irq把GPIO的PIN值轉(zhuǎn)換為相應(yīng)的IRQ值,調(diào)用gpio_request申請(qǐng)占用該IO口,調(diào)用request_irq申請(qǐng)中斷,如果失敗要調(diào)用free_irq釋放,該函數(shù)中g(shù)pio_info-firefly_irq是要申請(qǐng)的硬件中斷號(hào),firefly_gpio_irq是中斷函數(shù),gpio_info->firefly_irq_mode是中斷處理的屬性,”firefly-gpio”是設(shè)備驅(qū)動(dòng)程序名稱,gpio_info是該設(shè)備的device結(jié)構(gòu),在注冊(cè)共享中斷時(shí)會(huì)用到。
如何定義 GPIO 有哪些功能可以復(fù)用,在運(yùn)行時(shí)又如何切換功能呢?以 I2C4 為例作簡(jiǎn)單的介紹。
查規(guī)格表可知,I2C4_SDA 與 I2C4_SCL 的功能定義如下:
在 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi 里有:
此處,跟復(fù)用控制相關(guān)的是 pinctrl- 開頭的屬性:
-
pinctrl-names 定義了狀態(tài)名稱列表: default (i2c 功能) 和 gpio 兩種狀態(tài)。
-
pinctrl-0 定義了狀態(tài) 0 (即 default)時(shí)需要設(shè)置的 pinctrl: &i2c4_xfer
-
pinctrl-1 定義了狀態(tài) 1 (即 gpio)時(shí)需要設(shè)置的 pinctrl: &i2c4_gpio
這些 pinctrl 在kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi中這樣定義:
RK_FUNC_1,RK_FUNC_GPIO 的定義在 kernel/include/dt-bindings/pinctrl/rk.h 中:
另外,像”1 11”,”1 12”這樣的值是有編碼規(guī)則的,編碼方式與上一小節(jié)”輸入輸出”描述的一樣,”1 11”代表GPIO1_B3,”1 12”代表GPIO1_B4。
在復(fù)用時(shí),如果選擇了 “default” (即 i2c 功能),系統(tǒng)會(huì)應(yīng)用 i2c4_xfer 這個(gè) pinctrl,最終將 GPIO1_B3 和 GPIO1_B4 兩個(gè)針腳切換成對(duì)應(yīng)的 i2c 功能;而如果選擇了 “gpio” ,系統(tǒng)會(huì)應(yīng)用 i2c4_gpio 這個(gè) pinctrl,將 GPIO1_B3 和 GPIO1_B4 兩個(gè)針腳還原為 GPIO 功能。
我們看看 i2c 的驅(qū)動(dòng)程序 kernel/drivers/i2c/busses/i2c-rockchip.c 是如何切換復(fù)用功能的:
首先是調(diào)用 of_get_gpio 取出設(shè)備樹中 i2c4 結(jié)點(diǎn)的 gpios 屬于所定義的兩個(gè) gpio:
然后是調(diào)用 devm_gpio_request 來(lái)申請(qǐng) gpio,接著是調(diào)用 pinctrl_lookup_state 來(lái)查找 “gpio” 狀態(tài),而默認(rèn)狀態(tài) “default” 已經(jīng)由框架保存到 i2c->dev-pins->default_state 中了。
最后調(diào)用 pinctrl_select_state 來(lái)選擇是 “default” 還是 “gpio” 功能。
下面是常用的復(fù)用 API 定義:
在復(fù)雜的片上系統(tǒng)(SOC)中,設(shè)計(jì)者一般會(huì)將系統(tǒng)的供電分為多個(gè)獨(dú)立的block,這稱作電源域(Power Domain),這樣做有很多好處,例如:
-
在IO-Domain的DTS節(jié)點(diǎn)統(tǒng)一配置電壓域,不需要每個(gè)驅(qū)動(dòng)都去配置一次,便于管理;
-
依照的是Upstream的做法,以后如果需要Upstream比較方便;
-
IO-Domain的驅(qū)動(dòng)支持運(yùn)行過(guò)程中動(dòng)態(tài)調(diào)整電壓域,例如PMIC的某個(gè)Regulator可以1.8v和3.3v的動(dòng)態(tài)切換,一旦Regulator電壓發(fā)生改變,會(huì)通知IO-Domain驅(qū)動(dòng)去重新設(shè)置電壓域。
AIO-3399C原理圖上的 Power Domain Map 表以及配置如下表所示:
通過(guò)RK3399 SDK的原理圖可以看到bt656-supply 的電壓域連接的是vcc18_dvp, vcc_io是從PMIC RK808的VLDO1出來(lái)的; 在DTS里面可以找到vcc1v8_dvp, 將bt656-supply = <&vcc18_dvp>。 其他路的配置也類似,需要注意的是如果這里是其他PMIC,所用的Regulator也不一樣,具體以實(shí)際電路情況為標(biāo)準(zhǔn)。
IO指令
GPIO調(diào)試有一個(gè)很好用的工具,那就是IO指令,AIO-3399C的Android系統(tǒng)默認(rèn)已經(jīng)內(nèi)置了IO指令,使用IO指令可以實(shí)時(shí)讀取或?qū)懭朊總€(gè)IO口的狀態(tài),這里簡(jiǎn)單介紹IO指令的使用。 首先查看 io 指令的幫助:
從幫助上可以看出,如果要讀或者寫一個(gè)寄存器,可以用:
使用示例:
-
查看GPIO1_B3引腳的復(fù)用情況
-
從主控的datasheet查到GPIO1對(duì)應(yīng)寄存器基地址為:0xff320000
-
從主控的datasheet查到GPIO1B_IOMUX的偏移量為:0x00014
-
GPIO1_B3的iomux寄存器地址為:基址(Operational Base) + 偏移量(offset)=0xff320000+0x00014=0xff320014
-
用以下指令查看GPIO1_B3的復(fù)用情況:
-
從datasheet查到[7:6]:
因此可以確定該GPIO被復(fù)用為 i2c4sensor_sda。
-
如果想復(fù)用為GPIO,可以使用以下指令設(shè)置:
GPIO調(diào)試接口
Debugfs文件系統(tǒng)目的是為開發(fā)人員提供更多內(nèi)核數(shù)據(jù),方便調(diào)試。 這里GPIO的調(diào)試也可以用Debugfs文件系統(tǒng),獲得更多的內(nèi)核信息。 GPIO在Debugfs文件系統(tǒng)中的接口為 /sys/kernel/debug/gpio,可以這樣讀取該接口的信息:
從讀取到的信息中可以知道,內(nèi)核把GPIO當(dāng)前的狀態(tài)都列出來(lái)了,以GPIO0組為例,gpio-2(GPIO0_A2)作為3G模塊的電源控制腳(vcc3v3_3g),輸出高電平(out hi)。
Q1: 如何將PIN的MUX值切換為一般的GPIO?
A1: 當(dāng)使用GPIO request時(shí)候,會(huì)將該P(yáng)IN的MUX值強(qiáng)制切換為GPIO,所以使用該pin腳為GPIO功能的時(shí)候確保該pin腳沒有被其他模塊所使用。
Q2: 為什么我用IO指令讀出來(lái)的值都是0x00000000?
A2: 如果用IO命令讀某個(gè)GPIO的寄存器,讀出來(lái)的值異常,如 0x00000000或0xffffffff等,請(qǐng)確認(rèn)該GPIO的CLK是不是被關(guān)了,GPIO的CLK是由CRU控制,可以通過(guò)讀取datasheet下面CRU_CLKGATE_CON* 寄存器來(lái)查到CLK是否開啟,如果沒有開啟可以用io命令設(shè)置對(duì)應(yīng)的寄存器,從而打開對(duì)應(yīng)的CLK,打開CLK之后應(yīng)該就可以讀到正確的寄存器值了。
Q3: 測(cè)量到PIN腳的電壓不對(duì)應(yīng)該怎么查?
A3: 測(cè)量該P(yáng)IN腳的電壓不對(duì)時(shí),如果排除了外部因素,可以確認(rèn)下該pin所在的io電壓源是否正確,以及IO-Domain配置是否正確。
Q4: gpio_set_value()與gpio_direction_output()有什么區(qū)別?
A4: 如果使用該GPIO時(shí),不會(huì)動(dòng)態(tài)的切換輸入輸出,建議在開始時(shí)就設(shè)置好GPIO 輸出方向,后面拉高拉低時(shí)使用gpio_set_value()接口,而不建議使用gpio_direction_output(), 因?yàn)間pio_direction_output接口里面有mutex鎖,對(duì)中斷上下文調(diào)用會(huì)有錯(cuò)誤異常,且相比 gpio_set_value,gpio_direction_output 所做事情更多,浪費(fèi)。
AIO-3399JD4 開發(fā)板上有 9 個(gè)片上 I2C 控制器,各個(gè) I2C 的使用情況如下表:
本文主要描述如何在該開發(fā)板上配置 I2C。
配置 I2C 可分為兩大步驟:
-
定義和注冊(cè) I2C 設(shè)備
-
定義和注冊(cè) I2C 驅(qū)動(dòng)
下面以配置 GSL3680 為例。
在注冊(cè)I2C設(shè)備時(shí),需要結(jié)構(gòu)體 i2c_client 來(lái)描述 I2C 設(shè)備。然而在標(biāo)準(zhǔn)Linux中,用戶只需要提供相應(yīng)的 I2C 設(shè)備信息,Linux就會(huì)根據(jù)所提供的信息構(gòu)造 i2c_client 結(jié)構(gòu)體。
用戶所提供的 I2C 設(shè)備信息以節(jié)點(diǎn)的形式寫到 dts 文件中,如下所示:
定義 I2C 驅(qū)動(dòng)
在定義 I2C 驅(qū)動(dòng)之前,用戶首先要定義變量 of_device_id 和 i2c_device_id 。
of_device_id 用于在驅(qū)動(dòng)中調(diào)用dts文件中定義的設(shè)備信息,其定義如下所示:
定義變量 i2c_device_id:
i2c_driver 如下所示:
注:變量id_table指示該驅(qū)動(dòng)所支持的設(shè)備。
注冊(cè) I2C 驅(qū)動(dòng)
使用i2c_add_driver函數(shù)注冊(cè) I2C 驅(qū)動(dòng)。
在調(diào)用 i2c_add_driver 注冊(cè) I2C 驅(qū)動(dòng)時(shí),會(huì)遍歷 I2C 設(shè)備,如果該驅(qū)動(dòng)支持所遍歷到的設(shè)備,則會(huì)調(diào)用該驅(qū)動(dòng)的 probe 函數(shù)。
通過(guò) I2C 收發(fā)數(shù)據(jù)
在注冊(cè)好 I2C 驅(qū)動(dòng)后,即可進(jìn)行 I2C 通訊。
-
向從機(jī)發(fā)送信息:
-
向從機(jī)讀取信息:
Q1: 通信失敗,出現(xiàn)這種log:”timeout, ipd: 0x00, state: 1”該如何調(diào)試?
A1: 請(qǐng)檢查硬件上拉是否給電。
Q2: 調(diào)用i2c_transfer返回值為-6?
A2: 返回值為-6表示為NACK錯(cuò)誤,即對(duì)方設(shè)備無(wú)應(yīng)答響應(yīng),這種情況一般為外設(shè)的問題,常見的有以下幾種情況:
-
I2C地址錯(cuò)誤,解決方法是測(cè)量I2C波形,確認(rèn)是否I2C 設(shè)備地址錯(cuò)誤;
-
I2C slave 設(shè)備不處于正常工作狀態(tài),比如未給電,錯(cuò)誤的上電時(shí)序等;
-
時(shí)序不符合 I2C slave設(shè)備所要求也會(huì)產(chǎn)生Nack信號(hào)。
Q3: 當(dāng)外設(shè)對(duì)于讀時(shí)序要求中間是stop信號(hào)不是repeat start信號(hào)的時(shí)候,該如何處理?
A3: 這時(shí)需要調(diào)用兩次i2c_transfer, I2C read 拆分成兩次,修改如下:
AIO-3399JD4 開發(fā)板上使用紅外收發(fā)傳感器 IR (耳機(jī)接口和recovery之間)實(shí)現(xiàn)遙控功能,在IR接口處接上紅外接收器。本文主要描述在開發(fā)板上如何配置紅外遙控器。
其配置步驟可分為兩個(gè)部分:
-
修改內(nèi)核驅(qū)動(dòng):內(nèi)核空間修改,Linux 和 Android 都要修改這部分的內(nèi)容。
-
修改鍵值映射:用戶空間修改(僅限 Android 系統(tǒng))。
在 Linux 內(nèi)核中,IR 驅(qū)動(dòng)僅支持 NEC 編碼格式。以下是在內(nèi)核中配置紅外遙控的方法。 所涉及到的文件
定義相關(guān)數(shù)據(jù)結(jié)構(gòu)
以下是定義數(shù)據(jù)結(jié)構(gòu)的步驟:
注:第一列為鍵值,第二列為要響應(yīng)的按鍵碼。
如何獲取用戶碼和IR 鍵值
在 remotectl_do_something 函數(shù)中獲取用戶碼和鍵值:
注:用戶可以使用 DBG_CODE() 函數(shù)打印用戶碼。
使用下面命令可以使能DBG_CODE打印:
將 IR 驅(qū)動(dòng)編譯進(jìn)內(nèi)核
將 IR 驅(qū)動(dòng)編譯進(jìn)內(nèi)核的步驟如下所示:
(1)、向配置文件 drivers/input/remotectl/Kconfig 中添加如下配置:
(2)、修改 drivers/input/remotectl 路徑下的 Makefile,添加如下編譯選項(xiàng):
(3)、在 kernel 路徑下使用 make menuconfig ,按照如下方法將IR驅(qū)動(dòng)選中。
保存后,執(zhí)行 make 命令即可將該驅(qū)動(dòng)編進(jìn)內(nèi)核。
Android 鍵值映射
文件 /system/usr/keylayout/ff420030_pwm.kl 用于將 Linux 層獲取的鍵值映射到 Android 上對(duì)應(yīng)的鍵值。用戶可以添加或者修改該文件的內(nèi)容以實(shí)現(xiàn)不同的鍵值映射。
該文件內(nèi)容如下所示:
注:通過(guò) adb 修改該文件重啟后即可生效。
如下圖是通過(guò)按紅外遙控器按鈕,所產(chǎn)生的波形,主要由head,Control,information,signed free這四部分組成,具體可以參考RC6 Protocol。
AIO-3399JD4開發(fā)板默認(rèn)外置支持了兩個(gè)LCD屏接口,一個(gè)是LVDS,一個(gè)是EDP,接口對(duì)應(yīng)板子上的位置如下圖:
另外板子也支持MIPI屏幕,但需要注意的是MIPI和LVDS是復(fù)用的,使用MIPI之后不能使用LVDS。MIPI接口如下圖:
如Android7.1,由于使用的是mipi轉(zhuǎn)lvds,AIO-3399JD4默認(rèn)的配置文件kernel/arch/arm64/configs/firefly_defconfig已經(jīng)把LCD相關(guān)的配置設(shè)置好了,如果自己做了修改,請(qǐng)注意把以下配置加上:
引腳配置
LVDS屏
AIO-3399JD4的SDK有LVDS DSI的DTS文件:kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-aiojd4-lvds-HSX101H40C.dts,從該文件中我們可以看到以下語(yǔ)句:
保存配置并編譯內(nèi)核,把kernel.img 燒到AIO-3399JD4板子上 我們可以使用串口輸入命令,就可以看到藍(lán)燈不停的間隔閃爍
用戶還可以使用 cat 命令獲取 trigger 的可用值:
與攝像頭相關(guān)的代碼目錄如下:
設(shè)置攝像頭相關(guān)的引腳和時(shí)鐘,即可完成配置過(guò)程。
從以下攝像頭接口原理圖可知,需要配置的引腳有:MIPI_PDN0_CAM和MIPI_RST。
mipi接口
MIPI_PDN0_CAM 對(duì)應(yīng) RK3399 的 GPIO2_A0;
MIPI_RST 對(duì)應(yīng)GPIO0_B0;
在開發(fā)板中,這兩個(gè)引腳都是在 cam_board.xml 中設(shè)置。
配置 Android
修改device/rockchip/rk3399/XXX_PRODUCT/cam_board.xml 來(lái)注冊(cè)攝像頭:
最后執(zhí)行:
即可完成內(nèi)核的編譯。
終端下可以直接修改/system/etc/cam_board.xml調(diào)試各參數(shù)并重啟生效
1.無(wú)法打開攝像頭,首先確定sensor I2C是否通信。若不通則可檢查mclk以及供電是否正常(Power/PowerDown/Reset/Mclk/I2cBus)分別排查 2.支持列表? 13M? OV13850/IMX214-0AQH5 8M? OV8825/OV8820/OV8858-Z(R1A)/OV8858-R2A 5M? OV5648/OV5640 2M? OV2680 詳細(xì)資料可查詢SDK/RKDocs
AIO-3399JD4開發(fā)板上引出有 3 路 PWM 輸出,分別為:
PWM0 屏背光
PWM2 VDDLOG供電
PWM3 紅外IR
本章主要描述如何配置 PWM。
RK3399的 PWM 驅(qū)動(dòng)為: kernel/drivers/pwm/pwm-rockchip.c
配置 PWM 主要有以下三大步驟:配置 PWM DTS 節(jié)點(diǎn)、配置 PWM 內(nèi)核驅(qū)動(dòng)、控制 PWM 設(shè)備。
配置 PWM DTS節(jié)點(diǎn)
在 DTS 源文件kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi 添加 PWM DTS 配置,如下所示:
pwm_id:需要申請(qǐng)的pwm通道數(shù)。
min_period:周期時(shí)長(zhǎng)最小值。
max_period:周期時(shí)長(zhǎng)最大值。
duty_ns:pwm 的占空比激活的時(shí)長(zhǎng),單位 ns。
用戶可在其它驅(qū)動(dòng)文件中使用以上步驟生成的 PWM 節(jié)點(diǎn)。具體方法如下:
(1)、在要使用 PWM 控制的設(shè)備驅(qū)動(dòng)文件中包含以下頭文件:
該頭文件主要包含 PWM 的函數(shù)接口。
(2)、申請(qǐng) PWM使用
函數(shù)申請(qǐng) PWM。 例如:
(3)、配置 PWM使用
配置 PWM 的占空比, 例如:
(4)、使能PWM 函數(shù)
用于使能 PWM,例如:
(5)控制 PWM 輸出主要使用以下接口函數(shù):
功能:用于申請(qǐng) pwm
功能:用于釋放所申請(qǐng)的 pwm
功能:用于配置 pwm 的占空比
功能:使能 pwm
功能:禁止 pwm
參考Demo:kernel/drivers/pwm/pwm-firefly.c
通過(guò)內(nèi)核豐富的debug接口查看pwm注冊(cè)狀態(tài),adb shell或者串口進(jìn)入android終端 cat /sys/kernel/debug/pwm —注冊(cè)是否成功,成功則返回接口名和寄存器地址
Pwm無(wú)法注冊(cè)成功:
dts配置文件是否打開對(duì)應(yīng)的pwm。
pwm所在的io口是否被其他資源占用,可以根據(jù)報(bào)錯(cuò)的返回值去查看原因。
SPI是一種高速的,全雙工,同步串行通信接口,用于連接微控制器、傳感器、存儲(chǔ)設(shè)備等。 AIO-3399JD4 SPI引出來(lái)了一路SPI2(可復(fù)用GPIO)給外部使用。 AIO-3399JD4 開發(fā)板提供了 SPI2(單片選)接口,具體位置如下圖:
SPI以主從方式工作,這種模式通常有一個(gè)主設(shè)備和一個(gè)或多個(gè)從設(shè)備,需要至少4根線,分別是:
Linux內(nèi)核用CPOL和CPHA的組合來(lái)表示當(dāng)前SPI的四種工作模式:
CPOL:表示時(shí)鐘信號(hào)的初始電平的狀態(tài),0為低電平,1為高電平。CPHA:表示在哪個(gè)時(shí)鐘沿采樣,0為第一個(gè)時(shí)鐘沿采樣,1為第二個(gè)時(shí)鐘沿采樣。SPI的四種工作模式波形圖如下:
下面以 W25Q128FV Flash模塊為例簡(jiǎn)單介紹SPI驅(qū)動(dòng)的編寫。
硬件連接
AIO-3399JD4 與 W25Q128FV 硬件連接如下表:
在kernel/drivers/spi/Kconfig中添加對(duì)應(yīng)的驅(qū)動(dòng)文件配置:
在kernel/drivers/spi/Makefile中添加對(duì)應(yīng)的驅(qū)動(dòng)文件名:
config中選中所添加的驅(qū)動(dòng)文件,如:
配置DTS節(jié)點(diǎn)
在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi中添加SPI驅(qū)動(dòng)結(jié)點(diǎn)描述,如下所示:
status:如果要啟用SPI,則設(shè)為okay,如不啟用,設(shè)為disable。
spi-demo@00:由于本例子使用CS0,故此處設(shè)為00,如果使用CS1,則設(shè)為01。
compatible:這里的屬性必須與驅(qū)動(dòng)中的結(jié)構(gòu)體:of_device_id 中的成員compatible 保持一致。
reg:此處與spi-demo@00保持一致,本例設(shè)為:0x00。
spi-max-frequency:此處設(shè)置spi使用的最高頻率。Firefly-RK3399最高支持48000000。
spi-cpha,spi-cpol:SPI的工作模式在此設(shè)置,本例所用的模塊SPI工作模式為SPI_MODE_0或者SPI_MODE_3,這里我們選用SPI_MODE_0,如果使用SPI_MODE_3,spi_demo中打開spi-cpha和spi-cpol即可。
spidev0: 由于spi_demo與spidev0使用一樣的硬件資源,需要把spidev0關(guān)掉才能打開spi_demo
定義SPI驅(qū)動(dòng)
在內(nèi)核源碼目錄kernel/drivers/spi/中創(chuàng)建新的驅(qū)動(dòng)文件,如:spi-firefly-demo.c 在定義 SPI 驅(qū)動(dòng)之前,用戶首先要定義變量 of_device_id 。 of_device_id 用于在驅(qū)動(dòng)中調(diào)用dts文件中定義的設(shè)備信息,其定義如下所示:
此處的compatible與DTS文件中的保持一致。
spi_driver定義如下所示:
注冊(cè)SPI設(shè)備
在初始化函數(shù)static int __init spidev_init(void)中向內(nèi)核注冊(cè)SPI驅(qū)動(dòng): spi_register_driver(&firefly_spi_driver);
如果內(nèi)核啟動(dòng)時(shí)匹配成功,則SPI核心會(huì)配置SPI的參數(shù)(mode、speed等),并調(diào)用firefly_spi_probe。
讀寫 SPI 數(shù)據(jù)
firefly_spi_probe中使用了兩種接口操作讀取W25Q128FV的ID: firefly_spi_read_w25x_id_0接口直接使用了spi_transfer和spi_message來(lái)傳送數(shù)據(jù)。 firefly_spi_read_w25x_id_1接口則使用SPI接口spi_write_then_read來(lái)讀寫數(shù)據(jù)。
成功后會(huì)打?。?/p>
打開SPI demo
spi-firefly-demo默認(rèn)沒有打開,如果需要的話可以使用以下補(bǔ)丁打開demo驅(qū)動(dòng):
常用SPI接口
下面是常用的 SPI API 定義:
Linux提供了一個(gè)功能有限的SPI用戶接口,如果不需要用到IRQ或者其他內(nèi)核驅(qū)動(dòng)接口,可以考慮使用接口spidev編寫用戶層程序控制SPI設(shè)備。 在 Firefly-RK3399 開發(fā)板中對(duì)應(yīng)的路徑為: /dev/spidev0.0
spidev對(duì)應(yīng)的驅(qū)動(dòng)代碼: kernel/drivers/spi/spidev.c
內(nèi)核config需要選上SPI_SPIDEV:
DTS配置如下:
詳細(xì)使用說(shuō)明請(qǐng)參考文檔 spidev 。
Q1: SPI數(shù)據(jù)傳送異常
A1: 確保 SPI 4個(gè)引腳的 IOMUX 配置正確, 確認(rèn) TX 送數(shù)據(jù)時(shí),TX 引腳有正常的波形,CLK 頻率正確,CS 信號(hào)有拉低,mode 與設(shè)備匹配。
RK3399有12 個(gè)Timers (timer0-timer11),有12 個(gè)Secure Timers(stimer0~stimer11) 和 2 個(gè)Timers(pmutimer0~pmutimer1), 我們主要用到的是Timers(timer0-timer11)時(shí)鐘頻率為24MHZ ,工作模式有 free-running 和 user-defined count 模式
user-defined count:Timer 先載入初始值到 TIMERn_LOAD_COUNT3 和 TIMER_LOADn_COUNT2寄存器, 當(dāng)時(shí)間累加的值在寄存器TIMERn_LOAD_COUNT1和TIMERn_LOAD_COUNT0時(shí),將不會(huì)自動(dòng)載入到計(jì)數(shù)寄存器。 用戶需要重新關(guān)閉計(jì)數(shù)器和然后重新設(shè)置計(jì)數(shù)器相關(guān)才能繼續(xù)工作。
free-running:Timer先載入初始值到TIMER_LOAD_COUNT3 和 TIMER_LOAD_COUNT2寄存器, 當(dāng)時(shí)間累加的值在寄存器TIMERn_LOAD_COUNT1和TIMERn_LOAD_COUNT0時(shí),Timer將一直自動(dòng)加載計(jì)數(shù)寄存器。
1.在 dts 文件中定義 Timer 的相關(guān)配置 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi
其中定義的Timer0 的寄存器和中斷號(hào)和時(shí)鐘等
其他Timer 對(duì)應(yīng)的中斷號(hào)可看如下圖片
2.對(duì)應(yīng)的驅(qū)動(dòng)文件Kernel/drivers/clocksource/rockchip_timer.c
1.寄存器如下圖片
文件kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-port.dtsi 有spi轉(zhuǎn)uart相關(guān)節(jié)點(diǎn)的定義:
可以看到,在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-aiojd4.dts文件中使能該節(jié)點(diǎn)即可使用。另外,由于我們板子使用的spi轉(zhuǎn)uart串口模塊掛到spi1上,所以還要使能spi1節(jié)點(diǎn)。如下:
注意:由于spi1_rxd和spi1_txd兩個(gè)腳可復(fù)用為uart4_rx和uart4_tx,所以要留意關(guān)閉掉uart4的使用,如下:
配置好串口后,硬件接口對(duì)應(yīng)軟件上的節(jié)點(diǎn)分別為:
用戶可以根據(jù)不同的接口使用不同的主機(jī)的 USB 轉(zhuǎn)串口適配器向開發(fā)板的串口收發(fā)數(shù)據(jù),例如RS485的調(diào)試步驟如下:
(1) 連接硬件
將開發(fā)板RS485 的A、B、GND 引腳分別和主機(jī)串口適配器(USB轉(zhuǎn)485轉(zhuǎn)串口模塊)的 A、B、GND 引腳相連。
(2) 打開主機(jī)的串口終端
在終端打開kermit,并設(shè)置波特率:
/dev/ttyUSB0 為 USB 轉(zhuǎn)串口適配器的設(shè)備文件
(3) 發(fā)送數(shù)據(jù)
RS485 的設(shè)備文件為 /dev/ttysWK0。在設(shè)備上運(yùn)行下列命令:
主機(jī)中的串口終端即可接收到字符串“firefly RS485 test…”
(4) 接收數(shù)據(jù)
首先在設(shè)備上運(yùn)行下列命令:
然后在主機(jī)的串口終端輸入字符串 “Firefly RS485 test…”,設(shè)備端即可見到相同的字符串。
-->
-
嵌入式主板
+關(guān)注
關(guān)注
7文章
6081瀏覽量
34936 -
安卓
+關(guān)注
關(guān)注
5文章
2107瀏覽量
56691 -
Firefly
+關(guān)注
關(guān)注
2文章
538瀏覽量
6929
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論