SSブログ

BCM2835ライブラリ その6 [Raspberry Pi]

BCM2835ライブラリの日本語解説の最終回。サンプルコードをまとめておしまいにする。せっかくなので、今回の記事をまとめてLaTeXで整形したpdfをここに置いておく。BCM2835ライブラリを使おうという人のために。

4  サンプルコード

僕が使ったコードを入れようと思ったけど、いろいろなことをやるせいで回りくどくて長いので、もともとbcm2835の配布についているexamplesを解説することにする。
examplesには
  • blink
  • event
  • gpio
  • i2c
  • input
  • pwm
  • spi
  • spin
のやっつがあって、どれもmain()関数だけの簡単なものである。
examplesのコードはどれも
% cc example.c -o example -l bcm2835
% sudo ./example
で実行できる。もちろんライブラリ本体とヘッダが読めるパスの上にインストールされていることが前提である。

4.1  blink

Raspberry PiのP1コネクタの11番ピンを0.5秒ごとにオン/オフするサンプルコード。
#include <bcm2835.h>
#define PIN RPI_GPIO_P1_11

int main(int argc, char **argv)
{
    // これを実行してGPIOにアクセスできていなかったら
    // これを読んでテストする
    //    bcm2835_set_debug(1);
    
    if (!bcm2835_init())
        return 1;
    
    // ピンを出力に設定する
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);
    
    // Blink
    while (1)
    {
        // オン
        bcm2835_gpio_write(PIN, HIGH);
        // ちょっと待って
        bcm2835_delay(500);
        // オフ
        bcm2835_gpio_write(PIN, LOW);
        // また待って
        bcm2835_delay(500);
    }
    bcm2835_close();
    return 0;
}
解説不要のコードである。本体は無限ループでプロセスを殺さないと止まらないので、とうぜんソースにあるclose()関数は呼ばれることはない。

4.2  input

これはRaspberry PiのP1コネクタの15番ピンを読み込む。
#include <bcm2835.h>
#include <stdio.h>

#define PIN RPI_GPIO_P1_15

int main(int argc, char **argv)
{
    if (!bcm2835_init())
        return 1;
    
    // P1の15ピンを入力にセットする
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
    //  ついでにプルアップ
    bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_UP);
    
    // Blink
    while (1)
    {
        // データを読む
        uint8_t value = bcm2835_gpio_lev(PIN);
        printf("read from pin 15: %d\n", value);
        // ちょっと待つ
        delay(500);
    }
    bcm2835_close();
    return 0;
}

4.3  event

このサンプルはGPIOのイベントの使い方。15ピンがLOWに落ちたらイベントが発生する。
#include <bcm2835.h>
#include <stdio.h>

#define PIN RPI_GPIO_P1_15

int main(int argc, char **argv)
{
    if (!bcm2835_init())
        return 1;
    
    // P1の15ピンを入力に設定
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
    //  プルアップする
    bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_UP);
    // LOWの検出ができるようにする
    bcm2835_gpio_len(PIN);
    
    while (1) {
        if (bcm2835_gpio_eds(PIN)) {
            // 次のイベントを待つためにフラグをセットしなおす
            bcm2835_gpio_set_eds(PIN);
            printf("low event detect for pin 15\n");
        }
        // ちょっと待つ
        delay(500);
    }
    bcm2835_close();
    return 0;
}
ちょっとだけ注意が必要なのは、イベントが検出された状態はeds関数でチェックしたあとも変化しないらしい。従ってedsでチェックしたあとはset_edsでイベント検出をセットしなおす(検出済みであることを知らせる)必要がある。

このイベントという機能はbcm2835ライブラリ特有の考え方らしく、結局ポーリングしないといけないので、ちょっと中途半端。できればコールバックのような仕組みにしてもらったらよかった。

でも想定している使い方はおそらく、いわゆるイベントドリブンな、例えば細いパルスが入るとそれを合図に何かの作業をする、というのではないのだろう。主となる作業中に、ある条件が満たされないと先に進めないというような、初めから淡々と手順を進めていく途中での段階制御に使う、みたいな感じに思える。

組み込みにはよくあるパターンなのかもしれない。

4.4  spi

spiを使って1バイト送って1バイト読み込む。このサンプルではRaspberry Piのspi入力(MISO)をspi出力(MOSI)にそのままつないで、ループバックさせることを想定している。

データ転送の前に幾つかの設定が必要だけど、それは実際に接続されるスレーブデバイスに合わせることになる。設定の詳細は英語版のWikipediaを参照するのが手っ取り早い(残念だけど日本語版に情報はない)。
#include <bcm2835.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    if (!bcm2835_init())
        return 1;
    
    bcm2835_spi_begin();
    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);      // The default
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);                   // The default
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default
    bcm2835_spi_chipSelect(BCM2835_SPI_CS0);                      // The default
    bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default
    
    // 1バイトスレーブに送って同時にスレーブから返ってくる1バイトを読みこむ
    // MISOをMISOに接続してあったら、送ったものがそのまま読まれる
    uint8_t send_data = 0x23;
    uint8_t read_data = bcm2835_spi_transfer(send_data);
    printf("Sent to SPI: 0x%02X. Read back from SPI: 0x%02X.\n", send_data, read_data);
    if (send_data != read_data)
        printf("Do you have the loopback from MOSI to MISO connected?\n");
    bcm2835_spi_end();
    bcm2835_close();
    return 0;
}

4.5  spin

このサンプルはspiでマルチバイト転送する場合のもの。

1バイトとやりかたは同じだけど、バッファが使い回されてスレーブからのデータで上書きされることに注意を要する。
#include <bcm2835.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    if (!bcm2835_init())
        return 1;
    
    bcm2835_spi_begin();
    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);      // The default
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);                   // The default
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default
    bcm2835_spi_chipSelect(BCM2835_SPI_CS0);                      // The default
    bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default
    
    // 複数バイトをスレーブに送って同時に読む
    // たいていのSPIデバイスは1、2バイトのコマンドに対してそのあとデータを送り返すようになっている
    // そのような場合は、バッファの先頭にコマンドを書いて、残りに送り返されるデータバイト数の分だけ0を埋めておく
    // 転送が終わったら、送り返されたバイトをバッファから読み出すことができる
    // MISOをMOSIに直接つないてあったら、書いたものがそのまま読み込まれるはずである
    char buf[] = { 0x01, 0x02, 0x11, 0x33 }; // 送り出すデータ
    bcm2835_spi_transfern(buf, sizeof(buf));
    // bufにはスレーブから読み込まれたデータで書き換えられる
    printf("Read from SPI: %02X  %02X  %02X  %02X \n", buf[0], buf[1], buf[2], buf[3]);
    
    bcm2835_spi_end();
    bcm2835_close();
    return 0;
}

4.6  もうすこし実用的なサンプルコード

gpioとi2cのふたつのサンプルは、これまでとちがって実用的なコードになっている。長いのでここにはあげないけど、それほど難しいコードではない。

コマンドラインからgpio、あるいはi2cを読んだり書いたり設定したりできる。ハイフン('-')に続いてこれが顔文字みたいになったけどそうではなくて、コマンドキャラクタを続ける、というunixによくあるスタイルになっている。

引数無しでとりあえず動かしてみると、usageが表示されるので、それを参考に試してみればいい。

ソースは順に読んでいけばわかるようになっている。

i2cのほうには、ファイルの先頭のコメント部分にA/DコンバータのADC1015とD/AのMCP4725をi2cにつないだ場合に読み書きするためのコマンドラインシーケンスが書いてある。

5  まとめ

spiだけはもとからあるspidevモジュールを停止させないといけないけど、それ以外は他のモジュールと共存可能らしい(もちろん一つのピンを二つのプロセスから使ったりはできない)。

ライブラリそのものは見てきたように非常にシンプルなもので、自分で書いてもそれほど手間はかからないようなものだけど、他のライブラリを使っていないなら
  • BCM2835のレジスタ配置を調べる手間がない
  • ちゃんと動作確認がされてる
  • 機種ごとに異なるレジスタアドレスやピン配置を隠蔽してくれる
  • 整理されていて一貫している
のでこのライブラリを使わない手はない。C++を使う人なんかは、もっと使いやすいように自分専用のラッパを書くのがいいだろう。

僕はこのままでありがたく使わせてもらうことにする。
nice!(0)  コメント(1)  トラックバック(0) 

nice! 0

コメント 1

Cialis 20mg

沒有醫生的處方
cialis 20 mg cut in half http://kawanboni.com/ Tadalafil 20mg
by Cialis 20mg (2018-04-14 02:43) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。