FrontPage

2012/11/11からのアクセス回数 40645

Raspberry PiのSPI接続を試す

センサーのインタフェースには、RS232Cのシリアル通信を使ったものや先に接続を確認したI2Cの他に、 高速な通信をサポートするSPI接続があります。

今回は、Raspberry Piのドライバーを使ってSPIデバイスと接続する方法をArduinoを使いながら説明します。

ArduinoとのSPI接続を試す

液晶ディスプレイやデジタル・シリアル変換(DAC)などは、RS232CやI2C以上に高速な通信を必要とします。 そこで、Raspberry PiのSPIドライバーを使ってArduinoと接続することで、SPI接続の手順を確認してみます。

SPIと言ってもこれまで接続したことがないデバイスとつなぐのも大変ですし、いきなりカラー液晶と接続するのも無謀です。

そこで、Raspberry Pi+Arduino + SPI を手持ちのArduinoを使って動作を確認した後に、mbed互換ライブラリに追加してみることにします。

Arduinoとの接続

Raspberry PiとArduinoとの接続は、*1

raspi_arduino_spi.png

の通りに接続します。

Raspberry PIArduiono
p10 MOSI11
p11 MISO12
p12 SCKL13
p23 GNDGND

Arduino側のプログラムの組込み

Raspberry Pi+Arduino + SPI の説明通り、filearduino_spi_slave.pde のスケッチをArduino IDEで作成し、Arduinoに書き込みます。

Raspberry Pi側の設定

次にRaspberryPiにSPIドライバーをセットします。

I2Cと同様に/etc/modulesに以下の1行を追加します。

spidev

更に、/etc/modprobe.d/raspi-blacklist.confのblacklist spi-bcm2708を#でコメントアウトします。

#blacklist spi-bcm2708

ドバイバーを組み入れるためにRaspberryPiを再起動します。

$ sudo reboot

再起動後に正常にSPIモジュールが組み込まれたかlsmodで確認します。

$ lsmod | grep spi
spidev                  5136  0 
spi_bcm2708             4401  0 

Hello worldを送る

テスト用プログラム filespidev_test.c をコンパイルします。

$ gcc spidev_test.c -o spidev_test

ArduionoのIDEメニューで「ツール」→「シリアルモニター」を選択し、ボーレートを115200 bpsにセットします。

これで準備完了です。以下のコマンドを実行してHello worldという文字列をArduinoに送ります。

$ $ sudo ./spidev_test 
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)

と出力され、シリアルモニターにHelllo Worldが出力されたら成功です。

th_SPI-Test.jpg

mbed互換ライブラリにSPIを追加

接続確認ができたので、mbed互換ライブラリにSPIクラスを追加します。

SPI.h

I2Cと同様にmbedのSPIヘッダをベースに修正します。

fileSPI.h のprotectedとprivateを以下のように定義します。

protected:
    const char *    _name;
    PinName _mosi;
    PinName _miso;
    PinName _sclk;
    int     _fd;	
    int _bits;
    int _mode;
    int _hz;
    int _delay; // delay usecs
    
private:
    uint8_t _tx[1];
    uint8_t _rx[1];

SPI.cpp

次にfileSPI.cpp ですが、基本的にI2Cと同じ方式で作成しました。 SPIのデバイスをオープンし、ioctlを使って制御します。

SPI::SPI(PinName mosi, PinName miso, PinName sclk, const char *name)
    : _mosi(-1)
    , _miso(-1)
    , _sclk(-1)
    , _fd(-1)
    , _bits(8)
    , _hz(1000000)
    , _mode(0)
    , _delay(0)
{
    _name = (char *)name;
    // ハードSPIのみをサポート(ピン固定)
    if (mosi == MOSI && miso == MISO && sclk == SCKL) {
        _fd = open("/dev/spidev0.0", O_RDWR);
        if (ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &_bits) < 0)
            return;
        if (ioctl(_fd, SPI_IOC_WR_MODE, &_mode) < 0)
            return;
        if (ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_hz) < 0)
            return;
    }
}

void SPI::format(int bits, int mode) {
    if (_fd >= 0) {
        _bits = bits;
        _mode = mode;
        if (ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &_bits) < 0)
            return;
        if (ioctl(_fd, SPI_IOC_WR_MODE, &_mode) < 0)
            return;
    }
}

void SPI::frequency(int hz) {
    if (_fd >= 0) {
        _hz = hz;
        if (ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_hz) < 0)
            return;
    }
}

int SPI::write(int value) {
    int ret;
    _tx[0] = value;
    _rx[0] = 0;

    struct spi_ioc_transfer tr;
	tr.tx_buf = (unsigned long)_tx;
	tr.rx_buf = (unsigned long)_rx;
	tr.len = 1;
	tr.delay_usecs = _delay;
	tr.speed_hz = _hz;
	tr.bits_per_word = _bits;
    
    if ((ret = ioctl(_fd, SPI_IOC_MESSAGE(1), &tr)) < 0)
        return ret;
    return _rx[0];
}

動作確認

最後にテスト用のメインを作成し、動作を確認します。

SPITest.cppを以下のように作成し、

#include <mbed.h>
#include <stdio.h>

SPI spi(p10, p11, p12);

int main()
{
    char*   buf = "Hello world\n";
    int     value;
    
    spi.frequency(500000);
    while((value = *buf++)) {
        spi.write(value);
    }
}

コマンドを実行するには、以下のようにします。

$ sudo ./TestS

RaspberryPi+Arduino.png

最新のソース

互換ライブラリにSPIを追加したファイルを以下に置きます。

液晶モジュールとの接続は、raspberrypi/MARMEX_OBの液晶モジュールと接続に追記しました。

コメント

選択肢 投票
おもしろかった 14  
そうでもない 0  
わかりずらい 0  

皆様のご意見、ご希望をお待ちしております。


(Input image string)

*1 Raspberry Pi+Arduino + SPIからの転用

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
SmartDoc