RL78/G1D 簡易i2cのやり方について

初めまして。恐らく初歩的な質問となると思うのですが、よろしければご教授お願い致します。

使用している総合開発環境はCS+forCCです。

RL78/G1D R5F11AGJ の簡易i2cを使用して6軸加速度センサLSM6DS3との通信を実現したいと思っています。

今まではArduinoを使用していたのですが、諸事情によりRL78/G1Dに変更することになりました。

ハードウェアマニュアルやサンプルプログラムを見ながら試行錯誤しているのですが、いまいち要領を得ません。

シリアルアレイユニットのIIC00をコード生成後、加速度センサの値を読みたい時のおおまかな流れは以下の様な理解で良いのでしょうか?

/*********************************************************************************************/

R_SAU0_Create()/*シリアルアレイユニット0、IIC00初期設定*/

R_IIC00_Master_Send(uint8_t slave_address,uint8_t register_address,1)/*スレーブアドレス、アクセスするレジスタアドレス、バッファーサイズを指定*/

/***r_iic00_interrupt()により転送完了割り込みが発生,アドレスフィールド送信***/

R_IIC00_Master_Receive(uint8_t slave_address, (uint8_t *)data_address, buffer_size) /*data_addressはスレーブから受け取ったデータを格納*/

/***r_iic00_interrupt()により転送完了割り込みが発生,data_addressに指定したレジスタアドレスの値をバッファーサイズ分格納***/

 

/*********************************************************************************************/

割り込み処理についてよく理解ができておらず、その辺りの流れに頭を悩ませております。

この様なちゃんとした?マイコンを扱うのが初めてで、右も左もわからない状態なのですが是非よろしくお願いいたします。

 

 

以下にコード生成されたMaster_Send,Master_Receive,r_iic00_interruptのソースを貼ります。

/***********************************************************************************************************************
* Function Name: R_IIC00_Master_Send
* Description : This function starts transferring data for IIC00 in master mode.
* Arguments : adr -
* set address for select slave
* tx_buf -
* transfer buffer pointer
* tx_num -
* buffer size
* Return Value : None
***********************************************************************************************************************/
void R_IIC00_Master_Send(uint8_t adr, uint8_t * const tx_buf, uint16_t tx_num)
{
g_iic00_master_status_flag = _00_SAU_IIC_MASTER_FLAG_CLEAR; /* clear IIC00 master status flag */
adr &= 0xFEU; /* send mode */
g_iic00_master_status_flag = _01_SAU_IIC_SEND_FLAG; /* set master status flag */
SCR00 &= ~_C000_SAU_RECEPTION_TRANSMISSION;
SCR00 |= _8000_SAU_TRANSMISSION;
/* Set paramater */
g_iic00_tx_count = tx_num;
gp_iic00_tx_address = tx_buf;
/* Start condition */
R_IIC00_StartCondition();
IICIF00 = 0U; /* clear INTIIC00 interrupt flag */
IICMK00 = 0U; /* enable INTIIC00 */
SIO00 = adr;
}
/***********************************************************************************************************************
* Function Name: R_IIC00_Master_Receive
* Description : This function starts receiving data for IIC00 in master mode.
* Arguments : adr -
* set address for select slave
* rx_buf -
* receive buffer pointer
* rx_num -
* buffer size
* Return Value : None
***********************************************************************************************************************/
void R_IIC00_Master_Receive(uint8_t adr, uint8_t * const rx_buf, uint16_t rx_num)
{
g_iic00_master_status_flag = _00_SAU_IIC_MASTER_FLAG_CLEAR; /* clear master status flag */
adr |= 0x01U; /* receive mode */
g_iic00_master_status_flag = _02_SAU_IIC_RECEIVE_FLAG; /* set master status flag */
SCR00 &= ~_C000_SAU_RECEPTION_TRANSMISSION;
SCR00 |= _8000_SAU_TRANSMISSION;
/* Set parameter */
g_iic00_rx_length = rx_num;
g_iic00_rx_count = 0U;
gp_iic00_rx_address = rx_buf;
/* Start condition */
R_IIC00_StartCondition();
IICIF00 = 0U; /* clear INTIIC00 interrupt flag */
IICMK00 = 0U; /* enable INTIIC00 */
SIO00 = adr;
}

/***********************************************************************************************************************
* Function Name: r_iic00_interrupt
* Description : None
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
static void __near r_iic00_interrupt(void)
{
if (((SSR00 & _0002_SAU_PARITY_ERROR) == 0x0002U) && (g_iic00_tx_count != 0U))
{
r_iic00_callback_master_error(MD_NACK);
}
else if(((SSR00 & _0001_SAU_OVERRUN_ERROR) == 0x0001U) && (g_iic00_tx_count != 0U))
{
r_iic00_callback_master_error(MD_OVERRUN);
}
else
{
/* Control for master send */
if ((g_iic00_master_status_flag & _01_SAU_IIC_SEND_FLAG) == 1U)
{
if (g_iic00_tx_count > 0U)
{
SIO00 = *gp_iic00_tx_address;
gp_iic00_tx_address++;
g_iic00_tx_count--;
}
else
{
R_IIC00_StopCondition();
r_iic00_callback_master_sendend();
}
}
/* Control for master receive */
else
{
if ((g_iic00_master_status_flag & _04_SAU_IIC_SENDED_ADDRESS_FLAG) == 0U)
{
ST0 |= _0001_SAU_CH0_STOP_TRG_ON;
SCR00 &= ~_C000_SAU_RECEPTION_TRANSMISSION;
SCR00 |= _4000_SAU_RECEPTION;
SS0 |= _0001_SAU_CH0_START_TRG_ON;
g_iic00_master_status_flag |= _04_SAU_IIC_SENDED_ADDRESS_FLAG;

if (g_iic00_rx_length == 1U)
{
SOE0 &= ~_0001_SAU_CH0_OUTPUT_ENABLE; /* disable IIC00 out */
}

SIO00 = 0xFFU;
}
else
{
if (g_iic00_rx_count < g_iic00_rx_length)
{
*gp_iic00_rx_address = SIO00;
gp_iic00_rx_address++;
g_iic00_rx_count++;

if (g_iic00_rx_count == (g_iic00_rx_length - 1U))
{
SOE0 &= ~_0001_SAU_CH0_OUTPUT_ENABLE; /* disable IIC00 out */
SIO00 = 0xFFU;
}
else if (g_iic00_rx_count == g_iic00_rx_length)
{
R_IIC00_StopCondition();
r_iic00_callback_master_receiveend();
}
else
{
SIO00 = 0xFFU;
}
}
}
}
}
}

  • チョコです。

    RL78の割り込みを使ったシリアル制御でのコード生成されたAPIは基本的に,
    "R_IIC00_Master_Send"関数はスレーブへのデータ送信の起動を行い,
    スレーブ・アドレスを送信開始しただけで戻ってきます。
    ("R_IIC00_Master_Receive"関数も同様です。)
    指定されたデータの送信が完了したかどうかは,INTIIC00割り込み
    ハンドラーで判断しています。
    そこで,コード生成された"r_cg_serial_user.c"ファイルの中に
    "r_iic00_callback_master_sendend"関数が定義されています。
    指定されたデータの送信が完了したら,この関数が呼び出されるので,
    そこに「通信ステータスを示すフラグ」を送信完了にセットする処理
    を記述してください。(そのフラグは,"R_IIC00_Master_Send"関数を
    呼び出すときにクリアしておいてください。)
    送信がエラーになった(スレーブが存在しなかった等,スレーブ
    からACK応答がなかった)場合には,"r_iic00_callback_master_error"
    関数が呼び出されるので,そこには「通信ステータスを示すフラグ」
    を「通信エラー」にセットする処理を記述してください。
    "R_IIC00_Master_Send"関数を呼び出したら,そのフラグが「送信完了」
    にセットされるのを確認することで,送信完了を知ることができます。
    また,「通信エラー」になっていたら,スレーブが正常に応答しなかった
    ことが分かります。
    同様に,"R_IIC00_Master_Receive"関数で,指定されたデータの受信が
    完了したときには,"r_iic00_callback_master_receiveend"関数が
    呼び出されるので,「通信ステータスを示すフラグ」を「受信完了」に
    セットする処理を記述してください。
    (こういったフラグ類は,コード生成で準備してもらえば,使う方は
    割り込み処理の中を気にしなくて楽なんですが。)

    とにかく1バイトの送受信ごとに,INTIIC00が発生するので,そんなのは
    無視(勝手にやらせておいて)結果だけを確認して制御するようにして
    ください。

    また,RL78でのスレーブ・アドレスは8ビットで表現しているので,
    LSM6DS3の1101010bや1101011bは0xD4や0xD6と表してください。

    個人的には,コード生成されたシリアル関係のAPIは余り好きではないので,
    通常は自分で作ったライブラリを使っています。
  • チョコ様、丁寧なご回答ありがとうございます。フラグを立てればいいのですね!
    もう一つお聞きしたいのですが、レジスタの値をnバイト読むとき、tx_numで指定した分が だけ渡したレジスタアドレスに読まれるのでしょうか?
    if (g_iic00_rx_count < g_iic00_rx_length)
    {
    *gp_iic00_rx_address = SIO00;
    gp_iic00_rx_address++;
    g_iic00_rx_count++;
    ここの記述の部分なのですが
    例えばレジスタアドレスが0x002Bで、tx_numが2だとしたら0x002Bの値が*gp_iic00_rx_addressに代入され、0x002Cの値がが*(gp_iic00_rx_address+1)のアドレスに代入されるという認識でよろしいでしょうか?
    お手数おかけしますが、宜しければご回答よろしくお願いします。
  • チョコです。
    >レジスタの値をnバイト読むとき、tx_numで指定した分が だけ渡したレジスタアドレスに読まれるのでしょうか?
    指定した数の読み出した(I2Cバスから受信した)レジスタの値が,指定された受信データのバッファ領域に順番に格納されていきます。

    >例えばレジスタアドレスが0x002Bで、・・・・
    はい,そうです。
    最初に受信したデータ(=0x002Bの値)が指定されたバッファ・アドレス(*gp_iic00_rx_address)に格納され,次のアドレス(*(gp_iic00_rx_address+1))には次のデータ(=0x002Cの値)が格納されていきます。
  • チョコです。
    鈴木さん,現状の通信関係のコード生成されたAPIでは,慣れた人でないと使い辛いです。他のスレッドでも同様の書き込みがありました。改版(フラグ管理の追加)の検討をよろしくお願いします。
    (ついでに,ドキュメントも是非見直してください。)

    japan.renesasrulz.com/.../rl78-g13-csi
  • チョコ様ご回答有難うございました。
    大変分かりやすかったです。
    なんとか実現出来そうです。もしまたお世話になる事があればよろしくお願い致します。
    本当にありがとうございました。
  • チョコ様、hiro様

    チョコ様の回答において、
    >そこで,コード生成された"r_cg_serial_user.c"ファイルの中に
    >"r_iic00_callback_master_sendend"関数が定義されています。
    >指定されたデータの送信が完了したら,この関数が呼び出されるので,
    >そこに「通信ステータスを示すフラグ」を送信完了にセットする処理
    >を記述してください。(そのフラグは,"R_IIC00_Master_Send"関数を
    >呼び出すときにクリアしておいてください。)
    とありますが、これは、
    g_iic00_master_status_flag
    のことでしょうか?
    ご教示お願いします。
  • チョコです。
    >これは、
    >g_iic00_master_status_flag
    >のことでしょうか?
    違います。このフラグはiic00割り込み処理での処理状態(送信(0x01)/受信でアドレス送信(0x02)/データ受信(0x06))を格納するための変数として使われています。そんなフラグを勝手にいじるのは怖いです。
    それよりは,自前でフラグを準備して,そこで,通信中や通信完了及び通信エラーのステータスを確認できるようにすることをお勧めします。そうすれば,簡易IICだけでなくIICA0でも同じような使い方ができます。
  • チョコ様
    早速のご回答有難うございました。

    "r_iic00_callback_master_sendend"関数の中で、自前のフラグを設定し送信完了を確認するということですね。

    現在、簡易IICの使用方法を理解しようとしていますが、「かふぇルネ」で色々な情報があり、私自身混乱しております。hiro様のこのスレッドを元に、簡易IICを使い、次の手順で2バイトのデータをLCDに送信したいと考えています。

    混乱の一つは、次のとおりです。

    (1)簡易IICでは、1バイト送信後に5usのインターバルが必要という記事がありましたが、このスレッドでは、そのことに言及はなくR_IIC00_Master_Send(...) に引数をセットし実行、次に送信完了割り込み "r_iic00_callback_master_sendend"にて、自前フラグをセット送信完了かどうかをチェックすればOKとのことです。
    (2)自前フラグをセットするしないにかかわらず、実際には送信はされていると思います。
    (3)このMaster_Sendの実行でデータ送信は行われるのでしょうか。「かふぇルネ」の記事で、レジスタをセットしトリガを与えないと送信できないという記事もあったと思います。

    簡易IICによるデータ送信の方法について、まとまった情報を得たいのですが、RL78について、どこで見ればよいのでしょうか?ご教示よろしくお願いします。

    なお、CS+ for CC V8.0.1[03 Dec 2018]を使用しています。
  • チョコです。

    >(1)簡易IICでは、1バイト送信後に5usのインターバルが必要という記事がありましたが、

    簡易IICそのものにそのような制限事項はありません。問題はスレーブ側での処理速度です。RL78の簡易IICでは,スレーブ側からウエイトを掛けることができないので,その分をマスタ側でケアしておく必要があります。そのためのものが,5usのインターバルです。これは,スレーブがマイコンのようにソフトウェアで処理している場合には,すぐには次の通信が始められないことがあります。ここらへの対応です。

    汎用的なAPIとする場合には考慮しておきべきものです。コード生成ではここらの考慮が不足しています(と考えています)。

    >このスレッドでは、そのことに言及はなく

    このスレッドで使っている6軸加速度センサLSM6DS3のような専用のデバイスでは,IICの制御はハードウェアで実現していると考えられるので,ウエイトは必要ありません。(したがって,言及していません。)

    >自前フラグをセットするしないにかかわらず、実際には送信はされていると思います。

    問題は”R_IIC00_Master_Receive関数"や”R_IIC00_Master_Send関数"を呼び出して,そこから戻ってきた段階では通信は始まったばかりで完了していないということです。そのために通信が実際に完了するまで待つ必要があるということです。

    (今はどうなっているか確認していませんが,コード生成のAPIのマニュアルには,あたかも「関数から戻ってきたら通信が完了している」ような記述がありました。)

    >このMaster_Sendの実行でデータ送信は行われるのでしょうか。

    送信そのものは始まります。

    >レジスタをセットしトリガを与えないと送信できないという記事もあったと思います。

    それは,RL78でハードウエアを直接制御する場合のことだと思います。通信関係は,I/Fを起動しても,送信データまたはダミーデータを書きかまないと通信は始まらないの意味です。

    >簡易IICによるデータ送信の方法について、まとまった情報を得たいのですが、RL78について、どこで見ればよいのでしょうか?ご教示よろしくお願いします。

    かふぇルネのTOPページの上の方に「サンプルプログラム等」とあるので,そこをクリックしてください。(「サンプルプログラム等」が見えない場合には右の「More」をクリックすれば出てきます。)

    サンプルプログラム等に移動したら,少し下の方に投稿リストのエクセルファイルがダウンロードできるスレッドがあるので,エクセルファイルをダウンロードしてください。

    このリストの上の方にIIC関係の情報があります。リンクが張ってあるので,それらを参照してください。

  • チョコ様

    早速のご回答有難うございました。

    また、サンプルプログラムの入手方法についても、ただいまExcelファイルをDLし、17/12/18のチョコ様投稿の「IIC通信のマスタ側(RL78/G13の簡易IIC版)改 2C」をDLしコードを研究したいと思います。このDLしたプロジェクトのコード生成プロパティを添付しますが、「API関数出力制御」の"初期化関数のみ出力"が指定してありました。他のサンプルコードでも、同様に"初期化関数のみ出力"の指定が指示されてたものがありました。もう一つの選択肢である"設定に合わせすべて出力する"の違いが説明を読んでも具体的に分かりません。例えば、簡易IICで使用する"R_IIC00_Master_Send"関数については、コード生成されたものを使用すべきだと考えます。サンプルコードもこのコード生成された関数の仕様を前提に作成すべきだと思います。そうしないと、応用が利かないと思うのですが。。。あるいはコード生成されたコードは安定的に動作しないものでしょうか?

    今後のプログラム作成のときのために、よろしくご指導お願いします。