DragonBoard 410c(Debian)でGPIOプログラミング(C言語編)
以前のエントリーでは、設定まで行うまででした。そこで今回は動作確認を行ったサンプルのソースを確認していこうと思います。
先日ソースからインストールを行った96BoardsGPIO
のexampleディレクトリにサンプルはあります。
ドキュメント関係もこちらがいいかなと思います。
念のためピンアサインも
C言語編
exampleディレクトリにあるblink.c
ファイルを開きます。
このプログラムの処理としては以下のような手順になっています。
- GPIOのポート指定(といってもポート番号の設定だけ)
- 指定したGPIOポートのオープン(
open()
のような使い方をする模様) - 指定したGPIOポートへのRead/Write(exampleではLチカなのでwriteのみ)
こんな感じになります。なんとなくの印象ですがシステムコールのopen()
の引数にPathがないような使い方で良いようです。
ではソースを眺めてみます。
【example/blink.c】
#include <stdio.h> /* 96BoardsGPIO header file */ #include <gpio.h> /* Just make the pin numbers easier to remember */ int main(int argc, char * argv[]) { int x; unsigned int gpio_a = gpio_id("GPIO_A"); /* * GPIO_A can also be looked up with: * gpio_a = gpio_by_letter('A'); * gpio_a = gpio_by_pin(23); */ // Open the GPIO for use. Do so by pin number on the // Low Speed Expansion Connector. if (!gpio_open(gpio_a, "out")) { for (x=0; x<10; x++) { digitalWrite(gpio_a, HIGH); usleep(500000); digitalWrite(gpio_a, LOW); usleep(500000); } } else { fprintf(stderr, "Unable to open GPIO_A\n"); return -1; } return 0; }
include部分
いちばん重要なincludeの部分はgpio用のヘッダファイルをincludeファイルします。 この中ではlibsocのヘッダファイルもincludeされていますのでこれだけでいいようです。
/* 96BoardsGPIO header file */ #include <gpio.h>
GPIOのポート指定
あとは、ほぼ上記の手順そのままですが、GPIOのポート指定では3タイプの指定が可能のようです。
unsigned int gpio_a = gpio_id("GPIO_A"); /* * GPIO_A can also be looked up with: * gpio_a = gpio_by_letter('A'); * gpio_a = gpio_by_pin(23); */
GPIO_Aのような指定、ポートに割り当てられている文字の指定、ダイレクトにGPIOのpinナンバーの指定、この3つのうちのどれかを指定することになります。 自分が開発を行うのであれば、ピン番号を直接指定するほうが楽かなと思いますけど、96Boards仕様のボードでのソースの移植を行うのであればサンプルと同じ方がいいのかなと思います。動作は同じようです。
指定したGPIOポートのオープン
if (!gpio_open(gpio_a, "out")) {
使用するGPIOのポートとin/outの方向を指定してgpio_open()
を呼び出します。
出力処理
digitalWrite(gpio_a, HIGH); //略 digitalWrite(gpio_a, LOW); //略
あとは、GPIOのピンに対してHIGH/LOWを指定すれば出力が行われます。
make
そのファイルをmake
してみると以下のようなWarningが発生しますが、成功します。
$ make gcc -DPACKAGE_NAME=\"96BoardsGPIO\" -DPACKAGE_TARNAME=\"96boardsgpio\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"96BoardsGPIO\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"96boardsgpio\" -DVERSION=\"0.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -I. -l96BoardsGPIO -g -O2 -MT blink-blink.o -MD -MP -MF .deps/blink-blink.Tpo -c -o blink-blink.o `test -f 'blink.c' || echo './'`blink.c blink.c: In function ‘main’: blink.c:24:4: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration] usleep(500000); ^~~~~~ mv -f .deps/blink-blink.Tpo .deps/blink-blink.Po /bin/bash ../libtool --tag=CC --mode=link gcc -l96BoardsGPIO -g -O2 -o blink blink-blink.o -lsoc libtool: link: gcc -g -O2 -o blink blink-blink.o -l96BoardsGPIO -lsoc
usleep()
が明示的に宣言されてないよっていう感じなので宣言をすればWarningはなくなると思います。具体的にはinclude部分で#include <unistd.h>
を追加すればOKです。
【修正前】
#include <stdio.h> /* 96BoardsGPIO header file */ #include <gpio.h>
【修正後】
#include <stdio.h> #include <unistd.h> /* 96BoardsGPIO header file */ #include <gpio.h>
変更すると
$ make gcc -DPACKAGE_NAME=\"96BoardsGPIO\" -DPACKAGE_TARNAME=\"96boardsgpio\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"96BoardsGPIO\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"96boardsgpio\" -DVERSION=\"0.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -I. -l96BoardsGPIO -g -O2 -MT blink-blink.o -MD -MP -MF .deps/blink-blink.Tpo -c -o blink-blink.o `test -f 'blink.c' || echo './'`blink.c mv -f .deps/blink-blink.Tpo .deps/blink-blink.Po /bin/bash ../libtool --tag=CC --mode=link gcc -l96BoardsGPIO -g -O2 -o blink blink-blink.o -lsoc libtool: link: gcc -g -O2 -o blink blink-blink.o -l96BoardsGPIO -lsoc
Warningはなくなりました。
入力
digitalWrite()
でLチカができたので今度は入力もやってみたいなあと思いました。
#include <stdio.h> #include <unistd.h> #include <gpio.h> int main(int argc, char * argv[]) { int x; int v; unsigned int gpio_b = gpio_id("GPIO_B"); if (!gpio_open(gpio_b, "in")) { for (x=0; x<3; x++) { v = digitalRead(gpio_b); if (v != -1){ if (v == HIGH){ printf("HIGH\n"); } else { printf("LOW\n"); } } usleep(500000); } } else { fprintf(stderr, "Unable to open GPIO_B\n"); return -1; } return 0; }
このようなファイルにしてタクトスイッチの状態を調べたのですが、どうしてもうまくいきません。値が固定になっているような気がします。スイッチを押しても離してもHIGHのままで、スイッチ回路を諦めてGNDに直結してもNGでした。
$ make ; sudo ./blink HIGH HIGH HIGH
GPIO_Bを使用していたのでもしかしてGPIOのピン側に問題があるのかなと思い、output側でテストすると問題なくLチカはできました。
その後、同じプログラムを実行すると
$ sudo ./blink LOW LOW LOW
今度は固定的にLOWのままになってしまいました。起動時はHIGHで、変更があった際にはそのあとの値が保持されている様です。
ちょっと自分にはお手上げ感ありです。 inputのサンプル実験している人も見当たらず。うーん。
おわりに
Lチカが終わったので結構安心していたのですが、入力に関してはまだうまく行っていません。もう少し調べたいと思います。