2018年11月21日 星期三

使用 device tree overlay控制industrial i/o

Source http://gnitnawtw.blogspot.com/2015/07/device-tree-overlayindustrial-io.html

使用 device tree overlay控制industrial i/o

終於把我第1個device tree overlay生出來了!要趕快把心得寫下來。

Device tree的功用

想像若是沒有device tree,為不同的處理器寫kernel modules會變成一件看起來複雜實際上很簡單的事,舉例來說,以raspberry pi model B+跟raspberry pi 2來說,這兩者只有SoC、CPU、記憶體大小不一樣,但是其他該外部設備(I2C、SPI等)都差不多。可是若是沒有device tree,寫kernel module的時候就必須把以下步驟各做一次
  1. 弄一個machine type id
  2. 在kernel裏面建立關於此id的相關文件,設定SoC的相關代碼(包括外部設備如interrupt、timer、memory mapping等等)還有board-specific文件
  3. 設定其他的driver
但是現今的SoC都大同小異,了不起就是pin(gpio、I2C等)的位置不一樣,為了這些小差異,要把上面那三件事重做一次,增加一倍的coding到kerenl,使得kernel最後越來越肥搞到Linus本人都出來罵。Device tree的作法就是把外設資訊(怎麼連接、哪個memory mapping等)以bootloader傳送給kernel,讓kernel把外設需要的module根據Device tree的訊息連接起來。

實際做起來還挺有趣的。我自己寫了兩個可以在raspberry pi model B+連接industrial i/o (iio) driver用的device tree

MCP3008(adc)

如果編譯kernel的時候有勾選industrial i/o driver的時候就可以使用
可以在/lib/modules/{uname -r}/modules.alias找到這個module :
alias spi:mcp3008 mcp320x

根據kernel document 的說明
https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
我寫了mcp320x.dts:

/dts-v1/;
/plugin/;

/ {
    compatible = "brcm,bcm2835", "brcm,bcm2708";
    /* disable spi-dev for spi0.0 */
    fragment@0 {
        target = <&spi0>;
        __overlay__ {
            status = "okay";
            spidev@0{
                status = "disabled";
            };
        };
    };

    fragment@1 {
        target = <&spi0>;
        __overlay__ {
            /* needed to avoid dtc warning */
            #address-cells = <1>;
            #size-cells = <0>;
            mcp3x0x@0 {
                compatible = "mcp3008";
                reg = <0>;
                spi-max-frequency = <1000000>;
            };
        };
    };
};


dts寫好後用dtc編譯:
dtc -@ -I dts -O dtb -o mcp320x.dtb mcp320x.dts
然後把mcp320x.dtb copy到/boot/overlays/
最後在/boot/config.txt加上:dtoverlay=mcp320x  (跟我寫的mcp320x.dtb做連結)
重開機後,只要mcp3008有接對應該就沒問題了。

MPU6050(六軸陀螺儀)

一樣根據 https://www.kernel.org/doc/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt 來編輯mpu6050.dts

// Definitions for MPU6050
/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2708";

        fragment@0 {
                target = <&i2c1>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";
                        clock-frequency = <400000>;

                        inv-mpu6050@68 {
                                compatible = "invensense,mpu6050";
                                reg = <0x68>;
                                interrupt-parent = <&intc>;
                                interrupts = <2 22="">;
                        };
                };
        };
};


編譯後放到/boot/overlays,/boot/config.txt上加入:dtoverlay=mpu6050

如果想要debug,可以在/boot/config.txt上加入:dtdebug=1
重開機後執行sudo vcdbg log msg 就可看device tree載入訊息:

PS: 記得看看interrupt有沒有衝到(dmesg |tail),如果有衝到interrupts的值+1+2然後重開機應該就沒問題了。
參考資料:
  • Device Tree 背景介紹
    http://www.wowotech.net/linux_kenrel/why-dt.html
  • Device Trees, Overlays and Parameters
    https://www.raspberrypi.org/documentation/configuration/device-tree.md
  • https://patchwork.ozlabs.org/patch/464158/

沒有留言: