前回説明した謎現象一覧
・コード生成で指定する自局アドレスが送受信同時設定なのに8bit表記
・自局のアドレスより小さいアドレスに反応してエラーになる
・基本的にエラー状態になると有無を言わさずバスを占拠する
・スレーブからの送信時にマスターがデータ毎にACKを返さないとエラーになる
・マスターからのACKを正しく受け取れない
・送信受信のバッファ数と送受信数が一致してないと処理が中途半端になる
これらの対策案を考えたいと思います。
対処療法的な対策なので確実性があるかは不明です。
結論からいけば
・
r_iica0_callback_slave_error へ
LREL0 = 1U を追加
※必須・
iica0_slavehandler 内の
WTIM0 = 0U を
コメントアウト ※ラズパイと通信・
iica0_slavehandler 内の
if (1U == SPD0)部に
送受信完了処理を追加 ※送受信中断へ対応とりあえずこれだけやっておけば一部エラーは出ますがそれなりに通信できます。
一応最後にサンプルプロジェクトも付けておきます。
・
I2Cとは・
コード生成(準備編)・
コード生成(UART編)・
スレーブの謎現象編
対策に関連する変数
LREL0:現在の通信を終了させる
WREL0:待機状態を解除する
WTIM0:割り込みのタイミングを変更する
ACKD0:ACKの状態を検出する
SPIE0:ストップコンディション検出で割り込みを発生させる
SPD0:ストップコンディションを検出する
STD0:スタートコンディションを検出する
IICBSY0:バスの使用状態を検出する
COI0:自局アドレスとの一致を検出する※確認用
<コード生成で指定する自局アドレスが送受信同時設定なのに8bit表記>
設定時に気を付ける以外はありません。
自局アドレス設定を標準の設定の16のままだとすると。
7bit表記アドレス8(0x08)
8bit表記:送信アドレス16(0x10)、受信アドレス17(0x11)
<自局のアドレスより小さいアドレスに反応してエラーになる>
自局より小さなアドレスに反応させなくする方法は不明です。エラー扱いになったら強制的に解除するしかありません。
とりあえずエラー解除しておけば処理を続行できます。
<基本的にエラー状態になると有無を言わさずバスを占拠する>
バスの状態をスレーブが管理するのはおかしな話なので、
エラーになったら通信を解除します。
r_cg_iica_user.cの
r_iica0_callback_slave_error関数が実行されたら通信を
解除するように
static void r_iica0_callback_slave_error(MD_STATUS flag)
{
/* Start user code. Do not edit comment generated here */ LREL0 = 1U; //通信終了 /* End user code. Do not edit comment generated here */}
としておきます。
LREL0 = 1Uの代わりに
WREL0 = 1Uで通信を終了させるとラズパイのデバイスサーチコマンド
に誤反応します。
<スレーブからの送信時にマスターがデータ毎にACKを返さないとエラーになる>
エラーを無視する手段は無さそうです。
エラー扱いになったら強制的に解除するしかありません。
次項でラズパイからのACKを受け取れるように設定します。
とりあえずエラー解除しておけば処理を続行できます。
<マスターからのACKを正しく受け取れない>
ラズパイをマスターとしたときのACKを受け取れない問題の対策
割り込み等の判定基準は
R_IICA0_Createで初期化される際に
WTIM0 = 1U;にて
9クロック目の立下りに対して反応する様に設定されます。
ところが、
iica0_slavehandlerの114行目付近を見るとIDが一致して
受信を開始する際は
受信1Byte目に限り
WTIM0 = 0U;で
8クロック目の立下りに対して反応する様に設定されます。
どうやらこの設定が影響しているらしく、
この行をコメントアウトして常に
9クロック目の立下り基準にするとACKを受け取れるようになります。
ただしこの部分は
コード生成により自動生成された範囲なので、
再度コード生成を実行する
と
問答無用で消されてしまいます。
<送信受信のバッファ数と送受信数が一致してないと処理が中途半端になる>
とりあえず送受信バッファを使い切った場合の処理として
・
r_iica0_callback_slave_receiveendへ
受信完了処理を追加・
r_iica0_callback_slave_sendendへ
送信完了処理を追加とします。
送受信完了処理の内容は
・受信したデータを別の場所へコピー
・受信バッファをクリア
・先頭から受信できるように受信再設定(
R_IICA0_Slave_Receive)
・先頭から送信できるように送信再設定(
R_IICA0_Slave_Send)
などとします。
このままでは送受信バッファを使い切らない状態でマスターが通信を終了すると中途半端な
状態になるのので、
次に通信を開始する際にバッファの先頭から通信を開始できるように、
通信が終了時した時点で送受信完了処理を実行してしまいます。
エラーが出る事を気にしなければ、iica0_slavehandler内の
自動生成された範囲にある
ストップコンディションに対する処理
/* Control for stop condition */ if (1U ==
SPD0)
{
/* Get stop condition */ SPIE0 = 0U;
g_iica0_slave_status_flag = 1U;
/* この辺りに送受信完了処理を追加 */ }
部分で受信完了処理を行えば連続送受信には対応できそうです。
ただ、エラーを出さず
1Byteのみ送信してデバイス内アドレスを指定→指定アドレスからデータ出力
という機能を実装しようと思うと
・1個の受信データに対して即座に反応するには受信バッファを1に設定
・送信途中で中断してもエラーを出さないためには送信バッファを1に設定
・送信を続行するため
送信完了処理後の
WREL0 = 1Uを
コメントアウトが必要となり
・送信も受信も
自動処理されるバッファ数を1に設定・1Byte送受信する度に送受信完了関数を実行させる
・複数データを処理させる場合は
自分で逐次処理するように設定する
とするということになりそうです。
せめてiica0_slavehandlerの冒頭に自前の処理を記述できる場所があれば良かったの
ですが、他の機能だとr_cg_**_user.c内の関数は基本的に自前の処理を記述できる仕様
になっているのにiica0_slavehandlerは記述できる場所がありません。
I2Cはコード生成機能を使わない方が良さそうですが、とりあえず上書きされること覚悟
で
iica0_slavehandlerを編集してしまいます。
編集方針
改めてやっといた方が良い事
・
r_iica0_callback_slave_error へ
LREL0 = 1U を
追加 ※必須・
iica0_slavehandler 内の
WTIM0 = 0U を
コメントアウト ※ラズパイと通信・
iica0_slavehandler 内の
if (1U == SPD0)部に
送受信完了処理を追加 ※送受信中断へ対応とりあえずこれだけやっておけばそれなりに通信できます。
送受信バッファ1への対応
・
iica0_slavehandler 内に2ヶ所ある
r_iica0_callback_slave_sendend()直後の
WREL0 = 1Uをコメントアウト
これをやろうと思うとガッツリプログラムを編集する必要があります。
最後に10Y47用のプロジェクトを付けておきます。
RL78_10Y47_I2C_slave.zipダウンロードする際は
名前を付けて保存して下さい。
動作保証は致しません。
コード生成部分を編集しているのでコード生成を実行すると動作しなくなります。
デバイスのアドレスは標準設定の16のままなので
・7bit表記アドレス8(0x08)
・8bit表記:送信アドレス16(0x10)、受信アドレス17(0x11)
となります
送受信バッファを複数用意して内部アドレスの切替を対応してみました。
内部アドレスは0と1だけなので、それ以外を指定すると多分おかしな動きになります。
データを書き込む際も1Byte目は0または1を指定してください。