桜のはなびらどっとねっとロゴ

桜のはなびらどっとねっと

Raspberry Pi 2でSPI接続のグラフィック液晶の制御

この記事は1年以上前に投稿された記事です。 この警告表示について

IMG_4748_20150712

前回グラフィック液晶の制御を実施しました。この液晶はパラレル接続で全部で20本のピンヘッダがあり、データ転送及び制御で合計14本のGPIOポートを専有していました。
Raspberry Pi 2(とPi B+)はGPIOポートが26本あるのでそれなりに余裕がありますが、初代モデル(Pi ModelA/B)はGPIOポートが17本しかないので3本しか残りませんね。

そこで今回はSPI接続のグラフィック液晶を使用してみたいと思います。

関連記事リンク

用意するもの

必要なものは配線類を除けば SPI接続のグラフィック液晶ディスプレイのみで特別必要な物はありません。今回は秋月電子で買える超小型グラフィック液晶 AQM1248Aを使用しました。
この液晶はSPI接続+制御線2本で制御でき、3.3Vで消費電力1mAという仕様。
バックライトはついていません。

SPI通信とは

モトローラ社が提唱した接続方式で送受信2本、クロック、スレーブ選択信号にGNDの計5本でデバイス間の通信を可能としたシンプルなシリアル通信方式である。

古くから使われている形式でデファクトスタンダードとなっているものです。
この規格は決まりがいい加減で汎用性が高いのが特徴で、低速通信から数十Mbpsの高速通信まで対応したインターフェイスです。スレーブ側になるデバイスは数Mbpsの接続に対応した製品が多いようです。

また、一般的なパラレルとシリアルの比較になりますが、SPIとパラレル接続の比較として

  • 信号線が少ない
    データ線はパラレル通信は8bitバスの場合は8本16bitバスの場合は16本もあるのに対し、シリアル通信ではシリアルなので何bitのバスであろうと信号線は1本です。
  • 通信速度が速い
    低速通信の場合は8本のデータ線を使って通信をするパラレル接続のほうが高速ですが、高速通信をしようとすると全ポートにデータが到着するのを待ってそれを処理する必要が出てくるため、シリアル通信の方が数Gbps以上の高速化が容易になるようです。
    この程度のグラフィック液晶を制御する場合においてはそこまで気にする必要もないと思います。実際にインターフェイスの後はパラレル接続になっているものが多いみたいなので。

という2つが大きな特徴でしょう。

というわけで信号線が少なくて済むSPIインターフェイスの液晶を今回は制御したいと思います。

ちなみにもっと本数が少なくて済むI2Cという通信規格も存在します。こちらは転送速度が1Mbps程度のあまり高速な通信速度を必要としない機器向けで、その代わり信号線は3本(クロックとデータ送受信にGND)で済むという規格です。Raspberry PiはI2Cにも対応してますのでこちらもそのうち使ってみたいと思います。

接続方法

gpoio

Raspberry PiのSPI接続用のポートは決まっていて、物理品の19、21、23とスレーブ選択およびデバイス選択の24、26番を使用します。GPIO番号で言うと12、13、14と10or11ということになります。

それぞれ名称として MOSI MISO SCLK CE0/1と名付けられていてそれぞれのピンは

  • MOSI(Master-Out Slave-In)
    マスター(制御をする側)がスレーブ(制御される側)にデータを転送するためのポートです。Raspberry Piから見ると「送信」ポートになります。なお、このポートのみを使用して双方向通信をする事もできます。 RS-232Cで言うところのTxDですね。
  • MISO(Master-In Slave-Out)
    マスターにスレーブがデータを転送するためのポートです。Raspberry Pi側から見ると「受信」ポートになります。 RS-232Cで言うところのRxDになります。 ちなみに今回の液晶は「受信専用」なのでこのポートは使いません。宙ぶらりんにするなり、GNDに接続するなり、MOSIとループバックするなり好きにしてください。
  • SCLK(Serial Clock)
    データ転送タイミングを合わせるためのクロックです。
    この線で出力されるクロックによって決められたタイミングでデータを送る事によってシリアル通信を実現しています。
  • CE0/CE1
    本来はマスターとスレーブを決定する信号線のようですが、今回使用する液晶やセンサー類などの基本的にスレーブにしかなりえないデバイスの場合はそのデータをどのデバイスが受け取るのかを決めるための信号となっている場合が多いようです。

となっていて、このピンに+GNDでデータ転送をしています。

その配線に加え、この液晶を制御するにはリセット信号とレジスタ選択信号が必要になります。

接続

 

 

IMG_4684_20150705
今回購入した液晶は単体ではピンがたくさん出ていますが、変換基板を使用することでマイコンとのI/Fは7本にすることが出来ます。セットで700円程度なのでセットを買えばいいと思います。
というより、この変換基板を使わないと配線がめんどくさい事になるので基本的にセットで買うべきだと思います。

なお、液晶側の配線ピッチが細いですがハンダ付けの際の先が細いはんだごてを使うか、適当に盛って吸い取り線で吸い取るという方法をすると簡単にはんだづけできます。

IMG_4739_20150712
合体させた

IMG_4740_20150712
裏面

IMG_4741_20150712

こんなかんじで接続しました。

IMG_4742_20150712
液晶アップ
せっかく7本なので信号線を虹色にしてみました。(水色がないので一番は白ですが。)

コーディング

まず制御用のRSとリセットは今までどおりwiringPiを用いて制御します。
そしてSPIも一応wiringPiに制御用ライブラリがありますが、何故かそのライブラリが使えなかったのと、Piを起動するたびに下準備が必要なので今回は低水準入出力命令系を用いて直接叩いてやります。なんか難しそうに聞こえますが、やっていることはGPIO制御初回でGPIOのファイルを書き換えてGPIOを制御した方法とそんなに変わりません。

まず、必要なライブラリをインクルードします。
今回低水準入出力でSPI制御をするのに参考にしたのは公式サイトのドキュメントおよびそこに記載されているテストファイルなのですが。このインクルードはそれのコピペ+wiringPiなのでもしかしたら不要なライブラリもあるかもしれません。

次にSPI以外のIOピンの番号を定義します。

RS信号を5番 リセット信号を6番に設定しました。
このピンなら5番がMOSIポートの斜め上、6番がCE0の上となり、3.3VをMOSIポートの上のピンから、GNDを5と6の間のピンから取り出せば配線が4×2ピンに収まるのでスッキリします。

次に必要な定数などを定義します。

  • SPIMode = SPIモードの設定
    この液晶は説明書によれば クロックアイドル時H 立ち上がり読み込みとなっているため、SPIモードは3となります。 SPIモードについてはこのへんがわかりやすいです。
  • SPIbit = 1ワードあたりのビット数指定
    1ワードあたり何bitで表現するかという設定。デバイスが受け取る仕様に合わせて変更するが、基本8か16bitらしいが、詳しく説明されたサイトが(日本語で)なくてよくわからなかった。とりあえず8で動く。
  • SPISpeed = 転送速度(動作クロック)設定
    SCLKのクロック速度を設定します。この液晶のコントローラの仕様書によるとSCLKのパルス幅H/Lの最小値が25nsつまり1サイクルあたり50ナノ秒が最小値ということなので20MHzが最高ということで、今回は最高値である20MHzを指定しました。
    この液晶がデータ転送だけですべてを書き換えるのに6144回転送してやる事になり、アドレス指定命令も含めると4回命令を送っているので、1秒で画面を書き換えようと思ったらその4倍の24576kHz以上に設定しないといけないですね。スムーズな画面変更を行うなら最低でも0.5~1MHz程度はあったほうがいいでしょう。
  • *SPIDevice = SPIデバイスの設定。
    SPIデバイスはRaspberry Piの場合は以下のようになるっぽいです。
    .   CE0 → /dev/spidev0.0
    .   CE1 → /dev/spidev0.1
  • dot_w / dot_h
    液晶のドット数を指定します。_wが横で_hが縦になります。
    指定はピクセル数で指定しますが、縦は実際にはバイト単位で使用するのであとでバイト単位に直しています。

次にメイン関数を定義します。

今回も画像ファイル指定を引数で行うので受け取れるようにします。

次にGPIOを初期化して液晶をリセットします。

1行目でドット数を8で割ってバイト単位に置き換えています。+7の部分は例えば50pxや62pxみたいなバイト単位で端数が出てしまう場合にInt型だと切り捨てなので切り上げになるように+7しています。後はいつもどおりwiringPiを初期化してピンを初期化、液晶のリセット信号ON→OFF→ONをしています。

次にSPIの初期化を行います。

open命令にてファイルとして読み込み、その後ioctlでSPIモード、1ワードあたりのビット数、通信速度を指定しています。今回はライト(送信)のみを使用するのでWR系の設定のみをしていますが受信もする場合は下3行のWRの部分をRDに変更したものを追加してください。

次に液晶を初期化します。この後作成するDataSend命令を利用します。
基本的にはメーカー指定値を送っていますが、一部好みとペイントで出力されるBMP形式の仕様に合わせて変更しています。詳細はコード内のコメントを見て下さい。

次にBMPファイルを読み込む部分を書きます。

白黒BMPをBMPの仕様に合わせて読み込んでいます。
前回の128×64の液晶は丁度4バイトだったので気にする必要は無かったのですが、今回は128×48なので6バイトとなってちょっと足が出ますので穴埋め処理をしています。(本来は128×64でもするべきですが…。 それと実は48pxを穴埋めすると64pxになるので実際前のコードそのままでも動いたりする

BMPSend関数もこの後作ります。

最後にSPIデバイスを開放して終了

次に実際にデータを転送する関数を作ります。

wiringPiにてレジスタ選択信号を切り替え、先ほど作成したSPIデバイス変数に転送するデータを設定し、転送しています。この変数の戻り値は受信データになるようにしていますが、この液晶はPiからみて送信専用なので実際はデータは来ません。

この命令はこう使います。

DataSend(レジスタ選択信号,送信データ(1バイト));

※一部記号を全角にしていますが実際は半角で使用します。

次にBMPデータを転送する命令を作成します。

やっていることは前回のLCD_BMP();と同じで、使い方も同じです。BMPSend(BMPデータが入った配列);で行えます。やっていることが同じなので作成するデータも前回と同じで縦だけ48pxにすればいいだけです。(先ほど少し話したとおり、穴埋めすると64pxになるので実は全く同じデータが使えたりする。)

というわけでコーディングが完了しました。
基本的にパラレル接続とやっている手間はそこまで変わりません。ただデバイスとのやりとりの間に仲介業者が入るかどうかという感じです。

コンパイル方法やコンパイルしたプログラムの使用方法は前回と全く同じなので省略します。

SPIの設定

Raspberry PiでSPIを使う設定を行います。
といっても難しい設定はしなくてもよく、一番最初の記事で使用したraspi-configを利用することで簡単に設定できます。設定手順は以下のとおりです。

1.rootで raspi-config を起動する
2.8 Advanced Options を選択してエンター
spisetup01
3.A6 SPI を選択してエンターspisetup02

この後の問に <はい> → <了解> → <はい> → <了解> で設定を終了させてリブートしたら設定完了。

再起動後、「ls -l /dev/spidev*」と「lsmod」コマンドを実行して、
「/dev/spidev0.0」と「/dev/spidev0.1」、「spi_bcm2708」が表示されていたらSPIが使えるようになっているはずです。

spisetup04

 

なお、もしこの設定で使えない場合は手動でファイルを変更する必要があります。その方法は以下のとおりです。

1. /etc/modprobe.d/raspi-blacklist.conf から spi-bcm2708 が含まれている行を削除
2./etc/modules に spidev を追加する
3.再起動する

動作させてみる

上のコードを使ってBMPを表示してみます。

12848

例えばこのBMPファイルを液晶に転送してみると以下のようになります。

IMG_4748_20150712

 

ちなみにこの液晶で連続的にBMPを転送して見たところ、かなりかくかくしていました。何か方法があるのかもしれないけど…。

以下に完成したコードを載せておきます。

 

“Raspberry Pi 2でSPI接続のグラフィック液晶の制御” への1件のコメント

  1. […] 基本的には前回の白黒グラフィック液晶のコマンドコードと転送量が増えるだけですので結線は同じ。SPIの3線にRS信号とリセット信号。そしてGNDだけ。これは他のST7735R搭載の液晶でも同じはず。 […]

コメントを残す

メールアドレスが公開されることはありません。