[[FrontPage]]

#contents

2012/11/11からのアクセス回数 &counter;

** ArduinoとのSPI接続を試す [#b5139540]
I2Cが使えるようになったので、次はSPIを試すことにします。

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

そこで、[[Raspberry Pi+Arduino + SPI>http://mitchtech.net/raspberry-pi-arduino-spi/]] 
を手持ちのArduinoを使って動作を確認した後に、mbed互換ライブラリに追加してみることにします。

*** Arduinoとの接続 [#sb526373]
Raspberry PiとArduinoとの接続は、

&ref(raspi_arduino_spi.png);

の通りに接続します。

*** Arduino側のプログラムの組込み [#rdc1e83b]
[[Raspberry Pi+Arduino + SPI>http://mitchtech.net/raspberry-pi-arduino-spi/]] 
の説明通り、&ref(arduino_spi_slave.pde); のスケッチをArduino IDEで作成し、Arduinoに書き込みます。

** Raspberry Pi側の設定 [#o66c5c97]
次にRaspberryPiにSPIドライバーをセットします。

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

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

ドバイバーを組み入れるためにRaspberryPiを再起動します。
#pre{{
$ sudo reboot
}}

再起動後に正常にSPIモジュールが組み込まれたかlsmodで確認します。
#pre{{
$ lsmod | grep spi
spidev                  5136  0 
spi_bcm2708             4401  0 
}}

*** Hello worldを送る [#t0691142]
テスト用プログラム &ref(spidev_test.c); をコンパイルします。

#pre{{
$ gcc spidev_test.c -o spidev_test
}}

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

これで準備完了です。以下のコマンドを実行してHello worldという文字列をArduinoに送ります。
#pre{{
$ $ sudo ./spidev_test 
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)
}}

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

&ref(th_SPI-Test.jpg);

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

*** SPI.h [#d7fb64ac]
I2Cと同様にmbedのSPIヘッダをベースに修正します。

&ref(SPI.h); のprotectedとprivateを以下のように定義します。
#pre{{
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 [#n8e55fba]
次に&ref(SPI.cpp); ですが、基本的にI2Cと同じ方式で作成しました。
SPIのデバイスをオープンし、ioctlを使って制御します。
#pre{{
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];
}
}}

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

SPITest.cppを以下のように作成し、
#pre{{
#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);
    }
}
}}

コマンドを実行するには、以下のようにします。
#pre{{
$ sudo ./TestS
}}

&ref(RaspberryPi+Arduino.png);


** 最新のソース [#z1925ef7]
互換ライブラリにSPIを追加したファイルを以下に置きます。
- &ref(Raspberry-Pi.tgz);

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

** コメント [#rc1f1933]
#vote(おもしろかった[2],そうでもない[0],わかりずらい[0])

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

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