在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

fireflyCORE-3399主板JD4驅動開發簡介

firefly ? 來源:firefly ? 作者:firefly ? 2019-12-17 16:49 ? 次閱讀
驅動開發
ADC 使用
簡介

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

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

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

內核采用工業 I/O 子系統來控制 ADC,該子系統主要為 AD 轉換或者 DA 轉換的傳感器設計。

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

DTS配置

配置DTS節點

AIO-3399JD4 SAR-ADC 的 DTS 節點在 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>;};

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

在驅動文件中匹配 DTS 節點

用戶驅動可參考Firefly adc demo :kernel/drivers/adc/adc-firefly-demo.c,這是一個偵測Firefly-rk3399風扇狀態的驅動。 首先在驅動文件中定義 of_device_id 結構體數組:

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

然后將該結構體數組填充到要使用 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中對DTS所添加的資源進行解析:

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;}
驅動說明

獲取 AD 通道

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

注:iio_channel_get 通過 probe 函數傳進來的參數 pdev 獲取 IIO 通道結構體,probe 函數如下:

staticintXXX_probe(structplatform_device*pdev);

讀取 AD 采集到的原始數據

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

調用 iio_read_channel_raw 函數讀取 AD 采集的原始數據并存入 val 中。

計算采集到的電壓

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

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

注:

  • Vref 為標準電壓

  • n 為 AD 轉換的位數

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

  • raw 為 AD 采集的原始數據

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

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

  • 參數:

    • dev: 使用該通道的設備描述指針

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

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

  • 參數:

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

intiio_read_channel_raw(structiio_channel*chan,int*val);
  • 功能:讀取 chan 通道 AD 采集的原始數據。

  • 參數:

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

    • val:存放讀取結果的指針

調試方法

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

編譯內核,燒錄內核到Firefly-RK3399 開發板上,然后插拔風扇時,會打印內核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,會出現申請報錯的情況?

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

GPIO 使用
簡介

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

  • GPIO2_A2

  • CIF_D2

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

kernel/drivers/pinctrl/pinctrl-rockchip.c

其核心是填充 GPIO bank 的方法和參數,并調用 gpiochip_add 注冊到內核中。

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

kernel/drivers/gpio/gpio-firefly.c

以下就以該驅動為例介紹GPIO的操作。

輸入輸出

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

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*/};

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

firefly-gpioGPIO0_B4

AIO-3399JD4 的dts對引腳的描述與Firefly-RK3288有所區別,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,這個屬性將被驅動所讀取。

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

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的例子程序中還包含了一個中斷引腳,GPIO口的中斷使用與GPIO的輸入輸出類似,首先在DTS文件中增加驅動的資源描述:

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表示中斷由上升沿觸發,當該引腳接收到上升沿信號時可以觸發中斷函數。 這里還可以配置成如下:

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

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

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)//中斷函數{printk("Enter firefly gpio irq test program!\n");returnIRQ_HANDLED;}

調用gpio_to_irq把GPIO的PIN值轉換為相應的IRQ值,調用gpio_request申請占用該IO口,調用request_irq申請中斷,如果失敗要調用free_irq釋放,該函數中gpio_info-firefly_irq是要申請的硬件中斷號,firefly_gpio_irq是中斷函數,gpio_info->firefly_irq_mode是中斷處理的屬性,”firefly-gpio”是設備驅動程序名稱,gpio_info是該設備的device結構,在注冊共享中斷時會用到。

復用

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

查規格表可知,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";};

此處,跟復用控制相關的是 pinctrl- 開頭的屬性:

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

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

  • pinctrl-1 定義了狀態 1 (即 gpio)時需要設置的 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”這樣的值是有編碼規則的,編碼方式與上一小節”輸入輸出”描述的一樣,”1 11”代表GPIO1_B3,”1 12”代表GPIO1_B4。

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

我們看看 i2c 的驅動程序 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); // ... }

首先是調用 of_get_gpio 取出設備樹中 i2c4 結點的 gpios 屬于所定義的兩個 gpio:

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

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

最后調用 pinctrl_select_state 來選擇是 “default” 還是 “gpio” 功能。

下面是常用的復用 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

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

  • 在IO-Domain的DTS節點統一配置電壓域,不需要每個驅動都去配置一次,便于管理;

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

  • IO-Domain的驅動支持運行過程中動態調整電壓域,例如PMIC的某個Regulator可以1.8v和3.3v的動態切換,一旦Regulator電壓發生改變,會通知IO-Domain驅動去重新設置電壓域。

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

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

調試方法

IO指令

GPIO調試有一個很好用的工具,那就是IO指令,AIO-3399C的Android系統默認已經內置了IO指令,使用IO指令可以實時讀取或寫入每個IO口的狀態,這里簡單介紹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.

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

io-4-r0x1000//讀從0x1000起的4位寄存器的值io-4-w0x1000//寫從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 0xff320014ff320014:0000816a
  • 從datasheet查到[7:6]:

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

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

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

# io -4 -w 0xff320014 0x0000812a

GPIO調試接口

Debugfs文件系統目的是為開發人員提供更多內核數據,方便調試。 這里GPIO的調試也可以用Debugfs文件系統,獲得更多的內核信息。 GPIO在Debugfs文件系統中的接口為 /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

從讀取到的信息中可以知道,內核把GPIO當前的狀態都列出來了,以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是不是被關了,GPIO的CLK是由CRU控制,可以通過讀取datasheet下面CRU_CLKGATE_CON* 寄存器來查到CLK是否開啟,如果沒有開啟可以用io命令設置對應的寄存器,從而打開對應的CLK,打開CLK之后應該就可以讀到正確的寄存器值了。

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

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

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

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

I2C 使用
簡介

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

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

配置 I2C 可分為兩大步驟:

  • 定義和注冊 I2C 設備

  • 定義和注冊 I2C 驅動

下面以配置 GSL3680 為例。

定義和注冊 I2C 設備

在注冊I2C設備時,需要結構體 i2c_client 來描述 I2C 設備。然而在標準Linux中,用戶只需要提供相應的 I2C 設備信息,Linux就會根據所提供的信息構造 i2c_client 結構體。

用戶所提供的 I2C 設備信息以節點的形式寫到 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>;};};
定義和注冊 I2C 驅動

定義 I2C 驅動

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

of_device_id 用于在驅動中調用dts文件中定義的設備信息,其定義如下所示:

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指示該驅動所支持的設備。

注冊 I2C 驅動

使用i2c_add_driver函數注冊 I2C 驅動。

i2c_add_driver(&gsl_ts_driver);

在調用 i2c_add_driver 注冊 I2C 驅動時,會遍歷 I2C 設備,如果該驅動支持所遍歷到的設備,則會調用該驅動的 probe 函數。

通過 I2C 收發數據

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

  • 向從機發送信息:

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: 通信失敗,出現這種log:”timeout, ipd: 0x00, state: 1”該如何調試?

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

Q2: 調用i2c_transfer返回值為-6?

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

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

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

  • 時序不符合 I2C slave設備所要求也會產生Nack信號。

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

A3: 這時需要調用兩次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 開發板上使用紅外收發傳感器 IR (耳機接口和recovery之間)實現遙控功能,在IR接口處接上紅外接收器。本文主要描述在開發板上如何配置紅外遙控器。

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

  • 修改內核驅動:內核空間修改,Linux 和 Android 都要修改這部分的內容。

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

內核驅動

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

drivers/input/remotectl/rockchip_pwm_remotectl.c

定義相關數據結構

以下是定義數據結構的步驟:

&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 函數中獲取用戶碼和鍵值:

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() 函數打印用戶碼。

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

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

將 IR 驅動編譯進內核

將 IR 驅動編譯進內核的步驟如下所示:

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

configRK_REMOTECTL_PWMbool"rkxx remoctrl pwm0 capture"defaultn

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

obj-$(RK_REMOTECTL_PWM) += rk_pwm_remotectl.o

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

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

保存后,執行 make 命令即可將該驅動編進內核。

Android 鍵值映射

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

該文件內容如下所示:

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

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

IR 使用

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

LCD使用
簡介

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

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

Config配置

如Android7.1,由于使用的是mipi轉lvds,AIO-3399JD4默認的配置文件kernel/arch/arm64/configs/firefly_defconfig已經把LCD相關的配置設置好了,如果自己做了修改,請注意把以下配置加上:

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,從該文件中我們可以看到以下語句:

/{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

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

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 使用
簡介

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

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

接口效果圖

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

與攝像頭相關的代碼目錄如下:

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

設置攝像頭相關的引腳和時鐘,即可完成配置過程。

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

  • mipi接口

  • MIPI_PDN0_CAM 對應 RK3399 的 GPIO2_A0;

  • MIPI_RST 對應GPIO0_B0;

在開發板中,這兩個引腳都是在 cam_board.xml 中設置。

配置步驟

配置 Android

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

Multimediasupport--->camsysdriverRockChipcamerasystemdriver--->camsysdriverformarvinispcamsysdriverforcif

最后執行:

makeARCH=arm64rk3399-firefly-aiojd4.img

即可完成內核的編譯。

調試方法

終端下可以直接修改/system/etc/cam_board.xml調試各參數并重啟生效

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-3399JD4開發板上引出有 3 路 PWM 輸出,分別為:

  • PWM0 屏背光

  • PWM2 VDDLOG供電

  • PWM3 紅外IR

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

RK3399的 PWM 驅動為: kernel/drivers/pwm/pwm-rockchip.c

DTS配置

配置 PWM 主要有以下三大步驟:配置 PWM DTS 節點、配置 PWM 內核驅動、控制 PWM 設備。

配置 PWM DTS節點

在 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通道數。

  • min_period:周期時長最小值。

  • max_period:周期時長最大值。

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

接口說明

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

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

#include

該頭文件主要包含 PWM 的函數接口。

(2)、申請 PWM使用

structpwm_device*pwm_request(intpwm_id,constchar*label);

函數申請 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 函數

intpwm_enable(structpwm_device*pwm);

用于使能 PWM,例如:

pwm_enable(pwm0);

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

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

voidpwm_free(structpwm_device*pwm);
  • 功能:用于釋放所申請的 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

調試方法

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

FAQs

Pwm無法注冊成功:

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

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

SPI 使用

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

SPI工作方式

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

CS 片選信號 SCLK 時鐘信號 MOSI 主設備數據輸出、從設備數據輸入 MISO 主設備數據輸入,從設備數據輸出

Linux內核用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:表示時鐘信號的初始電平的狀態,0為低電平,1為高電平。CPHA:表示在哪個時鐘沿采樣,0為第一個時鐘沿采樣,1為第二個時鐘沿采樣。SPI的四種工作模式波形圖如下:

驅動編寫

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

硬件連接

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

編寫Makefile/Kconfig

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

configSPI_FIREFLYtristate"Firefly SPI demo support "defaultyhelpSelectthisoptionifyourFireflyboardneedstorunSPIdemo.

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

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

config中選中所添加的驅動文件,如:

│ 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節點

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

/*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,則設為okay,如不啟用,設為disable。

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

  • compatible:這里的屬性必須與驅動中的結構體:of_device_id 中的成員compatible 保持一致。

  • reg:此處與spi-demo@00保持一致,本例設為:0x00。

  • spi-max-frequency:此處設置spi使用的最高頻率。Firefly-RK3399最高支持48000000。

  • spi-cpha,spi-cpol:SPI的工作模式在此設置,本例所用的模塊SPI工作模式為SPI_MODE_0或者SPI_MODE_3,這里我們選用SPI_MODE_0,如果使用SPI_MODE_3,spi_demo中打開spi-cpha和spi-cpol即可。

  • spidev0: 由于spi_demo與spidev0使用一樣的硬件資源,需要把spidev0關掉才能打開spi_demo

定義SPI驅動

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

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

注冊SPI設備

在初始化函數static int __init spidev_init(void)中向內核注冊SPI驅動: spi_register_driver(&firefly_spi_driver);

如果內核啟動時匹配成功,則SPI核心會配置SPI的參數(mode、speed等),并調用firefly_spi_probe。

讀寫 SPI 數據

firefly_spi_probe中使用了兩種接口操作讀取W25Q128FV的ID: firefly_spi_read_w25x_id_0接口直接使用了spi_transfer和spi_message來傳送數據。 firefly_spi_read_w25x_id_1接口則使用SPI接口spi_write_then_read來讀寫數據。

成功后會打印:

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默認沒有打開,如果需要的話可以使用以下補丁打開demo驅動:

---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提供了一個功能有限的SPI用戶接口,如果不需要用到IRQ或者其他內核驅動接口,可以考慮使用接口spidev編寫用戶層程序控制SPI設備。 在 Firefly-RK3399 開發板中對應的路徑為: /dev/spidev0.0

spidev對應的驅動代碼: kernel/drivers/spi/spidev.c

內核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數據傳送異常

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

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時,將不會自動載入到計數寄存器。 用戶需要重新關閉計數器和然后重新設置計數器相關才能繼續工作。

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

軟件配置

1.在 dts 文件中定義 Timer 的相關配置 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 的寄存器和中斷號和時鐘等

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

2.對應的驅動文件Kernel/drivers/clocksource/rockchip_timer.c

對應寄存器和使用

1.寄存器如下圖片

DTS配置

文件kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-port.dtsi 有spi轉uart相關節點的定義:

&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文件中使能該節點即可使用。另外,由于我們板子使用的spi轉uart串口模塊掛到spi1上,所以還要使能spi1節點。如下:

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

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

&uart4{status="disabled";};
調試方法

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

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

用戶可以根據不同的接口使用不同的主機的 USB 轉串口適配器向開發板的串口收發數據,例如RS485的調試步驟如下:

(1) 連接硬件

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

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

在終端打開kermit,并設置波特率:

$ 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 轉串口適配器的設備文件

(3) 發送數據

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

echofireflyRS485test...>/dev/ttysWK0

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

(4) 接收數據

首先在設備上運行下列命令:

cat/dev/ttysWK0

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


-->

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
收藏 人收藏

    評論

    相關推薦

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

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

    fireflyCORE-3399主板JD4--FAQs方案

    FAQs HDMI無法4K顯示? AIO-3399JD4默認出廠固件是支持HDMI顯示,HDMI分辨率最高4K。如果HDMI無法支持4K分辨率可以重新燒寫默認固件,或者重新編譯內核
    的頭像 發表于 12-17 16:40 ?1470次閱讀
    <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,以太網,LVDS屏幕接口,eDP
    的頭像 發表于 12-18 14:21 ?1992次閱讀
    <b class='flag-5'>fireflyCORE-3399</b><b class='flag-5'>主板</b><b class='flag-5'>JD4</b>接口定義

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

    AIO-3399JD4 有靈活的啟動方式。
    的頭像 發表于 12-17 17:01 ?1830次閱讀
    <b class='flag-5'>fireflyCORE-3399</b><b class='flag-5'>主板</b><b class='flag-5'>JD4</b>燒寫固件<b class='flag-5'>簡介</b>

    fireflyCORE-3399主板JD4產品簡介

    Core-3399-JD4核心板采用Rockchip高性能六核64位處理器RK3399,板載AI神經網絡處理器NPU SPR2801S,
    的頭像 發表于 12-18 14:11 ?1766次閱讀

    Core 3399Pro JD4工具SDDiskTool

    電子發燒友網站提供《Core 3399Pro JD4工具SDDiskTool.txt》資料免費下載
    發表于 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核心板產品規格書

    電子發燒友網站提供《Core 3399Pro JD4文檔Core 3399Pro JD4核心板產品規格書.txt》資料免費下載
    發表于 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>核心板產品規格書

    Core 3399 JD4工具SD Firmware Tool

    電子發燒友網站提供《Core 3399 JD4工具SD Firmware Tool.txt》資料免費下載
    發表于 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)

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

    Core 3399 JD4固件Debian

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

    Core 3399 JD4文檔AIO 3399JD4產品規格書

    電子發燒友網站提供《Core 3399 JD4文檔AIO 3399JD4產品規格書.pdf》資料免費下載
    發表于 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>產品規格書

    Core 3399 JD4文檔AIO 3399JD4 Product Specifications

    電子發燒友網站提供《Core 3399 JD4文檔AIO 3399JD4 Product Specifications.pdf》資料免費下載
    發表于 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

    電子發燒友網站提供《Core 3399 JD4文檔mb jd4 rk3399&3399pro v1.1.pdf.pdf》資料免費下載
    發表于 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貼片圖

    電子發燒友網站提供《Core 3399 JD4 V2文檔MB JD4 RK3399/3399Pro V1.1貼片圖.pdf》資料免費下載
    發表于 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

    電子發燒友網站提供《Core 3399 JD4 V2文檔mb jd4 rk3399/3399pro v1.1.pdf》資料免費下載
    發表于 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
    主站蜘蛛池模板: 久久六月丁香婷婷婷 | 欧美又黄又嫩大片a级 | 自拍偷拍福利 | 99久久婷婷国产综合精品电影 | 色婷婷亚洲十月十月色天 | 伊人网址| 香蕉久久高清国产精品免费 | 国产亚洲自在精品久久 | 国产又黄又爽又猛的免费视频播放 | 免费在线观看一级片 | 人人爱天天做夜夜爽毛片 | 久久精品99无色码中文字幕 | 美女一级免费毛片 | 曰曰摸天天摸人人看久久久 | 国模于子涵啪啪大胆 | 噜噜噜久久久 | 在线午夜影院 | 久久久午夜精品 | 中文字幕在线视频第一页 | 亚洲一区色 | 午夜爽爽视频 | 亚洲一卡2卡3卡4卡5卡乱码 | 四虎国产成人亚洲精品 | 免费国产成高清人在线视频 | 色香蕉色香蕉在线视频 | 亚洲五月综合缴情婷婷 | 一区二区三区无码高清视频 | 久久亚洲免费视频 | 成人男女啪啪免费观看网站 | 你懂得福利 | 久久美女免费视频 | 高清国产一区二区三区 | 越南黄色录像 | 手机在线观看毛片 | 欧美三级视频在线 | 全是肉的高h短篇列车 | 狠狠狠狠狠操 | 4hc44四虎www在线影院男同 | 综合免费视频 | 伦理片第一页 | 国产精品17p |