R8CでLCDテスト

I2Cの前にSPI接続を試しておく予定だったのですが、前後してしまった。

で、早速、SPI接続の簡単なテストから始めてみました~

とりあえず、書き込みだけで、動作を確認できそうなので、LCDで実験してみます。
基板付きFSTN液晶モジュール(SPI) [M-G0812P7567]
このLCDモジュールは、128×32ピクセルで、LEDバックライト内臓のタイプです。

IMG_0750
※3.3Vで動作させる為、バックライトLED用の電源は、HT7750Aで昇圧しています。
※先日作ったシリアルモジュールを繋なげるようにして、フラッシュ書き込みのモードスイッチ、
リセットスイッチも設けました。

ビットマップグラフィックスでは、描画の利便性から、どうしても、解像度と同じメモリーが必要
です、R8C/M120AN の場合、RAM が1280バイトしか無いので、128×32だと512バイトの
RAMを消費します、この容量が、限界ギリギリのとこでしょうか・・・
LCDにデータを送ったら、このRAMは他の用途に使えるので、シェアリングする事も出来ると
思いますが、その場合を考えて、システムを設計しておかなければなりません・・

LCDの制御コードは、U8glib を参考にしましたが、ST7567の制御コードは無かったので、
多分近そうなST7565の初期化パターンを参考にしました。
※ST7567のデータシートはネットを探すとあるのですが、いくつかの流動的パラメーター
があり、とりあえず、どのようにするのか目安が必要です。
※Aitendoさんの商品は、安くて、魅力的なのが多いのですが、参考資料が少ないのが難点です。

カットアンドトライで、コードを変えながら、1時間くらいかかって、ようやく画面がまともに
出るとこまで来ました。
※まだ多少不安定な事があり、原因を究明中・・・

SPIでは、SCL、SDA_OUT、SDA_INPの3本が、ベースで、デバイスセレクトや、
アドレスセレクトは、別に考える必要があります、複数のSPIデバイスを繋ぐ場合、ベースの
制御信号は、シェアする為です。

spi_io クラスは、非常にシンプルで、基本、write、read のみです。(まだ write のみの実装)
※R8C/M120AN には、UARTの同期モードがあり、これを使うと良さそうですが、そうすると、
UARTが使えなくなってしまう為、ソフト制御としました。

lcd_io(ST7567の制御)では、LCD制御を含めて、SPIを制御します。

今回のLCDでは4本の制御線が必要です。
SPI(共通部分):
・SDA シリアルデータ
・SCL シリアルクロック

LCD(固有部分):
・A0  アドレスセレクト(コマンドレジスタとデータレジスタの切り替え)
・/CS チップセレクト
※RES信号は、R8Cのリセットに接続しています。

SPI制御ポートの定義

struct spi_base {
    void init() const {
        device::PD4.B2 = 1;
        device::PD4.B5 = 1;
    }
    void scl_out(bool b) const { device::P4.B2 = b; }
    void sda_out(bool b) const { device::P4.B5 = b; }
};

LCD制御ポート(A0、/CS)の定義

struct spi_ctrl {
    void init() const {
        device::PD3.B3 = 1;
        device::PD3.B7 = 1;
    }
    void a0_out(bool b) const { device::P3.B3 = b; }
    void cs_out(bool b) const { device::P3.B7 = b; }
};

IMG_0749s

GitHub R8C

R8C I2C(RTC)のテスト

「R8C M120AN/M110AN」には、I2C専用ハードは無いので、ポートを制御する事で
同等の機能を実現するしかない。

個人的には、I2Cは嫌いだ、ポートの制御が面倒で複雑だし、速度もあまり速くなく、
デバイスによっては、特別なケアが必要な場合もある。
SPIはもっと簡単で高速だ、デバイスを沢山繋げるとポートを消費するけど、少なく
とも、DI、DOは共通化できるので、デバイスセレクトのみで、I2Cのように、
ポートの入出力がこまめに変化したりしない。
2本の制御線でやりとりするなら、より良い方法が他にあると思う、しかしながら、業
界標準的な位置づけになると、規格がはびこってしまい、どれもがI2C通信となる
困った状況だ・・・
ここまで、I2Cが流通してしまうと、規格が悪いとか言ってられなくなるのも事実で、
とりあえず、ソフト制御のI2Cクラスを実装する事とした。

とりあえず、手持ちのI2Cデバイスでテストしてみた、今回はDS1371を選んだ
DS1371は32ビットのバイナリーカウンターを内臓したRTCで、以前に、マキ
シム社にサンプルをもらって評価したデバイスの余りで、RTCの中でも構成としては
使いやすいデバイスである。(32ビットのカウンターが基本で、1.7V~5.5Vで動作)
※但し、購入するとなると、安くは無い事が判る、もっと複雑で扱いが面倒な、秒、分、
時、日、月、年などで構成されたタイプの方が安い。
degikey の場合で、377円
※1個100円くらいだと助かるのだが・・(R8Cより高いので違和感があるのか)
以前にもRXにこのデバイスを接続した時のブログで紹介したが、時間管理のデバイス
では、バイナリーカウンターがあればそれで十分で、他の構成は、使いにくいだけで、
最悪だと思う。
結局、まっとうな時間管理が必要な場合は、秒単位にシリアライズしなければならない。
※ハードを設計する人が、ソフトの都合をまるで判っていない例の一つだと思う。

さて、I2C専用ハードの場合と違って、プロトコルを細部まで理解する必要がある。
※ここで、大きなミスは、ネットにある情報が、自分の知りたい部分以外が多くて、
重要な部分を理解しないまま、「多分こうだろう」的な感じで、実装してしまい、
それが悪くて、中々通信が出来なかった事。
最終的には、DS1371の英文マニュアルの一部を読んでいて気がついた・・・
スレーブからのリード時のACKの振る舞いが判ってなかった・・・

IMG_0747

I2C関係の構成としては、以下のようになっている。

common/i2c_io.hpp  --->  I2C基本制御クラス
common/ds1371_io.hpp  --->  DS1371制御クラス
I2C_test/main.cpp  --->  SCL、SDA、ポート定義クラス

ポートの定義

// DS1371 I2C ポートの定義クラス
// P1_B7: SCL
// P4_B5: SDA
struct scl_sda {
    void init() const {  // オープン・ドレイン設定
        device::POD1.B7 = 1;
        device::POD4.B5 = 1;
    }
    void scl_dir(bool b) const { device::PD1.B7 = b; }  // SCL 方向 (0:in, 1:out)
    void scl_out(bool b) const { device::P1.B7 = b; }   // SCL 出力
    bool scl_inp() const { return device::P1.B7(); }    // SCL 入力
    void sda_dir(bool b) const { device::PD4.B5 = b; }  // SDA 方向 (0:in, 1:out)
    void sda_out(bool b) const { device::P4.B5 = b; }   // SDA 出力
    bool sda_inp() const { return device::P4.B5(); }    // SDA 入力
};

このクラス定義は、少し冗長だけど、I2CのSCL、SDAをどのポートに対応さ
せるかを実装する。
※詳細なテストはしていないが、オープンドレインポートじゃなくても動作すると思う。

デバイスの制御
「ds1371_io.hpp」はテンプレートクラスで上のポート定義を渡す。
内部的には、ポート定義は、i2c_io クラスにそのまま渡している。
デバイスの制御では
・初期化 —> DS1371 の制御レジスターを設定する。
・リード —> 32ビットカウンターの読み出し(time_t で受け渡しをする)
※RTC特有の部分として、確率的に読み出すタイミングでカウントアップが行われた際、
全てのカウンタ値が確定する前に不正な値を読み出してしまう場合があり、複数回読み出
して比較する事でこれを回避している。
・ライト —> 32ビットカウンターへ書き込み(time_t で受け渡しをする)
※他のデバイスを制御するなら、このソースを参考にすれば、少しの手間で、色々なI2C
デバイスに対応できると思う。

I2C制御
基本的に、初期化と、読み出し、書き込みなどの関数しか無い。
また、7ビットのデバイスアドレスしか対応していないが、10ビットのアドレスを使って
いるデバイスは少ないようなので問題無いだろう。
一応、100KBPS、400KBPS を切り替えられるようにしてあるが、ソフトウェアーループによる
クロック生成なので、あまり正確ではなく、実際より10%以上遅いと思われる。

I2Cの仕様として、スレーブデバイスが、内部動作の影響で、応答出来ない場合に、SCL
を強制的に「0」にする事で、動作を遅延させる事が出来る。
初期設定では、その「待ち時間」の最大を「200」マイクロ秒としているが、

//-----------------------------------------------------------------//
/*!
    @brief  スレーブデバイスの「待ち」時間の最大値を設定
    @param[in]	busy	待ち時間(単位マイクロ秒)
*/
//-----------------------------------------------------------------//
void set_busy(uint16_t busy) { busy_ = busy; } 

関数で、大きな待ち時間を設定できるようにしてある。
この待ち時間を越えてSCLが引き伸ばされると、各関数はストールして、falseを返す。

——
libc の時間関数はかなり巨大な為、必要最小限な実装をした関数群を用意した。
・うるう年の補正、曜日の計算など含まれている。
・time_t から tm 構造体、双方向(シリアライズ、デシリアライズ)で変換可能
・タイムゾーンは+9時間(東京)にしてあり、ハードコーディングしてある。
・time_t はグリニッチ標準時間で管理している。

common/time.h
common/time.c

GitHub R8C

R8Cライターモジュール作成

R8Cの書き込みプログラム完成を受けて、とりあえず、まともなライターを製作してみた。
今回はライターモジュール側の製作です。

売られている比較的安価なR8C用ライターは、USBシリアルモジュールが乗っている。
しかし、シリアルモジュールは単独で動作させる事も多いので、別にしたいと思う。
これは、前回のブログの通りです。

一応、ライターモジュールを KiCAD で回路を引いてみた。
6Pのスイッチを設けて、「WRITER」モードと、「RUN」モードを切り替えている。
TXD 信号の扱いが、WRITE/RUN で代わるので、その切り替えも兼ねている。
「RUN」モード時、シリアルの入出力だけが、具体的に繋がる機能だけなので、LEDや、A/D
用のボリューム、スイッチなど取り付けるつもりだが、今回は、ケースの加工が面倒なので
今後の課題とする。
今回、TEXTOOL のICソケットを使って、ライターらしく仕上げてみた。

R8C_Writer
※KiCAD の関係ファイルは、GitHub にプッシュしてある。

IMG_0742

RXD、TXD は、どちら側から見ているのかで、逆の意味となる、今回は、シリアルモジュール側から見た、
端子名をそのまま使っているので、方向に十分注意してほしい。

FTDI:RXD <--- R8C:TXD
FTDI:TXD ---> R8C:RXD

又、TXD 端子は、ライターモードでは、P1_6 に接続している、これは、R8Cの書き込みモードではそ
のようになっているもので、何故そうなのかは不明。

IMG_0744

-----
FTDI 社の FT231X だけど、Windows7 ではデバイスドライバーのインストールが必要だったが、OS-X で
は、そのまま認識して、直ぐに使えた、ちょっとビックリ・・

FTDI 社のデバイスは、中国製のコピーデバイスが安価で出回っており、それを掴むと、純正ドライバー
では、コピーチップと認識して、弾くらしいので注意が必要。

R8Cフラッシュプログラムとりあえずベータ完成

まだ、機能的に欠けている部分もあるし、あまりにヒドイ実装の部分もあり、
手直しをしたいのだがーとりあえず、書き込み、読み出し、消去など、一通り
の機能は揃っているので、この辺で、ライタープログラムは、止めて、
R8C本体のプログラムなどを充実したい感じです〜
※ヒドイ実装とは、設定ファイルのパースとか、機能が分離出来ていない
モトローラーファイルフォーマットの入出力など。

※その為、バージョンは「0.72b」としている。

Renesas R8C Series Programmer Version 0.72b
Copyright (C) 2015, Hiramatsu Kunihito (hira@rvf-rc45.net)
usage:
r8c_prog[options] [mot file] ...

Options :
-d, --device=DEVICE		Specify device name
-e, --erase			Perform a device erase to a minimum
    --erase-all, --erase-chip	Perform rom and data flash erase
    --erase-rom			Perform rom flash erase
    --erase-data		Perform data flash erase
-i, --id=xx:xx:xx:xx:xx:xx:xx	Specify protect ID
-P, --port=PORT			Specify serial port
-a, --area=ORG,END		Specify read area
-r, --read			Perform data read
-s, --speed=SPEED		Specify serial speed
-v, --verify			Perform data verify
    --device-list		Display device list
-V, --verbose			Verbose output
-w, --write			Perform data write
    --progress			display Progress output
-h, --help			Display this

MacBook Pro でシリアル接続して、R8Cの書き込みや、消去、を色々試したけど、
とりあえず、何の問題も無い、十分に使えると思う。
自分としては、俺俺フレームワークでGUI版も作りたいけど、それはまた、後で
考えるとして・・

ソースコード一式は、GitHubにプッシュ済み、一応 MSYS2 でコンパイルと簡単な動作は
確認済みなので、Windows でも使えると思う、MSYS2 の clang では、シリアル制御関係の
ヘッダーが無い為、コンパイル出来ない、Makefile 内で、MSYS2 環境では gcc を使うよ
うにしてある。

ifeq ($(OS),Windows_NT)

R8C関係 GitHub

さて、R8Cは、メモリーが64K使える事が判ると、SDカードの操作も楽に出来そうだし、
色々と夢が膨らむ〜

R8C本体に行く前に、先週、買ってきたもので、ちゃんとしたライターを作っておこうと思う。
以前の書き込みハードはあまりにショボイ・・
色々考えた末、USBシリアル部分と、R8Cのライター部分を分離した構造にした。
USBシリアルは、色々な場合に使う事が多いので、分離しておけば、便利に利用できるだろう。

まず、USBシリアル変換、モジュールが比較的安く売られているので、それを使っても良いが、
小さいケースに収めて、綺麗に作りたかったので、部品をバラで買ってきた、デバイスは
FTDI の FT231XS、単品だと安くて210円だった。
SSOP20 ピンのハンダ付けが、少しだけ厳しい・・
それと、マイクロUSBコネクター、調べると、ミニUSBコネクターより、マイクロUSB
コネクターの方が、抜き差しの耐用が高いらしい。
また、スマホがマイクロUSBコネクターを採用している事が多く、ケーブルも調達がしやすい。
RTS、CTS、DTR、DSR など制御線を出しておきたいので10ピンのコネクターを出す。
それと、5V、3.3Vを切り替え出来るようにしておく。
3.3Vは、ICにレギュレーターが内蔵されているけど、取り出せる電流が少ないので、別途
三端子レギュレーターを載せる。

ケースは、「タカチ」の「TW4-2-6」を使った。

以前から、採用している構造で、非常に具合が良いのだが、L型の10ピンコネクターを横に出す
構造にして、反対側は、マイクロUSBコネクターの先端で受けるようにする事で、基板を抑える
事が出来、シンプルに収まる。

IMG_0733
IMG_0734
IMG_0735

一応KiCADで回路を引いた、この関係ファイルもGitHubにプッシュしてある。
SerialModule

IMG_0740
IMG_0741
IMG_0739

さて、これでシリアルモジュールが出来たー、次は本命のR8Cライターなんだけど、これは次回にでも~