かふぇルネの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のアドレスの値に関係するようです.見てみます.

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

  • チョコです。

    どこをどのように改造したのでしょうか。全体像 が分かるような情報(プロジェクト)を開示してもらえませんか。

    変な改造を行っていると動作は不定です。

    また、通信速度はいくつで、プルアップ抵抗値は何Ωでしょうか。

    ところで24FC6は24FC64の間違いですよね。

    以上

  • チョコさま

    毎回お世話になります.

    replyが当方にメールされていなかったようで返答が遅れました.

    EEPROMは,24FC64でしたが,deviceが悪いと思い,これを現在は24C256に交換しました.

    コードは以下のとおりです.

    1アドレスに1バイト書き込み,1バイト読むというコードに変更しました.

    以前intを書き込むプログラムは,アドレス指定に配列を使っていました.これが悪かったようで,下のコードでは,uint8_tを使用しいます.

    このプログラムでは,書き込み及び読み込みは一応動作します.一応というのは,次のような現象があります.

    E1エミュレータを使用していますが,例えばアドレスは同じにして,書き込むデータを変更して[F6] build and downloadし実行してもデータは変更されません.Disconnect from Debugger [Shift F6]を行い,再度[F6]を行うと正しく書き込みができます.

    EEPROMの問題か,あるいはプログラムの問題なのか分かりません.ご指導お願いします.

    void write_data_byte(uint8_t i2c_adr, uint16_t rom_adr, uint8_t data)
    {
        
        uint8_t adr_high, adr_low;

        adr_high = (uint8_t) (rom_adr >> 8 );
        adr_low = (uint8_t) (rom_adr & 0xFF);
        
        put_3byte_IIC00(i2c_adr, adr_high, adr_low, data);
        wait_10ms();

    }

    uint8_t read_data_byte(uint8_t i2c_adr, uint16_t rom_adr)
    {
        uint8_t adr_high, adr_low, data;

        adr_high = (uint8_t) (rom_adr >> 8 );
        adr_low = (uint8_t) (rom_adr & 0xFF);

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

    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);
        
    }

    MD_STATUS put_data_IIC00( uint8_t s_addr, uint8_t buffer1, uint8_t buffer2)
    {

        MD_STATUS status;
        
        g_write_data[0] = buffer1;         /* set data1        */
        g_write_data[1] = buffer2;         /* set data2        */
        
        /*--------------------------------------
         start transmission
         --------------------------------------*/
        
        status = R_IIC00_Master_Send(s_addr, (uint8_t *__near)g_write_data, 2);
        
        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);
        
    }

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

        MD_STATUS status;

        //g_write_data[0] = buffer2;           /* set register address         */

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

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

        //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)buffer1, 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);

    }

  • (追加) 読み込みも[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);

    }
Reply
  • 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);

    }
Children
  • チョコです。

    「かふぇルネの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の側にあることを理解してください。

    以上

  • チョコです。

    先ほどリプライしたように、原因はEEPROM側にあるので、EEPROMへのアクセスに制限を付けるのが一番です。

    256kビットのEEPROMに限定して、書き込みアドレスを16バイトごとの先頭にして、書き込むデータ数を16バイト以下に制限すれば、比較的簡単にできると思います。

    部品箱にに24FC256と24LC256があったので、少し時間をもらえれば、確認はできるかと思います。

    以上

  • チョコ様

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

    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」をプロジェクトから外してみてください。

    以上