2014年6月16日月曜日

SPI接続グラフィック液晶のAQM1248Aを動かす

さて、とある電子部品屋で買える激安小型グラフィック液晶のAQM1248Aですが、これをNTP時計の補助表示器として使いました。

多分、これをSPIで制御するの何のって話は、付属のデータシートを見ればだいたいわかりますし、ググればいっぱいその記事が出てくると思うので細かい話は割愛しようと思います。

ところで、とてもとても試行錯誤したのですが、ハードウェアSPIが上手く動いてくれなかったんですね…。

PIC24FJ64GA004は2つのSPIを持っているので、1つはENC28J60、もう1つはSPI液晶に割り当てればいいんですが、なんかどうも動いてくれないんですね…。
原因はよくわからないのですが、PIC32MX220F032Bなら何も問題なく動いてくれるんですよねえ。PIC24FJ64GA004のSPIモジュールには「受信は使わない」っていうオプションが無いからそれが原因なんでしょうか。よくわかりません。

仕方ないので、ソフトウェアでSPIを実装しました。まあ、受信しないのでとても実装は楽でした。

void SendSPI(uint8_t data, BOOL IsData)
{
    int i;

    LED7SEG_DisableInterrupt();

    LCD_CS_IO = 0;
    LCD_RS_IO = IsData;

    for(i = 0; i < 8; i++) {
        LCD_SDO_IO = (data & 0x80) != 0;
        LCD_SCK_IO = 0;
        LCD_SCK_IO = 1;
        data <<= 1;
    }
    LCD_CS_IO = 1;

    LED7SEG_EnableInterrupt();
}

あと、なぜだかSPIの送信中に7セグの割り込みが入ると7セグの表示がバグるんですねえ。本当に不思議ですねえ。液晶ががバグるんじゃなくて7セグの表示がバグるんです。LATxレジスタを叩いてるからビット操作の問題も起きないはずだし、本当に不思議です。

XCコンパイラって例えばLATBbits.LATB5 = 1っていう制御、実際は一回LATBをワーキングレジスタにコピー→OR演算を実行→LATBに書き戻すっていう3ステップの処理とかをしているんですかね。それだったら、例えばLATBをWregに読みだした時点で割り込みが入ってそこでLATBをいじったとしても、割り込みから復帰した後には割り込みが起こる前のLATBに演算をした結果がLATBに入ってしまいます(マルチスレッドプログラミングにおけるクリティカルセクションの話題のテンプレ的な例)。しかし、PIC24FJ64GA004はビット操作命令を持っています。コンパイラがこれをビット操作に置き換えてくれれば1命令で終わるので、割り込みに関するそのような問題は起こりません。確かに構造体を使ったビット操作は、1ビットに限らず任意のビット数の変数を構造体内に確保できる文法です。なので、1ビット分の制御でもわざわざOR/AND演算を用いてくる可能性は十分に考えられます。でも、これを解明しようとしたら…HEXを逆アセンブルしてPIC24シリーズのアセンブリ読まなきゃいけないの…ちょっと無理ん…。 PIC18までならアセンブリ開発はよくやってましたが…

プログラミングで「なぜだかわからないけど」は本当は良くないんでしょうが、 現状これでしっかりと動いてくれています。SPIが動かない原因や割り込みでバグる原因がちゃんと分かる人いたら教えて下さい><




液晶には2種類のフォントを搭載しました。
この液晶は縦8bitのデータを1バイトのデータとして送るので縦は8ピクセルごとの制御が便利です。というわけで縦8ドットのフォントを用意したのですが、とても小さすぎました。
なので、縦16ドットのフォントも用意しました。フォントだけでプログラムメモリ20%くらい持って行かれました(汗

そういえば、NTP時計を作製するにあたって初めて知ったのですが、 C言語にはstrftimeっていう関数があるんですね。sprintf関数があれば何かのデータをフォーマットしてテキスト化するのに困りませんが、strftimeはtm構造体をフォーマットするのにあたっていくつか便利な感じになっています。
例えば、写真の液晶の上段は

    strftime(text, sizeof(text) / sizeof(char), "%Y/%m/%d (%a)", &Time);

こんな関数の呼び出しでフォーマットしています。便利ですねえ。

0 件のコメント:

コメントを投稿