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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Q&A

解決済

3回答

3914閲覧

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

imokempi1002

総合スコア12

C

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

0グッド

1クリップ

投稿2016/04/06 00:11

編集2016/04/06 01:06

こんにちは。
先日「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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

imokempi1002

2016/04/06 00:39

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

回答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); }

投稿2017/02/09 10:07

johns

総合スコア27

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

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

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

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

投稿2016/04/09 12:48

ShinyaAnan

総合スコア241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ShinyaAnan

2016/04/14 13:59

申し訳ありません。 ItoTomonori さんの仰る通り、 「Frame 2 Pointer Register Byte」の処理はありますね。 改めて、よくよく見てみると、次の「Frame 3 I2C Slave Address Byte」の 先頭に、「Start By Master」と書いています。 ところが、掲載されているソースを見ると、Frame 2 の直後に、終了しないで、 続けて Frame 3 を送っています。 Frame 2 の後に、一度送信を終わらせて(停止条件を発行)、して、 改めて、Frame 3 の通信開始(開始条件の発行)を行ってみてはどうでしょうか?
guest

0

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

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

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

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

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

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

投稿2016/04/08 19:27

編集2016/04/08 19:37
ItoTomonori

総合スコア1283

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ItoTomonori

2016/04/10 00: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一般論としてですが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問