質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • C

    3825questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

H8/3687FのIIC2通信のマスタ受信について

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,325

imokempi1002

score 3

こんにちは。
先日「H8/3687FのIIC2通信の手順( https://teratail.com/questions/31067)」でも似たような質問させていただいた者です。

RenesasのマイコンH8/3687Fを使用して、温度測定をするC言語のプログラムをコーディングしています。 
その温度測定でIIC2通信を使用するのですが、マスタ受信動作時の挙動がおかしく、正しい値を得ることができません。

(変更)具体的には、通信自体はできるものの、得られた値を格納するICDRRが初期値0xFFのまま変わらず得られる温度が255℃になってしまいます。


(変更前)その挙動は、マスタ送信からマスタ受信に切り替えるためにICCR1のTRSビットを切り替えた後にクリアするICSRのTDREビットをクリアした際に、何故かICSRのTENDとRDRFが立ち上がってしまう、というものです。
その際、SDAOが1から0に切り替わっています。
(追記)通信中のレジスタの確認はステップモードとブレークポイントを利用して行なっていましたが、ブレークの位置でレジスタの値が変わってしまったため、質問内容を変えさせていただきます。
大変申し訳ありません


このような挙動が発生してしまう原因と対策を教えてください。
また、その他におかしな点があればご指摘願います。

宜しくお願い致します。

以下、プログラムのIIC2通信部分の関数です。

void reception_t(void)         
{
    unsigned int dmy;

    IIC2.ICCR1.BYTE = 0x85;            ////////////////    ICE=1,CKS3~0=0101
    IIC2.ICMR.BIT.MLS = 0;            //初期設定 (1)//    MLS
    IIC2.ICMR.BIT.WAIT = 1;            ////////////////    WAIT
    IIC2.SAR.BYTE = 0x90;            //スレーブアドレス:(1001000)+ I2C: (0)

    while(IIC2.ICCR2.BIT.BBSY == 1){;}

    IIC2.ICCR1.BIT.MST = 1;            //マスタ
    IIC2.ICCR1.BIT.TRS = 1;            //送信モード

    IIC2.ICCR2.BYTE = (IIC2.ICCR2.BYTE & 0x3F) | 0x80;        //開始条件発行

    IIC2.ICDRT = 0x90;            //スレーブアドレス(1001000)とR/W(0)を指定

    while(IIC2.ICSR.BIT.TDRE == 0){;}        //TDRE=1まで待機                                 

//    while(IIC2.ICSR.BIT.TEND == 0){;}        // TEND=1
    while(IIC2.ICIER.BIT.ACKBR == 1){;}        //アクノリッジ

    IIC2.ICDRT = 0x00;

    while(IIC2.ICSR.BIT.TDRE == 0){;}        //TDRE=1まで待機 

//    while(IIC2.ICSR.BIT.TEND == 0){;}        // TEND=1
    while(IIC2.ICIER.BIT.ACKBR == 1){;}        //アクノリッジ

    IIC2.ICDRT = 0x91;            //スレーブアドレス(1001000)とR/W(1)を指定

    while(IIC2.ICSR.BIT.TDRE == 0){;}        //TDRE=1まで待機 

//    while(IIC2.ICSR.BIT.TEND == 0){;}        // TEND=1
    while(IIC2.ICIER.BIT.ACKBR == 1){;}        //アクノリッジ    (この時点でICSR:0xC0)

    /* マスタ受信モード */

    IIC2.ICSR.BIT.TEND = 0;            /* TENDクリア */    
    IIC2.ICCR1.BIT.TRS = 0;            /* マスタ受信モード切替 */        
    IIC2.ICSR.BIT.TDRE = 0;            /* TDREクリア */    
    IIC2.ICIER.BIT.ACKBT = 0;        /* ACKBT=0を設定 */

    dmy = IIC2.ICDRR;                /* ダミーリード 受信開始 */    

    while(IIC2.ICSR.BIT.RDRF == 0){;}    /* データの受信完了待ち(受信データ転送時、RDRF=1) */
    IIC2.ICIER.BIT.ACKBT = 1;            /* 次の受信動作を禁止 */
    IIC2.ICCR1.BIT.RCVD = 1;                    

    temp_1 = IIC2.ICDRR;                /* データリード(上位ビット、整数値) */

    while(IIC2.ICSR.BIT.RDRF == 0){        /* データの受信完了待ち */
        }

    IIC2.ICSR.BIT.STOP = 0;                /* STOPフラグクリア */

    IIC2.ICCR2.BYTE = IIC2.ICCR2.BYTE & 0x3F;        //停止条件発行

    while(IIC2.ICSR.BIT.STOP == 0){;}            /* 停止条件生成待ち */

    temp_2 = IIC2.ICDRR;            /* データリード(下位ビット、小数値) */
    IIC2.ICCR1.BIT.RCVD = 0;        /* RCVDクリア */

    IIC2.ICCR1.BYTE = 0x85;            /* スレーブ受信モード切替 */
}

使用しているマイコンのマニュアルと学習用I/Oボードの説明書は以下のURL先です。 
マイコン:http://japan.renesas.com/products/mpumcu/h8/h8300h_tiny/h83687_h83687n/Documentation.jsp 
学習キット:http://www.hokutodenshi.co.jp/80/TinyEVA_s.pdf

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • daive

    2016/04/06 09:29

    続きであれば、その旨と、前スレのURL を記載していただくと、親切です。 前スレ:H8/3687FのIIC2通信の手順 https://teratail.com/questions/31067

    キャンセル

  • imokempi1002

    2016/04/06 09:39

    >davieさん ご指摘ありがとうございます。 文頭に追加いたしました。

    キャンセル

回答 3

0

もし可能であれば、ロジアナで、I2Cパケットを見てみるのがよいかと思います。
プログラムでは、きちんと書いたつもりが、

・余計なACKを戻していたり、逆にACKが抜けてるとか
・(かなり間抜けですが、アドレス間違っていてとか、さまざまな理由で)実はスレーブが応答していない
・ハードの問題(GNDが浮いてるとか、プルアップ抵抗値が速度にあってないとか)で、通信できてないとか

なんてことはよくあります。
電気は見えませんので、過信禁物です。
まして100Kbpsとかの速度ですから、テスター程度では話になりません。
オシロでがんばるという手もありますが、ロジアナのパケット解析機能を使ってしまうと・・・戻れません。

ロジアナ自体は、ちょっと価格は張りますが昔と違ってかなり安くなりました(秋月とかストロベリーリナックスとかであつかっている物で十分かと)。
特にUARTやI2Cなどの、シリアル通信系のデバッグには、有るのと無いのでは、大違いです。
今後も、ハードを続けられるならぜひ。

すいません、直接的な解決につながらない投稿ですが、お許しください。

P.S.
ちなみに、I2C通信のレジスタ状態を、デバッガーで、ブレークなどをして見ているとの事ですが、その方法では、スレーブ側が、マスタ応答がない(ACKが待ち時間以内に戻らないなと)などと判断して、途中で通信をやめてしまったり、以降通信不能などになる可能性があります(どの程度まで通信速度を落とせる(待ってくれる)かはデータシートをみないとわかりませんが)。
なので、ブレーク位置でレジスタの値がかわってしまったという現象は、実際何が原因かははっきりできないかと思います。
このあたりは、緩い規格のSPI(SPIはクロックださなければ、延々とまってくれるデバイスもあったり、まあこれもデバイス次第ですが・・・)とは、だいぶ違います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/10 09:25

    他の方の投稿で、気になったので、確認です。

    スレ主さんのコードを抜粋すると、

    IIC2.ICDRT = 0x90; //スレーブアドレス(1001000)とR/W(0)を指定
    while(IIC2.ICIER.BIT.ACKBR == 1){;} //ACK待ち
    IIC2.ICDRT = 0x00; //ポイントレジスタ = 0x00
    while(IIC2.ICIER.BIT.ACKBR == 1){;} //ACK待ち
    IIC2.ICDRT = 0x91; //スレーブアドレス(1001000)とR/W(1)を指定
    while(IIC2.ICIER.BIT.ACKBR == 1){;} //ACK待ち

    となっていますので、
    Pointer Register は、0x00 送信してるようで、
    なので、12ビットの、Temperature Registerが、戻る事を期待している動作かと。

    なので、見た目は読み込み手順はあっていそう?だと。
    ただ、H8のI2Cは触ったことないので、、、I2C一般論としてですが。

    キャンセル

0

おそらく、TMP101の使い方の問題だと思います。

自分が読んでいるのは以下のリンク先ですが、
リンク内容

この資料の13ページに、「Figure 8. I2C Timing Diagram for Read Word Format」
という図が掲載されていますが、この図でいう所の、「Frame 2 Pointer Register Byte」
の部分がコードに見当たりません。

まずは、データシート通りに、アクセスしないといけませんね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/14 22:59

    申し訳ありません。 ItoTomonori さんの仰る通り、
    「Frame 2 Pointer Register Byte」の処理はありますね。

    改めて、よくよく見てみると、次の「Frame 3 I2C Slave Address Byte」の
    先頭に、「Start By Master」と書いています。
    ところが、掲載されているソースを見ると、Frame 2 の直後に、終了しないで、
    続けて Frame 3 を送っています。

    Frame 2 の後に、一度送信を終わらせて(停止条件を発行)、して、
    改めて、Frame 3 の通信開始(開始条件の発行)を行ってみてはどうでしょうか?

    キャンセル

0

IICのリードの問題は、解決できましたでしょうか?
私も、かなり苦労しましたが、ハードウェアマニュアル通りに行うと、真面に動作しないことが解りました。
そして、ライト時も、一度のみの書き込みであれば、上手くいくのですが、2度目以降は、IICのレジスタが、狂ってしまい真面に動作しませんでした。
それは、一度、スレーブ受信にすると駄目な様です。
よって、3687のみでバスを制御するのであれば、スレーブにする必要もなく、BUSYチェックも必要ないと考えています。(タイミングは、3687で把握しているため)

ライト時は、TDREではなく、TENDを見ます。(最終データを格納する前もフローでは、抜けていますが必要です。)
コンパイラは、イエローソフトを使用していますが、アンド(&)や、オア(|)でも、アセンブラコードを見ると、最後にMOV命令で、各、レジスタに格納しているので、C言語のみで問題ないと思います。
他、気になる点としては、割り込み禁止区間が設定されていませんでしたので、追加した方が良いと思われます。

最後に、同じ様に苦労されている方の参考になれば幸いです。

        /*                                                                                                                */
        /*                        I2C-BUS EEPROM  Read/Write                                        */
        /*                                                                                                                */
        /****************************************************************************************************************/


#include <SYSIO.H>
#include <J3687.H>

#define        DEVICE_CODE    0xA0            /* 内蔵EEPROM デバイス・コード(Code  : 1010                 */
#define        SLAVE_ADRS    0x00            /*    〃     スレーブ・アドレス(Addr : 000                */
#define        IIC_DATA_W    0x00            /* データ書込指定コード                                                        */
#define        IIC_DATA_R    0x01            /* データ読出指定コード                                                        */
#define        WR_RETRY_CNT  10            /* 開始条件発行の最大リトライ値                                                */
#define        WR_OK  (WR_RETRY_CNT + 1)    /* 開始条件成立時の値                                                        */



    /**********    common.c    **********/
extern    void    wait();                /* 少し待つ */




    /********************************************************************************************************************/
    /*             デバイスアドレス設定                                                                                    */
    /*                                                                                                                    */
    /*    [概要]    デバイスのアドレス指定                                                                                */
    /*    [呼元]    uchar    eepwrite_page(uint addr, uchar *buf)                                                        */
    /*                uchar    eepread_n(uint addr, uchar *buf , uint cnt)                                                    */
    /*                uchar    eepwrite_byte(uint addr, uchar wr_dat)                                                        */
    /*    [引数]    uint addr    EEPROM先頭アドレス                                                                */
    /*    [戻値]    uchar    0:エラー    1:正常終了                                                                    */
    /*    [処理]                                                                                                        */
    /*    [使用]                                                                                                        */
    /********************************************************************************************************************/

uchar addr_set(uint addr)
{

    uchar    wk;

        *ICCR1 = 0xB4;                                        /* スレーブ受信モード 250kHz(20MHz)            */

        *ICCR2 = ((*ICCR2 & ~0x40) | 0x80);                    /* 開始設定                                    */

        *ICDRT = (uchar)(DEVICE_CODE | SLAVE_ADRS | IIC_DATA_W);

        while ( (*ICSR & 0x40) == 0 ){}                        /* TEND=1待ち(1バイト送信待ち)        */


        if ( *ICIER & 2 ){                                    /* ACKが無ければエラー                     */
            return(0);
        }

        *ICDRT = (uchar)(addr >> 8);                        /* EEPROM上位アドレス・セット             */
        while ( (*ICSR & 0x80) == 0 ){}                        /* TDRE=1待ち(データ・エンプティ)    */

        *ICDRT = (uchar)(addr & 0x00FF);                    /* EEPROM下位アドレス・セット             */
        while ( (*ICSR & 0x40) == 0 ){}                        /* TEND=1待ち(1バイト送信待ち)        */
//        while ( (*ICSR & 0x80) == 0 ){}                        /* TDRE=1待ち(データ・エンプティ)    */

        return(1);
}




    /********************************************************************************************************************/
    /*            任意数データ読み出し                                                                                    */
    /*                                                                                                                    */
    /*    [概要]    カレント・アドレス・リードとして、任意のアドレスより指定数のデータを読み出す                        */
    /*    [呼元]    メイン等で呼び出し                                                                                    */
    /*    [引数]    (uchar addr, uchar *buf, uint cnt)                                                                    */
    /*                    uchar addrは、EEPROM先頭アドレス(0~1FFh)                                            */
    /*                    uchar *bufは、読み出しデータを格納する先頭アドレスを指定する                                    */
    /*                    uint cntは、読み出しデータ数を指定する                                                            */
    /*    [戻値]    uchar    0:エラー発生    1:正常終了                                                                */
    /*    [処理]                                                                                                        */
    /*    [使用]                                                                                                        */
    /********************************************************************************************************************/

uchar eepread_n(uint addr, uchar *buf , uint cnt)
{
    uchar    ack, wk;
    ulong    i;

        ack = 0;

        if ( cnt == 0 )        return(ack);

        ack = addr_set(addr);                                /* 読み出し先頭アドレス セット                */

        if (ack == 0) {
            *ICSR  &= ~0x40;                                /* TENDクリア                            */
            *ICSR  &= ~0x04;                                /* STOPクリア                            */
            *ICCR2 &= ~0xC0;                                /* BBSY,SCPクリア                    */

            while ( (*ICSR & 4) == 0 ){}                    /* STOP=1待ち(停止条件生成待ち)        */

            *ICCR1 &= ~0x30;                                /* スレーブ受信モードに戻す                    */

            return(ack);
        }

        *ICCR2 = ((*ICCR2 & ~0x40) | 0x80);                    /* 開始設定                                    */

        *ICDRT = (uchar)(DEVICE_CODE | SLAVE_ADRS | IIC_DATA_R);    /* スレーブ・アドレス・セット        */

        while ( (*ICSR & 0x40) == 0 ){}                        /* TEND=1待ち(1バイト送信待ち)        */


        if ( *ICIER & 2 ){                                    /* ACKが無ければエラー                     */
            *ICSR  &= ~0x40;                                /* TENDクリア                            */
            *ICSR  &= ~0x04;                                /* STOPクリア                            */
            *ICCR2 &= ~0xC0;                                /* BBSY,SCPクリア                    */

            while ( (*ICSR & 4) == 0 ){}                    /* STOP=1待ち(停止条件生成待ち)        */
            *ICCR1 &= ~0x30;                                /* スレーブ受信モードに戻す                    */

            return(ack);
        }

        _di();

        *ICSR  &= ~0x40;                                    /* TENDクリア                            */
        *ICCR1 &= ~0x10;                                    /* マスター受信モード                        */

        *ICSR  &= ~0x80;                                    /* TDREクリア                            */

        if ( cnt == 1 )    goto BYTE_1;                        /* 1バイト受信時は、中省略                    */

        *ICIER &= ~0x01;                                    /* ACKで 「0」出力                        */

        *buf = *ICDRR;                                        /* ダミー・リード                            */

        _ei();

        for ( i = 0;  i < (cnt - 2);  i++ ){
            while ( (*ICSR & 0x20) == 0 ){}                    /* RDRF=1待ち(1バイト受信完了待ち)    */

            *buf = *ICDRR;                                    /* 1バイト受信                                */
            buf++;
        }

BYTE_1:
        _ei();

        if ( cnt != 1 ){
            while ( (*ICSR & 0x20) == 0 ){}                    /* RDRF=1待ち(1バイト受信完了待ち)    */
        }


        *buf = *ICDRR;                                        /* 1バイト受信時ダミーリード                */

        *ICIER |= 0x01;                                        /* ACKで 「0」出力禁止                    */
        *ICCR1 |= 0x40;                                        /* RCVD=1 次の受信禁止                */

        while ( (*ICSR & 0x20) == 0 ){}                        /* RDRF=1待ち(1バイト受信完了待ち)    */

        *ICSR  &= ~0x08;                                    /* STOPクリア                            */
        *ICCR2 &= ~0xC0;                                    /* BBSY,SCPクリア                    */

        while ( (*ICSR & 8) == 0 ){}                        /* STOP=1待ち(停止条件生成待ち)        */

        if ( cnt != 1 )    buf++;                                /* 2バイト以上受信                            */

        while ( (*ICSR & 0x20) == 0 ){}                        /* RDRF=1待ち(1バイト受信完了待ち)    */

        *buf = *ICDRR;                                        /* 1バイト受信                                */

        *ICCR1 &= ~0x40;                                    /* RCVD=0 次の受信継続                */

        return(ack);
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

関連した質問

同じタグがついた質問を見る

  • C

    3825questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。