2012/11/11からのアクセス回数 41249 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 の通りに接続します。
Arduino側のプログラムの組込み †Raspberry Pi+Arduino + SPI の説明通り、arduino_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を送る †テスト用プログラム spidev_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が出力されたら成功です。 mbed互換ライブラリにSPIを追加 †接続確認ができたので、mbed互換ライブラリにSPIクラスを追加します。 SPI.h †I2Cと同様にmbedのSPIヘッダをベースに修正します。 SPI.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 †次にSPI.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 最新のソース †互換ライブラリにSPIを追加したファイルを以下に置きます。 液晶モジュールとの接続は、raspberrypi/MARMEX_OBの液晶モジュールと接続に追記しました。 コメント †皆様のご意見、ご希望をお待ちしております。
Tweet |