先日、本ブログにRaspberry PiのI2Cを使用する実験で簡易電圧電流計を作ってみたというのを書かせて頂きました。
http://projectc3.seesaa.net/article/350916175.html
こんどはSPIシリアルを試そうと思いまして、何か制御対象物ないかなーとマイ積み基板BOXを漁っていたところ、出てきたのがaitendoで1年前に買ってた数百円程度で買える有機ELモジュールです。このモジュールはバスインターフェース(6800タイプ or 8080タイプ)と、SPIに対応してるということなんですね。で、取り出しました。
今回使用したモジュールの、aitendoのサイトでの商品情報へのリンクはこちら。
http://www.aitendo.com/product/2099

http://www.aitendo.com/product/2484

上記リンクの内、上のはSPIシリアル専用の回路になっていて、下のはバスのピンも全部出されてます。とはいえ今回はSPIで使用するのでどちらでも適用可能です。僕は、下のタイプを手持ちしていたのでそれを使ってます。
接続はこんなイメージ。

試したところ、とりあえずSPIからの制御自体はできたので、表示データを用意すべく昔の資産を掘り起こして簡易的な描画ライブラリを考えましたが、LinuxのコンソールやXの描画に使用されているフレームバッファ(/dev/fb0)をそのまま展開してしまえば、と思い、今回はそうしてみました。
動作させた状態の動画を作りました。良かったらどーーぞー!
従って、以下の様にフレームバッファをSPI経由で有機LEDモジュールに周期的に領域コピーするような構成にします。

結線は、以下のようにしてみました。有機ELモジュールのRS端子(D/C#端子)は、SPIで有機ELモジュールに対して通信している内容がコマンドなのか、データなのかを通知する為の信号です。
コマンドをやりとりする場合はLowにし、それ以外の時はHighに制御する為、Raspberry PiのGPIO_GEN0ピン(汎用入出力端子)を使用しています。

ディストリビューションはRaspbian "wheezy"を使用します。デフォルトではSPIシリアルはローダブルモジュールになっており、自動でロードされません。
以下のサイトに書いてあるような方法を参考にSPIのデバドラが叩けるようにしました。
http://www.pwv.co.jp/~take/TakeWiki/index.php?raspberrypi%2FSPI%E3%82%92%E8%A9%A6%E3%81%99
本記事のソースコードはgithubにて公開させていただいております。
https://github.com/yishii/RaspberryPi_SPI_OLED
Raspberry Pi環境でセルフビルドもできますし、PC上で、Ubuntu+Sourcery g++によるクロス環境でもビルド出来ました。src/Makefileに記載してますので、ご覧になってください。
有機ELモジュールはSPIモードで使用するため、変換基板ピンヘッダコネクタ部の3番、4番(BS1、BS2)は共にGNDに落としておきます。以下のように変換基板にすすメッキ線で配線しました。

実際に結線したイメージはこちら。

フレームバッファを展開するプログラムを作成し、実行すると、テキストもグラフィックも結構クッキリで、いい感じ。



それでは、コードを見ていきましょう。SPIの初期化です。有機ELコントローラの仕様書を参照すると、SPIのクロックは最高4[MHz]の規定ですが、高速に画面更新してみようということで、おためしで8[MHz]に設定しています。
一見問題なく使えているように見えますが、メーカーの仕様を超えた使い方であるので、商品等に組み込むソフトの制御などでは当然NGでしょうし、想定外の不具合の発生やデバイス寿命短縮などになるかもしれません。
void oled_main(void) { int fd; int result; uint8_t mode = SPI_MODE_0; uint8_t bits = 8; //uint32_t speed = 4000000; uint32_t speed = 8000000; // on the spec,SCLK max freq=4[MHz] uint16_t delay; fd = open("/dev/spidev0.0",O_RDWR); if(fd == -1){ printf("Device open error\n"); return; } /* set SPI read/write mode */ result = ioctl(fd,SPI_IOC_WR_MODE,&mode); if(result < 0){ printf("error(L%d)\n",__LINE__); return; } result = ioctl(fd,SPI_IOC_RD_MODE,&mode); if(result < 0){ printf("error(L%d)\n",__LINE__); return; } result = ioctl(fd,SPI_IOC_WR_BITS_PER_WORD,&bits); if(result < 0){ printf("error(L%d)\n",__LINE__); return; } result = ioctl(fd,SPI_IOC_RD_BITS_PER_WORD,&bits); if(result < 0){ printf("error(L%d)\n",__LINE__); return; } result = ioctl(fd,SPI_IOC_WR_MAX_SPEED_HZ,&speed); if(result < 0){ printf("error(L%d)\n",__LINE__); return; } result = ioctl(fd,SPI_IOC_RD_MAX_SPEED_HZ,&speed); if(result < 0){ printf("error(L%d)\n",__LINE__); return; }
フレームバッファは、以下のように/dev/fb0のデバイスをマップしてアクセスしています。
bool fb_init(void) { int fb_fd; struct fb_var_screeninfo vinfo; fb_fd = open("/dev/fb0",O_RDWR); if(fb_fd < 0){ printf("framebuffer open error\n"); return(false); } if(ioctl(fb_fd,FBIOGET_VSCREENINFO,&vinfo)){ printf("screen information retrieve error\n"); return(false); } printf("%dx%d,%dbpp\n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel); screen_size_x = vinfo.xres; screen_size_y = vinfo.yres; screen_bpp = vinfo.bits_per_pixel; if(vinfo.bits_per_pixel != 16){ printf("This color mode is not supported.\nOnly 16bpp is supported currently\n"); return(false); } fb_mem = (volatile unsigned char*)mmap( NULL, (vinfo.xres*vinfo.yres*vinfo.bits_per_pixel) >> 3, PROT_READ|PROT_WRITE, MAP_SHARED, fb_fd, 0); if(fb_mem == NULL){ printf("framebuffer mapping error\n"); return(false); } return(true); }
シリアル通信でイメージデータと制御コマンドとを切り分けるのにRSという信号を使用しますが、これはGPIO17番を使用します。実装のgpiolib.cご覧ください。
このように結構いい感じにカラーのイメージ展開が出来ました!
Raspberry Pi Model B (512MB)本体のみ
posted with amazlet at 13.04.17
kalron
売り上げランキング: 16,048
売り上げランキング: 16,048
Raspberry Piユーザーガイド
posted with amazlet at 13.04.17
Eben Upton Gareth Halfacree
インプレスジャパン
売り上げランキング: 1,492
インプレスジャパン
売り上げランキング: 1,492