かふぇルネのIICサンプルプログラムを改造したが,EEPROM (24FC6) の連続書き込みが不安定

皆様,

G13(CCRL)にてチョコさんのIICサンプルプログラムのMD_STATUS put_data_IIC00( uint8_t s_addr, uint8_t buffer1, uint8_t buffer2)を修正し,以下のプログラムを作成しました.

これはEEPROMのByte Writeを行うためのものです.これを5msのインターバルをおいて連続的に書き込むと,非常に不安定で正常に書き込めないことが多発しています.buffer1, buffer2 がEEPROMのアドレス,buffer3がデータです.ストップコンデイション云々の問題でしょうか?

ご指導お願いします.

=======

MD_STATUS put_3byte_IIC00( uint8_t s_addr, uint8_t buffer1, uint8_t buffer2, uint8_t buffer3)
{

    MD_STATUS status;
    //uint8_t work1, work2;
    
    //work1 = (uint8_t) ((buffer2 >>8) & 0x00FF);
    //work2 = (uint8_t) (buffer2 & 0x00FF);
    
    g_write_data[0] = buffer1;       /* set data1       */
    g_write_data[1] = buffer2;         /* set data2       */
    g_write_data[2] = buffer3;         /* set data3       */
    
    /*--------------------------------------
     start transmission
     --------------------------------------*/
    
     
    status = R_IIC00_Master_Send(s_addr, (uint8_t *__near)g_write_data, 3);
    
    if( IIC_SUCCESS == status )         /* check start successfully     */
    {
        
        /*--------------------------------------
         transmit start and
         wait for transmission end
         --------------------------------------*/
        
        do
        {                               /* wait for transmission end    */
            
            status = R_IIC00_check_comstate(); /* get IIC status          */
            
        }while( IIC_USING == ( status & IIC_STS_MASK ) );
        
        /*
         release IIC  bus
         */
        R_IIC00_StopCondition();          /* issue stop condition         */
        
    }
    else
    {
        /* do nothing */
    }
    
    return (status);
    
}

Parents
  • (追加)

    順番は関係ないようです.EEPROMのアドレスの値に関係するようです.見てみます.

  • (追加) アドレスも関係ないようです.

  • (追加) 読み込みも[Shift F6],そして[F6]をしないと正しく読み込みできません.

  • 画像を添付します.lcd_sii_goto1, lcd_sii_puts1はデバッグのための液晶ディスプレイ表示です.

  • チョコ様

    書き込みは正常のようです.読み込みが問題です.

    同じアドレスの読み込みを添付画面の「run the program after the cpu reset」ボタンをクリックすと指定していないアドレスのデータが読み込まれますが,もう一度このボタンを押すと正しく読み込みます.

    読み込みには,

     put_data_IIC00(i2c_adr, adr_high, adr_low);
     read_byte_IIC00(i2c_adr, &data);

    の関数を使用していますが,アドレスを指定するput_data_IIC00が動作不安定です.あらためて,EEPROMのrandom readを見ると,STOPが最後に出ていますが,put_data_IIC00はStop conditionを出しています.read_byte_IIC00もStop conditionを出しています.

  • 画面添付が不足していました.「run the program after the cpu reset」ボタンです.

  • read_byte_IIC00を次のように変更しましたが,状況は同じです.

    MD_STATUS read_byte_IIC00( uint8_t s_addr, uint16_t buffer1, uint8_t *const buffer2 )
    {

        MD_STATUS status;
        uint8_t work1, work2;
        work1 = (uint8_t) (buffer1 << 8);
        work2 = (uint8_t) (buffer1 & 0xFF);
       
        g_write_data[0] = work1;
        g_write_data[1] = work2;           /* set register address         */

    /*--------------------------------------
        transmit register address
    --------------------------------------*/

        status = R_IIC00_Master_Send(s_addr, (uint8_t *__near)g_write_data, 2);

        if( IIC_SUCCESS == status )         /* check start successfully     */
        {

    /*--------------------------------------
        wait for transmission end
    --------------------------------------*/

            do
            {

                status = R_IIC00_check_comstate(); /* get IIC status  */

            }while( IIC_USING == ( status & IIC_STS_MASK ) );

    /*--------------------------------------
       transmission end
    --------------------------------------*/

            if ( IIC_SUCCESS == status )    /* check result         */
            {

    /*--------------------------------------
       start IIC receiving
    --------------------------------------*/

                status = R_IIC00_Master_Receive(s_addr, (uint8_t * __near)buffer2, 1);

                if( status == 0)            /* check start successfully     */
                {

    /*--------------------------------------
        wait for receive end
    --------------------------------------*/

                    do
                    {
                        status = R_IIC00_check_comstate();

                    }while( IIC_USING == ( status & IIC_STS_MASK ) );
                }
                else
                {
                    /* do nothing */
                }

            }
            else
            {
                /* do nothing */
            }

        }

        R_IIC00_StopCondition();              /* issue stop condition     */

        return (status);

    }
  • チョコです。

    「かふぇルネのIICサンプルプログラム」とはどれのことでしょうか。いくつもプログラムが存在し、簡易IICのライブラリはステータス関係を何回か変更しているので、そこらを確定しないと先に進められません。

    「IIC通信のマスタ側(RL78/G13の簡易IIC版)改 2C」のことであれば、制御対象はスレーブのRL78に準備されたRAMを対象にしているので、シリアルEEPROMとは異なります。また、構造と関数名がかなり変わっていたり、関数の引数がポインタだったり、実体渡しだったりして混乱しまっているので、プロジェクト全体の情報がないとコメントできません。す。

    RL78/G13の簡易IICを使用したアプリケーションノートがあるので、そちらを参照される方がいいような気がします。

    renesasのトップページで"r01an2828"で険悪すると見つかります。このアプリケーションノートのサンプルコードは何種類のEEPROMに対応しているようです。

    以上

  • チョコ様

    ご指導ありがとうございます.

    調べたら私が使用しているものは,version 1.10です.別なスレッドでCCRL2CがUpされていますが,EEPROM対応ではないとのこと了解いたしました.なお,速度は400KbpsでPullupは,SDA,SCLとも4.2Kohmです(5V).

    r01an2828を調べてみます.

  • チョコ様

    r01an2828は初心者のレベルを超えていると思います.IICのような一般的なプロトコルを使うにはあまりにもH/Wレベルにより過ぎていると思います.EEPROMが動作するようなIICのAPIのようなものはないでしょうか?

  • チョコ様

    CCRL2CのAPIはEEPROMに使用できないでしょうか?

  • チョコです。

    I2Cは汎用的な通信方式ですが、それを使ってアクセスするEEPROMの方に制限があります。

    I2C対応のEEPROMは容量によって、内部のEEPROMのアドレスをスレーブアドレスの下位ビットに埋め込むことで、通信データ数を少なくするようになっているものがあります。それでも、容量によって、送信する内部のEEPROMのアドレスが1バイトで済むか、2バイト必要かが変わります。また、EEPROMの容量によって、容量が異なるいくつかのブロックに分割されていて、一度にはブロックをまたがった書き込みができません(読み出しはブロックを超えても可能です)。ライブラリ・レベルで、そこらにきちんと対応しようとするとあのような構成になってしまうと思います。このためのパラメータがIIC_EEPROM.cで、以下のように定義されています。

    ここらが、複雑になっている原因です。ここらは、EEPROMで異なるので、全てにまじめに対応しようとすると避けられません。

    RL78/G10のアプリケーションノート(r01an3081jj)ではブロックサイズを制限することでシンプルにしようとしています。ただし、使用しているのがR5F10Y16とコード領域が2kバイトと小さいのでアセンブラで記述されています。

    ここらを避けるためには、使用するEEPROM(の容量)を限定して、RL78/G10のように書き込むEEPROMのアドレスを制限して、一番小さなブロックサイズである16バイト単位に合わせ込み、ブロックを超えるような書き込みをしないという制限を行うとかなり簡単になるかと思います。

    とにかく、問題の原因がEEPROMの側にあることを理解してください。

    以上

Reply
  • チョコです。

    I2Cは汎用的な通信方式ですが、それを使ってアクセスするEEPROMの方に制限があります。

    I2C対応のEEPROMは容量によって、内部のEEPROMのアドレスをスレーブアドレスの下位ビットに埋め込むことで、通信データ数を少なくするようになっているものがあります。それでも、容量によって、送信する内部のEEPROMのアドレスが1バイトで済むか、2バイト必要かが変わります。また、EEPROMの容量によって、容量が異なるいくつかのブロックに分割されていて、一度にはブロックをまたがった書き込みができません(読み出しはブロックを超えても可能です)。ライブラリ・レベルで、そこらにきちんと対応しようとするとあのような構成になってしまうと思います。このためのパラメータがIIC_EEPROM.cで、以下のように定義されています。

    ここらが、複雑になっている原因です。ここらは、EEPROMで異なるので、全てにまじめに対応しようとすると避けられません。

    RL78/G10のアプリケーションノート(r01an3081jj)ではブロックサイズを制限することでシンプルにしようとしています。ただし、使用しているのがR5F10Y16とコード領域が2kバイトと小さいのでアセンブラで記述されています。

    ここらを避けるためには、使用するEEPROM(の容量)を限定して、RL78/G10のように書き込むEEPROMのアドレスを制限して、一番小さなブロックサイズである16バイト単位に合わせ込み、ブロックを超えるような書き込みをしないという制限を行うとかなり簡単になるかと思います。

    とにかく、問題の原因がEEPROMの側にあることを理解してください。

    以上

Children
  • チョコ様

    情報ありがとうございます.

    page毎のwriteを考えるとデバイスにより対応が違ってくると思いますが,一般的な64kbitあるいが256kbitに対するrandom write,random readではアドレスを2byte指定で1byte書き出し/読み取りで,かなり一般的な処理になると思います.

    ご紹介いただいたr01an2828では減算処理によるwaitがありました.RL78ではclockによりその時間は変動すると思います.

    10年位前ですが,78k0のKF2ではcode generateのAPIを使用してEEPROM(64Kbit)は動作しました.新しいRL78/G13で,このような問題で手間取っているのは,Renesasさんの問題だとはおもいますが,日の丸プロセッサの可用性を高めるにはこのような問題でトラブルのはよくないと思っております.

  • チョコです。

    >ご紹介いただいたr01an2828では減算処理によるwaitがありました.

    細かく見てないので、断定できませんが、R_IICr_SCL_TimeやR_IICr_SCL_highTimeでの処理でしょうか。

    それならば、簡易IICでスタートコンディション等をソフトで発生させるための時間測定で、32MHz動作でもクロックの規格(MIN)を満足させるようになっているようです。MINの規格なので、動作クロックが32MHzより低くなってもMIN規格より長くなるだけなので気にしていないのではないでしょうか。ダミークロック出力でも同じものを使っているようですね。

    >random write,random readではアドレスを2byte指定で1byte書き出し/読み取りで,かなり一般的な処理になると思います.

    これが一般的かどうかは疑問ですが、1バイトの読み書きであれば、EEPROMへのアクセスでのブロックの制限はなくなります。ただし、送信したデータをEEPROMの指定されたアドレスに書き込むためにはEEPROM内でチャージポンプを起動してから書き込むのにそれなりの時間(MAXで5ms)がかかります。その時間が、1バイトごとに許されるかどうかは使い方によっても変わってくるのではないかと思います。

    以上

  • チョコ様

    r01an2828を使い動作確認しました(Processorは変更したが,Code generateをしない状態で).

    問題は,これを通常のCode Generateを使用しているProjectに移植することです.

    Processorを変更し,32MHzからXtalを使用した20MHzに変更するため,Code generateをするとExplorerでは添付画面の左側になります.下のイメージの右側がCode Generateする前です.

    Code Generate後の状態でRebuildすると添付のエラーが出ます.InterruptがCode Generateの結果重複したためだと思いますが,どこを修正すべきでしょうか?

    それから,オリジナルのr_main.cにある,

    R_IICr_Init();   /* initialize IICr          */
    は,Code generate後は,コメントアウトすべきかと思いますがいかがでしょうか?

  • チョコです。

    R_IICr_Initとr_cg_serial.cおよびr_cg_timer.cの内容を眺めてみましたが特にえって位置に違いはないようなので、R_IICr_Initを呼び出さなくても初期化はできそうです。ただし、R_IICr_Initは最後に

    R_device_select(R1EX24016A);            /* set default EEPROM parameter */

    と使用するEEPROMを選択しているので、R_IICr_Initを呼び出しているところをこのEEPROM選択処理に変更することになるかと思います。

    エラーが発生している割り込み関係ですが、「r_cg_timer_user.c」と「r_cg_serial_user.c」をプロジェクトから外してみてください。

    以上

  • チョコ様

    ご指導ありがとうございます.

    「r_cg_timer_user.c」と「r_cg_serial_user.c」をプロジェクトから外しました.Build OKです.

    R_IICr_Init();  をコメントアウトせず実行すると動作OKです.

    なお,Clockは,20MHzにしたつもりですが,R_IICr_Init();でいろいろ処理しているようなので,よくわかりません.

    なお,device指定は,r_main.cにて,R_IICr_Init();の直後

    R_device_select(R1EX24256B);  

    がありますので,これでdeviceが最終的に指定されます.

    しかしながら,R_IICr_Init();をコメントアウトすると,

    MD_STATUS R_EEPROM_wait_write()

    while (g_comstatus & 0b10000000)
        {
            NOP();                              /* wait for last page   */
        }

    でステータス確認中のようで,ここから先に進みません.

    以上から,R_IICr_Init(); はMUSTでしょうか?Code Generateと同じようなことをしていると思っています.IIC00noClockは400Kbpsですので,20MHz Clockが正しければ,この速度が設定されていると思っています.

  • チョコです。

    1か所見落としていました。

    R_IICr_Init(); の中に以下の処理があり、これで初期化後に送信可能な状態にしていました。

    この処理を「R_device_select」を呼び出す前にでも追加してください。

    以上

  • チョコ様

    動きました!!

    ありがとうございました!!

    Code Generate された,

    void R_Systeminit(void)
    {
        PIOR = 0x00U;
        R_CGC_Create();
        R_PORT_Create();
        R_SAU0_Create();
        R_TAU0_Create();

        IAWCTL = 0x00U;
    }

    をそのまま使用しています.

    R_IICr_Init();はコメントアウト,

    さらにご指摘いただいた

    SCRmn   |= 0b1000000000000000;          /* set TxE00                */

    を, R_device_selectの前に,追加しました.

    この機会にお聞きしたいのですが,書き込みと読み出しの間には,5ms程度のwaitが無いようですが,内部的にはEEPROM書き込み後のチェックは行われているのですね?

  • チョコです。

    まだ、そこまではプログラムを完全には読み切れていません。

    今までで読めた範囲では、ブロックの書き込み後にTM02を起動して、100μsのタイマを起動し、INTTM02でスタートコンディションの発行とスレーブアドレスを送信している(これが書き込み完了のポーリング)ようなので、5msの固定時間を待つのではなく、100usごとに書き込み完了をポーリングしているようです。

    実際に、INTIICrでのエラー検出時の処理の中でステータス(g_comstatus)がAFT_TX以外でエラー処理をしていることからスピードを追究した処理方法をとっていると思われます。

    何しろ、割り込み処理の中で色々と操作しているので完全には追い切れていません。

    書き込んだデータそのものであれば、main関数の方でデータの読み出しを行っているので、そこらでわかると思います。

    以上

  • チョコ様

    書き込んだデータはその値を読み出しバイト単位に確認しています.問題ない状態です.EEPROMは,ありきたりのATMELの256Kbitのものです.本日の結果を踏まえ,これでアプリケーションの作成に移ることができます.

    ありがとうございました.

  • チョコです。

    ご連絡有難うございました。

    いよいよ、アプリの作成ですか。頑張ってください。

    以上