忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

RX220で簡易I2C(受信編)

送信編にて初期化に間違いがありました。
通信に使用する端子はオープンドレイン出力に設定してください。
また、送信・受信の許可/禁止は個別に行わず、一度に変更してください。

関連:
I2Cとは
送信編
割込編

送信編で初期化ができたものとして、とりあえず割込み無しで受信動作を確認します。
RX220ハードウェアマニュアルの「簡易 I2C モードのマスタ受信動作のフローチャート例
を参考にプログラムを作成します。※2023/02/25 資料の参照先を明記
引き続きDRV8830に指令を送ります。

DRV8830の取説に従って、通信の順は
・スタートコンディション
・スレーブアドレス(0xC8)
・サブアドレス(0x00)
・リスタートコンディション
・スレーブアドレス(0xC9)
・データ受信
・ストップコンディション
となります。

<設定>
char recv_i2c(){
    int i;
    char recv_data;

    //スタートコンディションの発行
    SCI9.SIMR3.BIT.IICSTIF=0;    //フラグクリア
    SCI9.SIMR3.BIT.IICSTAREQ=1;    //スタートコンディション生成指令
    SCI9.SIMR3.BIT.IICSDAS=0x1;    //SSDAn端子は開始条件、再開始条件、停止条件
    SCI9.SIMR3.BIT.IICSCLS=0x1;    //SSCLn端子は開始条件、再開始条件、停止条件
    while(SCI9.SIMR3.BIT.IICSTIF==0);    //開始/再開始/停止条件生成が完了するまで待機

    //データ送信準備
    SCI9.SIMR3.BIT.IICSTIF=0;    //フラグクリア
    SCI9.SIMR3.BIT.IICSDAS=0x0;    //SSDAn端子はデータ出力
    SCI9.SIMR3.BIT.IICSCLS=0x0;    //SSCLn端子はクロック出力

    //データ0(アドレス)送信
    SCI9.TDR=0xC8;    //宛先アドレス
    for(i=0;i<100;i++);    //ちょっとだけ空ループ
    while(SCI9.SSR.BIT.TEND==0);    //送信完了まで待機

    //データ1(サブアドレス)送信
    SCI9.TDR=0x00;    //サブアドレス
    for(i=0;i<100;i++);    //ちょっとだけ空ループ
    while(SCI9.SSR.BIT.TEND==0);    //送信完了まで待機

    //リスタートコンディションの発行
    SCI9.SIMR3.BIT.IICSTIF=0;    //フラグクリア
    SCI9.SIMR3.BIT.IICRSTAREQ=1;    //リスタートコンディション生成指令
    SCI9.SIMR3.BIT.IICSDAS=0x1;    //SSDAn端子は開始条件、再開始条件、停止条件
    SCI9.SIMR3.BIT.IICSCLS=0x1;    //SSCLn端子は開始条件、再開始条件、停止条件
    while(SCI9.SIMR3.BIT.IICSTIF==0);    //開始/再開始/停止条件生成が完了するまで待機

    //データ送信準備
    SCI9.SIMR3.BIT.IICSTIF=0;    //フラグクリア
    SCI9.SIMR3.BIT.IICSDAS=0x0;    //SSDAn端子はデータ出力
    SCI9.SIMR3.BIT.IICSCLS=0x0;    //SSCLn端子はクロック出力

    //データ2(アドレス)送信
    SCI9.TDR=0xC9;    //宛先アドレス
    for(i=0;i<100;i++);    //ちょっとだけ空ループ
    while(SCI9.SSR.BIT.TEND==0);    //送信完了まで待機

    SCI9.SIMR2.BIT.IICACKT=1;    //NACK送信(送信/最終データ受信用設定)

    //データ3 受信
    SCI9.TDR=0xFF;    //受信用
    for(i=0;i<100;i++);    //ちょっとだけ空ループ
    while(SCI9.SSR.BIT.TEND==0);    //送信完了まで待機

    recv_data=SCI9.RDR;                //受信データを読み取り

    //ストップコンディションの発行
    SCI9.SIMR3.BIT.IICSTPREQ=1;    //ストップコンディション
    SCI9.SIMR3.BIT.IICSDAS=0x1;    //SSDAn端子は開始条件、再開始条件、停止条件
    SCI9.SIMR3.BIT.IICSCLS=0x1;    //SSCLn端子は開始条件、再開始条件、停止条件
    while(SCI9.SIMR3.BIT.IICSTIF==0);    //開始/再開始/停止条件生成か完了するまで待機

    //送信終了の後処理
    SCI9.SIMR3.BIT.IICSTIF=0;    //フラグクリア
    SCI9.SIMR3.BIT.IICSDAS=0x3;    //SSDAn端子はハイインピーダンス状態
    SCI9.SIMR3.BIT.IICSCLS=0x3;    //SSCLn端子はハイインピーダンス状態

    return recv_data;

}
送信編で作った関数と併用して、「初期化→送信→受信」の順に実行して
設定した値(73:0x49)が戻ってくれば成功です。

受信許可が正しく実行できていない(送信許可と受信許可を個別に設定している)と受信データが0になります。
オープンドレイン設定ができてないと受信データが255になります。

受信データの確認には設定プログラムからシリアル通信(intSCI_rx220.cintSCI_rx220.h)を
使用しました。
シリアル通信を使うのにクロックの設定変更(hwsetup_rx220.chwsetup_rx220.h)と
タイマ設定(intCMT_rx220.cintCMT_rx220.h)も使いました。

次回は割込み対応を行います。
PR

コメント

1. 教えて下さい。

はじめまして、早速ですが、
 以下の部分、受信するのに送信しているのはどういう意図でしょうか。
 よろしくお願いします。

 //データ3 受信
SCI9.TDR=0xFF; //受信用
for(i=0;i<100;i++); //ちょっとだけ空ループ
while(SCI9.SSR.BIT.TEND==0); //送信完了まで待機

2. 返信が遅れて申し訳ありません

はじめまして。

記事へリンクを入れ忘れていましたが、I2Cの通信仕様は以下の記事に記載しております。
http://project12513.blog-fps.com/Entry/78/

この記事ではとりあえず受信してみようといった内容ですが、
I2Cではマスターが受信する場合はマスター側からクロックを送りますが、
その際にマスターが1をひたすら送っています(0xFF)。
マスターが1を送っている最中に
・スレーブが1を送ればバスが1
・スレーブが0を送ればバスが0
となり、マスターはこのバスを読み取ることでデータを受信することになります。
TDRで0xFFを送ればRDRでデータを読めるといった動作です。

ということで、受信処理をする際に1を送信する機能を使っているので、
 受信完了待ち=送信完了待ち
と処理を行いました。

4年前に書いたので当時のことを忘れていましたが、ハードウェアマニュアルの
「クロック同期式モードのシリアル受信のフローチャート例」を参考に作成
した様な気がします。

きっちり理解するために疑問に思った事は確認する(聞いてみる)ってのは大切だと思います。

3. ご回答ありがとうございます。

マスターもスレーブもSCL,SDA端子は
オープンドレイン出力で外付けPUだと
思うので、マスターはスレーブからの
受信待ちの間はSDAをHigh-Z(外付け
PUにより0xFFになる)にすべきと
思うのですが、
この例題では割り込みを使っていないので、
もしかして受信完了タイミングを計るために
あえて0xFFを送信されているのかなと
理解しましたが、如何でしょうか。

ちなみにオープンドレイン出力定義端子の
TDRに0xFFを書いた場合、実際にはHigh-Z
出力になるのでしょうかね?
(PUにより0xFFを実現の意)

4. ほぼご推察の通りです

ハードウェアマニュアルにて参照したのは
「クロック同期式モードのシリアル受信のフローチャート例」
ではなく、
「簡易 I2C モードのマスタ受信動作のフローチャート例」
が正解でした。

<オープンドレイン>
よくよく考えるとオープンドレイン関連の動作を自分でしっかり
確認したことは無いような気がするのですが、Nチャンネルオープン
ドレインで1を出力しておけばHi-Z状態になると考えて問題ありません。
これにプルアップが加わってバスがHiの状態になります。
おそらくポートの初期設定は対応できているものと思いますが、
ポートの初期設定については1つ前の記事「送信編」をご参照ください。

<0xFFの送信>
0xFFの送信については割り込み無しで動かす場合に受信完了の
タイミングを計る目的もあるのですが、マスターとしてSCLの
クロックを送信するための手段として使用しています。
I2CはUARTと違いマスターがクロックを送らないとスレーブが
データを送信しないので、マスターが受信する場合でもマスター
は何らかの方法でクロックを送信する必要があります。
公式のフローチャートによる割り込みを使った受信処理でもTDR
に0xFFを設定しているので、受信専用のクロック送信機能は無く、
送信用のクロック送信機能をそのまま受信でも使用するのが公式の
方法なのだと思います。

受信完了のタイミングについては割り込みを使う場合は素直に受信
完了割り込みで対応するのがベストだと思います。割り込みの詳細
を解説する記事は書いてないのですが、次の記事「割込編」にリンク
のある「intI2C_rx220.c」を名前を付けて保存して頂ければ割り込み
部分のサンプルコードもご参照可能です。

5. なるほど、ありがとうございます。

確かに「簡易 I2C モードのマスタ受信動作のフローチャート例」に
TDRにダミー0xFFをライトというのが記載されていました。
むしろクロック出力が目的だと腑に落ちました。

割り込みの記事も参考に読ませていただきます。
詳しくご教示いただきありがとうございました。


プロフィール

HN:
ぼんどF博士
性別:
男性
自己紹介:

最新コメント