[[FrontPage]]

#contents

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

** mbed互換ライブラリ [#xe6485ea]
mbedはC++のクラスライブラリとユーザの作成したデバイス用のソースコードが豊富で、
デバイスを接続して新しいガジェットを作るのに適しています。

このような環境を別のハードにも欲しいと思う人はいるもので、そらみみの声に
[[IDEを使わずにLPCXpresso LPC1768のプログラムを開発する>http://www.soramimi.jp/lpcxpresso/gnu/index.html]]
というブログにLPC1768用にmbed互換ライブラリの作成記事がありました。

mbed互換ライブラリでは、mbedのDigitalOut, BusOut, TextLCDが実装されているだけですが、
これをRaspberryPiに移植すれば、mbedユーザが作った豊富なライブラリを活用できるのではないかと思い移植してみることにしました。

WiringPiライブラリのインストールについては、
[[raspberrypi/Raspberry PiでIO制御]]
を参照してください。

** mbed互換ライブラリのRaspberryPiへの移植 [#q3f080af]
*** ピン定義(PinNames.h) [#s59c51dc]
最初にRaspberryPiのピン番号をmbedに習い1番ピンから反時計回りに割り振ることにしました。

&ref(My-Pin-Layout.jpg);

これを&ref(PinNames.h);に定義しました。

*** wait関数 [#m07c0691]
mbed互換ライブラリにはwait_usしかありませんが、mbedのwait_api.hの関数を&ref(wait_api.c);に実装しました。残念ながら、wait_usはnanosleepシステム関数を使った場合、TextLCDが正常に動作しなかったためビジーウェイトで実装しました。

wait_msの実装は以下のような感じです。
#pre{{
void wait_ms(int ms)
{
    struct timespec sleeper, dummy ;
    
    sleeper.tv_sec  = (time_t)(ms / 1000) ;
    sleeper.tv_nsec = (long)(ms % 1000) * 1000000 ;
    
    nanosleep (&sleeper, &dummy) ;
}
}}

*** DigitalOutクラス [#c34e5a27]
DigitalOutには、WiringPiのライブラリを使用したので、とてもすっきり実装できました。

&ref(DigitalOut.h);で保持しているのは、ピン名(_pin)と対応するWiringPiのピン番号(_wiring)のみです。

#pre{{
protected:
	PinName        _pin;
	int                 _wiring;
}}

&ref(DigitalOut.cpp); の実装は、ピン名のチェック以外はそのままWiringPiの関数digitalWrite, digitalReadを呼び出すだけです。

#pre{{
void DigitalOut::write(int value)
{
    if (_wiring > 0) {
        if (value) {
            digitalWrite (_wiring, 1);
        }
        else {
            digitalWrite (_wiring, 0);
        }
    }
}

int DigitalOut::read()
{
    if (_wiring > 0) {
        return (digitalRead(_wiring));
    }
    else {
        return (0);
    }
}
}}

*** Makefileの変更 [#t351eea0]
上記以外のBusOut.h, BusOut.cpp, TextLCD.h, TextLCD.cppはそのまま使用しました。

残るは&ref(Makefile);ですが、以下の部分を変更しました。
WiringPiのライブラリが/usr/local/includeにインストールされているので、-I, -Lオプションで指定しています。また、wiringPiライブラリを使用しているので、LIBSに追加しています。
#pre{{
#DEBUG  = -g -O0
INCLUDE = -I/usr/local/include -I.
CFLAGS = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe
LDFLAGS = -L/usr/local/lib
LIBS    = -lwiringPi
}}

** LED点滅プログラム [#yb7f3a97]
GPIO18を使ってLEDを1秒間隔で点滅させるプログラムをLEDTest.cppを以下のように作成しました。
#pre{{
#include <mbed.h>

#include <stdlib.h>
#include <unistd.h>

DigitalOut led(p21);

int main()
{
    while(1) {
        led = !led;
        wait_us(1000000);
    }
}
}}

ほとんどmbedのテンプレートと同じ形式でRaspberryPiで動かすことができます。

** TextLCDを試す [#l2a12d79]
後閑さんの「C言語によるPICプログラミング入門」で紹介されていた3行表示のLCD

&ref(LCD.png);

を使って、TextLCD.cppをテストしました。このLCDの接続は、

&ref(3LineLCD-sch.png);

でデータ転送には、4bitのみを使っています。

私の備忘録として、接続コネクタのピンは以下のようになっています。

- 1(白)5V
- 2 DB7
- 3 DB6
- 4 DB5
- 5 DB4
- 6 E
- 7 RS
- 8, 9 は未接続
- 10 GND

&ref(LCDTest.cpp); でのlcdの定義は、
#pre{{
lcd(p4, p7, p8, p16, p18, p19)
}}

とし、
- p4: RS
- p7: E
- p8: DB4
- p16: DB5
- p18: DB6
- p19: DB7

に接続しました。

以下に動作中の様子を示します。

&ref(TextLCD-Sample.png);

** I2Cの追加 [#taad0f67]
RaspberryPi版の追加機能として、I2Cを実装しました。

&ref(I2C.cpp); では、デバイス/dev/i2c-0をオープンし、ioctlを使ってI2Cアドレスをセットした後に、
read, writeを行う簡単なものです。

#pre{{
I2C::I2C(PinName sda, PinName scl, const char *name)
{
	_name = (char *)name;
    _fd = -1;
    // ハードI2Cのみをサポート(ピン固定)
    if (sda == SDA && scl == SCL) {
        _fd = open("/dev/i2c-0", O_RDWR);
    }    
}
int I2C::read(int address, char *data, int length, bool repeated) {
    int len;
    if (_fd >= 0) {
        ioctl(_fd, I2C_SLAVE, address>>1);
        if ((len = ::read(_fd, data, length)) > 0) {
            // 今は、戻り値のサイズをチェックしない
            return (0);
        }
        else
            return (-1);
    }
    else
        return (-1);
}
int I2C::write(int address, const char *data, int length, bool repeated) {
    int len;
    if (_fd >= 0) {
	int addr = address>>1;
        ioctl(_fd, I2C_SLAVE, addr);
        if ((len = ::write(_fd, data, length)) > 0) {
            // 今は、戻り値のサイズをチェックしない
            return (0);
        }
        else
            return (-1);
    }
    else
        return (-1);
}

}}

*** LM73の例題 [#mb05ffc0]
I2Cの例題として、LM73を使って温度を読み取るクラスを作成します。

&ref(LM73.cpp);

#pre{{
#include <mbed.h>
#include "LM73.h"

LM73::LM73(PinName sda, PinName scl) : i2c(sda, scl)
{
	char cmd[2];
	// LM73設定
	cmd[0]    = 0x04;	// register 4
	cmd[1]    = 0x60;   	// 14bit resolution
	i2c.write( LM73_ADDR, cmd, 2);
	// ポインタを0にしておく(readするだけで温度が読めるようになる)
	cmd[0]    = 0x00; 
	i2c.write( LM73_ADDR, cmd, 1);
}

LM73::~LM73()
{
}

float LM73::read()
{
	char cmd[2];

	i2c.read( LM73_ADDR, cmd, 2); // Send command string    
	int int_val = cmd[0] <<1 | cmd[1]>>7;
	int ceil_val = ((cmd[1] & 0x7f)*200) >>8;
	return float(int_val + ceil_val/100.0);
}
}}

LM73との接続は以下のようにしました。

&ref(LM73-setting.png);

システムのIOを使用するため、互換ライブラリを使ったプログラムの実行には、sudoコマンドが必要です。

以下のようにI2CTestを実行します。
#pre{{
$ sudo ./I2CTest 
22.18
22.21
22.21
}}

** Raspberry版mbed互換ライブラリのソース [#me02eac0]
今回作成したRaspberry版mbed互換ライブラリを以下におきます。

- &ref(Raspberry-Pi.tgz);

SPIを追加したバージョンは、以下を参照してください。
- [[raspberrypi/SPIを試す]]

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

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

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
SmartDoc