8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Raspberry PiでPPSをGPIOに出力する

Last updated at Posted at 2016-11-15

GPSのPPS入力はやっていたが、カーネルでGPIOにPPSが出力できるだなんて、知らなかった。
ただし、内蔵クロックの精度で。多分。

pps-gen-gpio

pps-gen-gpioというオープンソースがあるのを教えてもらった。知らなかった。
元は、パラレルポートに出力していたものを、Device Treeを参照するように変えたらしい。

Device Tree

BeagleBoneでのDTの書き方

README.meには、BeagleBoneの例が書いてある。
GPIO1_19という端子があり、&gpio1 19 GPIO_ACTIVE_HIGHと書くらしい。
我らがRaspberry Piではどうか。

Raspberry PiでのDTの書き方

まずはRaspberry Pi本家のDT情報。いっぱい書いてあるが、pps-genに使えそうな書き方については、えーと…。Linux本家の情報でも勉強しつつ…。

Raspberry Piのdtsファイル

わからないときは、真似をするのも有効。というわけで、Raspberry Piで今使っているDTSを見る。
bcm2708-rpi-b.dtb, bcm2708-rpi-b-plus.dtb, bcm2708-rpi-cm.dtb, and bcm2709-rpi-2-b.dtbの4つがあるとのことで、確かに

~/git/raspberrypi/linux$ ls -1 arch/arm/boot/dts/bcm270*.dts
arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
arch/arm/boot/dts/bcm2708-rpi-b.dts
arch/arm/boot/dts/bcm2708-rpi-cm.dts
arch/arm/boot/dts/bcm2709-rpi-2-b.dts

あるのだが、いきなり、無い。自分の手元にあるModel A+用のものが。
よく読むと、

Note that Model As and A+s will use the "b" and "b-plus" variants, respectively.

とあるので、b-plusを使えということか。ややこしい。

bcm2708-rpi-b-plus.dtsの内容

gpioで検索すると、

&spi0 {
        pinctrl-names = "default";
	pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
        cs-gpios = <&gpio 8 1>, <&gpio 7 1>;

という記載がある。こちらを見ると、SPI0はGPIO7と8で共用っぽいので、第1引数がGPIOの番号だろう。
それでは、第2引数にある1とは、何だろうか。

他の例を見ると、

&hdmi {
        hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>;
};

とあるので、GPIO_ACTIVE_LOWというマクロで書くのがわかりやすそうだ。
他にどんなマクロがあるか探してみると、

include/dt-bindings/gpio/gpio.h
/* Bit 0 express polarity */
# define GPIO_ACTIVE_HIGH 0
# define GPIO_ACTIVE_LOW 1

とあるので、1GPIO_ACTIVE_LOWか。想像と逆だった。

GPIOの初期状態

こちらの記事によると、GPIOの番号によって初期状態が異なる。
初期状態が0(Low)のGPIOに対して、Active Highに設定すれば、問題ないのではないか(勘)。

dtsへの追記

pps-gen-gpio.txtを見ながら、記載。

/ {
        compatible = "brcm,bcm2708";
        model = "Raspberry Pi Model B+";
        pps-gen {
                compatible = "pps-generator-gpios";
                pps-gen-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>;
                /* assert-falling-edge; */
        };
};

AssertはRising Edgeにしてみたかったので、コメントに。

dtsのbuild

Raspberry Pi本家のKernel building情報をもとに、

~/git/raspberrypi/linux$ make -j8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

とすると、色々出た後、

  DTC     arch/arm/boot/dts/bcm2708-rpi-b-plus.dtb

と出て、dtbが作成される。

dtbのインストール

先ほどのbuild手順の一部をそのまま

~/git/raspberrypi/linux$ sudo mount /dev/sdb1 mnt/fat32
~/git/raspberrypi/linux$ sudo cp arch/arm/boot/dts/*.dtb mnt/fat32/
~/git/raspberrypi/linux$ sudo umount mnt/fat32

起動してDTの確認

またも本家DT情報に、procでの確認方法が書いてある。なんて教育的なんだ(当たり前)。

pi@raspberrypi:~ $ dtc -I fs /proc/device-tree
:
	pps-gen {
		compatible = "pps-generator-gpios";
		pps-gen-gpios = <0xa 0x12 0x0>;
	};

反映されている模様。

再度pps-gen-gpio

ようやくpps-gen-gpioに戻ってきた。これをbuildする。
…が、build通らず。さらに、通してinsmodしても、反応無しだった…。
そこで、2点修正。

devm_gpiod_get()への第3引数の追加

kernel 4.4.30では、引数を3つ取るらしい。

pps_gen_gpio.c
@@ -198,7 +198,7 @@ static int pps_gen_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;

        /* pps-gen is the function associated with gpio list pps-gen-gpios */
-       devdata->pps_gpio = devm_gpiod_get(dev, "pps-gen");
+       devdata->pps_gpio = devm_gpiod_get(dev, "pps-gen", GPIOD_ASIS); /* from enum gpiod_flags */
        if (IS_ERR(devdata->pps_gpio)) {
                dev_err(dev, "cannot get PPS GPIO %ld\n",
                        PTR_ERR(devdata->pps_gpio));

GPIOD_ASISなら、デフォルトの端子状態から変えないんだろうな(また勘)。
これ以外には、こんなのがあるらしい。

include/linux/gpio/consumer.h
enum gpiod_flags {
        GPIOD_ASIS      = 0,
        GPIOD_IN        = GPIOD_FLAGS_BIT_DIR_SET,
        GPIOD_OUT_LOW   = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT,
        GPIOD_OUT_HIGH  = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
                          GPIOD_FLAGS_BIT_DIR_VAL,
};

compatibleがドキュメントと異なる

README.mepps-gen-gpioによると、

pps-generator-gpios value of ".compatible" property in pps-gen node

とあるが、ドライバのソース上は{ .compatible = "pps-gen-gpios", },となっているように見える。
DTとドライバでcompatibleが異なると、probeが呼ばれず、dmesgしても

[  369.273294] pps_gen_gpio: GPIO PPS signal generator

より先が表示されない気がしたので、ソースをドキュメントに合わせて修正。

pps_gen_gpio.c
@@ -233,7 +233,7 @@ static int pps_gen_gpio_remove(struct platform_device *pdev)
  * when a match is found, the corresponding DT node name is passed
  * backed in pdev->name */
 static const struct of_device_id pps_gen_gpio_dt_ids[] = {
-       { .compatible = "pps-gen-gpios", },
+       { .compatible = "pps-generator-gpios", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, pps_gen_gpio_dt_ids);

pps-gen-gpioのbuild例

カーネルソースの場所は環境に合わせて下さい。

$ make -C ~/git/raspberrypi/linux ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=`pwd` CONFIG_PPS_GENERATOR_GPIO=m

実行

pi@raspberrypi:~ $ sudo insmod pps_gen_gpio.ko

dmesgでこんなログが出てきていれば、きっと動いている。

[  671.795926] pps_gen_gpio: GPIO PPS signal generator
[  671.796269] pps_gen_gpio: found 1 GPIOS defined in DT
[  671.796391] pps_gen_gpio: port write takes 500ns

測定

active_high.png

パルス幅は約28usくらいらしい。

おまけ::Active Low

active_low.png

おお、逆になっている。
あ、DTにassert-falling-edge付けるの忘れたが、edgeはどっちになるんだろ。

自由研究

  • ドリフトとジッタの調査
  • dmesgに出るエラー(?)の内容の調査
  • NTP補正との関係の調査

修正ソース

こちら

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?