RL78G14 音声再生について

ケロリといいます。

現在RL78G14で音声を再生を試みています。

R_tfat_f_stat関数などの挙動を一度知っておきたく、r_main.cにて#include "r_tfat_lib.h" 後関数を実行しました。
 
しかし,
Undefined external symbol "_R_tfat_f_stat" referenced in "DefaultBuild\r_main.obj"
とエラーメッセージが表示され、ビルドが完了できません。
 
上記エラー後ライブラリtfat_rl78.libを入れていないことが原因と考え、プロジェクトに入れた後にビルドすると以下のエラーが出てきます。
external symbol "_R_tfat_disk_write" referenced in "r_TinyFAT"
 
r_TinyFATに関するファイルを調べたのですが、出てこなかった為、対処に困っています。
どのように対処したらよろしいでしょうか。
Parents
  • ケロリさん

    こんにちは、シェルティです。ルネサス社員です。

    RX、RA、RL78などの汎用マイコンのデバイスドライバ(RX Driver PackageやFlexible Software Packageなど)、
    リアルタイムOS(ITRONやFreeRTOS)、ネットワークやセキュリティ、音声再生、SDカードドライバなどのミドルウェア周りの開発を担当しています。

    RL78の音声再生をご検討いただきありがとうございます。
    以下アプリノート・サンプルコードを参照されているのでは、と思います。
    www.renesas.com/.../D3017501.html

    このサンプルコードでは、ファイルシステムによるSDカードからの圧縮音声ファイル読み込み⇒ADPCM伸長による音声データデコード⇒PWM機能付きタイマへの16ビット音声データ入力⇒マイコンのPWM端子から音声波形をPWMで疑似再現した波形が出る、の一連の流れに必要なコードを全て組み立て済の状態で構築しています。

    R_tfat_disk_write()のシンボルがないというエラーですが、これはファイルシステムからストレージアクセスする際の抽象化関数ですね。
    上記サンプルコードで言うところの以下コードに収録されています。ご確認ください。
    \an_r20an0194jj0102_rl78_s2_sound\workspace\sample\yrdkrl78g14\CS+ for CC\src\tfat_mmc_if
    ⇒r_tfat_drv_if.c

    以上です
  • シェルティさんへ

    迅速な対応して頂き、ありがとうございます。
    また開発担当の方から教えて頂けるとは非常に助かります!

    もう少しサンプルコードについて詳しい質問をさせてください。
    このサンプルコードはwhile文とswitch文を併用することで、状態遷移していることを確認しながら、ファイルの索敵や音楽の実行などを行っていると考えています。

    質問したい部分はgListFileの代入箇所についてです。
    ・気になった経緯
    音楽ファイルの索敵を行うkennsaku_first2()関数で、R_tfat_f_stat関数などを行う際にcard_read_list_t型のgListFile変数を使用しています。ですがgListFileはdemo_main()関数では値を代入する処理はありません。
    ・処理をしている箇所
    gListFileに値を代入しているのはtimerで動いているR_encode_stop()関数内のR_tfat_f_lseek関数であっていますでしょうか。

    説明下手で申し訳ありませんが、どうぞよろしくお願いいたします。
  • もう1つ追加で質問をさせてください。
    現在SDカードを使わないで、音声再生ができないか検討をしています。

    そこで音声データをROMに保存するなどの方法などありましたら、教えて頂けないでしょうか。
    それができない場合はシリアル通信などで送れるか検討を考えています。
    どうぞよろしくお願いいたします。
  • ケロリさん

    シェルティです、こんにちは。

    回答少しお時間ください。
    確かこのアプリケーションノート、初版を10年くらい前に作ったものでさすがにあまり覚えてないですね。
    コード見ながら回答してみます。

    すぐ回答できる(覚えている)ところとしては、音声データをROM(内蔵・外部問わず)から持ってくることは可能、ということです。
    サンプルとして音声データの格納先がどこが良いかユースケースを並べてみて考えたときに、
    「RL78で実現可能なユースケースのうち最も処理負荷が高そうなSDカードからの読み込み」をサンプルコードとしたという経緯があります。

    先のアプリノートのサンプルコードではRL78@32MHzでCSI(だったかな?)にSDカード繋いでSPI通信で音声データをSDカードからCPUの内蔵RAMにロード、ADPCMの伸張処理を行いリングバッファに音声データをバッファリングし、サンプリングレート22kHzでリングバッファに溜まっている音声データを繰り返しPWM出力用のタイマレジスタに書き込む、というような動作をさせてたはずです。
    PWMのタイマはTAU(だったかな?)を2chカスケード接続して16ビットのPWMが出せるモードで動作させてたと思います。
    このへんはサンプルコードをCS+で読み込んでコード生成ツールでどんな設定になっているか見ていただければだいたい分かるように作った記憶があります。

    このような動かし方で「データ読み込み⇒再生」を同時に行う所謂リアルタイム再生が可能で、そのときのCPU負荷率は50%程度で済んでおり、重たい処理はSDカードデータのCRCチェックなどなので、内蔵ROMや外部シリアルフラッシュから音声データを読み込むユースケースの方がCPU負荷率は下がり実現可能です。

    実際の商談を見てもRL78にSDカードを外付けすることはあまりなくて、内蔵ROMに音声データを置いて数フレーズだけ喋るようにする、とか、たくさん音声フレーズをシステムに持たせたい場合もSDカードではなくて基板上にシリアルフラシュを配置してそこに音声データを焼いておく、という使い方をしているユーザが多いようです。

    また、時間を見つけて回答書き込みます。

    以上です
  • シェルティさんへ

    ケロリです。おはようございます。

    >回答少しお時間ください。
    >確かこのアプリケーションノート、初版を10年くらい前に作ったものでさすがにあまり覚えてないですね。
    >コード見ながら回答してみます。
    10年以上前のものだったんですね。
    細かいところの対応ありがとうございます。
    承知いたしました。回答お待ちしております。

    >すぐ回答できる(覚えている)ところとしては、音声データをROM(内蔵・外部問わず)から持ってくること>は可能、ということです。
    >サンプルとして音声データの格納先がどこが良いかユースケースを並べてみて考えたときに、
    >「RL78で実現可能なユースケースのうち最も処理負荷が高そうなSDカードからの読み込み」をサンプルコード>としたという経緯があります。
    できること承知しました!
    組込み初心者で申し訳ないのですが、内臓ROMに保存する方法なども教えて頂けないでしょうか。
    それともマニュアルなどに方法など記載されているものがありますでしょうか。

    質問ばかりで本当に申し訳ありません。
    また返信なのですが、明日以降になってしまいそうです。
    どうぞよろしくお願いいたします。
  • ケロリさん

    こんにちは、シェルティです。

    >>組込み初心者で申し訳ないのですが、内臓ROMに保存する方法なども教えて頂けないでしょうか。

    分かりました。確かリンカの設定でユーザが作ったバイナリをマイコン内蔵のメモリ空間の任意アドレスに割り付ける設定があったと思います。これも調べてガイドします。

    #変に役職がつき日中は打ち合わせやメール処理などに拘束され、
     なかなかソースコードベースの調べものがし辛くなってしまいました。
     ソースコードベースの話は一旦バッファリングしておいて週末に対処する感じになってます。

    以上です
Reply
  • ケロリさん

    こんにちは、シェルティです。

    >>組込み初心者で申し訳ないのですが、内臓ROMに保存する方法なども教えて頂けないでしょうか。

    分かりました。確かリンカの設定でユーザが作ったバイナリをマイコン内蔵のメモリ空間の任意アドレスに割り付ける設定があったと思います。これも調べてガイドします。

    #変に役職がつき日中は打ち合わせやメール処理などに拘束され、
     なかなかソースコードベースの調べものがし辛くなってしまいました。
     ソースコードベースの話は一旦バッファリングしておいて週末に対処する感じになってます。

    以上です
Children
  • シェルティさんへ

    ケロリです。

    >分かりました。確かリンカの設定でユーザが作ったバイナリをマイコン内蔵のメモリ空間の任意アドレスに割り付ける設定があったと思います。これも調べてガイドします。

    ありがとうございます。
    また自分でもリンカ設定を見てみようと思います。

    >#変に役職がつき日中は打ち合わせやメール処理などに拘束され、
    > なかなかソースコードベースの調べものがし辛くなってしまいました。
    > ソースコードベースの話は一旦バッファリングしておいて週末に対処する感じになってます。
    役職おめでとうございます!大変だとは思いますが、頑張ってください。
    忙しいところ本当に申し訳ありません。
    どうぞよろしくお願いいたします。
  • ケロリさん

    シェルティです、こんにちは。

    下記回答します。

    > 質問したい部分はgListFileの代入箇所についてです。
    > ・気になった経緯
    > 音楽ファイルの索敵を行うkennsaku_first2()関数で、R_tfat_f_stat関数などを行う際にcard_read_list_t型のgListFile変数を使用しています。ですがgListFileはdemo_main()関数では値を代入する処理はありません。
    > ・処理をしている箇所
    > gListFileに値を代入しているのはtimerで動いているR_encode_stop()関数内のR_tfat_f_lseek関数であっていますでしょうか。

    いえ、違いますね。kennsaku_first2()関数の最初の方にある以下処理でgListFile.fp (ファイルポインタ)に書き込んでます。
    if (TFAT_FR_OK != R_tfat_f_open(&gListFile.fp, (const uint8_t *)LIST_FILENAME, TFAT_FA_READ)/* リストファイルが開けない */)

    TFATというファイルシステムは中身がFatFsというファイルシステムで、”R_tfat_" の接頭語を取り除けばFatFsと機能が同じです。
    irtos.sourceforge.net/.../open.html

    それで、上記R_tfat_f_open()ではファイル名を固定値のLIST_FILENAME→ sampling.txt を第2引数に指定して、SDカードからサーチしてこのファイルがあればファイルポインタをgListFile.fpに記録しています。

    sampling.txt は以下のようなテキストが書いてあることが前提となっています。
    このファイルに音声データのファイル名が書いてあるわけですね。

    08k adpcm1.dat
    11k adpcm2.dat
    16k adpcm3.dat
    22k adpcm4.dat
    ::

    sampling.txtの中身の説明は以下アプリノートの「3.4.4 ADPCM データを準備する」にあります。
    www.renesas.com/.../r20an0194jj0102_rl78_s2.pdf

    あとは、RL78がsampling.txt の中身をR_tfat_f_read()で読み出して、再生したいファイル名とペアになっているサンプリングレート情報を呼んできて、サンプリングレートを決めるタイマにセットして再生を実行する、といった感じです。

    上記adpcm1.datはADPCMの圧縮データなのですが、waveファイル等と異なりヘッダ情報などでサンプリングレート情報を格納する仕掛けがないので、sampling.txtのようなテキストデータでADPCMファイル毎のサンプリングレートを別途ファイルとして持たせる必要がありました。

    ちなみにR_tfat_f_lseek()は現在アクセスしているファイルの読み出し位置を移動させる関数で、読み出し自体は行っていません。
    irtos.sourceforge.net/.../lseek.html

    以上です
  • ケロリさん

    シェルティです、こんにちは。

    バイナリのリンクは以下の方法で出来ました。リンクオプションのバイナリファイルという項目です。

    以上です

  • ケロリさん

    シェルティです、こんにちは。

    今回見ていただいているサンプルコードは以下ボードで動作します。
    www.marutsu.co.jp/.../1305_131_renesas

    デバッガでソフトウェアの動作を追いかけながら見ていくと動きが理解しやすいと思います。
    動きが理解で来たら、SDカードから読み出しているところを削除していき、
    代わりにROMから音声データを読み込んでくるように改造していくというのが実現が早いと思います。

    以上です
  • シェルティさんへ

    ケロリになります。
    非常に詳しいコードの説明ありがとうございます。実際のコードの動きが分かり、凄く助かりました。
    またバイナリのリンク、今後の動き方のアドバイスもありがとうございます。
    ぜひ参考させていただきます。

    バイナリのリンクの話なのですが、ROMに読み込ませた情報はどのように引き出せばよろしいのでしょうか。
    質問ばかりで申し訳ないのですが、どうぞよろしくお願いいたします。
  • ケロリさん

    シェルティです、こんにちは。

    参考になったようでよかったです。
    先にはったスクリーンショットですと、aaa.bin(aaa_sectoin.aaa_symbol)という指定になっており、
    スクリーンショット中の解説文(黄色のメッセージボックス)をよく見ると、[.<シンボル>]と書いてあり、
    "." (ドット)の後ろに続く文字列がシンボル情報となることが分かります。つまりこの場合シンボル情報は aaa_symbol です。
    コンパイル時に生成されるマップファイル(*.map)を見るとどのセクションどのアドレスに
    どのシンボルが割りついているか確認できます。マップファイルも合わせて確認してください。

    ちょっと実験してみないと分かりませんが、たぶんaaa_symbolはメモリ空間上のアドレスを指し示すポインタになってると思うので、以下のようにすればaaa_symbolからdata_bufferサイズ分のデータを引っ張り出してdata_bufferの先にコピーすることが出来ると思います。

    uint8_t data_buffer[256];
    memcpy(data_buffer, (void*)aaa_symbol, sizeof(data_buffer));

    #試してないので間違ってたらすみません

    以上です
  • ケロリさん、こんにちは。シェルティさんも、こんにちは。NoMaYです。

    > バイナリのリンクの話なのですが、ROMに読み込ませた情報はどのように引き出せばよろしいのでしょうか。

    RL78ですので変数はfarになります。また、サイズ不定でも以下のような感じに出来る筈ですよ。リンカ側で変数の実体が確保されますので、リンカオプションでのシンボルを例えば_voice_data_1とすれば、Cソース側は以下のようにextern __farでの宣言になります。


    定義側
    extern __far uint8_t voice_data_1[];

    参照側

    1バイト目 voice_data_1[0]
    2バイト目 voice_data_1[1]
    3バイト目 voice_data_1[2]
    。。。

  • シェルティさん、NoMayさんへ

    バイナリリンクでの情報の引き出し方の方法を教えてくださりありがとうございます。
    現在ファイル読込をして音を鳴らす方法を検討中ですので、それが終わり次第行ってみようと思います。

    現在シェルティさんがおっしゃっていた基板(www.marutsu.co.jp/.../G14 Fast Prototyping Boardを使用しています。
    その為コードそのまま動かすことが未だにできていません。

    R_tfat_f_openなどのファイルを扱う関数を使用したいのですが、以下のようなエラーコードの対処ができていません。一番最初の話に戻ってしまうみたいで恐縮なのですが、このような場合はどのような原因が考えられるでしょうか。

    (E) E0562310 E0562310:Undefined external symbol "_R_tfat_f_read" referenced in "DefaultBuild\r_s2_decode.obj" serial.mtpj
  • ケロリさん、こんにちは。NoMaYです。

    これは、R_tfat_f_read()関数が記述されたソースファイルがプロジェクトに追加されていない、またはソースファイルは追加されているけれどもR_tfat_f_read()関数の記述部分が#if ~ #endif条件コンパイル文等でコンパイル対象から外れている、のではないでしょうか?なので、ソースを検索して、R_tfat_f_read()関数が記述されているソースファイルがどれか、また条件コンパイル文などが無いか、それを調べる必要があると思います。

    > R_tfat_f_openなどのファイルを扱う関数を使用したいのですが、以下のようなエラーコードの対処ができていません。一番最初の話に戻ってしまうみたいで恐縮なのですが、このような場合はどのような原因が考えられるでしょうか。
    > (E) E0562310 E0562310:Undefined external symbol "_R_tfat_f_read" referenced in "DefaultBuild\r_s2_decode.obj" serial.mtpj

    [追記]

    以下は対処されたとのことですが、まだ必要なソースファイルでプロジェクトに追加されていないものがある、のだと思うのです。

    > Undefined external symbol "_R_tfat_f_stat" referenced in "DefaultBuild\r_main.obj"
    > とエラーメッセージが表示され、ビルドが完了できません。
    > 上記エラー後ライブラリtfat_rl78.libを入れていないことが原因と考え、プロジェクトに入れた後にビルドすると以下のエラーが出てきます。
    > external symbol "_R_tfat_disk_write" referenced in "r_TinyFAT"

  • NoMaYさん

    シェルティです、こんにちは。

    ご支援ありがとうございます。R_tfat_f_xxxxxxx() は TFATというファイルシステムのAPIですね。

    ミドルウェア系のものは色々な人が作ったものを1個のシステムとしてプロジェクト登録する必要があり、

    ソースコードが見えているとヘッダ同士がぶつかったりするので、

    私が作ったアプリケーションノートではバイナリ化してサンプルコードに組み込んであることが多いですね。

    ケロリさん

    NoMaYさんの仰る通りで、上記エラーはR_tfat_f_xxxxxxx() という関数を持つコード(バイナリかもしれないしソースコードかもしれない)がプロジェクト中に存在しないときに出ます。

     

    このアプリケーションノートのサンプルコード現物を改めて確認しました。無改造状態では問題なくビルドが通ります。

    https://www.renesas.com/jp/ja/software/D3017501.html

     ビルド確認したプロジェクト:\an_r20an0194jj0102_rl78_s2_sound\workspace\sample\yrdkrl78g14\CS+ for CC

     

    それで、エラー原因のR_tfat_f_xxxxxxx() は、TFATのバイナリ(tfat_rl78.lib)の内側に存在しておりまして、

    ケロリさんの環境ではこのファイルがプロジェクト・ツリーに存在しないか、ビルド対象から外れてしまっているか、どちらかかと思います。

     

    > Undefined external symbol "_R_tfat_f_stat" referenced in "DefaultBuild\r_main.obj"

    この関数については、私の前のポストに書いたように、r_tfat_drv_if.c に存在します。

    このエラーは私の前のポストを見たケロリさんがこのファイルをプロジェクト・ツリーに登録したので解消したのだと思います。

     

    いずれにしても、何か色々自分で手を入れる前に、配布されているサンプルをとにかく無改造で動くことを確認することをお勧めします。

    いったん動いてしまえば、自分で新たに作った環境が動かなくても、動いている環境と比較しながら詰めていけば原因がすぐ見つかります。

     

    以上です