contents
    1. むとうたけし@K*BUG <mutoh@610t.org>
  1. GPIOってなあに?
  2. FreeBSDでGPIOを使う
  3. ユーザランドから使うGPIO
    1. GPIOポートモード一覧
    2. GPIOモードの設定
    3. GPIO出力
    4. GPIO入力
  4. 応用: MZTX-PI-EXTをFreeBSDで使う
    1. MZTX-PI-EXT用Linuxアプリケーション
    2. FreeBSDのGPIO経由で簡単な描画ができるところまで実装する
    3. デモ1: 文字列、円を描画する
    4. デモ2: loadavgを表示する
  5. おわりに

FreeBSDでRaspberry PiのGPIOを使う

むとうたけし@K*BUG <mutoh@610t.org>

この文章は、 FreeBSD Advent Calendar 2016の17日目として書かれたものです。 2015年03月07日(土)の関西*BSDユーザ会研究会2015年第1回研究会の発表FreeBSDでRaspberry PiのGPIOを使ってみたが元になっています。

GPIOってなあに?

GPIOは、General Purpose Input/Outputの略で、汎用入出力という意味です。 GPIOでは、コンピュータへのデジタルの入出力を比較的簡単に扱うことができます。 デジタル入出力以外にも、Pull-upやPull-downモードにすることができる場合もあります。

Raspberry Piでは、GPIOのためにBroadcom BCM2835の機能を使っています。

FreeBSDでGPIOを使う

FreeBSDでRaspberry PiのGPIOを使うためには、 WORKING WITH GPIO ON RASPBERRY PI WITH FREEBSDが参考になります。

FreeBSDの起動時には、以下のdmesgのようにGPIOデバイスが認識されます。

mutoh@raspberry-pi:~ % dmesg
  (snip)
gpio0: <BCM2708/2835 GPIO controller> mem 0x200000-0x2000af irq 57,59,58,60 on simplebus0
gpio0: read-only pins: 46,47,48,49,50,51,52,53.
gpio0: reserved pins: 48,49,50,51,52,53.
gpioc0: <GPIO controller> on gpio0
gpiobus0: <OFW GPIO bus> on gpio0
gpioled0: <GPIO led> at pin(s) 16 on gpiobus0
iichb0: <BCM2708/2835 BSC controller> mem 0x205000-0x20501f irq 61 on simplebus0
iicbus0: <OFW I2C bus> on iichb0
iic0: <I2C generic I/O> on iicbus0
iichb1: <BCM2708/2835 BSC controller> mem 0x804000-0x80401f irq 61 on simplebus0
iicbus1: <OFW I2C bus> on iichb1
iic1: <I2C generic I/O> on iicbus1
spi0: <BCM2708/2835 SPI controller> mem 0x204000-0x20401f irq 62 on simplebus0
spibus0: <OFW SPI bus> on spi0
  (snip)

GPIOの制御用デバイスは/dev/gpioc0になります。

ユーザランドから使うGPIO

コマンドラインからGPIOを使うためには、gpioctlが利用できます。

gpioctlでは、GPIOポートを指定し、モード設定や実際の入出力が可能です。

以下、順に見ていきます。

GPIOポートモード一覧

以下のようにして、GPIOポートのモードを確認できます。

mutoh@raspberry-pi:~ % sudo gpioctl -lv
  (snip)
pin 23:	0	pin 23<IN>, caps:<IN,OUT,PU,PD>
pin 24:	0	pin 24<IN>, caps:<IN,OUT,PU,PD>
pin 25:	0	pin 25<IN>, caps:<IN,OUT,PU,PD>
  (snip)
pin 45:	0	pin 45<>, caps:<IN,OUT,PU,PD>

GPIOモードの設定

GPIOモードの設定は、-cオプションを与えて指定します。

mutoh@raspberry-pi:~ %	sudo gpioctl -c 25 OUT
0/OUT
mutoh@raspberry-pi:~ % sudo gpioctl -lv | egrep 25
pin 25:	0	pin 25<OUT>, caps:<IN,OUT,PU,PD>
mutoh@raspberry-pi:~ % sudo gpioctl -c 23 IN
0/IN
mutoh@raspberry-pi:~ % sudo gpioctl -lv | egrep 23
pin 23:	0	pin 23<IN>, caps:<IN,OUT,PU,PD>

GPIO出力

出力は、GPIOポート番号の後ろに、出力したい0 or 1を与えます。

mutoh@raspberry-pi:~ % sudo gpioctl 25 0
0/25
1/0
mutoh@raspberry-pi:~ % sudo gpioctl 25 1
0/25
1/1

GPIO入力

入力は、入力したいポート番号を指定します。

mutoh@raspberry-pi:~ % sudo gpioctl 23
0/23
0
mutoh@raspberry-pi:~ % sudo gpioctl 23
0/23
1

応用: MZTX-PI-EXTをFreeBSDで使う

MZTX-PI-EXTは、初代Raspberry Pi Type Bで使える320x240のLCDモニタ+タッチパネルのデバイスです。 2000円ぐらいで入手可能でした。 基板の形状の問題で、2 B+や3 Bなどでは利用できません。

MZTX-PI-EXTのピン配置は、以下のようになっています。

ピン番号意味備考
8SPICS
25SPIRS
23SPIRST
11SPISCL
10SPISCI
18LCDPWM

MZTX-PI-EXT用Linuxアプリケーション

Rasbianなどには、以下のようなドライバが用意されています。

LCD表示には、 https://s3.amazonaws.com/tontec/24usingmanual.zip (Github) が利用できます。 このドライバは、 /dev/memを経由してGPIOにアクセスします。 デモプログラムでは、フレームバッファを読み込んで、液晶に表示する様になっています。 主なプログラムファイルは、以下の通りです。

  • bcm2835.c: BCM2708/2835 GPIO controller用ライブラリ
  • mztx06a.c: アプリケーション本体

タッチパネルは、Xから使えるLinux用kernelモジュールがあるようですが、実際に試したことはありません。

FreeBSDのGPIO経由で簡単な描画ができるところまで実装する

では、FreeBSDからMZTX-PI-EXTを利用するためのプログラムを記述していきます。

ここで紹介したプログラムは、以下のURLから入手可能です。

ここでは、最低限動作させることを目標にプログラムを作成することとし、以下のLinuxのドライバのソースコードで使えるものは再利用します。

bcm2835_new.cとして6つの関数を実装します。

  • int bcm2835_init()
  • void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode)
  • void bcm2835_gpio_write(uint8_t pin,uint8_t val)
    • void bcm2835_gpio_clr(uint8_t pin)
    • void bcm2835_gpio_set(uint8_t pin)
  • void bcm2835_delay(unsigned int millis)

GPIOモードを設定するGPIOSETCONFIGを bcm2835_gpio_fsel() で、GPIO出力を行うGPIOSETを bcm2835_gpio_write() で、それぞれioctl(2)を実行しています。

デモプログラムmztx06a.cには、以下の変更を行います。

  • SPIを使わないようにする(#undef BCM2708SPI)
  • LCD_WR_Data()のinlineを消す (LLVMのみ?)

デモ1: 文字列、円を描画する

ひとつめのデモでは、オリジナルのライブラリで提供されている関数を利用して、文字列を描画したり、円を描画したりしてみます。

先程、bcm2835_new.cとして実装した関数を使って、MZTX-PI-EXTの初期化などを行います。

実際に描画する関数は、文字列が DisplayString("String",x,y) で、円が draw_circle(x,y,radius,color) です。 描画10回ごとに、画面をランダムな色でクリアします。

int main (void)
{
    int c;
  (snip)
    printf("bcm2835 init now\n");
    if (!bcm2835_init())
    {
        printf("bcm2835 init error\n");
        return 1;
    }
    bcm2835_gpio_fsel(SPICS, BCM2835_GPIO_FSEL_OUTP) ;
    bcm2835_gpio_fsel(SPIRS, BCM2835_GPIO_FSEL_OUTP) ;
    bcm2835_gpio_fsel(SPIRST, BCM2835_GPIO_FSEL_OUTP) ;
    bcm2835_gpio_fsel(LCDPWM, BCM2835_GPIO_FSEL_OUTP) ;
    
 #ifdef BCM2708SPI
        bcm2835_spi_begin();
        bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
        bcm2835_spi_setDataMode(BCM2835_SPI_MODE3);
        bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_2);
 #else
    bcm2835_gpio_fsel(SPISCL, BCM2835_GPIO_FSEL_OUTP) ;
    bcm2835_gpio_fsel(SPISCI, BCM2835_GPIO_FSEL_OUTP) ;
 #endif
    LCD_PWM_CLR;
  (snip)
    LCD_Init();
    LCD_clear(RGB565(130,130,150));
    srandom(0);
    for (;;)
    {
        int x,y,radius,r,g,b;

        x=myrand(200);
        y=myrand(200);
        radius=myrand(200);
        r=myrand(255);
        g=myrand(255);
        b=myrand(255);
        printf("%d %d %d RGB(%d %d %d)\n",x,y,radius,r,g,b);
        draw_circle(x,y,radius,RGB565(r,g,b));

        DisplayString("K*BUG FreeBSD",myrand(30),myrand(15));

        if ((c++ % 10)==0) LCD_clear(RGB565(r,g,b));
    }
 (snip)
}

動作の様子は、以下のようになります。 静止画ではわからないですが、実際には描画はかなり遅いです。

demo-MZTX-PI-EXT.jpeg

デモ2: loadavgを表示する

二つ目のデモとして、loadavgをLCDに表示してみます。 このデモは、OSC2016 Kyotoで展示を行いました。

loadavgを取得するためにC言語でloadavg.cを作成しました。 getloadavg(3)を使ってloadavgを取得し、その値に応じた垂直線を描画します。 GPIO経由での描画はかなり遅いのとMZTX-PI-EXT側の現在描画されてる情報を取得するための方法が無いため、xload(1)の様に右端まで描画した時にスクロールするのは難しいので、右端まで行くとまた左端から描画するようにしました。 これだけでは、更新されている場所がわかりづらいので、更新している場所に黒で垂直線を引いた後で、それを白で消去しています。

実際の動作の様子は以下の通りです。

loadavg_MZTX-PI-EXT.jpg

おわりに

Raspberry Piには、多くのGPIOが用意されており、デジタルの入出力で十分な場合には、比較的簡単に電子工作などに利用できます。

LEDを点滅するLチカや、スイッチの値を読み取ることなどの簡単な実装から、今回デモで行ったようなLCDへの描画まで色々な応用が考えられます。

是非、皆さんもFreeBSD + Raspberry Pi + GPIOで遊んでみませんか?

Last modified: 2016-12-16
Post-it: New Post-it (help)

Text color: [_][_][_][_]

Background: [_][_][_][_][_][_]

Draw Line:

x: y: