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

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

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

fireflyCORE-3399主板JD4驅(qū)動(dòng)開發(fā)簡(jiǎn)介

firefly ? 來(lái)源:firefly ? 作者:firefly ? 2019-12-17 16:49 ? 次閱讀
驅(qū)動(dòng)開發(fā)
ADC 使用
簡(jiǎn)介

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配置

配置DTS節(jié)點(diǎn)

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

saradc:saradc@ff100000{compatible="rockchip,rk3399-saradc";reg=<0x00xff1000000x00x100>;interrupts=;#io-channel-cells = <1>;clocks=<&cruSCLK_SARADC>,<&cruPCLK_SARADC>;clock-names="saradc","apb_pclk";status="disabled";};

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

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

這里申請(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ù)組:

staticconststructof_device_idfirefly_adc_match[]={{.compatible="firefly,rk3399-adc"},{},};

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

staticstructplatform_driverfirefly_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中對(duì)DTS所添加的資源進(jìn)行解析:

staticintfirefly_adc_probe(structplatform_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);}return0;}
驅(qū)動(dòng)說(shuō)明

獲取 AD 通道

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

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

staticintXXX_probe(structplatform_device*pdev);

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

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

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

計(jì)算采集到的電壓

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

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

注:

  • 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,則:

Vresult=(1800mv*568)/1023;
接口說(shuō)明
structiio_channel*iio_channel_get(structdevice*dev,constchar*consumer_channel);
  • 功能:獲取 iio 通道描述

  • 參數(shù):

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

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

voidiio_channel_release(structiio_channel*chan);
  • 功能:釋放 iio_channel_get 函數(shù)獲取到的通道

  • 參數(shù):

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

intiio_read_channel_raw(structiio_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=<&saradc3>;};

編譯內(nèi)核,燒錄內(nèi)核到Firefly-RK3399 開發(fā)板上,然后插拔風(fēng)扇時(shí),會(huì)打印內(nèi)核log信息如下:

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

獲取所有ADC值

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

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

為何按上面的步驟申請(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 使用
簡(jiǎn)介

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)的:

kernel/drivers/pinctrl/pinctrl-rockchip.c

其核心是填充 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的路徑為:

kernel/drivers/gpio/gpio-firefly.c

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

輸入輸出

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

kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-demo.dtsigpio_demo:gpio_demo{status="okay";compatible="firefly,rk3399-gpio";firefly-gpio=<&gpio012GPIO_ACTIVE_HIGH>;/*GPIO0_B4*/firefly-irq-gpio=<&gpio429IRQ_TYPE_EDGE_RISING>;/*GPIO4_D5*/};

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

firefly-gpioGPIO0_B4

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)行解析,代碼如下:

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 配置編號(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è)置成輸入模式,然后再讀取值:

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

下面是常用的 GPIO API 定義:

#include #include enumof_gpio_flags{OF_GPIO_ACTIVE_LOW=0x1,};intof_get_named_gpio_flags(structdevice_node*np,constchar*propname,intindex,enumof_gpio_flags*flags);intgpio_is_valid(intgpio);intgpio_request(unsignedgpio,constchar*label);voidgpio_free(unsignedgpio);intgpio_direction_input(intgpio);intgpio_direction_output(intgpio,intv);
中斷

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

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

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

IRQ_TYPE_NONE //默認(rèn)值,無(wú)定義中斷觸發(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ù)中對(duì)DTS所添加的資源進(jìn)行解析,再做中斷的注冊(cè)申請(qǐng),代碼如下:

staticintfirefly_gpio_probe(structplatform_device*pdev){intret;intgpio;enumof_gpio_flagsflag;structfirefly_gpio_info*gpio_info;structdevice_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%drequest failed!\n",gpio);gpio_free(gpio);returnIRQ_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);}return0;}staticirqreturn_tfirefly_gpio_irq(intirq,void*dev_id)//中斷函數(shù){printk("Enter firefly gpio irq test program!\n");returnIRQ_HANDLED;}

調(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ì)用到。

復(fù)用

如何定義 GPIO 有哪些功能可以復(fù)用,在運(yùn)行時(shí)又如何切換功能呢?以 I2C4 為例作簡(jiǎn)單的介紹。

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

Pad# func0 func1I2C4_SDA/GPIO1_B3gpio1b3i2c4_sdaI2C4_SCL/GPIO1_B4gpio1b4i2c4_scl

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

i2c4:i2c@ff3d0000{compatible="rockchip,rk3399-i2c";reg=<0x00xff3d00000x00x1000>;clocks=<&pmucruSCLK_I2C4_PMU>,<&pmucruPCLK_I2C4_PMU>;clock-names="i2c","pclk";interrupts=;pinctrl-names="default","gpio";pinctrl-0=<&i2c4_xfer>;pinctrl-1=<&i2c4_gpio>;//此處源碼未添加#address-cells = <1>;#size-cells = <0>;status="disabled";};

此處,跟復(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中這樣定義:

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=<112RK_FUNC_1&pcfg_pull_none>,<111RK_FUNC_1&pcfg_pull_none>;};i2c4_gpio:i2c4-gpio{rockchip,pins=<112RK_FUNC_GPIO&pcfg_pull_none>,<111RK_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。

在復(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ù)用功能的:

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é)點(diǎn)的 gpios 屬于所定義的兩個(gè) gpio:

gpios=<&gpio1GPIO_B3GPIO_ACTIVE_LOW>,<&gpio1GPIO_B4GPIO_ACTIVE_LOW>;

然后是調(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 定義:

#include structdevice{//...#ifdef CONFIG_PINCTRLstructdev_pin_info*pins;#endif//...};structdev_pin_info{structpinctrl*p;structpinctrl_state*default_state;#ifdef CONFIG_PMstructpinctrl_state*sleep_state;structpinctrl_state*idle_state;#endif};structpinctrl_state*pinctrl_lookup_state(structpinctrl*p,constchar*name);intpinctrl_select_state(structpinctrl*p,structpinctrl_state*s);
IO-Domain

在復(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)。

調(diào)試方法

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 指令的幫助:

#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) -lLength in bytes of area to access (defaults to one access, or whole file length) -r|w Read from or Write to memory (default read) -fFile to write on memory read, or to read on memory writeThe memory address to accessThe 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.

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

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

使用示例:

  • 查看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ù)用情況:

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

gpio1b3_selGPIO1B[3]iomuxselect2'b00: gpio2'b01: i2c4sensor_sda2'b10: reserved2'b11: reserved

因此可以確定該GPIO被復(fù)用為 i2c4sensor_sda。

  • 如果想復(fù)用為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-2 ( |vcc3v3_3g ) out hi gpio-4 ( |bt_default_wake_host) in lo gpio-5 ( |power ) in hi gpio-9 ( |bt_default_reset ) out lo gpio-10 ( |reset ) out lo gpio-13 ( |? ) out lo GPIOs 32-63, platform/pinctrl, gpio1: gpio-32 ( |vcc5v0_host ) out hi gpio-34 ( |int-n ) in hi gpio-35 ( |vbus-5v ) out lo gpio-45 ( |pmic-hold-gpio ) out hi gpio-49 ( |vcc3v3_pcie ) out hi gpio-54 ( |mpu6500 ) out hi gpio-56 ( |pmic-stby-gpio ) out hi GPIOs 64-95, platform/pinctrl, gpio2: gpio-83 ( |bt_default_rts ) in hi gpio-90 ( |bt_default_wake ) in lo gpio-91 ( |? ) out hi GPIOs 96-127, platform/pinctrl, gpio3: gpio-111 ( |mdio-reset ) out hi GPIOs 128-159, platform/pinctrl, gpio4: gpio-149 ( |hp-con-gpio ) out lo

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

FAQs

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)。

I2C 使用
簡(jiǎn)介

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

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

配置 I2C 可分為兩大步驟:

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

  • 定義和注冊(cè) I2C 驅(qū)動(dòng)

下面以配置 GSL3680 為例。

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

在注冊(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 文件中,如下所示:

kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-mini-edp.dts&i2c4{status="okay";gsl3680:gsl3680@41{compatible="gslX680";reg=<0x41>;screen_max_x=<1536>;screen_max_y=<2048>;touch-gpio=<&gpio120IRQ_TYPE_LEVEL_LOW>;reset-gpio=<&gpio012GPIO_ACTIVE_HIGH>;};};
定義和注冊(cè) I2C 驅(qū)動(dòng)

定義 I2C 驅(qū)動(dòng)

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

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

staticstructof_device_idgsl_ts_ids[]={{.compatible="gslX680"},{}};

定義變量 i2c_device_id:

staticconststructi2c_device_idgsl_ts_id[]={{GSLX680_I2C_NAME,0},{}};MODULE_DEVICE_TABLE(i2c,gsl_ts_id);

i2c_driver 如下所示:

staticstructi2c_drivergsl_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ū)動(dòng)所支持的設(shè)備。

注冊(cè) I2C 驅(qū)動(dòng)

使用i2c_add_driver函數(shù)注冊(cè) I2C 驅(qū)動(dòng)。

i2c_add_driver(&gsl_ts_driver);

在調(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ā)送信息:

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; }
  • 向從機(jī)讀取信息:

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: 請(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 拆分成兩次,修改如下:

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-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))。

內(nèi)核驅(qū)動(dòng)

在 Linux 內(nèi)核中,IR 驅(qū)動(dòng)僅支持 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+};};

注:第一列為鍵值,第二列為要響應(yīng)的按鍵碼。

如何獲取用戶碼和IR 鍵值

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

caseRMC_USERCODE:{//ddata->scanData<<=1;//ddata->count++;if((RK_PWM_TIME_BIT1_MINperiod)&&(ddata->periodscanData|=(0x01<count);}ddata->count++;if(ddata->count==0x10){//16bitusercodeDBG_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{//usercodeerrorddata->state=RMC_PRELOAD;}}}

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

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

echo1>/sys/module/rockchip_pwm_remotectl/parameters/code_print

將 IR 驅(qū)動(dòng)編譯進(jìn)內(nèi)核

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

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

configRK_REMOTECTL_PWMbool"rkxx remoctrl pwm0 capture"defaultn

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

obj-$(RK_REMOTECTL_PWM) += rk_pwm_remotectl.o

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

DeviceDrivers--->Inputdevicesupport----->[*]rkxxremotectl------->[*]rkxxremoctrlpwm0capture.

保存后,執(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)容如下所示:

key28ENTERkey116POWERWAKEkey158BACKkey139MENUkey217SEARCHkey232DPAD_CENTERkey108DPAD_DOWNkey103DPAD_UPkey102HOMEkey105DPAD_LEFTkey106DPAD_RIGHTkey115VOLUME_UPkey114VOLUME_DOWNkey143NOTIFICATIONWAKEkey113VOLUME_MUTEkey388TV_KEYMOUSE_MODE_SWITCHkey400TV_MEDIA_MULT_BACKWARDkey401TV_MEDIA_MULT_FORWARDkey402TV_MEDIA_PLAY_PAUSEkey64TV_MEDIA_PLAYkey65TV_MEDIA_PAUSEkey66TV_MEDIA_STOP

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

IR 使用

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

LCD使用
簡(jiǎn)介

AIO-3399JD4開發(fā)板默認(rèn)外置支持了兩個(gè)LCD屏接口,一個(gè)是LVDS,一個(gè)是EDP,接口對(duì)應(yīng)板子上的位置如下圖:

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

Config配置

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

CONFIG_LCD_MIPI=yCONFIG_MIPI_DSI=yCONFIG_RK32_MIPI_DSI=y
DTS配置

引腳配置

LVDS屏

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

/{model="AIO-3399JD4 Board lvds HSX101H40C (Android)";compatible="rockchip,android","rockchip,rk3399-firefly-lvds","rockchip,rk3399";};&backlight{status="okay";pwms=<&pwm00250001>;enable-gpios=<&gpio11GPIO_ACTIVE_HIGH>;default-brightness-level=<200>;polarity=<1>;brightness-levels=LEDSupport--->LEDTriggersupport--->LEDTimerTrigger

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

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

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

root@rk3399_firefly_box:/# cat sys/class/leds/firefly\:blue\:power/triggernonerc-feedbacktest_ac-onlinetest_battery-charging-or-fulltest_battery-chargingtest_battery-fulltest_battery-charging-blink-full-solidtest_usb-onlinemmc0mmc1ir-user-click[timer]heartbeatbacklightdefault-onrfkill0mmc2rfkill1rfkill2
MIPI CSI 使用
簡(jiǎn)介

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

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

接口效果圖

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

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

Android: `- hardware/rockchip/camera/ |- CameraHal // 攝像頭的 HAL 源碼 `- SiliconImage // ISP 庫(kù),包括所有支持模組的驅(qū)動(dòng)源碼 `- isi/drv/OV13850 // OV13850 模組的驅(qū)動(dòng)源碼 `- 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ū)動(dòng)源碼 `- kernel/include/media/camsys_head.h
配置原理

設(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è)攝像頭:

Multimediasupport--->camsysdriverRockChipcamerasystemdriver--->camsysdriverformarvinispcamsysdriverforcif

最后執(zhí)行:

makeARCH=arm64rk3399-firefly-aiojd4.img

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

調(diào)試方法

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

FAQs

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

PWM 使用
前言

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

  • PWM0 屏背光

  • PWM2 VDDLOG供電

  • PWM3 紅外IR

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

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

DTS配置

配置 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_demo:pwm_demo{status="okay";compatible="firefly,rk3399-pwm";pwm_id=<1>;min_period=<0>;max_period=<10000>;duty_ns=<5000>;};
  • pwm_id:需要申請(qǐng)的pwm通道數(shù)。

  • min_period:周期時(shí)長(zhǎng)最小值。

  • max_period:周期時(shí)長(zhǎng)最大值。

  • duty_ns:pwm 的占空比激活的時(shí)長(zhǎng),單位 ns。

接口說(shuō)明

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

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

#include

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

(2)、申請(qǐng) PWM使用

structpwm_device*pwm_request(intpwm_id,constchar*label);

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

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

(3)、配置 PWM使用

intpwm_config(structpwm_device*pwm,intduty_ns,intperiod_ns);

配置 PWM 的占空比, 例如:

pwm_config(pwm0, 500000, 1000000);

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

intpwm_enable(structpwm_device*pwm);

用于使能 PWM,例如:

pwm_enable(pwm0);

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

structpwm_device*pwm_request(intpwm_id,constchar*label);
  • 功能:用于申請(qǐng) pwm

voidpwm_free(structpwm_device*pwm);
  • 功能:用于釋放所申請(qǐng)的 pwm

intpwm_config(structpwm_device*pwm,intduty_ns,intperiod_ns);
  • 功能:用于配置 pwm 的占空比

intpwm_enable(structpwm_device*pwm);
  • 功能:使能 pwm

voidpwm_disable(structpwm_device*pwm);
  • 功能:禁止 pwm

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

調(diào)試方法

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

FAQs

Pwm無(wú)法注冊(cè)成功:

  • dts配置文件是否打開對(duì)應(yīng)的pwm。

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

SPI 使用

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

SPI工作方式

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

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

Linux內(nèi)核用CPOL和CPHA的組合來(lái)表示當(dāng)前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:表示時(shí)鐘信號(hào)的初始電平的狀態(tài),0為低電平,1為高電平。CPHA:表示在哪個(gè)時(shí)鐘沿采樣,0為第一個(gè)時(shí)鐘沿采樣,1為第二個(gè)時(shí)鐘沿采樣。SPI的四種工作模式波形圖如下:

驅(qū)動(dòng)編寫

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

硬件連接

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

編寫Makefile/Kconfig

在kernel/drivers/spi/Kconfig中添加對(duì)應(yīng)的驅(qū)動(dòng)文件配置:

configSPI_FIREFLYtristate"Firefly SPI demo support "defaultyhelpSelectthisoptionifyourFireflyboardneedstorunSPIdemo.

在kernel/drivers/spi/Makefile中添加對(duì)應(yīng)的驅(qū)動(dòng)文件名:

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

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

│ 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é)點(diǎn)

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

/*FireflySPIdemo*/&spi2{spi_demo:spi-demo@00{status="okay";compatible="firefly,rk3399-spi";reg=<0x00>;spi-max-frequency=<48000000>;/*rk3399driversupportSPI_CPOL|SPI_CPHA|SPI_CS_HIGH*///spi-cpha;/*SPImode:CPHA=1*///spi-cpol;/*SPImode: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ū)動(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è)備信息,其定義如下所示:

staticstructof_device_idfirefly_match_table[]={{.compatible="firefly,rk3399-spi",},{},};

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

spi_driver定義如下所示:

staticstructspi_driverfirefly_spi_driver={.driver={.name="firefly-spi",.owner=THIS_MODULE,.of_match_table=firefly_match_table,},.probe=firefly_spi_probe,};

注冊(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>

root@rk3399_firefly_box:/# dmesg | grep firefly-spi[1.006235]firefly-spispi0.0:FireflySPIdemoprogram[1.006246]firefly-spispi0.0:firefly_spi_probe:setupmode0,8bits/w,48000000Hzmax[1.006298]firefly-spispi0.0:firefly_spi_read_w25x_id_0:ID=ef40180000[1.006361]firefly-spispi0.0:firefly_spi_read_w25x_id_1:ID=ef40180000

打開SPI demo

spi-firefly-demo默認(rèn)沒有打開,如果需要的話可以使用以下補(bǔ)丁打開demo驅(qū)動(dòng):

---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@@/*FireflySPIdemo*/&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 定義:

voidspi_message_init(structspi_message*m);voidspi_message_add_tail(structspi_transfer*t,structspi_message*m);intspi_sync(structspi_device*spi,structspi_message*message);intspi_write(structspi_device*spi,constvoid*buf,size_tlen);intspi_read(structspi_device*spi,void*buf,size_tlen);ssize_tspi_w8r8(structspi_device*spi,u8cmd);ssize_tspi_w8r16(structspi_device*spi,u8cmd);ssize_tspi_w8r16be(structspi_device*spi,u8cmd);intspi_write_then_read(structspi_device*spi,constvoid*txbuf,unsignedn_tx,void*rxbuf,unsignedn_rx);
接口使用

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:

│ 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>;};};

詳細(xì)使用說(shuō)明請(qǐng)參考文檔 spidev 。

FAQs

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

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

TIMER 使用
前言

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

rktimer:rktimer@ff850000{compatible="rockchip,rk3399-timer";reg=<0x00xff8500000x00x1000>;interrupts=;clocks=<&cruPCLK_TIMER0>,<&cruSCLK_TIMER00>;clock-names="pclk","timer";};

其中定義的Timer0 的寄存器和中斷號(hào)和時(shí)鐘等

其他Timer 對(duì)應(yīng)的中斷號(hào)可看如下圖片

2.對(duì)應(yīng)的驅(qū)動(dòng)文件Kernel/drivers/clocksource/rockchip_timer.c

對(duì)應(yīng)寄存器和使用

1.寄存器如下圖片

DTS配置

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

&spi1{spi_wk2xxx:spi_wk2xxx@00{status="disabled";compatible="firefly,spi-wk2xxx";reg=<0x00>;spi-max-frequency=<10000000>;power-gpio=<&gpio24GPIO_ACTIVE_HIGH>;reset-gpio=<&gpio1173GPIO_ACTIVE_HIGH>;irq-gpio=<&gpio12IRQ_TYPE_EDGE_FALLING>;cs-gpio=<&gpio110GPIO_ACTIVE_HIGH>;/*rk3399driversupportSPI_CPOL|SPI_CPHA|SPI_CS_HIGH*///spi-cpha;/*SPImode:CPHA=1*///spi-cpol;/*SPImode:CPOL=1*///spi-cs-high;};}

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

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

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

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

配置好串口后,硬件接口對(duì)應(yīng)軟件上的節(jié)點(diǎn)分別為:

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

用戶可以根據(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è)置波特率:

$ 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è)備上運(yùn)行下列命令:

echofireflyRS485test...>/dev/ttysWK0

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

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

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

cat/dev/ttysWK0

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


-->

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

    評(píng)論

    相關(guān)推薦

    fireflyCORE-3399PRO主板JD4燒寫固件簡(jiǎn)介

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

    fireflyCORE-3399主板JD4--FAQs方案

    FAQs HDMI無(wú)法4K顯示? AIO-3399JD4默認(rèn)出廠固件是支持HDMI顯示,HDMI分辨率最高4K。如果HDMI無(wú)法支持4K分辨率可以重新燒寫默認(rèn)固件,或者重新編譯內(nèi)核
    的頭像 發(fā)表于 12-17 16:40 ?1302次閱讀
    <b class='flag-5'>fireflyCORE-3399</b><b class='flag-5'>主板</b><b class='flag-5'>JD4</b>--FAQs方案

    fireflyCORE-3399主板JD4接口定義

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

    fireflyCORE-3399主板JD4燒寫固件簡(jiǎn)介

    AIO-3399JD4 有靈活的啟動(dòng)方式。
    的頭像 發(fā)表于 12-17 17:01 ?1627次閱讀
    <b class='flag-5'>fireflyCORE-3399</b><b class='flag-5'>主板</b><b class='flag-5'>JD4</b>燒寫固件<b class='flag-5'>簡(jiǎn)介</b>

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

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

    Core 3399Pro JD4工具SDDiskTool

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

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

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

    Core 3399 JD4工具SD Firmware Tool

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4工具SD Firmware Tool.txt》資料免費(fèi)下載
    發(fā)表于 09-02 10:13 ?0次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b>工具SD Firmware Tool

    Core 3399 JD4解合包工具(Linux)

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4解合包工具(Linux).txt》資料免費(fèi)下載
    發(fā)表于 09-02 10:08 ?0次下載
    Core <b class='flag-5'>3399</b> <b class='flag-5'>JD4</b>解合包工具(Linux)

    Core 3399 JD4固件Debian

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4固件Debian.txt》資料免費(fèi)下載
    發(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產(chǎn)品規(guī)格書

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

    Core 3399 JD4文檔AIO 3399JD4 Product Specifications

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4文檔AIO 3399JD4 Product Specifications.pdf》資料免費(fèi)下載
    發(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 rk3399&3399pro v1.1.pdf

    電子發(fā)燒友網(wǎng)站提供《Core 3399 JD4文檔mb jd4 rk3399&3399pro v1.1.pdf.pdf》資料免費(fèi)下載
    發(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'>3399</b>pro 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èi)下載
    發(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'>3399</b>Pro 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èi)下載
    發(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'>3399</b>pro v1.1