Sim's blog

電子工作はじめてみました

AVRでNokia5110を使ってみる (初ネギ)

2008-10-03 00:51:30 | AVR
ノキア液晶5110の続きになります。
その後、マイコン工作実験日記さんからトラックバックをいただきました。同じLCDを使っておられます(記事)。


その後見つけた参考になりそうなコードです。
(1) LCD Nokia 3310 (PCD8544) Driver in WinAVR(avr-gcc)。ソースコードもダウンロードできます。
(2) トラ技2008年1月号のp.106「フォント内蔵のグラフィック液晶制御IC」という記事です。こちらはソースのダウンロードはできませんが付録CD-ROMにソースが格納されています。


前回紹介させていただいたトラ技2006年3月号の記事のプログラムですが、初期化の部分にバグがあります。GLCD.cの285行目です。元のコードは
SPI_tx_command(0b00001000 | 4); /* Bias=4 (0-7) */
となっています。biasを設定するコマンドは0x10なのでビット位置が違っています。また4に設定したいときは実際には3を書く必要があります。正しくは以下になります。
SPI_tx_command(0b00010000 | 3); /* Bias=4 (0-7) */


AVRのSPIで遊びたいときって、どうすればいいのか不思議でした。プログラマのISPと同じピンを使うからです。信号がぶつかったりとかしないのかと思っていました。そのあたりの話はすんさんの掲示板で色々教えてもらいました。プログラマはプログラムが終わるとハイインピーダンスになるので、気にせずそのままつないでいいみたいです。リセットしてから実際にSPIを使い始めるまではSPI関連の線が浮いた状態になるのがちょっと気にかかるところです。


AVRでSPIを使うには3つのレジスタを使います。SPCRは制御、SPSRはステータス、SPDRはデータです。今回はマスターで使用します。I2Cと違って面倒なことがありません。初期化したあとは、SPDRに書き込むとデータ送信が始まってSPSRのSPIFビットを見て送信完了を待つだけです。


Nokia5110の端子ですが、用心のために3pinのSCEはpull-up、4pinのRESETはpull-downしています。SCEはISP中に変なコマンドが飛んだりしないように、RESETは電源投入直後に確実にLOWになるようにです。また、Vcc(1pin)とGND(2pin)の間にパスコン(0.1uF)をいれています。

ソースです。
#include <avr/io.h>
#include <util/delay.h>

// pin接続
// 1 Vcc
// 2 GND
// 3 SCE   PB2(16) pull-up
// 4 RESET PB1(15) pull-down
// 5 D/C   PB0(14)
// 6 SDIN  PB3/MOSI(17)
// 7 SCLK  PB5/SCK(19)
// 8 LED+

typedef unsigned char byte;

// ピン割り当て
#define SCK   PB5
#define MOSI  PB3
#define SCE   PB2
#define RESET PB1
#define DC    PB0

// LCDコマンド
// H=0 or 1    76543210
#define FSET 0b00100000 // 2:PD 1:V 0:H
// H=0         76543210
#define DISP 0b00001000 // 2:D 0:E
#define SETY 0b01000000 // 2-0:Y (0-5)
#define SETX 0b10000000 // 6-0:X (0-83)
// H=1         76543210
#define TMP  0b00000100 // 1-0:TC (0-3)
#define BIAS 0b00010000 // 2-0:BS (0-7) 3のとき1/48duty
#define VOP  0b10000000 // 6-0:Vop (0-127) コントラスト

// コマンドを送る
void lcd_cmd(byte cmd)
{
    PORTB &= ~(_BV(SCE) | _BV(DC)); // SCE=0 DC=0
    SPDR = cmd; // コマンド送信
    while(!(SPSR & _BV(SPIE))); // SPIE=1になるまで待つ
    PORTB |= _BV(SCE) | _BV(DC); // SCE=1 DC=1
}

// データを送る
void lcd_data(byte d)
{
    PORTB &= ~_BV(SCE); // SCE=0 DC=1
    SPDR = d; // データ送信
    while(!(SPSR & _BV(SPIE))); // SPIE=1になるまで待つ
    PORTB |= _BV(SCE); // SCE=1 DC=1
}

// LCDクリア
void lcd_clear(void)
{
    int i;

    for(i = 0; i < 84 * 6; i++) lcd_data(0);
}

// 座標変更 x:0-83 y:0-5
void lcd_locate(byte x, byte y)
{
    lcd_cmd(SETX | (x & 0x7f));
    lcd_cmd(SETY | (y & 7));
}

// LCD初期化
void lcd_init(void)
{
    PORTB = _BV(SCE); // SCLK=0 SDIN=0 D/C=0 RESET=0 SCE=1
    DDRB =  _BV(SCK) | _BV(MOSI) | _BV(DC) | _BV(RESET) | _BV(SCE);

    // SPI初期化 (Nokia5510LCDは4MHzまで)
    SPCR = _BV(SPE) | _BV(MSTR); // SPI許可、マスター、fosc/4
    SPSR = _BV(SPI2X); // 2倍速

    // reset
    _delay_ms(100); // 100ミリ秒待つ
    PORTB |= _BV(RESET);

    // LCD初期化
    lcd_cmd(FSET | 1);  // H=1
    lcd_cmd(BIAS | 3);  // BIAS n=4 1:48 dup rate
    lcd_cmd(VOP  | 16); // Vop コントラスト(変わらない、なんで?)
    lcd_cmd(TMP  | 1);  // TC=1
    lcd_cmd(FSET);      // H=0
    lcd_cmd(DISP | 4);  // display mode 4:normal 5:reverse

    lcd_clear();
    lcd_locate(0, 0);
}

int main()
{
    lcd_init();

    // 描画 lcd_locateで移動してlcd_dataでデータを送る
    // コード省略

    while(1) ; // 無限ループ
}

LCDの初期化は以下のようにします。
(1) リセットを100ミリ秒以上Lにする(電源投入直後からずっとLにしてもいい)。
(2) H=1にして拡張コマンドを使えるようにする
(3) BIASの設定。48ラインなので3にします(データシートのn=4の設定)。
(4) Vopの設定。コントラストの設定です。後述
(5) TCの設定。温度補償らしいのですが、よく分かりません。他と同じ1にしています。
(6) H=0にして通常コマンドに切り替える
(7) display modeをnormalまたはreverseにする。
(8) ビデオRAMをクリアする。

(4)のVopの設定でコントラストを変えれるはずなのですが、なぜかうまくいきません。値を変えてもコントラストは変わりません。Vopは変な値にすると定格を超えてしまうので注意深く設定する必要のあるレジスタなのですが、設定がききません。何か変です。
(6)の時点で、縦書きモードと横書きモードを選択できます。データを送った後に座標が縦に進むか横に進むかの切り替えです。

Nokia5110のデータ形式はマイコン工作実験日記さんの解説が分かりやすいです。LCDの上の方がLSBになるところが注意点です。


何を表示しようかと思いましたが、最近のお約束みたいなのでネギ振りに挑戦してみました。絵心がないので、データを変換しただけです。今回、一番時間がかかった所です。ubuntsuに入っていたGIMPというグラフィックツールで縮小とモノクロ化しています。動かしてみると、ちらちらするドットがいたりしますが、修正していません。画像サイズは56x48で1枚あたり336バイトです。6枚あるので2016バイトになります。SRAMには展開できないのでROMから直接読み込むようにしています。
SPIの通信速度は4Mbpsです(Nokia5110の最大)。336バイトを送るのにオーバーヘッドを考えないと0.7ミリ秒くらいです。
データが大きいので描画部分のソースは省きました。
撮影は携帯なのでぶれています。

描画の高速化について少し考えてみました。
(1) 連続してデータを送るときは、SCEの制御を行わない。
(2) 送信待ちの間に次に送信するデータを読み出す。
(3) 縦書きモードと横書きモードを利用して、x, y座標の設定を減らす


絵が動くと楽しいですね。変換した画像はあまりきれいでないので、もう少しなんとかしたいものです。

最新の画像もっと見る

コメントを投稿