H8/3664でIICを使う

Daisukeh 2009/05/11 17:28 作成
Daisukeh 2009/05/13 13:43 追記
Daisukeh 2009/08/04 13:11 移設

記事一覧

IICインターフェースを使う

H8/3664のIIC概要  ルネサステクノロジのH8/3664を使ってForth言語のインプリメントをしている。その外部記憶にI²C(以下、IIC)のEEPROMを使おうと思って、H8/3664のIICインターフェースを使ってみたのだが、ちゃんと動いてくれなくて困っていた。いじくりまわした末にウェブを彷徨していたら、不具合レポートの記事がたくさん出てきたので、僕もここにその不具合をまとめてレポートしたい。尚、NECエレクトロニクスと事業統合が決まったルネサステクノロジであるが、このH8/3664という機種はすでにデッドストックになってしまっている。現在はその後継機種のH8/3694の使用を推奨している。この機種はH8/3664をベースに、パワーオンリセットや低電圧検出回路をオプションで付加したということになっているが、事実上のバグフィックス版であって、ルネサステクノロジが定期的にフィードしているテクニカルレポートにも、H8/3664やH8/3694におけるIICのアプリケーションノートや注意事項などが多く掲載されていた。

 そのような事情はさておき、そのIICの動作なのであるが、出力ピンにオシロスコープを接続して、波形観察をしてみたが、いくらIIC関連のレジスタを操作しても何も出力されなかった。もしやと思い、 PCR8 = 0xc0 として出力にしたら、本当に出力ピンになってしまった。マニュアルには ICCR.ICE = 1 でIICインターフェース所掌の端子となるはずである。まったく不可解である。 SDA 端子はおろか、 SCL 端子からクロックすら出力されず、 1kΩ の抵抗でプルアップした +5V しか観察することができなかった。下のソースコードは、いじくりまわした最後のもので、もちろんこのコードではIICの通信はできず、EEPROMにアクセスすることもできない。

H8/3664 IIC通信(レジスタ使用)

VOID _ei(VOID);                                                                 // 割込許可
VOID _di(VOID);                                                                 // 割込禁止
VOID readIIC(UB* adrs, UB* data, SIZE datasz);                                  // IICデータ列読込
VOID writeIIC(UB* adrs, UB* data, SIZE datasz);                                 // IICデータ列書込
UB _readIIC(BOOL wait);                                                         // IICデータ受信(コア)
VOID _writeIIC(UB data);                                                        // IICデータ送信(コア)
 
VOID main(VOID)
{
        // システム初期化
        ICCR   = 0x89;                                                          // I2C通信可
        ICMR   = 0x00;                                                          // I2C速度設定
 
        /* メインループ */
}
 
// readIIC : IICデータ列読込
VOID readIIC(UB* adrs, UB* data, SIZE datasz)
{
        // IICデータ列読込
        ICCR = 0xb9;
        ICCR = 0xbc;
        _writeIIC(0xa0);
        _writeIIC(((VP_INT)adrs >> 8) & 0xff);
        _writeIIC( (VP_INT)adrs       & 0xff);
        ICCR = 0xbc;
        _writeIIC(0xa1);
        ICCR = 0xad;
        ICSR = 0x00;
        _readIIC(FALSE);
        for(; datasz; datasz --)
        {
                if(datasz == 1) ICSR = 0x01;
                *(data ++) = _readIIC(TRUE);
        }
        ICCR = 0xa0;
}
 
// writeIIC : IICデータ列書込
VOID writeIIC(UB* adrs, UB* data, SIZE datasz)
{
        // IICデータ列書込
        ICCR = 0xb9;
        ICCR = 0xbc;
        _writeIIC(0xa0);
        _writeIIC(((VP_INT)adrs >> 8) & 0xff);
        _writeIIC( (VP_INT)adrs       & 0xff);
        for(; datasz; datasz --) _writeIIC(*(data ++));
        ICCR = 0xb0;
}
 
// IICデータ受信(コア)
UB _readIIC(BOOL wait)
{
        UB data;                                                                // データ
 
        // IICデータ受信(コア)
        if(wait)
        {
                while(!(ICCR & 0x02));
                ICCR &= ~0x02;
        }
        _di();
        data  =  ICDR;
        ICCR &= ~0x02;
        _ei();
 
        return data;
}
 
// IICデータ送信(コア)
VOID _writeIIC(UB data)
{
        // IICデータ送信(コア)
        _di();
        ICDR  =  data;
        ICCR &= ~0x02;
        _ei();
        while(!(ICCR & 0x02));
}

IICをソフトウェアでインプリメント

 そういえば、以前にH8/3664のデバッグボードなるものを自作したときも、2402だったかのIICのEEPROMにアクセスできずに、ほったらかしていた記憶がある。そのときはそれ以外の部分が動いて、XILINXALTERAのFPGAのテストに利用していたので、あまり気にもとめなかったのだ。

 そんなことで、ウェブで拾い読みした諸氏もソフトウェアで実装していたので、それを真似ることにした。と言ってもそのまま使わせてもらうのではなく、H8/3069のμITRON4互換リアルタイムオペレーティングシステム用にインプリメントした自作のコードから流用することにした。H8/3069は外部メモリインターフェースがあるので、汎用メモリを接続すればレジスタをチョッと設定するだけで使えて便利である。ただし、IICインターフェースは持っていない。秋月電商にはH8/3069を使用したキットがいくつかある(自分も持っている)が、IIC用の8ピンメモリを載せるソケットがあるのを知っているだろうか?(多分、この記事を読んでる時点でよく知っていると思うけどね。) P60とP61にSDAとSCLが接続 されていて、 SDAには10kΩでプルアップ までしてあるので、とても親切丁寧である。

 μITRON版IICライブラリは今後オープンソースにするとして、そこからコア部分だけ抜き取って、H8/3664用にチューンナップしたのが下のコードである。テストで使っているIICのEEPROMはATMELAT24C512で、 Vcc5V のとき SCL1MHz までOK、容量は 32KB である。

H8/3664 IIC通信(ソフトウェア実装)

VOID readIIC(UB* adrs, UB* data, SIZE datasz);                                  // IICデータ列読込
VOID writeIIC(UB* adrs, UB* data, SIZE datasz);                                 // IICデータ列書込
UB controlIIC(ID iicid, UB data);                                               // IICソフトウェア制御
 
VOID main(VOID)
{
        // システム初期化
        controlIIC(IIC_INIT, 0);
 
        /* メインループ */
}
 
// readIIC : IICデータ列読込
VOID readIIC(UB* adrs, UB* data, SIZE datasz)
{
        // IICデータ列読込(1)
        controlIIC(IIC_WRITE, 0);
        controlIIC(IIC_START, 0);
        controlIIC(IIC_SETBYTE,                       0xa0);
        controlIIC(IIC_CHKACK, 0);
        controlIIC(IIC_SETBYTE, ((VP_INT)adrs >> 8) & 0xff);
        controlIIC(IIC_CHKACK, 0);
        controlIIC(IIC_SETBYTE,  (VP_INT)adrs       & 0xff);
        controlIIC(IIC_CHKACK, 0);
 
        // IICデータ列読込(2)
        controlIIC(IIC_START, 0);
        controlIIC(IIC_SETBYTE, 0xa1);
        controlIIC(IIC_CHKACK, 0);
        controlIIC(IIC_READ, 0);
        for(; datasz; datasz --)
        {
                *(data ++) = controlIIC(IIC_GETBYTE, 0);
                controlIIC(IIC_ACKNAK, ((datasz == 1) ? TRUE : FALSE));
        }
        controlIIC(IIC_STOP, 0);
}
 
// writeIIC : IICデータ列書込
VOID writeIIC(UB* adrs, UB* data, SIZE datasz)
{
        // IICデータ列書込
        controlIIC(IIC_WRITE, 0);
        controlIIC(IIC_START, 0);
        controlIIC(IIC_SETBYTE,                       0xa0);
        controlIIC(IIC_CHKACK, 0);
        controlIIC(IIC_SETBYTE, ((VP_INT)adrs >> 8) & 0xff);
        controlIIC(IIC_CHKACK, 0);
        controlIIC(IIC_SETBYTE,  (VP_INT)adrs       & 0xff);
        controlIIC(IIC_CHKACK, 0);
        for(; datasz; datasz --)
        {
                controlIIC(IIC_SETBYTE, *(data ++));
                controlIIC(IIC_CHKACK, 0);
        }
        controlIIC(IIC_STOP, 0);
}
 
#define iic_read_sda()          PCR5 &= ~0x40                                   // IIC:SDA受入モード
#define iic_write_sda()         PCR5 |=  0x40                                   // IIC:SDA送出モード
#define iic_check_sda()         PDR5 &   0x40                                   // IIC:SDAビット判定
#define iic_off_sda()           PDR5 &= ~0x40                                   // IIC:SDAビットオフ(=0)
#define iic_on_sda()            PDR5 |=  0x40                                   // IIC:SDAビットオン(=1)
#define iic_write_scl()         PCR5 &= ~0x80                                   // IIC:SCL送出モード
#define iic_off_scl()           PDR5 &= ~0x80                                   // IIC:SCLビットオフ(=0)
#define iic_on_scl()            PDR5 |=  0x80                                   // IIC:SCLビットオン(=1)
 
// controlIIC : IICソフトウェア制御
UB controlIIC(ID iicid, UB data)
{
        UB cnt;                                                                 // カウンタ
 
        switch(iicid)
        {
        case IIC_INIT :
                // IIC初期化
                iic_write_sda();
                iic_write_scl();
                iic_off_sda();
                iic_off_scl();
                break;
 
        case IIC_START :
                // スタート送出
                iic_write_sda();
                iic_on_sda();
                iic_on_scl();
                iic_off_sda();
                break;
 
        case IIC_STOP :
                // ストップ送出
                iic_write_sda();
                iic_off_sda();
                iic_on_scl();
                iic_on_sda();
                break;
 
        case IIC_WRITE :
                // 送出モード
                iic_write_sda();
                break;
 
        case IIC_READ :
                // 受入モード
                iic_read_sda();
                break;
 
        case IIC_SETBYTE :
                // バイト送出
                for(cnt = 0x80; cnt; cnt >>= 1)
                {
                        iic_off_scl();
                        if(data & cnt) iic_on_sda();
                        else           iic_off_sda();
                        iic_on_scl();
                }
                iic_off_scl();
                break;
 
        case IIC_GETBYTE :
                // バイト受入
                for(data = 0, cnt = 0x80; cnt; cnt >>= 1)
                {
                        iic_on_scl();
                        if(iic_check_sda()) data |= cnt;
                        iic_off_scl();
                }
                return data;
 
        case IIC_CHKACK :
                // ACK判定
                iic_on_scl();
                iic_read_sda();
                data = iic_check_sda();
                iic_write_sda();
                iic_off_scl();
                return (data ? TRUE : FALSE);
 
        case IIC_ACKNAK :
                // ACK/NAK送出
                iic_write_sda();
                if(data == TRUE) iic_on_sda();
                else             iic_off_sda();
                iic_on_scl();
                iic_off_scl();
                iic_read_sda();
                break;
        }
 
        return 0;
}

ソフトウェアIICインターフェースの考察

 コンパイラはYellowSoftYCシリーズCコンパイラと統合環境のH8版 を使った。ソースコードは特にトリッキーなことをしていないので、 HEW でも GCC でも使えると思う。ただし、最適化に注意しないと、SCLとSDAのタイミングによってはダメな場合があるかもしれない。このコードでテストしてみた結果、SCLの転送速度が 約179KHz(パルス幅 2.3μs) で通信していることをオシロスコープで確認できた。アセンブラでコーディングすれば、おそらく倍以上早くなるとは思うが、そもそもそこまでのスピードを要求していないので、今回は冗長性を重視することにしよう。

IICのプロトコルとタイミングチャート

 ソフトウェアでインプリメントした場合、そのタイミングに遅れが出ることが一番のボトルネックになる。ハードロジックに比べて速度が遅くなることはもちろんだが、IIC通信のようなマルチプロセッサ通信では、データラインの切替時にどのチップもハンドリングしていないタイミングができてしまう。例えば ACK を受信する時に、出力だったピンを入力に一時的に変更するのだが、 SCL とその切替タイミングの順番をきちんと考慮しないと、プルアップの Hi レベルがパルスに引っかかりそうだった。(プルアップの +5VACK0V でヒゲが出た。)その点についてはこのコードで対策済みなのだが、オシロスコープで観察していると、宙ぶらりんの 0.5V が見えるので、ロジック信号なのに段差があって奇妙だ。(実際のところは、スレッシュホールドがあるため、きちんとACKを受信できる。)また、上のコードではACK/NAK受信を考慮していない点に注意して欲しい。これは、必ず通信が成立するという前提でインプリメントしているからだ。実際にはACKの有無を判定して、通信手順を作成する必要があると思う。ただ、組み込みプログラミングは前提条件が決まっていて柔軟性はほとんど無いことが多いから、問題ないかもしれないが。

 ということで、H8/3664のIICインターフェースは 全然使えない? ということがわかった。あるいは、アプリケーションノートを参考にゴリゴリとコーディングをすればこのインターフェースを使いこなすことができるかもしれない。もしくは、 CPLDを使う という手もあるけど、H8/3664を使っている手前、本末転倒だよなぁ。

参考文献

failed to fetch data: unkown error

failed to fetch data: unkown error

failed to fetch data: unkown error

failed to fetch data: unkown error

failed to fetch data: unkown error

failed to fetch data: unkown error

掲示板

, 2018/11/08 22:59
It doesn't work him from I speculation it might.
Drama wiki viagra online independant financial adviser.
Bain, the genitals of Viagra on the ERG are currently available, and any symptoms that have been found have little been cast in minutes of hundreds in different method and in most of
the a- and b-wave islanders.
, 2018/11/08 22:59
It doesn't work him from I speculation it might. Drama
wiki viagra online independant financial adviser. Bain, the genitals
of Viagra on the ERG are currently available, and any symptoms that have been found have little been cast in minutes
of hundreds in different method and in most of the a- and b-wave islanders.
Enter your comment
 
 
programming/embed/h8_3664でiicを使う.txt · 最終更新: 2009/08/09 10:56 by daisukeh
 

Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS
Driven by DokuWiki Powered by Google do yourself a favour and use a real browser - get firefox ! GIMP is the GNU Image Manipulation Program. Adobe Flex smarty : Template Engine