0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

fireflyCORE-3399PRO主板JD4驅(qū)動開發(fā)介紹

firefly ? 來源:firefly ? 作者:firefly ? 2019-12-17 16:24 ? 次閱讀
驅(qū)動開發(fā)
ADC 使用
簡介

AIO-3399PRO-JD4 開發(fā)板上的 AD 接口有兩種,分別為:溫度傳感器 (Temperature Sensor)、逐次逼近ADC (Successive Approximation Register)。其中:

  • TS-ADC(Temperature Sensor):支持兩通道,時鐘頻率必須低于800KHZ

  • SAR-ADC(Successive Approximation Register):支持六通道單端10位的SAR-ADC,時鐘頻率必須小于13MHZ。

內(nèi)核采用工業(yè) I/O 子系統(tǒng)來控制 ADC,該子系統(tǒng)主要為 AD 轉(zhuǎn)換或者 DA 轉(zhuǎn)換的傳感器設(shè)計。

下面以SAR-ADC使用ADC風扇為例子,介紹 ADC 的基本配置方法。

DTS配置

配置DTS節(jié)點

AIO-3399PRO-JD4 SAR-ADC 的 DTS 節(jié)點在 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi 文件中定義,如下所示:

saradc: saradc@ff100000 { compatible = "rockchip,rk3399-saradc"; reg = <0x0 0xff100000 0x0 0x100>; interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH 0>; #io-channel-cells = <1>; clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>; clock-names = "saradc", "apb_pclk"; resets = <&cru SRST_P_SARADC>; reset-names = "saradc-apb"; };

用戶首先需在DTS文件中添加ADC的資源描述:

kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi : adc_demo: adc_demo{ status = "disabled"; compatible = "firefly,rk3399-adc"; io-channels = <&saradc 3>; };

這里申請的是SARADC通道3,在 AIO-3399PRO-JD4 中是不提供給客戶外部使用的,而且也沒有風扇接口,這里只是提供一個參考, 客戶可自行參考這個例子 運用SARADC通道0 去做自己的一些開發(fā)。

在驅(qū)動文件中匹配 DTS 節(jié)點

用戶驅(qū)動可參考Firefly adc demo :kernel/drivers/adc/adc-firefly-demo.c,這是一個偵測AIO-3399PROJD4風扇狀態(tài)的驅(qū)動。 首先在驅(qū)動文件中定義 of_device_id 結(jié)構(gòu)體數(shù)組:

static const struct of_device_id firefly_adc_match[] = { { .compatible = "firefly,rk3399-adc" }, {}, };

然后將該結(jié)構(gòu)體數(shù)組填充到要使用 ADC 的 platform_driver 中:

static struct platform_driver firefly_adc_driver = { .probe = firefly_adc_probe, .remove = firefly_adc_remove, .driver = { .name = "firefly_adc", .owner = THIS_MODULE, .of_match_table = firefly_adc_match, }, };

接著在firefly_adc_probe中對DTS所添加的資源進行解析:

static int firefly_adc_probe(struct platform_device *pdev) { printk("firefly_adc_probe!\n"); chan = iio_channel_get(&(pdev->dev), NULL); if (IS_ERR(chan)){ chan = NULL; printk("%s() have not set adc chan\n", __FUNCTION__); return -1; } fan_insert = false; if (chan) { INIT_DELAYED_WORK(&adc_poll_work, firefly_demo_adc_poll); schedule_delayed_work(&adc_poll_work,1000); } return 0; }
驅(qū)動說明

獲取 AD 通道

struct iio_channel *chan; //定義 IIO 通道結(jié)構(gòu)體 chan = iio_channel_get(&pdev->dev, NULL); //獲取 IIO 通道結(jié)構(gòu)體

注:iio_channel_get 通過 probe 函數(shù)傳進來的參數(shù) pdev 獲取 IIO 通道結(jié)構(gòu)體,probe 函數(shù)如下:

static int XXX_probe(struct platform_device *pdev);

讀取 AD 采集到的原始數(shù)據(jù)

int val,ret; ret = iio_read_channel_raw(chan, &val);

調(diào)用 iio_read_channel_raw 函數(shù)讀取 AD 采集的原始數(shù)據(jù)并存入 val 中。

計算采集到的電壓

使用標準電壓將 AD 轉(zhuǎn)換的值轉(zhuǎn)換為用戶所需要的電壓值。其計算公式如下:

Vref / (2^n-1) = Vresult / raw

注:

  • Vref 為標準電壓

  • n 為 AD 轉(zhuǎn)換的位數(shù)

  • Vresult 為用戶所需要的采集電壓

  • raw 為 AD 采集的原始數(shù)據(jù)

例如,標準電壓為 1.8V,AD 采集位數(shù)為 10 位,AD 采集到的原始數(shù)據(jù)為 568,則:

Vresult = (1800mv * 568) / 1023;
接口說明
struct iio_channel *iio_channel_get(struct device *dev, const char *consumer_channel);
  • 功能:獲取 iio 通道描述

  • 參數(shù):

    • dev: 使用該通道的設(shè)備描述指針

    • consumer_channel: 該設(shè)備所使用的 IIO 通道描述指針

void iio_channel_release(struct iio_channel *chan);
  • 功能:釋放 iio_channel_get 函數(shù)獲取到的通道

  • 參數(shù):

    • chan:要被釋放的通道描述指針

int iio_read_channel_raw(struct iio_channel *chan, int *val);
  • 功能:讀取 chan 通道 AD 采集的原始數(shù)據(jù)。

  • 參數(shù):

    • chan:要讀取的采集通道指針

    • val:存放讀取結(jié)果的指針

調(diào)試方法

Demo程序使用

在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi中使能adc_demo,將”disabled” 改為 “okay”:

adc_demo: adc_demo{ status = "okay"; compatible = "firefly,rk3399-adc"; io-channels = <&saradc 3>; };

編譯內(nèi)核,燒錄內(nèi)核到AIO-3399PROJD4 開發(fā)板上,然后插拔風扇時,會打印內(nèi)核log信息如下:

[ 85.158104] Fan insert! raw= 135 Voltage= 237mV [ 88.422124] Fan out! raw= 709 Voltage=1247mV

獲取所有ADC值

有個便捷的方法可以查詢到每個SARADC的值:

cat /sys/bus/iio/devices/iio\:device0/in_voltage*_raw
FAQs

為何按上面的步驟申請SARADC,會出現(xiàn)申請報錯的情況?

驅(qū)動需要獲取ADC通道來使用時,需要對驅(qū)動的加載時間進行控制,必須要在saradc初始化之后。saradc是使用module_platform_driver()進行平臺設(shè)備驅(qū)動注冊,最終調(diào)用的是module_init()。所以用戶的驅(qū)動加載函數(shù)只需使用比module_init()優(yōu)先級低的,例如:late_initcall(),就能保證驅(qū)動的加載的時間比saradc初始化時間晚,可避免出錯。

GPIO 使用
簡介

GPIO, 全稱 General-Purpose Input/Output(通用輸入輸出),是一種軟件運行期間能夠動態(tài)配置和控制的通用引腳。 RK3399有5組GPIO bank:GPIO0~GPIO4,每組又以 A0~A7, B0~B7, C0~C7, D0~D7 作為編號區(qū)分(不是所有 bank 都有全部編號,例如 GPIO4 就只有 C0~C7, D0~D2)。 所有的GPIO在上電后的初始狀態(tài)都是輸入模式,可以通過軟件設(shè)為上拉或下拉,也可以設(shè)置為中斷腳,驅(qū)動強度都是可編程的。 每個 GPIO 口除了通用輸入輸出功能外,還可能有其它復用功能,例如 GPIO2_A2,可以利用成以下功能:

  • GPIO2_A2

  • CIF_D2

每個 GPIO 口的驅(qū)動電流、上下拉和重置后的初始狀態(tài)都不盡相同,詳細情況請參考《RK3399 規(guī)格書》中的 “Chapter 10 GPIO” 一章。 RK3399 的 GPIO 驅(qū)動是在以下 pinctrl 文件中實現(xiàn)的:

kernel/drivers/pinctrl/pinctrl-rockchip.c

其核心是填充 GPIO bank 的方法和參數(shù),并調(diào)用 gpiochip_add 注冊到內(nèi)核中。

本文以TP_RST(GPIO0_B4)和LCD_RST(GPIO4_D5)這兩個通用GPIO口為例寫了一份簡單操作GPIO口的驅(qū)動,在SDK的路徑為:

kernel/drivers/gpio/gpio-firefly.c

以下就以該驅(qū)動為例介紹GPIO的操作。

輸入輸出

首先在DTS文件中增加驅(qū)動的資源描述:

kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi gpio_demo: gpio_demo { status = "okay"; compatible = "firefly,rk3399-gpio"; firefly-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; /* GPIO0_B4 */ firefly-irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>; /* GPIO4_D5 */ };

這里定義了一個腳作為一般的輸出輸入口:

firefly-gpio GPIO0_B4

AIO-3399PRO-JD4 的dts對引腳的描述與Firefly-RK3288有所區(qū)別,GPIO0_B4被描述為:<&gpio0 12 GPIO_ACTIVE_HIGH>,這里的12來源于:8+4=12,其中8是因為GPIO0_B4是屬于GPIO0的B組,如果是A組的話則為0,如果是C組則為16,如果是D組則為24,以此遞推,而4是因為B4后面的4。 GPIO_ACTIVE_HIGH表示高電平有效,如果想要低電平有效,可以改為:GPIO_ACTIVE_LOW,這個屬性將被驅(qū)動所讀取。

然后在probe函數(shù)中對DTS所添加的資源進行解析,代碼如下:

static int firefly_gpio_probe(struct platform_device *pdev) { int ret; int gpio; enum of_gpio_flags flag; struct firefly_gpio_info *gpio_info; struct device_node *firefly_gpio_node = pdev->dev.of_node; printk("Firefly GPIO Test Program Probe\n"); gpio_info = devm_kzalloc(&pdev->dev,sizeof(struct firefly_gpio_info *), GFP_KERNEL); if (!gpio_info) { return -ENOMEM; } gpio = of_get_named_gpio_flags(firefly_gpio_node, "firefly-gpio", 0, &flag); if (!gpio_is_valid(gpio)) { printk("firefly-gpio: %d is invalid\n", gpio); return -ENODEV; } if (gpio_request(gpio, "firefly-gpio")) { printk("gpio %d request failed!\n", gpio); gpio_free(gpio); return -ENODEV; } gpio_info->firefly_gpio = gpio; gpio_info->gpio_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1; gpio_direction_output(gpio_info->firefly_gpio, gpio_info->gpio_enable_value); printk("Firefly gpio putout\n"); ...... }

of_get_named_gpio_flags 從設(shè)備樹中讀取 firefly-gpio 和 firefly-irq-gpio 的 GPIO 配置編號和標志,gpio_is_valid 判斷該 GPIO 編號是否有效,gpio_request 則申請占用該 GPIO。如果初始化過程出錯,需要調(diào)用 gpio_free 來釋放之前申請過且成功的 GPIO 。 在驅(qū)動中調(diào)用 gpio_direction_output 就可以設(shè)置輸出高還是低電平,這里默認輸出從DTS獲取得到的有效電平GPIO_ACTIVE_HIGH,即為高電平,如果驅(qū)動正常工作,可以用萬用表測得對應的引腳應該為高電平。 實際中如果要讀出 GPIO,需要先設(shè)置成輸入模式,然后再讀取值:

int val; gpio_direction_input(your_gpio); val = gpio_get_value(your_gpio);

下面是常用的 GPIO API 定義:

#include #include enum of_gpio_flags { OF_GPIO_ACTIVE_LOW = 0x1, }; int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags); int gpio_is_valid(int gpio); int gpio_request(unsigned gpio, const char *label); void gpio_free(unsigned gpio); int gpio_direction_input(int gpio); int gpio_direction_output(int gpio, int v);
中斷

在Firefly的例子程序中還包含了一個中斷引腳,GPIO口的中斷使用與GPIO的輸入輸出類似,首先在DTS文件中增加驅(qū)動的資源描述:

kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-port.dtsi gpio { compatible = "firefly-gpio"; firefly-irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>; /* GPIO4_D5 */ };

IRQ_TYPE_EDGE_RISING表示中斷由上升沿觸發(fā),當該引腳接收到上升沿信號時可以觸發(fā)中斷函數(shù)。 這里還可以配置成如下:

IRQ_TYPE_NONE //默認值,無定義中斷觸發(fā)類型 IRQ_TYPE_EDGE_RISING //上升沿觸發(fā) IRQ_TYPE_EDGE_FALLING //下降沿觸發(fā) IRQ_TYPE_EDGE_BOTH //上升沿和下降沿都觸發(fā) IRQ_TYPE_LEVEL_HIGH //高電平觸發(fā) IRQ_TYPE_LEVEL_LOW //低電平觸發(fā)

然后在probe函數(shù)中對DTS所添加的資源進行解析,再做中斷的注冊申請,代碼如下:

static int firefly_gpio_probe(struct platform_device *pdev) { int ret; int gpio; enum of_gpio_flags flag; struct firefly_gpio_info *gpio_info; struct device_node *firefly_gpio_node = pdev->dev.of_node; ...... gpio_info->firefly_irq_gpio = gpio; gpio_info->firefly_irq_mode = flag; gpio_info->firefly_irq = gpio_to_irq(gpio_info->firefly_irq_gpio); if (gpio_info->firefly_irq) { if (gpio_request(gpio, "firefly-irq-gpio")) { printk("gpio %d request failed!\n", gpio); gpio_free(gpio); return IRQ_NONE; } ret = request_irq(gpio_info->firefly_irq, firefly_gpio_irq, flag, "firefly-gpio", gpio_info); if (ret != 0) free_irq(gpio_info->firefly_irq, gpio_info); dev_err(&pdev->dev, "Failed to request IRQ: %d\n", ret); } return 0; } static irqreturn_t firefly_gpio_irq(int irq, void *dev_id) //中斷函數(shù) { printk("Enter firefly gpio irq test program!\n"); return IRQ_HANDLED; }

調(diào)用gpio_to_irq把GPIO的PIN值轉(zhuǎn)換為相應的IRQ值,調(diào)用gpio_request申請占用該IO口,調(diào)用request_irq申請中斷,如果失敗要調(diào)用free_irq釋放,該函數(shù)中g(shù)pio_info-firefly_irq是要申請的硬件中斷號,firefly_gpio_irq是中斷函數(shù),gpio_info->firefly_irq_mode是中斷處理的屬性,”firefly-gpio”是設(shè)備驅(qū)動程序名稱,gpio_info是該設(shè)備的device結(jié)構(gòu),在注冊共享中斷時會用到。

復用

如何定義 GPIO 有哪些功能可以復用,在運行時又如何切換功能呢?以 I2C4 為例作簡單的介紹。

查規(guī)格表可知,I2C4_SDA 與 I2C4_SCL 的功能定義如下:

Pad# func0 func1 I2C4_SDA/GPIO1_B3 gpio1b3 i2c4_sda I2C4_SCL/GPIO1_B4 gpio1b4 i2c4_scl

在 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi 里有:

i2c4: i2c@ff3d0000 { compatible = "rockchip,rk3399-i2c"; reg = <0x0 0xff3d0000 0x0 0x1000>; clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>; clock-names = "i2c", "pclk"; interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH 0>; pinctrl-names = "default", "gpio"; pinctrl-0 = <&i2c4_xfer>; pinctrl-1 = <&i2c4_gpio>; //此處源碼未添加 #address-cells = <1>; #size-cells = <0>; status = "disabled"; };

此處,跟復用控制相關(guān)的是 pinctrl- 開頭的屬性:

  • pinctrl-names 定義了狀態(tài)名稱列表: default (i2c 功能) 和 gpio 兩種狀態(tài)。

  • pinctrl-0 定義了狀態(tài) 0 (即 default)時需要設(shè)置的 pinctrl: &i2c4_xfer

  • pinctrl-1 定義了狀態(tài) 1 (即 gpio)時需要設(shè)置的 pinctrl: &i2c4_gpio

這些 pinctrl 在kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi中這樣定義:

pinctrl: pinctrl { compatible = "rockchip,rk3399-pinctrl"; rockchip,grf = <&grf>; rockchip,pmu = <&pmugrf>; #address-cells = <0x2>; #size-cells = <0x2>; ranges; i2c4 { i2c4_xfer: i2c4-xfer { rockchip,pins = <1 12 RK_FUNC_1 &pcfg_pull_none>, <1 11 RK_FUNC_1 &pcfg_pull_none>; }; i2c4_gpio: i2c4-gpio { rockchip,pins = <1 12 RK_FUNC_GPIO &pcfg_pull_none>, <1 11 RK_FUNC_GPIO &pcfg_pull_none>; }; };

RK_FUNC_1,RK_FUNC_GPIO 的定義在 kernel/include/dt-bindings/pinctrl/rk.h 中:

#define RK_FUNC_GPIO 0 #define RK_FUNC_1 1 #define RK_FUNC_2 2 #define RK_FUNC_3 3 #define RK_FUNC_4 4 #define RK_FUNC_5 5 #define RK_FUNC_6 6 #define RK_FUNC_7 7

另外,像”1 11”,”1 12”這樣的值是有編碼規(guī)則的,編碼方式與上一小節(jié)”輸入輸出”描述的一樣,”1 11”代表GPIO1_B3,”1 12”代表GPIO1_B4。

在復用時,如果選擇了 “default” (即 i2c 功能),系統(tǒng)會應用 i2c4_xfer 這個 pinctrl,最終將 GPIO1_B3 和 GPIO1_B4 兩個針腳切換成對應的 i2c 功能;而如果選擇了 “gpio” ,系統(tǒng)會應用 i2c4_gpio 這個 pinctrl,將 GPIO1_B3 和 GPIO1_B4 兩個針腳還原為 GPIO 功能。

我們看看 i2c 的驅(qū)動程序 kernel/drivers/i2c/busses/i2c-rockchip.c 是如何切換復用功能的:

static int rockchip_i2c_probe(struct platform_device *pdev) { struct rockchip_i2c *i2c = NULL; struct resource *res; struct device_node *np = pdev->dev.of_node; int ret;// ... i2c->sda_gpio = of_get_gpio(np, 0); if (!gpio_is_valid(i2c->sda_gpio)) { dev_err(&pdev->dev, "sda gpio is invalid\n"); return -EINVAL; } ret = devm_gpio_request(&pdev->dev, i2c->sda_gpio, dev_name(&i2c->adap.dev)); if (ret) { dev_err(&pdev->dev, "failed to request sda gpio\n"); return ret; } i2c->scl_gpio = of_get_gpio(np, 1); if (!gpio_is_valid(i2c->scl_gpio)) { dev_err(&pdev->dev, "scl gpio is invalid\n"); return -EINVAL; } ret = devm_gpio_request(&pdev->dev, i2c->scl_gpio, dev_name(&i2c->adap.dev)); if (ret) { dev_err(&pdev->dev, "failed to request scl gpio\n"); return ret; } i2c->gpio_state = pinctrl_lookup_state(i2c->dev->pins->p, "gpio"); if (IS_ERR(i2c->gpio_state)) { dev_err(&pdev->dev, "no gpio pinctrl state\n"); return PTR_ERR(i2c->gpio_state); } pinctrl_select_state(i2c->dev->pins->p, i2c->gpio_state); gpio_direction_input(i2c->sda_gpio); gpio_direction_input(i2c->scl_gpio); pinctrl_select_state(i2c->dev->pins->p, i2c->dev->pins->default_state); // ... }

首先是調(diào)用 of_get_gpio 取出設(shè)備樹中 i2c4 結(jié)點的 gpios 屬于所定義的兩個 gpio:

gpios = <&gpio1 GPIO_B3 GPIO_ACTIVE_LOW>, <&gpio1 GPIO_B4 GPIO_ACTIVE_LOW>;

然后是調(diào)用 devm_gpio_request 來申請 gpio,接著是調(diào)用 pinctrl_lookup_state 來查找 “gpio” 狀態(tài),而默認狀態(tài) “default” 已經(jīng)由框架保存到 i2c->dev-pins->default_state 中了。

最后調(diào)用 pinctrl_select_state 來選擇是 “default” 還是 “gpio” 功能。

下面是常用的復用 API 定義:

#include struct device { //... #ifdef CONFIG_PINCTRL struct dev_pin_info *pins; #endif //... }; struct dev_pin_info { struct pinctrl *p; struct pinctrl_state *default_state; #ifdef CONFIG_PM struct pinctrl_state *sleep_state; struct pinctrl_state *idle_state; #endif }; struct pinctrl_state * pinctrl_lookup_state(struct pinctrl *p, const char *name); int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
IO-Domain

在復雜的片上系統(tǒng)(SOC)中,設(shè)計者一般會將系統(tǒng)的供電分為多個獨立的block,這稱作電源域(Power Domain),這樣做有很多好處,例如:

  • 在IO-Domain的DTS節(jié)點統(tǒng)一配置電壓域,不需要每個驅(qū)動都去配置一次,便于管理;

  • 依照的是Upstream的做法,以后如果需要Upstream比較方便;

  • IO-Domain的驅(qū)動支持運行過程中動態(tài)調(diào)整電壓域,例如PMIC的某個Regulator可以1.8v和3.3v的動態(tài)切換,一旦Regulator電壓發(fā)生改變,會通知IO-Domain驅(qū)動去重新設(shè)置電壓域。

AIO-3399ProJD4原理圖上的 Power Domain Map 表以及配置如下表所示:

通過RK3399Pro SDK的原理圖可以看到bt656-supply 的電壓域連接的是vcc18_dvp, vcc_io是從PMIC RK808的VLDO1出來的; 在DTS里面可以找到vcc1v8_dvp, 將bt656-supply = <&vcc18_dvp>。 其他路的配置也類似,需要注意的是如果這里是其他PMIC,所用的Regulator也不一樣,具體以實際電路情況為標準。

調(diào)試方法

IO指令

GPIO調(diào)試有一個很好用的工具,那就是IO指令,Android系統(tǒng)默認已經(jīng)內(nèi)置了IO指令,使用IO指令可以實時讀取或?qū)懭朊總€IO口的狀態(tài),這里簡單介紹IO指令的使用。 首先查看 io 指令的幫助:

#io --help Unknown option: ? Raw memory i/o utility - $Revision: 1.5 $ io -v -1|2|4 -r|w [-l ] [-f ] [] -v Verbose, asks for confirmation -1|2|4 Sets memory access size in bytes (default byte) -l Length in bytes of area to access (defaults to one access, or whole file length) -r|w Read from or Write to memory (default read) -f File to write on memory read, or to read on memory write The memory address to access The value to write (implies -w) Examples: io 0x1000 Reads one byte from 0x1000 io 0x1000 0x12 Writes 0x12 to location 0x1000 io -2 -l 8 0x1000 Reads 8 words from 0x1000 io -r -f dmp -l 100 200 Reads 100 bytes from addr 200 to file io -w -f img 0x10000 Writes the whole of file to memory Note access size (-1|2|4) does not apply to file based accesses.

從幫助上可以看出,如果要讀或者寫一個寄存器,可以用:

io -4 -r 0x1000 //讀從0x1000起的4位寄存器的值 io -4 -w 0x1000 //寫從0x1000起的4位寄存器的值

使用示例:

  • 查看GPIO1_B3引腳的復用情況

  • 從主控的datasheet查到GPIO1對應寄存器基地址為:0xff320000

  • 從主控的datasheet查到GPIO1B_IOMUX的偏移量為:0x00014

  • GPIO1_B3的iomux寄存器地址為:基址(Operational Base) + 偏移量(offset)=0xff320000+0x00014=0xff320014

  • 用以下指令查看GPIO1_B3的復用情況:

# io -4 -r 0xff320014 ff320014: 0000816a
  • 從datasheet查到[7:6]:

gpio1b3_sel GPIO1B[3] iomux select 2'b00: gpio 2'b01: i2c4sensor_sda 2'b10: reserved 2'b11: reserved

因此可以確定該GPIO被復用為 i2c4sensor_sda。

  • 如果想復用為GPIO,可以使用以下指令設(shè)置:

# io -4 -w 0xff320014 0x0000812a

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,可以這樣讀取該接口的信息:

# cat /sys/kernel/debug/gpio GPIOs 0-31, platform/pinctrl, gpio0: gpio-1 ( |? ) out hi gpio-4 ( |sysfs ) out hi gpio-5 ( |bt_default_wake_host) in hi gpio-10 ( |sysfs ) out hi gpio-11 ( |sysfs ) out hi GPIOs 32-63, platform/pinctrl, gpio1: gpio-32 ( |sysfs ) out hi gpio-33 ( |vcc3v3_3g ) out hi gpio-35 ( |sysfs ) out hi gpio-36 ( |sysfs ) out lo gpio-45 ( |? ) out lo gpio-46 ( |vsel ) out lo gpio-49 ( |vsel ) out lo gpio-54 ( |sysfs ) out hi gpio-55 ( |sysfs ) out hi gpio-56 ( |sysfs ) out hi GPIOs 64-95, platform/pinctrl, gpio2: gpio-70 ( |reset-gpio ) out hi gpio-72 ( |irq-gpio ) in hi gpio-76 ( |cs-gpio ) out hi gpio-83 ( |bt_default_rts ) in hi gpio-90 ( |bt_default_wake ) in hi gpio-91 ( |reset ) out hi gpio-92 ( |bt_default_reset ) out lo GPIOs 96-127, platform/pinctrl, gpio3: gpio-111 ( |mdio-reset ) out hi GPIOs 128-159, platform/pinctrl, gpio4: gpio-149 ( |vbus-gpio ) out hi gpio-154 ( |vcc5v0_host ) out hi GPIOs 511-511, platform/rk805-pinctrl, rk817-gpio, can sleep:

從讀取到的信息中可以知道,內(nèi)核把GPIO當前的狀態(tài)都列出來了,以GPIO0組為例,gpio-2(GPIO0_A2)作為3G模塊的電源控制腳(vcc3v3_3g),輸出高電平(out hi)。

FAQs

Q1: 如何將PIN的MUX值切換為一般的GPIO?

A1: 當使用GPIO request時候,會將該PIN的MUX值強制切換為GPIO,所以使用該pin腳為GPIO功能的時候確保該pin腳沒有被其他模塊所使用。

Q2: 為什么我用IO指令讀出來的值都是0x00000000?

A2: 如果用IO命令讀某個GPIO的寄存器,讀出來的值異常,如 0x00000000或0xffffffff等,請確認該GPIO的CLK是不是被關(guān)了,GPIO的CLK是由CRU控制,可以通過讀取datasheet下面CRU_CLKGATE_CON* 寄存器來查到CLK是否開啟,如果沒有開啟可以用io命令設(shè)置對應的寄存器,從而打開對應的CLK,打開CLK之后應該就可以讀到正確的寄存器值了。

Q3: 測量到PIN腳的電壓不對應該怎么查?

A3: 測量該PIN腳的電壓不對時,如果排除了外部因素,可以確認下該pin所在的io電壓源是否正確,以及IO-Domain配置是否正確。

Q4: gpio_set_value()與gpio_direction_output()有什么區(qū)別?

A4: 如果使用該GPIO時,不會動態(tài)的切換輸入輸出,建議在開始時就設(shè)置好GPIO 輸出方向,后面拉高拉低時使用gpio_set_value()接口,而不建議使用gpio_direction_output(), 因為gpio_direction_output接口里面有mutex鎖,對中斷上下文調(diào)用會有錯誤異常,且相比 gpio_set_value,gpio_direction_output 所做事情更多,浪費。

I2C 使用
簡介

AIO-3399PRO-JD4 開發(fā)板上有 9 個片上 I2C 控制器,各個 I2C 的使用情況如下表:

本文主要描述如何在該開發(fā)板上配置 I2C。

配置 I2C 可分為兩大步驟:

  • 定義和注冊 I2C 設(shè)備

  • 定義和注冊 I2C 驅(qū)動

下面以配置 GSL3680 為例。

定義和注冊 I2C 設(shè)備

在注冊I2C設(shè)備時,需要結(jié)構(gòu)體 i2c_client 來描述 I2C 設(shè)備。然而在標準Linux中,用戶只需要提供相應的 I2C 設(shè)備信息,Linux就會根據(jù)所提供的信息構(gòu)造 i2c_client 結(jié)構(gòu)體。

用戶所提供的 I2C 設(shè)備信息以節(jié)點的形式寫到 dts 文件中,如下所示:

kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-aiojd4-edp.dts &i2c4 { status = "okay"; gsl3680: gsl3680@41 { compatible = "gslX680"; reg = <0x41>; screen_max_x = <1536>; screen_max_y = <2048>; touch-gpio = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>; reset-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; }; };
定義和注冊 I2C 驅(qū)動

定義 I2C 驅(qū)動

在定義 I2C 驅(qū)動之前,用戶首先要定義變量 of_device_id 和 i2c_device_id 。

of_device_id 用于在驅(qū)動中調(diào)用dts文件中定義的設(shè)備信息,其定義如下所示:

static struct of_device_id gsl_ts_ids[] = { {.compatible = "gslX680"}, {} };

定義變量 i2c_device_id:

static const struct i2c_device_id gsl_ts_id[] = { {GSLX680_I2C_NAME, 0}, {} }; MODULE_DEVICE_TABLE(i2c, gsl_ts_id);

i2c_driver 如下所示:

static struct i2c_driver gsl_ts_driver = { .driver = { .name = GSLX680_I2C_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(gsl_ts_ids), }, #ifndef CONFIG_HAS_EARLYSUSPEND //.suspend = gsl_ts_suspend, //.resume = gsl_ts_resume, #endif .probe = gsl_ts_probe, .remove = gsl_ts_remove, .id_table = gsl_ts_id, };

注:變量id_table指示該驅(qū)動所支持的設(shè)備。

注冊 I2C 驅(qū)動

使用i2c_add_driver函數(shù)注冊 I2C 驅(qū)動。

i2c_add_driver(&gsl_ts_driver);

在調(diào)用 i2c_add_driver 注冊 I2C 驅(qū)動時,會遍歷 I2C 設(shè)備,如果該驅(qū)動支持所遍歷到的設(shè)備,則會調(diào)用該驅(qū)動的 probe 函數(shù)。

通過 I2C 收發(fā)數(shù)據(jù)

在注冊好 I2C 驅(qū)動后,即可進行 I2C 通訊。

  • 向從機發(fā)送信息:

int i2c_master_send(const struct i2c_client *client, const char *buf, int count) { int ret; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.len = count; msg.buf = (char *)buf; ret = i2c_transfer(adap, &msg, 1); /* + If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ return (ret == 1) ? count : ret; }
  • 向從機讀取信息:

int i2c_master_recv(const struct i2c_client *client, char *buf, int count) { struct i2c_adapter *adap = client->adapter; struct i2c_msg msg; int ret; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.len = count; msg.buf = buf; ret = i2c_transfer(adap, &msg, 1); /* + If everything went ok (i.e. 1 msg received), return #bytes received, + else error code. */ return (ret == 1) ? count : ret; } EXPORT_SYMBOL(i2c_master_recv);
FAQs

Q1: 通信失敗,出現(xiàn)這種log:”timeout, ipd: 0x00, state: 1”該如何調(diào)試?

A1: 請檢查硬件上拉是否給電。

Q2: 調(diào)用i2c_transfer返回值為-6?

A2: 返回值為-6表示為NACK錯誤,即對方設(shè)備無應答響應,這種情況一般為外設(shè)的問題,常見的有以下幾種情況:

  • I2C地址錯誤,解決方法是測量I2C波形,確認是否I2C 設(shè)備地址錯誤;

  • I2C slave 設(shè)備不處于正常工作狀態(tài),比如未給電,錯誤的上電時序等;

  • 時序不符合 I2C slave設(shè)備所要求也會產(chǎn)生Nack信號。

Q3: 當外設(shè)對于讀時序要求中間是stop信號不是repeat start信號的時候,該如何處理?

A3: 這時需要調(diào)用兩次i2c_transfer, I2C read 拆分成兩次,修改如下:

static int i2c_read_bytes(struct i2c_client *client, u8 cmd, u8 *data, u8 data_len) { struct i2c_msg msgs[2]; int ret; u8 *buffer; buffer = kzalloc(data_len, GFP_KERNEL); if (!buffer) return -ENOMEM;; msgs[0].addr = client->addr; msgs[0].flags = client->flags; msgs[0].len = 1; msgs[0].buf = &cmd; ret = i2c_transfer(client->adapter, msgs, 1); if (ret < 0) { dev_err(&client->adapter->dev, "i2c read failed\n"); kfree(buffer); return ret; } msgs[1].addr = client->addr; msgs[1].flags = client->flags | I2C_M_RD; msgs[1].len = data_len; msgs[1].buf = buffer; ret = i2c_transfer(client->adapter, &msgs[1], 1); if (ret < 0) dev_err(&client->adapter->dev, "i2c read failed\n"); else memcpy(data, buffer, data_len); kfree(buffer); return ret; }
IR 使用
紅外遙控配置

AIO-3399PRO-JD4 開發(fā)板上使用紅外收發(fā)傳感器 IR (耳機接口和recovery之間)實現(xiàn)遙控功能,在IR接口處接上紅外接收器。本文主要描述在開發(fā)板上如何配置紅外遙控器。

其配置步驟可分為兩個部分:

  • 修改內(nèi)核驅(qū)動:內(nèi)核空間修改,Linux 和 Android 都要修改這部分的內(nèi)容。

  • 修改鍵值映射:用戶空間修改(僅限 Android 系統(tǒng))。

內(nèi)核驅(qū)動

在 Linux 內(nèi)核中,IR 驅(qū)動僅支持 NEC 編碼格式。以下是在內(nèi)核中配置紅外遙控的方法。 所涉及到的文件

drivers/input/remotectl/rockchip_pwm_remotectl.c

定義相關(guān)數(shù)據(jù)結(jié)構(gòu)

以下是定義數(shù)據(jù)結(jié)構(gòu)的步驟:

&pwm3 { status = "okay"; interrupts = ; compatible = "rockchip,remotectl-pwm"; remote_pwm_id = ; handle_cpu_id = ; ir_key1{ rockchip,usercode = ; rockchip,key_table = { {0xeb, KEY_POWER}, // Power //Control {0xa3, 250}, // Settings {0xec, KEY_MENU}, // Menu {0xfc, KEY_UP}, // Up {0xfd, KEY_DOWN}, // Down {0xf1, KEY_LEFT}, // Left {0xe5, KEY_RIGHT}, // Right {0xf8, KEY_REPLY}, // Ok {0xb7, KEY_HOME}, // Home {0xfe, KEY_BACK}, // Back // Vol {0xa7, KEY_VOLUMEDOWN}, // Vol- {0xf4, KEY_VOLUMEUP}, // Vol+ }; };

注:第一列為鍵值,第二列為要響應的按鍵碼。

如何獲取用戶碼和IR 鍵值

在 remotectl_do_something 函數(shù)中獲取用戶碼和鍵值:

case RMC_USERCODE: { //ddata->scanData <<= 1; //ddata->count ++; if ((RK_PWM_TIME_BIT1_MIN < ddata->period) && (ddata->period < RK_PWM_TIME_BIT1_MAX)){ ddata->scanData |= (0x01<<ddata->count); } ddata->count ++; if (ddata->count == 0x10){//16 bit user code DBG_CODE("GET USERCODE=0x%x\n",((ddata->scanData) & 0xffff)); if (remotectl_keybdNum_lookup(ddata)){ ddata->state = RMC_GETDATA; ddata->scanData = 0; ddata->count = 0; }else{ //user code error ddata->state = RMC_PRELOAD; } } }

注:用戶可以使用 DBG_CODE() 函數(shù)打印用戶碼。

使用下面命令可以使能DBG_CODE打印:

echo 1 > /sys/module/rockchip_pwm_remotectl/parameters/code_print

將 IR 驅(qū)動編譯進內(nèi)核

將 IR 驅(qū)動編譯進內(nèi)核的步驟如下所示:

(1)、向配置文件 drivers/input/remotectl/Kconfig 中添加如下配置:

config RK_REMOTECTL_PWM bool "rkxx remoctrl pwm0 capture" default n

(2)、修改 drivers/input/remotectl 路徑下的 Makefile,添加如下編譯選項:

obj-$(RK_REMOTECTL_PWM) += rk_pwm_remotectl.o

(3)、在 kernel 路徑下使用 make menuconfig ,按照如下方法將IR驅(qū)動選中。

Device Drivers --->Input device support -----> [*] rkxx remotectl ------->[*] rkxx remoctrl pwm0 capture.

保存后,執(zhí)行 make 命令即可將該驅(qū)動編進內(nèi)核。

Android 鍵值映射

文件 /system/usr/keylayout/ff420030_pwm.kl 用于將 Linux 層獲取的鍵值映射到 Android 上對應的鍵值。用戶可以添加或者修改該文件的內(nèi)容以實現(xiàn)不同的鍵值映射。

該文件內(nèi)容如下所示:

key 28 ENTER key 116 POWER WAKE key 158 BACK key 139 MENU key 217 SEARCH key 232 DPAD_CENTER key 108 DPAD_DOWN key 103 DPAD_UP key 102 HOME key 105 DPAD_LEFT key 106 DPAD_RIGHT key 115 VOLUME_UP key 114 VOLUME_DOWN key 143 NOTIFICATION WAKE key 113 VOLUME_MUTE key 388 TV_KEYMOUSE_MODE_SWITCH key 400 TV_MEDIA_MULT_BACKWARD key 401 TV_MEDIA_MULT_FORWARD key 402 TV_MEDIA_PLAY_PAUSE key 64 TV_MEDIA_PLAY key 65 TV_MEDIA_PAUSE key 66 TV_MEDIA_STOP

注:通過 adb 修改該文件重啟后即可生效。

IR 使用

如下圖是通過按紅外遙控器按鈕,所產(chǎn)生的波形,主要由head,Control,information,signed free這四部分組成,具體可以參考RC6 Protocol。

LCD使用
簡介

AIO-3399PRO-JD4開發(fā)板默認外置支持了兩個LCD屏接口,一個是LVDS,一個是EDP,接口對應板子上的位置如下圖:

另外板子也支持MIPI屏幕,但需要注意的是MIPI和LVDS是復用的,使用MIPI之后不能使用LVDS。MIPI接口如下圖:

Config配置

如Android8.1,由于使用的是mipi轉(zhuǎn)lvds,AIO-3399PRO-JD4默認的配置文件kernel/arch/arm64/configs/firefly_defconfig已經(jīng)把LCD相關(guān)的配置設(shè)置好了,如果自己做了修改,請注意把以下配置加上:

CONFIG_LCD_MIPI=y CONFIG_MIPI_DSI=y CONFIG_RK32_MIPI_DSI=y
DTS配置

引腳配置

LVDS屏

AIO-3399PRO-JD4的SDK有LVDS DSI的DTS文件:kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-aiojd4-lvds-HSX101H40C.dts,從該文件中我們可以看到以下語句:

/ { model = "AIO-3399PRO-JD4 Board lvds HSX101H40C (Android)"; compatible = "rockchip,android", "rockchip,rk3399-firefly-lvds", "rockchip,rk3399"; }; &backlight { status = "okay"; pwms = <&pwm0 0 25000 1>; enable-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; default-brightness-level = <200>; polarity = <1>; brightness-levels = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35*/36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255>; }; &dsi { status = "okay"; dsi_panel: panel { compatible ="simple-panel-dsi"; reg = <0>; //ddc-i2c-bu //power-supply = <&vcc_lcd>; //pinctrl-0 = <&lcd_panel_reset &lcd_panel_enable>; backlight = <&backlight>; /* enable-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>; */ dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>; dsi,format = <MIPI_DSI_FMT_RGB888>; //bus-format = <MEDIA_BUS_FMT_RGB666_1X18>; dsi,lvds-force-clk = <800>; // 800/2/3 ~= 65Mhz dsi,lanes = <4>; dsi,channel = <0>; enable-delay-ms = <35>; prepare-delay-ms = <6>; unprepare-delay-ms = <0>; disable-delay-ms = <20>; size,width = <120>; size,height = <170>; status = "okay"; panel-init-sequence = [ 29 02 06 3C 01 09 00 07 00 29 02 06 14 01 06 00 00 00 29 02 06 64 01 0B 00 00 00 29 02 06 68 01 0B 00 00 00 29 02 06 6C 01 0B 00 00 00 29 02 06 70 01 0B 00 00 00 29 02 06 34 01 1F 00 00 00 29 02 06 10 02 1F 00 00 00 29 02 06 04 01 01 00 00 00 29 02 06 04 02 01 00 00 00 29 02 06 50 04 20 01 F0 03 29 02 06 54 04 19 00 5A 00 //5A 29 02 06 58 04 20 03 24 00 29 02 06 5C 04 0A 00 19 00 29 02 06 60 04 00 05 0A 00 29 02 06 64 04 01 00 00 00 29 02 06 A0 04 06 80 44 00 29 02 06 A0 04 06 80 04 00 29 02 06 04 05 04 00 00 00 29 02 06 80 04 00 01 02 03 29 02 06 84 04 04 07 05 08 29 02 06 88 04 09 0A 0E 0F 29 02 06 8C 04 0B 0C 0D 10 29 02 06 90 04 16 17 11 12 29 02 06 94 04 13 14 15 1B 29 02 06 98 04 18 19 1A 06 29 02 06 9C 04 31 04 00 00 ]; panel-exit-sequence = [ 05 05 01 28 05 78 01 10 ]; power_ctr: power_ctr { rockchip,debug = <0>; power_enable = <1>; bl_en:bl_en { gpios = <&gpio1 RK_PC5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&lcd_panel_bl_en>; rockchip,delay = <0>; }; lcd_en:lcd_en { gpios = <&gpio4 RK_PD6 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&lcd_panel_lcd_en>; rockchip,delay = <10>; }; lcd_pwr_en: lcd-pwr-en { gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&lcd_panel_pwr_en>; rockchip,delay = <10>; }; lcd_rst: lcd-rst { gpios = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&lcd_panel_reset>; rockchip,delay = <6>; }; }; disp_timings: display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <166000000>; //166000000 @50 hactive = <800>; vactive = <1280>; hsync-len = <10>; //20, 50 hback-porch = <100>; //50, 56 hfront-porch = <1580>;//50, 30 //1580 vsync-len = <10>; vback-porch = <25>; vfront-porch = <10>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <0>; }; }; }; };

這里定義了LCD的電源控制引腳:

bl_en:(GPIO1_C5)GPIO_ACTIVE_HIGH lcd_en:(GPIO4_D6)GPIO_ACTIVE_HIGH lcd_pwr_en:(GPIO1_A2)GPIO_ACTIVE_HIGH lcd_rst:(GPIO4_D1)GPIO_ACTIVE_HIGH

都是高電平有效,具體的引腳配置請參考《GPIO 使用》一節(jié)。

LVDS配置背光

AIO-3399PRO-JD4開發(fā)板外置了一個背光接口用來控制屏幕背光,如下圖所示:

在DTS文件:kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-core.dtsi中配置了背光信息,如下:

/ { compatible = "rockchip,rk3399-firefly-core", "rockchip,rk3399"; backlight: backlight { status = "disabled"; compatible = "pwm-backlight"; pwms = <&pwm0 0 25000 0>; brightness-levels = < 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255>; default-brightness-level = <200>; };

pwms屬性:配置PWM,范例里面默認使用pwm0,25000ns是周期(40 KHz)。LVDS需要加背光電源控制腳,在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-aiojd4-lvds-HSX101H40C.dts中可以看到以下語句:

&backlight { status = "okay"; enable-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; brightness-levels = < 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255>; };

因此使用時需修改DTS文件。

brightness-levels屬性:配置背光亮度數(shù)組,最大值為255,配置暗區(qū)和亮區(qū),并把亮區(qū)數(shù)組做255的比例調(diào)節(jié)。比如范例中暗區(qū)是255-221,亮區(qū)是220-0。 default-brightness-level屬性:開機時默認背光亮度,范圍為0-255。 具體請參考kernel中的說明文檔:kernel/Documentation/devicetree/bindings/leds/backlight/pwm-backlight.txt

配置顯示時序

LVDS屏

與EDP屏不同,LVDS屏的 Timing 寫在DTS文件中,在kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-aiojd4-lvds-HSX101H40C.dts中可以看到以下語句:

disp_timings: display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <166000000>; //166000000 @50 hactive = <800>; vactive = <1280>; hsync-len = <10>; //20, 50 hback-porch = <100>; //50, 56 hfront-porch = <1580>;//50, 30 //1580 vsync-len = <10>; vback-porch = <25>; vfront-porch = <10>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <0>; }; };

時序?qū)傩詤⒖枷聢D:

Init Code

LVDS屏

lvds屏上完電后需要發(fā)送初始化指令才能使之工作。

  • dts 可以在kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-aiojd4-lvds-HSX101H40C.dts中可以看到lvds的初始化指令列表:

&dsi { status = "okay"; ... panel-init-sequence = [ 29 00 06 3C 01 09 00 07 00 29 00 06 14 01 06 00 00 00 29 00 06 64 01 0B 00 00 00 29 00 06 68 01 0B 00 00 00 29 00 06 6C 01 0B 00 00 00 29 00 06 70 01 0B 00 00 00 29 00 06 34 01 1F 00 00 00 29 00 06 10 02 1F 00 00 00 29 00 06 04 01 01 00 00 00 29 00 06 04 02 01 00 00 00 29 00 06 50 04 20 01 F0 03 29 00 06 54 04 32 00 B4 00 29 00 06 58 04 80 07 48 00 29 00 06 5C 04 0A 00 19 00 29 00 06 60 04 38 04 0A 00 29 00 06 64 04 01 00 00 00 29 01 06 A0 04 06 80 44 00 29 00 06 A0 04 06 80 04 00 29 00 06 04 05 04 00 00 00 29 00 06 80 04 00 01 02 03 29 00 06 84 04 04 07 05 08 29 00 06 88 04 09 0A 0E 0F 29 00 06 8C 04 0B 0C 0D 10 29 00 06 90 04 16 17 11 12 29 00 06 94 04 13 14 15 1B 29 00 06 98 04 18 19 1A 06 29 02 06 9C 04 33 04 00 00 ]; panel-exit-sequence = [ 05 05 01 28 05 78 01 10 ]; ... };

命令格式以及說明可參考以下附件: Rockchip DRM Panel Porting Guide.pdf

  • kernel 發(fā)送指令可以看到在kernel/drivers/gpu/drm/panel/panel-simple.c文件中的操作:

static int panel_simple_enable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); int err; if (p->enabled) return 0; DBG("enter\n"); if (p->on_cmds) { err = panel_simple_dsi_send_cmds(p, p->on_cmds); if (err) dev_err(p->dev, "failed to send on cmds\n"); } if (p->desc && p->desc->delay.enable) { DBG("p->desc->delay.enable=%d\n", p->desc->delay.enable); msleep(p->desc->delay.enable); } if (p->backlight) { DBG("open backlight\n"); p->backlight->props.power = FB_BLANK_UNBLANK; backlight_update_status(p->backlight); } p->enabled = true; return 0; }
  • u-boot 發(fā)送指令可以看到在u-boot/drivers/video/rockchip-dw-mipi-dsi.c文件中的操作:

static int rockchip_dw_mipi_dsi_enable(struct display_state *state) { struct connector_state *conn_state = &state->conn_state; struct crtc_state *crtc_state = &state->crtc_state; const struct rockchip_connector *connector = conn_state->connector; const struct dw_mipi_dsi_plat_data *pdata = connector->data; struct dw_mipi_dsi *dsi = conn_state->private; u32 val; DBG("enter\n"); dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); if (!pdata->has_vop_sel) return 0; if (pdata->grf_switch_reg) { if (crtc_state->crtc_id) val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16); else val = pdata->dsi0_en_bit << 16; writel(val, RKIO_GRF_PHYS + pdata->grf_switch_reg); } debug("vop %s output to dsi0\n", (crtc_state->crtc_id) ? "LIT" : "BIG"); //rockchip_dw_mipi_dsi_read_allregs(dsi); return 0; }
DTS配置

引腳配置

EDP屏

AIO-3399PRO-JD4的SDK有EDP DSI的DTS文件:kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-aiojd4-edp.dts,從該文件中我們可以看到以下語句:

edp_panel: edp-panel { /* config 2 */ compatible = "lg,lp079qx1-sp0v"; /* config 3 */ //compatible = "simple-panel"; bus-format = ; backlight = <&backlight>; ports { panel_in_edp: endpoint { remote-endpoint = <&edp_out_panel>; }; }; power_ctr: power_ctr { power_enable = <1>; rockchip,debug = <0>; lcd_en: lcd-en { gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&lcd_panel_enable>; rockchip,delay = <20>; }; lcd_pwr_en: lcd-pwr-en { gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&lcd_panel_pwr_en>; rockchip,delay = <10>; }; }; }; ··· &pinctrl { lcd-panel { lcd_panel_enable: lcd-panel-enable { rockchip,pins = <1 4 RK_FUNC_GPIO &pcfg_pull_up>; }; lcd_panel_pwr_en: lcd-panel-pwr-en { rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_pull_up>; }; }; };

這里定義了LCD的電源控制引腳:

lcd_en:(GPIO1_A4)GPIO_ACTIVE_HIGH lcd_pwr_en:(GPIO0_A1)GPIO_ACTIVE_HIGH

都是高電平有效,具體的引腳配置請參考《GPIO 使用》一節(jié)。

EDP配置背光

因為背光接口是公用的,所以可參考上述LVDS的配置方法。

EDP配置顯示時序

kernel 把 Timing 寫在 panel-simple.c 中, 直接以短字符串匹配 在drivers/gpu/drm/panel/panel-simple.c文件中有以下語句

static const struct drm_display_mode lg_lp079qx1_sp0v_mode = { .clock = 200000, .hdisplay = 1536, .hsync_start = 1536 + 12, .hsync_end = 1536 + 12 + 16, .htotal = 1536 + 12 + 16 + 48, .vdisplay = 2048, .vsync_start = 2048 + 8, .vsync_end = 2048 + 8 + 4, .vtotal = 2048 + 8 + 4 + 8, .vrefresh = 60, .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, }; static const struct panel_desc lg_lp097qx1_spa1 = { .modes = &lg_lp097qx1_spa1_mode, .num_modes = 1, .size = { .width = 320, .height = 187, }, }; ... ... static const struct of_device_id platform_of_match[] = { { .compatible = "simple-panel", .data = NULL, },{ }, { .compatible = "lg,lp079qx1-sp0v", .data = &lg_lp079qx1_sp0v, }, { }, { /* sentinel */ } };

MODULE_DEVICE_TABLE(of, platform_of_match); 時序的參數(shù)在結(jié)構(gòu)體lg_lp079qx1_sp0v_mode中配置。

*U-boot 把 Timing 寫在 rockchip_panel.c 中, 直接以短字符串匹配 在drivers/video/rockchip_panel.c文件中有以下語句:

static const struct drm_display_mode lg_lp079qx1_sp0v_mode = { .clock = 200000, .hdisplay = 1536, .hsync_start = 1536 + 12, .hsync_end = 1536 + 12 + 16, .htotal = 1536 + 12 + 16 + 48, .vdisplay = 2048, .vsync_start = 2048 + 8, .vsync_end = 2048 + 8 + 4, .vtotal = 2048 + 8 + 4 + 8, .vrefresh = 60, .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, }; static const struct rockchip_panel g_panel[] = { { .compatible = "lg,lp079qx1-sp0v", .mode = &lg_lp079qx1_sp0v_mode, }, { .compatible = "auo,b125han03", .mode = &auo_b125han03_mode, }, };

時序的參數(shù)在結(jié)構(gòu)體lg_lp079qx1_sp0v_mode中配置。

MIPI屏

客戶根據(jù)需要在自行添加mipi硬件接口之后,配置MIPI屏的 Timing dts文件,在kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-aiojd4-mipi.dts中可以看到以下語句:

disp_timings: display-timings { native-mode = <&timing0>; timing0: timing0 { clock-frequency = <80000000>; hactive = <768>; vactive = <1024>; hsync-len = <20>; //20, 50 hback-porch = <130>; //50, 56 hfront-porch = <150>;//50, 30 vsync-len = <40>; vback-porch = <130>; vfront-porch = <136>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <0>; }; } }

Kernel 在kernel/drivers/gpu/drm/panel/panel-simple.c中可以看到在初始化函數(shù)panel_simple_probe中初始化了獲取時序的函數(shù)。

static int panel_simple_probe(struct device *dev, const struct panel_desc *desc){ ··· panel->base.funcs = &panel_simple_funcs; ··· }

該函數(shù)的在kernel/drivers/gpu/drm/panel/panel-simple.c中也有定義:

static int panel_simple_get_timings(struct drm_panel *panel,unsigned int num_timings,struct display_timing *timings) { struct panel_simple *p = to_panel_simple(panel); unsigned int i; if (!p->desc) return 0; if (p->desc->num_timings < num_timings) num_timings = p->desc->num_timings; if (timings) for (i = 0; i < num_timings; i++) timings[i] = p->desc->timings[i]; return p->desc->num_timings; }

mipi屏上完電后需要發(fā)送初始化指令才能使之工作,可以在kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-mipi.dts中可以看到mipi的初始化指令列表:

&mipi_dsi { status = "okay"; ... panel-init-sequence = [ 05 20 01 29 05 96 01 11 ]; panel-exit-sequence = [ 05 05 01 28 05 78 01 10 ]; ... };

命令格式以及說明可參考以下附件: Rockchip DRM Panel Porting Guide.pdf

發(fā)送指令可以看到在kernel/drivers/gpu/drm/panel/panel-simple.c文件中的操作:

static int panel_simple_enable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); int err; if (p->enabled) return 0; DBG("enter\n"); if (p->on_cmds) { err = panel_simple_dsi_send_cmds(p, p->on_cmds); if (err) dev_err(p->dev, "failed to send on cmds\n"); } if (p->desc && p->desc->delay.enable) { DBG("p->desc->delay.enable=%d\n", p->desc->delay.enable); msleep(p->desc->delay.enable); } if (p->backlight) { DBG("open backlight\n"); p->backlight->props.power = FB_BLANK_UNBLANK; backlight_update_status(p->backlight); } p->enabled = true; return 0; }

U-boot 發(fā)送指令可以看到在u-boot/drivers/video/rockchip-dw-mipi-dsi.c文件中的操作:

static int rockchip_dw_mipi_dsi_enable(struct display_state *state) { struct connector_state *conn_state = &state->conn_state; struct crtc_state *crtc_state = &state->crtc_state; const struct rockchip_connector *connector = conn_state->connector; const struct dw_mipi_dsi_plat_data *pdata = connector->data; struct dw_mipi_dsi *dsi = conn_state->private; u32 val; DBG("enter\n"); dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE); if (!pdata->has_vop_sel) return 0; if (pdata->grf_switch_reg) { if (crtc_state->crtc_id) val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16); else val = pdata->dsi0_en_bit << 16; writel(val, RKIO_GRF_PHYS + pdata->grf_switch_reg); } debug("vop %s output to dsi0\n", (crtc_state->crtc_id) ? "LIT" : "BIG"); //rockchip_dw_mipi_dsi_read_allregs(dsi); return 0; }
LED 使用
前言

AIO-3399PRO-JD4 開發(fā)板上有 2 個 LED 燈,如下表所示:

以設(shè)備的方式控制 LED可通過使用 LED 設(shè)備子系統(tǒng)或者直接操作 GPIO 控制該 LED。

標準的 Linux 專門為 LED 設(shè)備定義了 LED 子系統(tǒng)。 在 AIO-3399PRO-JD4 開發(fā)板中的兩個 LED 均以設(shè)備的形式被定義。

用戶可以通過 /sys/class/leds/ 目錄控制這兩個 LED。

開發(fā)板上的 LED 的默認狀態(tài)為:

  • Blue: 系統(tǒng)上電時打開

  • Yellow:用戶自定義

用戶可以通過 echo 向其 brightness屬性輸入命令控制每一個 LED:

root@rk3399_firefly_box:~ # echo 0 >/sys/class/leds/firefly:blue:power/brightness //藍燈滅 root@rk3399_firefly_box:~ # echo 1 >/sys/class/leds/firefly:blue:power/brightness //藍燈亮
使用trigger 方式控制 LED

Trigger 包含多種方式可以控制LED,這里就用兩個例子來說明

  • Simple trigger LED

  • Complex trigger LED

更詳細的說明請參考 leds-class.txt 。

首先我們需要知道定義多少個LED,同時對應的LED的屬性是什么。

在 kernel/arch/arm64/boot/dts/rockchip/rk3399pro-firefly-port.dts 文件中定義LED節(jié)點,具體定義如下:

leds { compatible = "gpio-leds"; power_led: power { label = "firefly:blue:power"; linux,default-trigger = "ir-power-click"; default-state = "on"; gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&led_power>; }; user_led: user { label = "firefly:yellow:user"; linux,default-trigger = "ir-user-click"; default-state = "off"; gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&led_user>; }; };

注意:compatible 的值要跟 drivers/leds/leds-gpio.c 中的 .compatible 的值要保持一致。

Simple trigger LED

按名字來是看就是簡單的觸發(fā)方式控制LED,如下就默認打開黃燈,AIO-3399PRO-JD4開機后黃燈就亮

(1)定義 LED 觸發(fā)器 在kernel/drivers/leds/trigger/led-firefly-demo.c 文件中有如下添加

DEFINE_LED_TRIGGER(ledtrig_default_control);

(2)注冊該觸發(fā)器

led_trigger_register_simple("ir-user-click", &ledtrig_default_control);

(3)控制 LED 的亮。

led_trigger_event(ledtrig_default_control, LED_FULL); //yellow led on

(4)打開LED demo

led-firefly-demo默認沒有打開,如果需要的話可以使用以下補丁打開demo驅(qū)動:

--- a/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi +++ b/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi @@ -52,7 +52,7 @@ led_demo: led_demo { - status = "disabled"; + status = "okay"; compatible = "firefly,rk3399-led"; };

Complex trigger LED

如下是trigger方式控制LED復雜一點的例子,timer trigger 就是讓LED達到不斷亮滅的效果

我們需要在內(nèi)核把timer trigger配置上

在 kernel 路徑下使用 make menuconfig ,按照如下方法將timer trigger驅(qū)動選中。

Device Drivers --->LED Support --->LED Trigger support --->LED Timer Trigger

保存配置并編譯內(nèi)核,把kernel.img 燒到AIO-3399PRO-JD4板子上 我們可以使用串口輸入命令,就可以看到藍燈不停的間隔閃爍

echo "timer" > sys/class/leds/firefly\:blue\:power/trigger

用戶還可以使用 cat 命令獲取 trigger 的可用值:

root@rk3399_firefly_box:/ # cat sys/class/leds/firefly\:blue\:power/trigger none rc-feedback test_ac-online test_battery-charging-or-full test_battery-charging test_battery-full test_battery-charging-blink-full-solid test_usb-online mmc0 mmc1 ir-user-click [timer] heartbeat backlight default-on rfkill0 mmc2 rfkill1 rfkill2
MIPI CSI 使用
簡介

AIO-3399PRO-JD4 開發(fā)板分別帶有兩個MIPI,MIPI最高支持支持4K拍照,并支持1080P 30FPS以上視頻錄制。此外,開發(fā)板還支持 USB 攝像頭。

本文以 OV13850 攝像頭為例,講解在該開發(fā)板上的配置過程。

接口效果圖

DTS配置
isp0: isp@ff910000 { … status = "okay"; } isp1: isp@ff920000 { … status = "okay"; }
驅(qū)動說明

與攝像頭相關(guān)的代碼目錄如下:

Android: `- hardware/rockchip/camera/ |- CameraHal // 攝像頭的 HAL 源碼 `- SiliconImage // ISP 庫,包括所有支持模組的驅(qū)動源碼 `- isi/drv/OV13850 // OV13850 模組的驅(qū)動源碼 `- calib/OV13850.xml // OV13850 模組的調(diào)校參數(shù) `- device/rockchip/rk3399/ |- rk3399_firefly_aio_box | `- cam_board.xml // 攝像頭的參數(shù)設(shè)置 Kernel: |- kernel/drivers/media/video/rk_camsys // CamSys 驅(qū)動源碼 `- kernel/include/media/camsys_head.h
配置原理

設(shè)置攝像頭相關(guān)的引腳和時鐘,即可完成配置過程。

從以下攝像頭接口原理圖可知,需要配置的引腳有:CIF_PWR、DVP_PWR和MIPI_RST。

  • mipi接口

  • DVP_PWR 對應 RK3399 的 GPIO1_C1;

  • CIF_PWR 對應 RK3399 的 GPIO1_A1;

  • MIPI_RST 對應GPIO0_B0;

在開發(fā)板中,這三個引腳都是在 cam_board.xml 中設(shè)置。

配置步驟

配置 Android

修改device/rockchip/rk3399/XXX_PRODUCT/cam_board.xml 來注冊攝像頭:

<BoardFile> <BoardXmlVersion version="v0.0xf.0">BoardXmlVersion> <CamDevie> <HardWareInfo> <Sensor> <SensorName name="OV13850"/> <SensorLens name="50013A1"/> <SensorDevID IDname="CAMSYS_DEVID_SENSOR_1B"/> <SensorHostDevID busnum="CAMSYS_DEVID_MARVIN"/> <SensorI2cBusNum busnum="1"/> <SensorI2cAddrByte byte="2"/> <SensorI2cRate rate="100000"/> <SensorAvdd name="NC" min="28000000" max="28000000" delay="0"/> <SensorDvdd name="NC" min="12000000" max="12000000" delay="0"/> <SensorDovdd name="NC" min="18000000" max="18000000" delay="5000"/> <SensorMclk mclk="24000000" delay="1000"/> <SensorGpioPwen ioname="RK30_PIN1_PC1" active="1" delay="1000"/> <SensorGpioRst ioname="RK30_PIN0_PB0" active="0" delay="1000"/> <SensorGpioPwdn ioname="RK30_PIN2_PA1" active="0" delay="0"/> <SensorFacing facing="back"/> <SensorInterface interface="MIPI"/> <SensorMirrorFlip mirror="0"/> <SensorOrientation orientation="180"/> <SensorPowerupSequence seq="1234"/> <SensorFovParemeter h="60.0" v="60.0"/> <SensorAWB_Frame_Skip fps="15"/> <SensorPhy phyMode="CamSys_Phy_Mipi" lane="2" phyIndex="0" sensorFmt="CamSys_Fmt_Raw_10b"/> Sensor> <VCM> <VCMDrvName name="DW9714"/> <VCMName name="HuaYong6505"/> <VCMI2cBusNum busnum="1"/> <VCMI2cAddrByte byte="0"/> <VCMI2cRate rate="0"/> <VCMVdd name="NC" min="0" max="0" delay="0"/> <VCMGpioPower ioname="NC" active="0" delay="1000"/> <VCMGpioPwdn ioname="NC" active="0" delay="0"/> <VCMCurrent start="20" rated="80" vcmmax="100" stepmode="13" drivermax="100"/> VCM> <Flash> <FlashName name="Internal"/> <FlashI2cBusNum busnum="0"/> <FlashI2cAddrByte byte="0"/> <FlashI2cRate rate="0"/> <FlashTrigger ioname="NC" active="0"/> <FlashEn ioname="NC" active="0"/> <FlashModeType mode="1"/> <FlashLuminance luminance="0"/> <FlashColorTemp colortemp="0"/> Flash> HardWareInfo> <SoftWareInfo> <AWB> <AWB_Auto support="1"/> <AWB_Incandescent support="1"/> <AWB_Fluorescent support="1"/> <AWB_Warm_Fluorescent support="1"/> <AWB_Daylight support="1"/> <AWB_Cloudy_Daylight support="1"/> <AWB_Twilight support="1"/> <AWB_Shade support="1"/> AWB> <Sence> <Sence_Mode_Auto support="1"/> <Sence_Mode_Action support="1"/> <Sence_Mode_Portrait support="1"/> <Sence_Mode_Landscape support="1"/> <Sence_Mode_Night support="1"/> <Sence_Mode_Night_Portrait support="1"/> <Sence_Mode_Theatre support="1"/> <Sence_Mode_Beach support="1"/> <Sence_Mode_Snow support="1"/> <Sence_Mode_Sunset support="1"/> <Sence_Mode_Steayphoto support="1"/> <Sence_Mode_Pireworks support="1"/> <Sence_Mode_Sports support="1"/> <Sence_Mode_Party support="1"/> <Sence_Mode_Candlelight support="1"/> <Sence_Mode_Barcode support="1"/> <Sence_Mode_HDR support="1"/> Sence> <Effect> <Effect_None support="1"/> <Effect_Mono support="1"/> <Effect_Solarize support="1"/> <Effect_Negative support="1"/> <Effect_Sepia support="1"/> <Effect_Posterize support="1"/> <Effect_Whiteboard support="1"/> <Effect_Blackboard support="1"/> <Effect_Aqua support="1"/> Effect> <FocusMode> <Focus_Mode_Auto support="1"/> <Focus_Mode_Infinity support="1"/> <Focus_Mode_Marco support="1"/> <Focus_Mode_Fixed support="1"/> <Focus_Mode_Edof support="1"/> <Focus_Mode_Continuous_Video support="0"/> <Focus_Mode_Continuous_Picture support="1"/> FocusMode> <FlashMode> <Flash_Mode_Off support="1"/> <Flash_Mode_On support="1"/> <Flash_Mode_Torch support="1"/> <Flash_Mode_Auto support="1"/> <Flash_Mode_Red_Eye support="1"/> FlashMode> <AntiBanding> <Anti_Banding_Auto support="1"/> <Anti_Banding_50HZ support="1"/> <Anti_Banding_60HZ support="1"/> <Anti_Banding_Off support="1"/> AntiBanding> <HDR support="1"/> <ZSL support="1"/> <DigitalZoom support="1"/> <Continue_SnapShot support="1"/> <InterpolationRes resolution="0"/> <PreviewSize width="1920" height="1080"/> <FaceDetect support="0" MaxNum="1"/> <DV> <DV_QCIF name="qcif" width="176" height="144" fps="10" support="1"/> <DV_QVGA name="qvga" width="320" height="240" fps="10" support="1"/> <DV_CIF name="cif" width="352" height="288" fps="10" support="1"/> <DV_VGA name="480p" width="640" height="480" fps="10" support="0"/> <DV_480P name="480p" width="720" height="480" fps="10" support="0"/> <DV_720P name="720p" width="1280" height="720" fps="10" support="1"/> <DV_1080P name="1080p" width="1920" height="1080" fps="10" support="1"/> DV> SoftWareInfo> CamDevie> BoardFile>

主要修改的內(nèi)容如下:

  • Sensor 名稱

<SensorName name="OV13850" >SensorName>

該名字必須與 Sensor 驅(qū)動的名字一致,目前提供的 Sensor 驅(qū)動格式如下:

libisp_isi_drv_OV13850.so
  • Sensor 軟件標識

<SensorDevID IDname="CAMSYS_DEVID_SENSOR_1A">SensorDevID>

注冊標識不一致即可,可填寫以下值:

CAMSYS_DEVID_SENSOR_1A CAMSYS_DEVID_SENSOR_1B CAMSYS_DEVID_SENSOR_2
  • 采集控制器名稱

<SensorHostDevID busnum="CAMSYS_DEVID_MARVIN" >SensorHostDevID>

目前只支持:

CAMSYS_DEVID_MARVIN
  • Sensor 所連接的主控 I2C 通道號

<SensorI2cBusNum busnum="1">SensorI2cBusNum>

具體通道號請參考攝像頭原理圖連接主控的 I2C 通道號。

  • Sensor 寄存器地址長度,單位:字節(jié)

<SensorI2cAddrByte byte="2">SensorI2cAddrByte>
  • Sensor 的 I2C 頻率,單位:Hz,用于設(shè)置 I2C 的頻率。

<SensorI2cRate rate="100000">SensorI2cRate>
  • Sensor 輸入時鐘頻率, 單位:Hz,用于設(shè)置攝像頭的時鐘。

<SensorMclk mclk="24000000">SensorMclk>
  • Sensor AVDD 的 PMU LDO 名稱。如果不是連接到 PMU,那么只需填寫 NC。

<SensorAvdd name="NC" min="0" max="0">SensorAvdd>
  • Sensor DOVDD 的 PMU LDO 名稱。

<SensorDovdd name="NC" min="18000000" max="18000000">SensorDovdd>

如果不是連接到 PMU,那么只需填寫 NC。注意 min 以及 max 值必須填寫,這決定了 Sensor 的 IO 電壓。

  • Sensor DVDD 的 PMU LDO 名稱。

<SensorDvdd name="NC" min="0" max="0">SensorDvdd>

如果不是連接到 PMU,那么只需填寫 NC。

  • Sensor PowerDown 引腳。

<SensorGpioPwdn ioname="RK30_PIN2_PA1" active="0">SensorGpioPwdn>

直接填寫名稱即可,active 填寫休眠的有效電平。

  • Sensor Reset 引腳。

<SensorGpioRst ioname="RK30_PIN3_PB0" active="0">SensorGpioRst>

直接填寫名稱即可,active 填寫復位的有效電平。

  • Sensor Power 引腳。

<SensorGpioPwen ioname="RK30_PIN1_PC1" active="1">SensorGpioPwen>

直接填寫名稱即可, active 填寫電源有效電平。

  • 選擇 Sensor 作為前置還是后置。

<SensorFacing facing="front">SensorFacing>

可填寫 “front” 或 “back”。

  • Sensor 的接口方式

<SensorInterface mode="MIPI">SensorInterface>

可填寫如下值:

CCIR601 CCIR656 MIPI SMIA
  • Sensor 的鏡像方式

<SensorMirrorFlip mirror="0">SensorMirrorFlip>

目前暫不支持。

  • Sensor 的角度信息

<SensorOrientation orientation="0">SensorOrientation>
  • 物理接口設(shè)置

MIPI

<SensorPhy phyMode="CamSys_Phy_Mipi" lane="2" phyIndex="0" sensorFmt="CamSys_Fmt_Raw_10b">SensorPhy>

hyMode:Sensor 接口硬件連接方式,對 MIPI Sensor 來說,該值取 “CamSys_Phy_Mipi” Lane:Sensor mipi 接口數(shù)據(jù)通道數(shù) Phyindex:Sensor mipi 連接的主控 mipi phy 編號 sensorFmt:Sensor 輸出數(shù)據(jù)格式,目前僅支持 CamSys_Fmt_Raw_10b

編譯內(nèi)核需將 drivers/media/video/rk_camsys 驅(qū)動源碼編進內(nèi)核,其配置方法如下:

在內(nèi)核源碼目錄下執(zhí)行命令:

make menuconfig

然后將以下配置項打開:

Device Drivers ---> Multimedia support ---> camsys driver RockChip camera system driver ---> camsys driver for marvin isp camsys driver for cif

最后執(zhí)行:

make ARCH=arm64 rk3399-firefly-aio.img

即可完成內(nèi)核的編譯。

調(diào)試方法

終端下可以直接修改/system/etc/cam_board.xml調(diào)試各參數(shù)并重啟生效

FAQs

1.無法打開攝像頭,首先確定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 詳細資料可查詢SDK/RKDocs

PWM 使用
前言

AIO-3399PRO-JD4開發(fā)板上引出有 3 路 PWM 輸出,分別為:

  • PWM0 屏背光

  • PWM2 VDDLOG供電

  • PWM3 紅外IR

本章主要描述如何配置 PWM。

RK3399的 PWM 驅(qū)動為: kernel/drivers/pwm/pwm-rockchip.c

DTS配置

配置 PWM 主要有以下三大步驟:配置 PWM DTS 節(jié)點、配置 PWM 內(nèi)核驅(qū)動、控制 PWM 設(shè)備。

配置 PWM DTS節(jié)點

在 DTS 源文件kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi 添加 PWM DTS 配置,如下所示:

pwm_demo: pwm_demo { status = "okay"; compatible = "firefly,rk3399-pwm"; pwm_id = <1>; min_period = <0>; max_period = <10000>; duty_ns = <5000>; };
  • pwm_id:需要申請的pwm通道數(shù)。

  • min_period:周期時長最小值。

  • max_period:周期時長最大值。

  • duty_ns:pwm 的占空比激活的時長,單位 ns。

接口說明

用戶可在其它驅(qū)動文件中使用以上步驟生成的 PWM 節(jié)點。具體方法如下:

(1)、在要使用 PWM 控制的設(shè)備驅(qū)動文件中包含以下頭文件:

#include

該頭文件主要包含 PWM 的函數(shù)接口。

(2)、申請 PWM使用

struct pwm_device *pwm_request(int pwm_id, const char *label);

函數(shù)申請 PWM。 例如:

struct pwm_device * pwm1 = NULL;pwm0 = pwm_request(1, “firefly-pwm”);

(3)、配置 PWM使用

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);

配置 PWM 的占空比, 例如:

pwm_config(pwm0, 500000, 1000000);

(4)、使能PWM 函數(shù)

int pwm_enable(struct pwm_device *pwm);

用于使能 PWM,例如:

pwm_enable(pwm0);

(5)控制 PWM 輸出主要使用以下接口函數(shù):

struct pwm_device *pwm_request(int pwm_id, const char *label);
  • 功能:用于申請 pwm

void pwm_free(struct pwm_device *pwm);
  • 功能:用于釋放所申請的 pwm

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
  • 功能:用于配置 pwm 的占空比

int pwm_enable(struct pwm_device *pwm);
  • 功能:使能 pwm

void pwm_disable(struct pwm_device *pwm);
  • 功能:禁止 pwm

參考Demo:kernel/drivers/pwm/pwm-firefly.c

調(diào)試方法

通過內(nèi)核豐富的debug接口查看pwm注冊狀態(tài),adb shell或者串口進入android終端 cat /sys/kernel/debug/pwm —注冊是否成功,成功則返回接口名和寄存器地址

FAQs

Pwm無法注冊成功:

  • dts配置文件是否打開對應的pwm。

  • pwm所在的io口是否被其他資源占用,可以根據(jù)報錯的返回值去查看原因。

SPI 使用

SPI是一種高速的,全雙工,同步串行通信接口,用于連接微控制器、傳感器、存儲設(shè)備等。 AIO-3399PRO-JD4 SPI引出來了一路SPI2(可復用GPIO)給外部使用。 AIO-3399PRO-JD4 開發(fā)板提供了 SPI2(單片選)接口,具體位置如下圖:

SPI工作方式

SPI以主從方式工作,這種模式通常有一個主設(shè)備和一個或多個從設(shè)備,需要至少4根線,分別是:

CS 片選信號 SCLK 時鐘信號 MOSI 主設(shè)備數(shù)據(jù)輸出、從設(shè)備數(shù)據(jù)輸入 MISO 主設(shè)備數(shù)據(jù)輸入,從設(shè)備數(shù)據(jù)輸出

Linux內(nèi)核用CPOL和CPHA的組合來表示當前SPI的四種工作模式:

CPOL=0,CPHA=0 SPI_MODE_0 CPOL=0,CPHA=1 SPI_MODE_1 CPOL=1,CPHA=0 SPI_MODE_2 CPOL=1,CPHA=1 SPI_MODE_3

CPOL:表示時鐘信號的初始電平的狀態(tài),0為低電平,1為高電平。CPHA:表示在哪個時鐘沿采樣,0為第一個時鐘沿采樣,1為第二個時鐘沿采樣。SPI的四種工作模式波形圖如下:

驅(qū)動編寫

下面以 W25Q128FV Flash模塊為例簡單介紹SPI驅(qū)動的編寫。

硬件連接

AIO-3399PRO-JD4 與 W25Q128FV 硬件連接如下表:

編寫Makefile/Kconfig

在kernel/drivers/spi/Kconfig中添加對應的驅(qū)動文件配置:

config SPI_FIREFLY tristate "Firefly SPI demo support " default y help Select this option if your Firefly board needs to run SPI demo.

在kernel/drivers/spi/Makefile中添加對應的驅(qū)動文件名:

obj-$(CONFIG_SPI_FIREFLY) += spi-firefly-demo.o

config中選中所添加的驅(qū)動文件,如:

│ Symbol: SPI_FIREFLY [=y] │ Type : tristate │ Prompt: Firefly SPI demo support │ Location: │ -> Device Drivers │ -> SPI support (SPI [=y]) │ Defined at drivers/spi/Kconfig:704 │ Depends on: SPI [=y] && SPI_MASTER [=y]

配置DTS節(jié)點

在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi中添加SPI驅(qū)動結(jié)點描述,如下所示:

/* Firefly SPI demo */ &spi2 { spi_demo: spi-demo@00{ status = "okay"; compatible = "firefly,rk3399-spi"; reg = <0x00>; spi-max-frequency = <48000000>; /* rk3399 driver support SPI_CPOL | SPI_CPHA | SPI_CS_HIGH */ //spi-cpha; /* SPI mode: CPHA=1 */ //spi-cpol; /* SPI mode: CPOL=1 */ //spi-cs-high; }; }; &spidev0 { status = "disabled"; };
  • status:如果要啟用SPI,則設(shè)為okay,如不啟用,設(shè)為disable。

  • spi-demo@00:由于本例子使用CS0,故此處設(shè)為00,如果使用CS1,則設(shè)為01。

  • compatible:這里的屬性必須與驅(qū)動中的結(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ū)動

在內(nèi)核源碼目錄kernel/drivers/spi/中創(chuàng)建新的驅(qū)動文件,如:spi-firefly-demo.c 在定義 SPI 驅(qū)動之前,用戶首先要定義變量 of_device_id 。 of_device_id 用于在驅(qū)動中調(diào)用dts文件中定義的設(shè)備信息,其定義如下所示:

static struct of_device_id firefly_match_table[] = {{ .compatible = "firefly,rk3399-spi",},{},};

此處的compatible與DTS文件中的保持一致。

spi_driver定義如下所示:

static struct spi_driver firefly_spi_driver = { .driver = { .name = "firefly-spi", .owner = THIS_MODULE, .of_match_table = firefly_match_table,}, .probe = firefly_spi_probe, };

注冊SPI設(shè)備

在初始化函數(shù)static int __init spidev_init(void)中向內(nèi)核注冊SPI驅(qū)動: spi_register_driver(&firefly_spi_driver);

如果內(nèi)核啟動時匹配成功,則SPI核心會配置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來傳送數(shù)據(jù)。 firefly_spi_read_w25x_id_1接口則使用SPI接口spi_write_then_read來讀寫數(shù)據(jù)。

成功后會打?。?/p>

root@rk3399_firefly_box:/ # dmesg | grep firefly-spi [ 1.006235] firefly-spi spi0.0: Firefly SPI demo program [ 1.006246] firefly-spi spi0.0: firefly_spi_probe: setup mode 0, 8 bits/w, 48000000 Hz max [ 1.006298] firefly-spi spi0.0: firefly_spi_read_w25x_id_0: ID = ef 40 18 00 00 [ 1.006361] firefly-spi spi0.0: firefly_spi_read_w25x_id_1: ID = ef 40 18 00 00

打開SPI demo

spi-firefly-demo默認沒有打開,如果需要的話可以使用以下補丁打開demo驅(qū)動:

--- a/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi +++ b/kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsi @@ -64,7 +64,7 @@ /* Firefly SPI demo */ &spi1 {spi_demo: spi-demo@00{ - status = "disabled"; + status = "okay"; compatible = "firefly,rk3399-spi"; reg = <0x00>; spi-max-frequency = <48000000>; @@ -76,6 +76,6 @@ }; &spidev0 { - status = "okay"; + status = "disabled"; };

常用SPI接口

下面是常用的 SPI API 定義:

void spi_message_init(struct spi_message *m); void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m); int spi_sync(struct spi_device *spi, struct spi_message *message) ; int spi_write(struct spi_device *spi, const void *buf, size_t len); int spi_read(struct spi_device *spi, void *buf, size_t len); ssize_t spi_w8r8(struct spi_device *spi, u8 cmd); ssize_t spi_w8r16(struct spi_device *spi, u8 cmd); ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd); int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx);
接口使用

Linux提供了一個功能有限的SPI用戶接口,如果不需要用到IRQ或者其他內(nèi)核驅(qū)動接口,可以考慮使用接口spidev編寫用戶層程序控制SPI設(shè)備。 在 Firefly-RK3399 開發(fā)板中對應的路徑為: /dev/spidev0.0

spidev對應的驅(qū)動代碼: kernel/drivers/spi/spidev.c

內(nèi)核config需要選上SPI_SPIDEV:

│ Symbol: SPI_SPIDEV [=y] │ Type : tristate │ Prompt: User mode SPI device driver support │ Location: │ -> Device Drivers │ -> SPI support (SPI [=y]) │ Defined at drivers/spi/Kconfig:684 │ Depends on: SPI [=y] && SPI_MASTER [=y]

DTS配置如下:

&spi1 { status = "okay"; max-freq = <48000000>; spidev@00 { compatible = "linux,spidev"; reg = <0x00>; spi-max-frequency = <48000000>; }; };

詳細使用說明請參考文檔 spidev 。

FAQs

Q1: SPI數(shù)據(jù)傳送異常

A1: 確保 SPI 4個引腳的 IOMUX 配置正確, 確認 TX 送數(shù)據(jù)時,TX 引腳有正常的波形,CLK 頻率正確,CS 信號有拉低,mode 與設(shè)備匹配。

TIMER 使用
前言

RK3399有12 個Timers (timer0-timer11),有12 個Secure Timers(stimer0~stimer11) 和 2 個Timers(pmutimer0~pmutimer1), 我們主要用到的是Timers(timer0-timer11)時鐘頻率為24MHZ ,工作模式有 free-running 和 user-defined count 模式

框架圖

工作模式

user-defined count:Timer 先載入初始值到 TIMERn_LOAD_COUNT3 和 TIMER_LOADn_COUNT2寄存器, 當時間累加的值在寄存器TIMERn_LOAD_COUNT1和TIMERn_LOAD_COUNT0時,將不會自動載入到計數(shù)寄存器。 用戶需要重新關(guān)閉計數(shù)器和然后重新設(shè)置計數(shù)器相關(guān)才能繼續(xù)工作。

free-running:Timer先載入初始值到TIMER_LOAD_COUNT3 和 TIMER_LOAD_COUNT2寄存器, 當時間累加的值在寄存器TIMERn_LOAD_COUNT1和TIMERn_LOAD_COUNT0時,Timer將一直自動加載計數(shù)寄存器。

軟件配置

1.在 dts 文件中定義 Timer 的相關(guān)配置 kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi

rktimer: rktimer@ff850000 { compatible = "rockchip,rk3399-timer"; reg = <0x0 0xff850000 0x0 0x1000>; interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&cru PCLK_TIMER0>, <&cru SCLK_TIMER00>; clock-names = "pclk", "timer"; };

其中定義的Timer0 的寄存器和中斷號和時鐘等

其他Timer 對應的中斷號可看如下圖片

2.對應的驅(qū)動文件Kernel/drivers/clocksource/rockchip_timer.c

對應寄存器和使用

1.寄存器如下圖片

2.使用方式 查看對應寄存器

rk3399pro_firefly_aiojd4:/ # io -4 0xff85001c //查看當前控制寄存器的狀態(tài) ff85001c: 00000007 rk3399pro_firefly_aiojd4:/ # io -4 0xff850000 //查看寄存器時時的值 ff850000: 0001639f

控制對應寄存器

root@rk3399_firefly_box:/ # io -4 -w 0xff85001c 0x06 //關(guān)閉時間計數(shù)功能
UART 使用
簡介

AIO-3399PRO-JD4 支持SPI橋接/擴展4個增強功能串口(UART)的功能,分別為UART1,UART2,RS232RS485。每個UART都擁有256字節(jié)的FIFO緩沖區(qū),用于數(shù)據(jù)接收和發(fā)送。 其中:

  • UART1、UART2為TTL電平接口,RS232為RS232電平接口,RS485為RS485電平接口

  • UART1、UART2最高支持波特率691200。RS232、RS485受通訊媒介影響一般只支持115200以下。

  • 每個子通道具備收/發(fā)獨立的256 BYTE FIFO,FIFO的中斷可按用戶需求進行編程觸發(fā)點

  • 具備子串口接收FIFO超時中斷

  • 支持起始位錯誤檢測

AIO-3399PRO-JD4開發(fā)板的串口接口圖如下:

DTS配置

文件kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-port.dtsi 有spi轉(zhuǎn)uart相關(guān)節(jié)點的定義:

&spi1 { spi_wk2xxx: spi_wk2xxx@00{ status = "disabled"; compatible = "firefly,spi-wk2xxx"; reg = <0x00>; spi-max-frequency = <10000000>; power-gpio = <&gpio2 4 GPIO_ACTIVE_HIGH>; reset-gpio = <&gpio1 17 3 GPIO_ACTIVE_HIGH>; irq-gpio = <&gpio1 2 IRQ_TYPE_EDGE_FALLING>; cs-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; /* rk3399 driver support SPI_CPOL | SPI_CPHA | SPI_CS_HIGH */ //spi-cpha; /* SPI mode: CPHA=1 */ //spi-cpol; /* SPI mode: CPOL=1 */ //spi-cs-high; }; }

可以看到,在kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-aiojd4.dts文件中使能該節(jié)點即可使用。另外,由于我們板子使用的spi轉(zhuǎn)uart串口模塊掛到spi1上,所以還要使能spi1節(jié)點。如下:

&spi1 { status = "okay"; }; &spi_wk2xxx { status = "okay"; };

注意:由于spi1_rxd和spi1_txd兩個腳可復用為uart4_rx和uart4_tx,所以要留意關(guān)閉掉uart4的使用,如下:

&uart4 { status = "disabled"; };
調(diào)試方法

配置好串口后,硬件接口對應軟件上的節(jié)點分別為:

RS485:/dev/ttysWK0 RS232:/dev/ttysWK1 UART1:/dev/ttysWK2 UART2:/dev/ttysWK3

用戶可以根據(jù)不同的接口使用不同的主機的 USB 轉(zhuǎn)串口適配器向開發(fā)板的串口收發(fā)數(shù)據(jù),例如RS485的調(diào)試步驟如下:

(1) 連接硬件

將開發(fā)板RS485 的A、B、GND 引腳分別和主機串口適配器(USB轉(zhuǎn)485轉(zhuǎn)串口模塊)的 A、B、GND 引腳相連。

(2) 打開主機的串口終端

在終端打開kermit,并設(shè)置波特率:

$ sudo kermit C-Kermit> set line /dev/ttyUSB0 C-Kermit> set speed 9600 C-Kermit> set flow-control none C-Kermit> connect
  • /dev/ttyUSB0 為 USB 轉(zhuǎn)串口適配器的設(shè)備文件

(3) 發(fā)送數(shù)據(jù)

RS485 的設(shè)備文件為 /dev/ttysWK0。在設(shè)備上運行下列命令:

echo firefly RS485 test... > /dev/ttysWK0

主機中的串口終端即可接收到字符串“firefly RS485 test…”

(4) 接收數(shù)據(jù)

首先在設(shè)備上運行下列命令:

cat /dev/ttysWK0

然后在主機的串口終端輸入字符串 “Firefly RS485 test…”,設(shè)備端即可見到相同的字符串。


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 嵌入式主板
    +關(guān)注

    關(guān)注

    7

    文章

    6081

    瀏覽量

    34942
  • 安卓
    +關(guān)注

    關(guān)注

    5

    文章

    2107

    瀏覽量

    56706
  • Firefly
    +關(guān)注

    關(guān)注

    2

    文章

    538

    瀏覽量

    6930
收藏 人收藏

    評論

    相關(guān)推薦

    fireflyCORE-3399PRO主板JD4接口定義

    AIO-3399PRO-JD4 提供了豐富的接口,主要包括:電源接口, 1 x USB3.0(host/device),7 x USB2.0(接口×5,座子×2),HDMI,以太網(wǎng),LVDS屏幕接口
    的頭像 發(fā)表于 12-17 16:08 ?1869次閱讀
    <b class='flag-5'>fireflyCORE-3399PRO</b><b class='flag-5'>主板</b><b class='flag-5'>JD4</b>接口定義

    fireflyCORE-3399PRO主板JD4燒寫固件簡介

    AIO-3399PRO-JD4 有靈活的啟動方式。一般情況下,除非硬件損壞,AIO-3399PRO-JD4 開發(fā)板是不會變磚的。 如果在升級過程中出現(xiàn)意外,bootloader 損壞,導致無法重新升級,此時仍可以進入 Ma
    的頭像 發(fā)表于 12-17 16:32 ?2130次閱讀
    <b class='flag-5'>fireflyCORE-3399PRO</b><b class='flag-5'>主板</b><b class='flag-5'>JD4</b>燒寫固件簡介

    fireflyCORE-3399PRO主板JD4產(chǎn)品簡介

    Core-3399PRO-JD4核心板采用Rockchip高性能六核64位處理器RK3399Pro,處理器內(nèi)置AI神經(jīng)網(wǎng)絡(luò)處理器NPU,高算力,超高效能,擁有強大的硬解碼能力與豐富的擴展接口,可靈活應用到集群服務器、計算機視覺、商顯一體設(shè)備等行業(yè)中。
    的頭像 發(fā)表于 12-17 16:51 ?1821次閱讀

    fireflyCORE-3399主板JD4驅(qū)動開發(fā)簡介

    AIO-3399JD4 開發(fā)板上的 AD 接口有兩種
    的頭像 發(fā)表于 12-17 16:49 ?3334次閱讀
    <b class='flag-5'>fireflyCORE-3399</b><b class='flag-5'>主板</b><b class='flag-5'>JD4</b><b class='flag-5'>驅(qū)動</b><b class='flag-5'>開發(fā)</b>簡介

    fireflyCORE-3399主板JD4產(chǎn)品簡介

    Core-3399-JD4核心板采用Rockchip高性能六核64位處理器RK3399,板載AI神經(jīng)網(wǎng)絡(luò)處理器NPU SPR2801S,
    的頭像 發(fā)表于 12-18 14:11 ?1591次閱讀

    Core 3399Pro JD4工具SDDiskTool

    電子發(fā)燒友網(wǎng)站提供《Core 3399Pro JD4工具SDDiskTool.txt》資料免費下載
    發(fā)表于 09-02 14:31 ?1次下載
    Core <b class='flag-5'>3399Pro</b> <b class='flag-5'>JD4</b>工具SDDiskTool

    Core 3399Pro JD4 Linux SDK源碼包(僅支持RK3399Pro

    電子發(fā)燒友網(wǎng)站提供《Core 3399Pro JD4 Linux SDK源碼包(僅支持RK3399Pro).txt》資料免費下載
    發(fā)表于 09-02 10:59 ?0次下載
    Core <b class='flag-5'>3399Pro</b> <b class='flag-5'>JD4</b> Linux SDK源碼包(僅支持RK<b class='flag-5'>3399Pro</b>)

    Core 3399Pro JD4文檔Core 3399Pro JD4核心板產(chǎn)品規(guī)格書

    電子發(fā)燒友網(wǎng)站提供《Core 3399Pro JD4文檔Core 3399Pro JD4核心板產(chǎn)品規(guī)格書.txt》資料免費下載
    發(fā)表于 09-02 10:44 ?17次下載
    Core <b class='flag-5'>3399Pro</b> <b class='flag-5'>JD4</b>文檔Core <b class='flag-5'>3399Pro</b> <b class='flag-5'>JD4</b>核心板產(chǎn)品規(guī)格書

    Core 3399 JD4固件Debian

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4固件Debian.txt》資料免費下載
    發(fā)表于 09-02 09:44 ?0次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b>固件Debian

    Core 3399 JD4文檔AIO 3399JD4 Product Specifications

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4文檔AIO 3399JD4 Product Specifications.pdf》資料免費下載
    發(fā)表于 09-02 09:40 ?2次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b>文檔AIO <b class='flag-5'>3399JD4</b> Product Specifications

    Core 3399 JD4文檔MB JD4 RK33993399Pro V1.1貼片圖

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4文檔MB JD4 RK33993399Pro V1.1貼片圖.pdf》資料免費下載
    發(fā)表于 09-02 09:39 ?1次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b>文檔MB <b class='flag-5'>JD4</b> RK33993399<b class='flag-5'>Pro</b> V1.1貼片圖

    Core 3399 JD4文檔mb jd4 rk3399&3399pro v1.1.pdf

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4文檔mb jd4 rk3399&3399pro v1.1.pdf.pdf》資料免費下載
    發(fā)表于 09-02 09:38 ?1次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b>文檔mb <b class='flag-5'>jd4</b> rk<b class='flag-5'>3399</b>&<b class='flag-5'>3399pro</b> v1.1.pdf

    Core 3399 JD4 V2文檔MB JD4 RK3399/3399Pro V1.1貼片圖

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4 V2文檔MB JD4 RK3399/3399Pro V1.1貼片圖.pdf》資料免費下載
    發(fā)表于 09-16 09:48 ?2次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b> V2文檔MB <b class='flag-5'>JD4</b> RK<b class='flag-5'>3399</b>/<b class='flag-5'>3399Pro</b> V1.1貼片圖

    Core 3399 JD4 V2文檔mb jd4 rk3399/3399pro v1.1

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4 V2文檔mb jd4 rk3399/3399pro v1.1.pdf》資料免費下載
    發(fā)表于 09-16 09:47 ?1次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b> V2文檔mb <b class='flag-5'>jd4</b> rk<b class='flag-5'>3399</b>/<b class='flag-5'>3399pro</b> v1.1

    Core 1808 JD4文檔MB JD4 RK3399Pro V1.1貼片圖

    電子發(fā)燒友網(wǎng)站提供《Core 1808 JD4文檔MB JD4 RK3399Pro V1.1貼片圖.pdf》資料免費下載
    發(fā)表于 09-20 17:02 ?2次下載
    Core 1808 <b class='flag-5'>JD4</b>文檔MB <b class='flag-5'>JD4</b> RK<b class='flag-5'>3399Pro</b> V1.1貼片圖