EK-RA4W1 で ガスセンサZMOD4410など使ってみた

がじぇるね岡宮です。

またちょっと趣味と中での仕事も兼ねて、「ガスセンサのZMOD4410を使ってみた」ということで少し書き込みます。

ベースの環境としてはFSPの他に以下で公開しているArduino用プロジェクトを使っています。ガスセンサZMOD4410を使うには専用のライブラリを使う必要があり、ルネサスのページに公開されていますが、取得するにはちょっとした認証が必要でした。なので本当はライブラリを含めて動くプロジェクトとして公開したかったのですが、ちょっと控えたいと思います。

(+) EK-RA4W1 で Arduinoスケッチ - RA - かふぇルネ - Renesas Rulz - Japan

接続イメージは以下です。EK-RA4W1のPMODの部分にPMOD HYGRO(温湿度センサ)と、ZMOD4410をつなげています。あと簡易的にグラフ表示するためにILI9341のTFTシールドを使いました。センサは2つともI2Cですが、HYGROのアドレスは0x40、ZMOD4410は0x32なのでアクセスはぶつかりません。

以下は、IAQ 1st Gen(第一世代の屋内空気質のライブラリ)のサンプルを実行した結果です。TVOC(空気中の有機化合物)やIAQの指標が表示されます。結果の取得には2秒~3秒程度のインターバルが必要です。(サンプルのまま実行するとそうなります)

ZMOD4410のライブラリは様々なコンパイラでコンパイルできるようになっていますが、RA4W1用にCortex-M4用のライブラリを選択してコンパイルすると以下のエラーが発生しました。

色々ググって調べた結果、浮動小数点のABIをHardからSoftに変更すればエラーが発生せずに正常にビルドでき、動作しました(どれくらい性能に影響するかなどは調べてません)。ちなみにこの設定は、FSPのコード生成を行うたびに変更が必要になるようです。いずれライブラリのコンパイル時の設定を変えてもらうように中の人間に要求しようかとは思っています。

ZMOD4410のライブラリを使うにはI2Cを使用するため、HALを自分で用意する必要があります。サンプルにはWindows用のプログラム(FTDIのドライバ仕様)が用意されていましたが、以下のようなプログラムを組むことで、EK-RA4W1+Arduinoスケッチでは問題なく動かすことができました。


zmod4xxx_dev_t dev; 
dev.read = hal_i2c_read;
dev.write = hal_i2c_write;
dev.delay_ms = hal_sleep;

int8_t hal_i2c_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *buf, uint8_t len)
{
  Wire.beginTransmission (i2c_addr);
  Wire.write (reg_addr);
  Wire.endTransmission (false);
  Wire.requestFrom (i2c_addr, len, (uint8_t) true);
  for (int i = 0; i < (int) len; i++)
  {
    buf[i] = (uint8_t) Wire.read ();
  }
  return 0;
}

int8_t hal_i2c_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *buf, uint8_t len)
{
  Wire.beginTransmission (i2c_addr);
  Wire.write (reg_addr);
  for (int i = 0; i < len; i++)
  {
    Wire.write (buf[i]);
  }
  Wire.endTransmission ();
  return 0;
}
Parents
  • 岡宮さん、こんにちは。NoMaYです。

    ちなみに、FSPのHALのI2C(やUARTやSPI)の通信関数は、ブロッキングリード(orライト)でしょうか?それとも、ノンブロッキングリード(orライト)でしょうか?RL78やRXのコード生成機能が生成したコードのAPIは、初学者さんにとっては、トラブルの元、なのですが、FSPはどうなっているのかな?と気になったのです。

    もし、ブロッキングリード(orライト)ならば、初学者さんでも容易に使えるAPI、という点をガンガンアピールしても良いのかも、と思ったのです。

    あと、FSPのI2Cの通信関数は安心して使えるものでしょうか?RL78のI2Cの通信関数は、チョコさんのサンプルプログラムを探し出して、それを使わないと安心出来ない、というイメージがあったりします。そのせいで、RXスマートコンフィグレータでも安心して使えるのか、ちょっと不安が無い訳では無い、という心境です。あと、FITのI2CのAPIは超難解そうで、APIドキュメントの初めの方で状態遷移図が出て来たところで放棄しました。FSPのI2CのAPIは簡単そうですね。(FITの難解っぽさからみると完璧では無いのかも知れませんけれども、、、)

  • こんにちは、NoMaYさん

    APIとしてはノンブロッキングです。FSPのマニュアルにあるサンプルソースはブロッキングになるような記載です。以下はそれを参考に作ったArduinoライブラリの一部分です。Arduinoライブラリにポーティングするのに2時間くらいで終わったので、結構簡単な方だと思いました。RXのスマートコンフィグレータでコード生成したときは(FITじゃないです)、サンプルがしょぼかった印象あり、例えばアドレスを1ビットするかしないかなどしょうもないところでつまづいた記憶があります。。

    uint32_t timeout_ms = TIMEOUT;
    R_IIC_MASTER_SlaveAddressSet (&g_i2c_master0_ctrl, address, I2C_MASTER_ADDR_MODE_7BIT);
    R_IIC_MASTER_Read(&g_i2c_master0_ctrl, data, length, !sendStop);
    while ((I2C_MASTER_EVENT_RX_COMPLETE != g_i2c_callback_event) && timeout_ms)
    {
      timeout_ms--;
      delay(1);
    }
    if (I2C_MASTER_EVENT_ABORTED == g_i2c_callback_event)
    {
      return(0); // 何も送れてない
      // __BKPT(0); // ブレーク
    }

Reply
  • こんにちは、NoMaYさん

    APIとしてはノンブロッキングです。FSPのマニュアルにあるサンプルソースはブロッキングになるような記載です。以下はそれを参考に作ったArduinoライブラリの一部分です。Arduinoライブラリにポーティングするのに2時間くらいで終わったので、結構簡単な方だと思いました。RXのスマートコンフィグレータでコード生成したときは(FITじゃないです)、サンプルがしょぼかった印象あり、例えばアドレスを1ビットするかしないかなどしょうもないところでつまづいた記憶があります。。

    uint32_t timeout_ms = TIMEOUT;
    R_IIC_MASTER_SlaveAddressSet (&g_i2c_master0_ctrl, address, I2C_MASTER_ADDR_MODE_7BIT);
    R_IIC_MASTER_Read(&g_i2c_master0_ctrl, data, length, !sendStop);
    while ((I2C_MASTER_EVENT_RX_COMPLETE != g_i2c_callback_event) && timeout_ms)
    {
      timeout_ms--;
      delay(1);
    }
    if (I2C_MASTER_EVENT_ABORTED == g_i2c_callback_event)
    {
      return(0); // 何も送れてない
      // __BKPT(0); // ブレーク
    }

Children
  • 岡宮さん、こんにちは。NoMaYです。

    リプライありがとうございました。それで、ごめんなさい、FSPのI2CのAPIですが、てっきり、以下の方のAPIかと勘違いしていました。先日、RAフォーラムで、このAPI(細部まで覚えていませんがreg_addrがあったのは覚えています)で良いのですよね?という質問があったような記憶があったからです。(でも、今見ると、そのようなスレッドが無いので、別製品のフォーラムへの投稿だったのかも知れません。(でも、Synergyにも無いですし、REにもRZにも無いですので、ご本人様が消してしまわれたのかも知れません、、、)

    hal_i2c_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *buf, uint8_t len)
    hal_i2c_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *buf, uint8_t len)

    またまた、追加で気になったのですが、しばらく前にQiitaに投稿されていた記事にもいっぱい使われていたのですが、__BKPT(0)って何なのでしょうか?自前でソフトウェアブレーク命令を埋め込むものだろうなとは思っているのですが、なぜ自前で埋め込むのかちょっとピンと来ないのです?まさか、フラッシュメモリ上にソフトウェアブレークポイントを設定出来ない、ということは無いと思っているのですが、、、

    Renesas RA:環境構築~シリアル出力時計開発
    qiita.com/omuraisu49/items/b1ea9deb621abf7d030d

    すみません、今この記事を読み直したら、ノンブロッキング操作になっていることがわかりますね。以前に読んだ時のことを忘れていました、、、

    以前読んだ時

    やっちゃうんですね(やっちゃったんですね、かな)
    japan.renesasrulz.com/cafe_rene/f/ra/5990/thread/37163#37163
     

  • NoMaYさん、こんばんは

    なるほど。ZMOD4410-EVKがWindows用のサンプルで、そのHAL APIがたまたまそんな感じでした(そういう意味ではこのAPIはブロッキングです)。

    __BKPT(0)はBreak Point(ソフトウェアブレーク)ですね。これはFSPのマニュアルに記載されているサンプルでよく使われていまして、完全にデバッグ用ですね。もちろん本来は何かしらのエラーコードを書いて、そこにブレーク設定すればよいだけですので、私も使いたくて使っているわけではないですw

  • 岡宮さん、こんにちは。NoMaYです。

    リプライありがとうございました。__BKPT()は、FSPを開発しているチームのリーダー格の人の習慣といったところなのかも知れませんね、、、

    > これはFSPのマニュアルに記載されているサンプルでよく使われていまして、

  • こんにちは。NoMaYです。#すみません、ひとりごとです。

    このスレッドで以下のHAL APIを見てからというもの、「どうして reg_addr が1バイト決め打ちなのだろう」と気になっていたのですが、風呂に入っていて合点の行く理由が思い浮かびました。というのは、このAPIは、決して汎用的にI2Cの機能を抽象化したわけでは無くて、単に、ガスセンサZMOD4410を操作するのに必要充分な機能のみを抽象化しただけのものですね、きっと、、、

    hal_i2c_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *buf, uint8_t len)
    hal_i2c_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *buf, uint8_t len)

     
    ガスセンサZMOD4410のソフトウェアのセールスの人が、ウチは、このAPIで下位のドライバ層をコールしますので、そちらで、このAPIに従って受け皿を作っておいて下さいね、というものですね、(実際、岡宮さんが、それに従ってソフトウェアを組んでいますね)、勘違いしていました、、、

    それを、てっきり汎用的にI2Cの機能を抽象化したHALなのだと思い込んで、う~ん、と唸っていました、、、

    #どうも別スレッドでも同じようなことをやらかしているような(あるいは、やらかそうとしていたところ、だったような)気がします、、、