ストロベリーリナックスのミニLCDのライブラリ公開
(7/10/09)
最近、売り出した低電圧で動くI2Cを使ったストロベリーリナックスの液晶ディスプレイのドライバーがやっと公開できるレベルに達した。このLCD、小さいが2行16文字が表示でき、低電圧(2.7Vまで)で動くのが嬉しい。昇圧用のDC-DCコンバーターなどが要らない。ただインタフェースがI2Cなので知らない人にはとっつきにくいだろう。
今度公開するライブラリは、標準のTWI(I2CのことをAVRではこう呼ぶ。ライセンスの関係らしい)を持っているAVRチップ(Megaシリーズ)だけでなく、持っていないチップ(Tinyシリーズなど)でも、GPIO(普通のIOピン)を使って、簡単な関数呼び出しだけで文字、アイコンを、このミニLCDに自由に出すことが出来る。I2Cに関する知識は要らない。ライブラリだけならフラッシュサイズは1Kバイトそこそこで入る。
ソフトウエアで実現するI2Cは当研究所では、ずっと前にTiny26でUSIインターフェースを使ったドライバー(マスター・スレーブとも)を完成させている。当初はこれを組み込んで、TWIとの二本立てと考えていたが、途中で気が変わった。USIインターフェースそのものがTinyシリーズでしか実装しておらず、しかもピンが固定されている。MegaシリーズでもI2Cを2チャンネル使いたい時もある。GPIOを使ったI2Cの方が汎用性が高い。
それなら、このあいだのChaNさんのFatFSの中にあるAVR用のRTCドライバーである。この前FatFSを使った時、このソースを読み、I2Cインターフェースを実に軽妙にソフトで実現しているのに感動した覚えがある。
このときはフラッシュサイズを縮めるためこのRTC.cをそのまま使わず、TWIに替えたので、実際にはこのコードは使ったことがない。ちょうど良い機会だ、これを使わせてもらおう。早速FatFSのライブラリのRTC.cから必要なコードを取り出し、#ifでソースを入れ込んでいく。
気が抜けるくらい余りにも少ないコードでI2Cを実現している。1バイトを送信するだけなら、RTC.c全体の1/3くらいしかない。たいしたもんだ。これで本当に動くのか半信半疑でテストに入る。悪い予想があたってGPIOのI2Cはエラーを大量に吐き出してつながらなかった。
オシロではそれらしい波形が見えたのに、ロジアナでは全く反応がない。実はこのコードにはもともとよく理解できないところがある。GPIOピンを上下にドライブするのに、DDRという入出力指定レジスターだけを叩いている。これがどうもよくわからない。
(オリジナル)
#define SCL_LOW() DDRE |= 0x04 /* SCL = LOW */
#define SCL_HIGH() DDRE &= 0xFB /* SCL = High-Z */
(DDREはポートEのDDRレジスター、PE2(0x04)がSCL)
ChaNさんが書いたコードだ。ぬかりがあるわけはない。どこかに何かを設定するとこれで動くのだろう。しかし、それが何なのか見つけられない。色々いじったが事態は全く好転しない。どうもおかしい。オシロで見えて、ロジアナで見えないというのが何か気になる。臭い。しかしこうなるとハードの問題で、これ以上はちょっと手が出せない。
悩んだ挙句、強引だがこのDDRレジスター以外に、PORTもドライブするコードを入れてテストしてみた。
(変更したもの)
#define SCL_LOW() {mLCD_DDDR|=(1<<mLCD_SCL); mLCD_DPORT&=~(1<<mLCD_SCL);}while(0) /* SCL = LOW */
#define SCL_HIGH() mLCD_DDDR &= ~(1<<mLCD_SCL) /* SCL = High-Z */
(mLCD_DPORTはSCLのポート番号、mLCD_SCLはSCLピン)
スイッチを入れる。おおお、ロジアナにそれらしい波形が戻った。ちゃんとスタートコンディションを作っている。立派、立派。しかし、依然としてLCDは動かない。 でも、ここまで来れば光が見えてきた。
printfメッセージを沢山出してコードを追う。どうもC言語のBOOL変数はわかりにくい。こちらはアセンブラー育ちなので、等しいとき、正常終了のときはリターンコード0という観念からぬけられない。C言語のTRUE=1 FALSE=0というのがどうにもなじめない。特にif文の中で式なしで使われると大混乱する。やっぱりいくつか勘違いが見つかり修正する。
#ifを使って分離したTWIのコードとあわせてリターンコードを揃え、祈る気持ちで電源ON。やった。Welcome画面がLCDに出た。これでGPIOのI2CでもLCDが動いた。#defineを設定し直してTWIに戻してみる。動かない!今までの苦労は水の泡か。頭から血が引いていく。はっはっは、ハード接続を替えていなかった。ジャンパーコードを差し込みなおして問題なく稼動。慌ててはいけない。
アイコンの表示と消去がちょっと難しかったけれど、このあとの開発は順調に進み、だいたいこれでミニLCDのライブラリは完成した。アイコンも関数ひとつで任意の絵柄を表示/消去できる。コントラストもコマンドで調整できる。そろそろ公開できるレベルのようだ。
これで少しはストロベリーリナックスさんにも顔が立った。前回の記事で営業妨害で訴えられる心配もないだろう。このライブラリでLCDが沢山売れることを願っている。
以下に、AVRstudioのプロジェクトファイルの形でソースコードとヘッダーファイルを置きます。mLCD168はライブラリmLCD.cをテストするためのやっつけのモニターです。10以上を1文字で入力する時は、;、:、などを入れてください。詳しくはフォルダー内の、mLCD_readme.txtを見てください。
7/10に公開したソースコードにはgoposにバグがありました。以下のものは修正されたものです。コメントにあるような変更もしてあります。コードは80バイト近く減っています。前のmLCD.lzhをダウンロードした方はダウンロードしなおし、前のソースは破棄してください。
| 固定リンク
「AVR」カテゴリの記事
- ソフトI2Cはクロックストレッチまで手を出してあえなく沈没(2017.09.02)
- オシロのテストどころかソフト開発で大はまり(2017.07.26)
- 超音波方式の人感センサーI2C化と新しいオシロ(2017.06.29)
- motionの動体検知はRaspi3の電源が安定しない(2017.04.16)
- 赤外線学習リモコンはデータ再現で挫折したまま進まず(2016.07.21)
コメント
回路の作りしだいだと思います。(ワイヤードORの構造になっている)
プルアップ抵抗を外付けするか、マイコンのプルアップを使用するかです。
ChaNさんの回路図を見ると、プルアップ抵抗(4.7kΩ)は外付けですね。IoInit()で該当するポートを'0'にされています。
ゆきさんのHPにマイコン内部のプルアップ抵抗を利用してI2Cを実現されている例があります。ソースコード、回路図共に公開されていますので参考になります。
http://yuki-lab.jp/hw/cougar-fm.html
プルアップ抵抗の値はデバイスや通信速度によるのでマイコンの内部プルアップを使用する場合は制限が付きそうですが…。
投稿: jujurou | 2009年7月13日 (月) 12時20分
I2CのSDA,SDLの駆動部はオープンドレインかオープンコレクタで、Highレベル時は全てのI2CデバイスがHi-Z出力とし、プルアップ抵抗で信号線をHighへ引き上る仕様なので、HighのときにHi-ZになるようにDDRで制御していると思います。
そのため、PORTは0にしてプルアップ禁止にしないとI2Cの規格から外れます。
たぶん、デバイスと1対1で通信しているならHi-Zでなくても大丈夫だと思います。
投稿: そら。 | 2009年7月11日 (土) 18時36分
ええー、そんなことで動くのですか。早速やってみました。ひゃあー動きますね。そうか、あと一歩だったんだなあ。ちらっと、これ考えたのですが、まさか0にしておくだけでDDRで0に戻るとは考えられなかったものでやってみませんでした。ありがとうございました。今のライブラリは...まああれでも動いているから少し様子をみましょう。
投稿: がた老 | 2009年7月11日 (土) 00時38分
うまく送信できてませんでした…すみません。
下行の<を半角に直してソースに追加し試してみてください。
mLCD_PORT &=~((1<<mLCD_SCL)|(1<<mLCD_SDA));
投稿: ねむい | 2009年7月10日 (金) 23時51分
static void iic_init(void)の冒頭に
を追加するとDDRレジスタの制御だけでもうまくいきました。
"mLCD_PORT &=~((1<
AVR_Coreでi2c液晶動かそうとしてた時、私も似たような
ところで引っかかってたもので…(結局PORTの処理は残しましたが)。
投稿: ねむい | 2009年7月10日 (金) 23時45分