簡易I2Cについて

stlと申します。

RA2E1マイコンで簡易I2Cの機能を使用しています。デバッグを実行してみると、送信用のAPI関数の戻り値としては「成功」となりますが、オシロスコープでピンの出力を確認すると、SDAとSCLKの出力波形が確認できず、関数の実行タイミングで5Vから0Vに変化するだけでした。 この問題について何かわかることがありますでしょうか?

Parents
  • チョコです。

    RL78は日頃使っていますが、RAは使ったことがありませんので、想像になりますが、コメントさせてもらいます。

    おそらく、SCを使ってコード生成されていると思いますが、送信用のAPIは送信処理を起動するだけで戻ってきている

    のではないでしょうか。

    また、「SDAとSCLKの出力波形が確認できず、関数の実行タイミングで5Vから0Vに変化するだけでした。」は、

    スタート・コンディションが発行された状態ではないかと思います。

    つまり、通信が開始した時点までの波形しか確認していないのではないでしょうか。

    通信が完了したことを確認して、そこまでの波形を確認されることをお勧めします。

    以上

  • ご回答ありがとうございます。

    >>通信が完了したことを確認して、そこまでの波形を確認されることをお勧めします。

    送信用のAPIが、通信が完了までいかなくても起動した段階で「成功」を返してきている可能性があるということでしょうか?

  • チョコさん

    スレーブアドレスを送る場合でいうと、0b01010000というようにデータを記述すれば良いというのであっていますか?

  • チョコです。

    >このデバイスはRepeated Start Condition対応デバイスのようですからRead API前のSTOPコンディションを省いています。

    わたしがコメントしたのは、データ書き込みオペレーションの方なのですが。

    ReadAPI前にはストップコンディションは発行しません。

    以上

  • EEPRMやI2Cは初めて使用するので、いろいろ教えていただきありがとうございます。

    Write Cycle Timeというのは、マイコンのデータシートなどに記載があるものなのでしょうか?

  • 実機で確認したわけでもなく開発環境で確認したわけでもないAPI説明だけで記述しました。スレーブアドレスはconfiguration.xmlの中で以下のように設定されていますが、上位アドレスがスレーブアドレスに含まれるためWrite APIに先立ちスレーブアドレスを毎回セットする必要があると思います。

    <property id="module.driver.i2c_master.slave" value="0x50"/>


    多分、以下のようなコードになるはずです。割り込みで完了をg_iic_event変数を使って通知しています。5ms待ち関数の作成が必要です。実行すると先頭から01h, 23h, 45h, 67h, 89h, ABh, CDh, EFhを繰り返し埋めます。全部埋めたら端まで読み取りアクセスします。全く開発環境通してないので細かいミスなどがあるかもですが、こういう感じになるはずです。なお、私はこれを参考に下を書いています(古い書き込みのものですのでAPIの仕様変更があるかもです)。


    https://community.renesas.com/mcu-mpu/ra/f/forum/19490/i2c-eeprom

    volatile i2c_master_event_t g_iic_event = 0;

    /* Callback function */
    void g_iic_callback(i2c_master_callback_args_t *p_args) {
    g_iic_event = p_args->event;
    }

    void hal_entry(void) {
    fsp_err_t err;
    err = R_IIC_MASTER_Open(&g_i2c_master_ctrl, &g_i2c_master_cfg);
    uint8_t write_data[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
    uint8_t read_data[32];

    if (FSP_SUCCESS != err) {
    __BKPT(1);
    }
    int mem_addr;
    // Write Memory
    for (mem_addr = 0; mem_addr < 0x20000; mem_addr+= sizeof(write_data)) {
    uint32_t slave = 0x50UL + 0x1 & (mem_addr >> 16);
    uint8_t send_data[2 + sizeof(write_data)];
    // Lower Memory Address
    send_data[0] = (uint8_t)(0xFFU & (mem_addr >> 8));
    send_data[1] = (uint8_t)(0xFFU & (mem_addr));
    // Data
    memcpy(&send_data[2], write_data, sizeof(write_data));
    // Set Slave Address
    err = R_IIC_MASTER_SlaveAddressSet(&g_i2c_master_ctrl, slave, I2C_MASTER_ADDR_MODE_7BIT);
    if (FSP_SUCCESS != err) {
    __BKPT(1);
    }
    // Write 2byte lower Address and 8 bytes Data
    g_iic_event = 0;
    err = R_IIC_MASTER_Write(&g_i2c_master_ctrl, send_data, sizeof(send_data), false);
    if (FSP_SUCCESS != err) {
    __BKPT(1);
    }
    // Wait for the callback signally the write has completed
    while (0 == g_iic_event) {
    // do nothing
    }
    if (I2C_MASTER_EVENT_TX_COMPLETE != g_iic_event) {
    __BKPT(1);
    }
    // wait for 5ms
    wait_for_5ms();
    }
    // Read Memory
    for (mem_addr = 0; mem_addr < 0x20000; mem_addr+= sizeof(read_data)) {
    uint32_t slave = 0x50UL + 0x1 & (mem_addr >> 16);
    uint8_t send_data[2];
    // Lower Memory Address
    send_data[0] = (uint8_t)(0xFFU & (mem_addr >> 8));
    send_data[1] = (uint8_t)(0xFFU & (mem_addr));
    // Set Slave Address
    err = R_IIC_MASTER_SlaveAddressSet(&g_i2c_master_ctrl, slave, I2C_MASTER_ADDR_MODE_7BIT);
    if (FSP_SUCCESS != err) {
    __BKPT(1);
    }
    // Write Lower Address
    g_iic_event = 0;
    err = R_IIC_MASTER_Write(&g_i2c_master_ctrl, send_data, 2, false);
    if (FSP_SUCCESS != err) {
    __BKPT(1);
    }
    // Wait for the callback signally the write has completed
    while (0 == g_iic_event) {
    // do nothing
    }
    if (I2C_MASTER_EVENT_TX_COMPLETE != g_iic_event) {
    __BKPT(1);
    }
    // Read 32 bytes
    g_iic_event = 0;
    err = R_IIC_MASTER_Read(&g_i2c_master_ctrl, read_data, sizeof(read_data), true);
    if (FSP_SUCCESS != err) {
    __BKPT(1);
    }
    // Wait for the callback signally the write has completed
    while (0 == g_iic_event) {
    // do nothing
    }
    if (I2C_MASTER_EVENT_RX_COMPLETE != g_iic_event) {
    __BKPT(1);
    }
    }
    }
  • 電気特性のところに普通は書いてあります。ほとんどのメーカのほとんどの型式が5msですね。呼び方はメーカによって変わるかもしれません。

  •  

    SlaveAddressSetでスレーブアドレスをセットすれば、MASTER_Writeでは、スレーブアドレスを送らなくてもよいのでしょうか?

    Write Cycle Timeについて教えていただきありがとうございました。

  • コード生成してWrite APIの中身を見たわけじゃないですが、GUIでスレーブアドレスを設定できてデータ送信をR_IIC_MASTER_Writeのみで完結する(コールバックで終了確認)とAPI説明に書いてあるのでAPIの中でスレーブアドレスの送信処理をやってくれていると思います。正し、スレーブアドレス7ビットの下位3ビットのうち一番下のビットが上位のメモリアドレスビットになるのでGUI設定のスレーブアドレスではダメですね。それをすると128Kバイトのうち64Kバイトしか利用できない。

  • チョコです。

    >スレーブアドレスを送る場合でいうと、0b01010000というようにデータを記述すれば良いというのであっていますか?

    スレーブアドレスの指定ということかと思いますが、0b01010000でいいかと思います。

    問題は、使用するAPI関数がどうなっているかです。これまでのやり取りで、RAのFSP環境なら、これでいいはずです。

    以上

  • チョコです。

    RL78/G13 シリアル・アレイ・ユニット(SAU)(簡易IICによるEEPROM制御編)(R01AN1351JJ0201)のアプリケーションノート辺りはどうでしょうか。

    I2C通信について、以下のようなタイミングチャートがかかれていたりします。RL78のハードウェア・マニュアルにはもっと詳しいのが記述されています。

    元が結構古いので、EEPROMとしては、16kbitとか32kbitが対象のようですが、512kbitまでは考慮はしてあるようです(メモリアドレスとして1バイトおよび2バイトまで対応しているようです)。EEPROMの制御に必要な内容がかかれているようです。

    以上

  • stlさま

    SLAVEアドレスが 0b1010000 (R/Wビットを除く7bit)で、送信するデータが 0x12 0x34 の場合、

    GUIの Slave Addressの欄に、0x50と指定する

    unsigned char tx_buffer[2] = {0x12, 0x34);

    R_SCI_I2C_Write(&g_i2c9_ctrl, &tx_buffer[0], 2, false);

    で、実際は3バイト(0xA0, 0x12, 0x34)が送信されるかと思います。

    0xA0は、0b1010000 << 1 | 0b0(Writeなので0)です。

    R/Wビット込みで、1バイト目に 0b01010000を送りたい場合は、Slave Addressを0b0101000 = 0x28に設定すると良いでしょう。

    EEPROMの2ページ目というのでしょうか、途中からSLAVEアドレスを変えてアクセス(例えば、0x38)する場合は、

    R_SCI_I2C_SlaveAddressSet(&g_i2c9_ctrl, 0x38, I2C_MASTER_ADDR_MODE_7BIT);

    R_SCI_I2C_Write(&g_i2c9_ctrl, &tx_buffer[0], 2, false);

    の様にするのがシンプルで良いと思うのですが。

    I2Cは、1つのマイコンに複数のセンサ等を接続できる仕様です。(複数のSLAVEアドレスのデバイスをつなげる事は、普通に行われます。EEPROMのSLAVEアドレス違いで別なページにアクセスするというのも、複数のSLAVEアドレスを扱う一例です。)FSPでは、

    I2C Communication Device(別々のSLAVEアドレスの指定が可能)を追加して、Shared Busでつないで、そこにつながるマイコン側のハードが、1つのI2C(またはSCI_I2C)という使い方ができます。この接続方法ですと、複数のSLAVEデバイスを1つのI2C(またはSCI_I2C)インタフェースからアクセスする事が可能です。

    (g_i2c0インタフェースにdevice0とdevice1のi2c_deviceの接続)(3つ以上もできます)

    このような機能があるということ、参考までに。

Reply
  • stlさま

    SLAVEアドレスが 0b1010000 (R/Wビットを除く7bit)で、送信するデータが 0x12 0x34 の場合、

    GUIの Slave Addressの欄に、0x50と指定する

    unsigned char tx_buffer[2] = {0x12, 0x34);

    R_SCI_I2C_Write(&g_i2c9_ctrl, &tx_buffer[0], 2, false);

    で、実際は3バイト(0xA0, 0x12, 0x34)が送信されるかと思います。

    0xA0は、0b1010000 << 1 | 0b0(Writeなので0)です。

    R/Wビット込みで、1バイト目に 0b01010000を送りたい場合は、Slave Addressを0b0101000 = 0x28に設定すると良いでしょう。

    EEPROMの2ページ目というのでしょうか、途中からSLAVEアドレスを変えてアクセス(例えば、0x38)する場合は、

    R_SCI_I2C_SlaveAddressSet(&g_i2c9_ctrl, 0x38, I2C_MASTER_ADDR_MODE_7BIT);

    R_SCI_I2C_Write(&g_i2c9_ctrl, &tx_buffer[0], 2, false);

    の様にするのがシンプルで良いと思うのですが。

    I2Cは、1つのマイコンに複数のセンサ等を接続できる仕様です。(複数のSLAVEアドレスのデバイスをつなげる事は、普通に行われます。EEPROMのSLAVEアドレス違いで別なページにアクセスするというのも、複数のSLAVEアドレスを扱う一例です。)FSPでは、

    I2C Communication Device(別々のSLAVEアドレスの指定が可能)を追加して、Shared Busでつないで、そこにつながるマイコン側のハードが、1つのI2C(またはSCI_I2C)という使い方ができます。この接続方法ですと、複数のSLAVEデバイスを1つのI2C(またはSCI_I2C)インタフェースからアクセスする事が可能です。

    (g_i2c0インタフェースにdevice0とdevice1のi2c_deviceの接続)(3つ以上もできます)

    このような機能があるということ、参考までに。

Children