今更恥ずかしくて聞けない、RL78/I1Eの簡易IIC通信を教えてください。

こんにちは、NAKAといいます。

 

すみませんどうもI2C通信とは相性が悪いみたいで、なかなかゆうことを聞いてくれません。
以前RXの時もつまづいて、原因もあやふやなまま動いてしまったのでそのままの経緯があります。

今回、RL78/I1Eで初、簡易I2Cですがなんか上手く受信できてないような気がします。

もし、愛と少々のお時間がありましたら、お付き合いお願いできませんでしょうか?


まず、RL78をマスタにし、接続した開発中のデバイス(スレーブ)の仕様は
スレーブアドレス 0x77
レジスタアドレス 0x03、0x04、0x05 の 3Byte のデータを読みたいのですが
オートインクリメントができるみたいで、こんな感じ


そして
/*************************************************************************
// 関数名 : fn_Init_IIC00(void)
// 動作 : I2Cシリアル通信の初期化
// 引数 :
// 作成 : NAKA  19.10.14
// 備考 :  SAU0   ユニット=0 ch0=IIC00 (P14⇒SDA00  P15⇒SCL00)
// ***********************************************************************/
void fn_Init__IIC00(void)
{
    SAU0EN = 1;      //クロック供給
    SPS0 = 0x0000;  //クロック選択

    ST0 |= 0x0001;  //IIC00停止
    IICMK00 = 1;     //IIC00割り込み禁止
    IICIF00 = 0;     //IIC00割り込み要求フラグクリア
    IICPR100 = 1;  //IIC00割り込みプライオリティ設定
    IICPR000 = 1;
 
    SIR00 = 0x0003;  //全てエラーフラグのクリア
    SMR00 = 0x0024;  //簡易I2Cモードに設定
    SCR00 = 0x8017;  //1stopビット、8ビットデータ長
    SDR00 = 0xC600;  //ボーレート設定
    SO0 |= 0x0101;  //_シリアルクロックを1から | シリアルデータを1から
   
    POM1 |= 0x10;  //ポートの設定
    P1 |= 0x30;
    PM1 &= 0xCF;
 
    IICMK00 = 0;     //IIC00割り込み許可
 
}


※割込みの中では f_IIC00というフラグを立ててるだけです。(ベクタの設定もやってます。)
/************************************************************************/
/* IIC00の割り込み関数            */
/************************************************************************/
void __near IIC00_INT(void)
{
 IICIF00 = 0;     //IIC00割り込み要求フラグクリア
 f_IIC00 = 1;     //IIC通信完了フラグON!
}


こんな感じで設定して、

 

MAINの中で1秒毎に


    //①アドレス・フィールド送信
    SO0 &= 0xFFFE;              //スタートコンデション発行   SO00=0
    for(j=0;j<=10;j++)            //ウエイト
    {
     __nop();
    }
    f_IIC00 = 0;                       //IIC完了フラグクリア
    SO0 &= 0xFEFF;                 //クロックを"0"にして通信準備 CKO00=0
    SOE0 |= 0x0001;                //シリアル出力許可レジスタを許可 SOE00=1
    SS0 |= 0x0001;                 //シリアル動作許可状態にする SS00=1
   
    SCR00 &= ~0xC000;              //送受信を止める  TXE00=0 RXE00=0
    SCR00 |= 0x8000;               //送信状態にする   TXE00=1    
   
    SIO00 = (0x77 << 1) | 0x00;    //スレーブアドレスデータを入力****暫定 スレーブアドレス0x77 Wite:0 Read:1
    while(!f_IIC00)                //IIC完了割込み待ち
    {
     __nop();    
    }
    f_IIC00 = 0;                   //IIC完了フラグクリア
    if((SSR00 & 0x0002) != 0)      //ACK確認
    {
     c_ARK_ERR++;                  //エラー処理
    }
    //②レジスタアドレスデータ送信
    SIO00 = 0x03;                  //レジスタアドレスデータを入力
    while(!f_IIC00)                //IIC完了割込み待ち
    {
     __nop();    
    }
    f_IIC00 = 0;                   //IIC完了フラグクリア
    if((SSR00 & 0x0002) != 0)      //ACK確認
    {
     c_ARK_ERR++;                  //エラー処理
    }
   
    //③データ受信   
    SIO00 = (0x77 << 1) | 0x01;    //スレーブアドレスデータを入力****暫定 スレーブアドレス0x77 Wite:0 Read:1
    while(!f_IIC00)                //IIC完了割込み待ち
    {
     __nop();    
    }
    f_IIC00 = 0;                   //IIC完了フラグクリア
    if((SSR00 & 0x0002) != 0)      //ACK確認
    {
     c_ARK_ERR++;                 //エラー処理
    }
   
    ST0 |= 0x0001;                //シリアル動作停止状態にする  ST00=1
    SCR00 &= ~0xC000;             //送受信を止める    TXE00=0 RXE00=0
    SCR00 |= 0x4000;              //受信状態にする   RXE00=1
    SS0 |= 0x0001;                //シリアル動作許可状態にする SS00=1   
   
   
    SIO00 = 0xFF;                //ダミーデータ書き込み
    while(!f_IIC00)              //IIC完了割込み待ち
    {
     __nop();    
    }
    f_IIC00 = 0;                 //IIC完了フラグクリア
    IIC_RX_DATA[0] = SIO00;   
   
    SIO00 = 0xFF;                //ダミーデータ書き込み
    while(!f_IIC00)              //IIC完了割込み待ち
    {
     __nop();    
    }
    f_IIC00 = 0;                //IIC完了フラグクリア
    IIC_RX_DATA[1] = SIO00;
   
    //最後なので
    SOE0 &= 0xFFFE;             //シリアル出力許可レジスタを停止
   
    SIO00 = 0xFF;               //ダミーデータ書き込み
    while(!f_IIC00)             //IIC完了割込み待ち
    {
     __nop();    
    }
    f_IIC00 = 0;               //IIC完了フラグクリア
    IIC_RX_DATA[2] = SIO00;

    //④ストップコンディション発行
    ST0 |= 0x0001;            //シリアル動作停止状態にする  ST00=1
    SOE0 &= 0xFFFE;           //出力禁止状態    SOE00=0
    SO0 &= 0xFFFE;            //SDA出力を0にする   SO00=0
    for(j=0;j<=100;j++)       //ウエイト HWM-P649   必要らしい
    {
     __nop();
    }   
    SO0 |= 0x0100;            //クロック出力を1にする   CKO00=1
    for(j=0;j<=10;j++)        //ウエイト HWM-P649   必要らしい
    {
     __nop();
    }
    SO0 |= 0x0001;             //SDA出力を1にする   SO00=1

 


ってやるとIIC_RX_DATA[0]~[2]に受信データが入っていることを期待していますが
全部 ダミーと同じ 0xFF が入ってます。

 

エラー処理は取り合えず保留でACKが帰らなかったったら
c_ARK_ERRっていうカウンタをインクリメントすることにしてます。
c_ARK_ERRがインンクリメントされないので、ACKは受信できてそうだし、
(※スレーブアドレスを0x77以外にするとACKは来ずにc_ARK_ERRはインクリメントされる)
f_IIC00フラグも立つので割込みも発生している感じです。


なんかあんぽんたんなことをやってる感じでしょうか?

Parents
  • チョコです。
    さっと見始めたところですが,2つほど気になるところがあります。
    スレーブは,MCUでしょうかそれとも専用のスレーブでしょうか。
    RL78の簡易I2Cではスレーブからウエイトをかけることができないので,1バイトごとの通信の間隔をマスタ側で確保(通信の間に時間を空ける)必要があります。
    次がI2Cの基本に関する重大な欠陥です。②の処理に引く続いて,③でスレーブ・アドレスを送信開始しているつもりのようですが,ここは,②の処理の後に,リスタート(スタート・コンディションを発行)してから③を処理すべきです。このままでは,単にレジスタアドレス0x03に0xEFというデータを書き込んでいるだけです。
  • チョコ先生 NAKAです。

    まだすっきりしてません。I2Cの基礎から教わる必要があるかも?です。(~_~;)

    ご指摘の通り、下図の①のスタートコンディション発行を忘れていました。また送受信毎にウエイトも入れてみました。

    (あと、最初のご確認のスレーブは専用のスレーブデバイスです。)

    質問ですが、

    リスタートかける場合は下図②の部分にストップコンディションを発行しておく必要があるのでしょうか?

    ストップコンディションを発行しないと、下図①部分のスタートコンデションを発行しても(SO00=0にしてウエイトしてるだけ)

    クロック発生のためのダミー送信した0xFFがSIO00から読めるだけです。(0xAAをダミー送信するとSIO00も0xAA)

    下図②部分にストップコンディションを入れると、ダミー送信の値にかかわらずSIO00から0x00が読めます。

    (※まだ、開発デバイスの仕様が読み切れてないので、他のレジスタを設定しないと動作しないため0x00が読めるのかもしれません。)

    お気づきの点がございましたら、アドバイス願えませんでしょうか?

  • チョコです。
    このように,スレーブ内部のレジスタアドレスを指定して,読み出すような場合には,ストップコンディションは不要です。
    レジスタアドレスの送信が完了した段階で,マスタが通信方向を切り替えるためにスタートコンディションを発行することで,スレーブは次がスレーブアドレスと認識します。つまり,通信方向を切り替えることができるようになります。

    >下図①部分のスタートコンデションを発行しても
    リスタートの場合と通常のスタートコンディションの場合では,SCL信号の状態が異なっています。RL78の簡易I2Cでは,まずSDA信号をHにして,SDA信号がHになったら,SCL信号を立ち上げます。SCL信号がHになってからSDA信号を立ち下げることで,スタートコンディションになります。RL78の簡易I2Cではここらの手順が面倒なので,よく波形を確認してみてください。

    スレーブが専用のデバイスならウエイトは必要ないかもしれません。
  • チョコ先生! NAKAです。

    手ごわいです。

    >リスタートの場合と通常のスタートコンディションの場合では,SCL信号の状態が異なっています。
    >RL78の簡易I2Cでは,SDA信号をHにして,SDA信号がHになったら,SCL信号を立ち上げます。
    >SCL信号がHになってからSDA信号を立ち下げることで,スタートコンディションになります。

    ⇒SDAやSCLをソフトで操作するためには、SEmn=0(チャンネル動作停止)やSOE00=0(シリアル出力禁止)にしないといけないので、結局ほぼストップコンディションを発行しているのと同じことになるのではないでしょうか?

    //③データ受信
    weit_100();              //ウエイト
    ST0 |= 0x0001;        //シリアル動作停止状態にする  ST00=1(SE00=0)
    SOE0 &= ~0x0001;  //シリアル出力許可レジスタを禁止 SOE00=0
    SO0 |= 0x00001;     //SDAをHに
    weit_100();             //ウエイト
     SS0 |= 0x0001;      //シリアル動作許可状態にする SS00=1(SE00=1)
    SO0 |= 0x0100;      //SCLをHにする
    weit_100();             //ウエイト 
    SO0 &= 0xFFFE;      //スタートコンデションもう一度発行 SO00=0
    weit_100();            //ウエイト
    SOE0 |= 0x0001;    //シリアル出力許可レジスタを許可 SOE00=1

Reply
  • チョコ先生! NAKAです。

    手ごわいです。

    >リスタートの場合と通常のスタートコンディションの場合では,SCL信号の状態が異なっています。
    >RL78の簡易I2Cでは,SDA信号をHにして,SDA信号がHになったら,SCL信号を立ち上げます。
    >SCL信号がHになってからSDA信号を立ち下げることで,スタートコンディションになります。

    ⇒SDAやSCLをソフトで操作するためには、SEmn=0(チャンネル動作停止)やSOE00=0(シリアル出力禁止)にしないといけないので、結局ほぼストップコンディションを発行しているのと同じことになるのではないでしょうか?

    //③データ受信
    weit_100();              //ウエイト
    ST0 |= 0x0001;        //シリアル動作停止状態にする  ST00=1(SE00=0)
    SOE0 &= ~0x0001;  //シリアル出力許可レジスタを禁止 SOE00=0
    SO0 |= 0x00001;     //SDAをHに
    weit_100();             //ウエイト
     SS0 |= 0x0001;      //シリアル動作許可状態にする SS00=1(SE00=1)
    SO0 |= 0x0100;      //SCLをHにする
    weit_100();             //ウエイト 
    SO0 &= 0xFFFE;      //スタートコンデションもう一度発行 SO00=0
    weit_100();            //ウエイト
    SOE0 |= 0x0001;    //シリアル出力許可レジスタを許可 SOE00=1

Children
No Data