RA2A2でC++の標準出力が使えない

こんにちは。こじこじです。

RAファミリのRA2A2を使用しています。C++言語の標準出力が使用できなくて原因を調査中です。

開発環境は以下の通りです。

IDE:Renesas e² studio (Version: 2024-01.1)

言語:C++

コンパイラ:GNU Tools for ARM Embedded Processors (arm-none-eabi-gcc) (Version:13.2.1.arm-13-7)

FSP:v5.3.0

使用ボード:EK-RA2A2

<iostream>をインクルードしてもcoutを使用しなければ問題なく動作します。

hal_entry.cpp

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

#include "hal_data.h"
#include "main.h"
#include <iostream>

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
void hal_entry(void)
{
    Main main ;
   
    //std::cout << "Hello, World!" << std::endl;

    /* TODO: add your own code here */
    main.Loop() ;    
#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

ただ、上記コードの std::cout~~を記述すると、hal_entry()前のSystemInit()内でエラーとなってしまいます。

場所は以下です。

SytemInit()内の

__init_array_start[i]()実行時にbsp_common.cの__assert_funcに飛んでしまい、無限ループとなるので、これ以上プログラムが進みません。

C++言語のサンプルプロジェクトの【cpp_ek_ra2a2_ep】で同じことをすると、上記画像部分は問題ないのですが、

coutの行を実行しようとすると”_swiwrite()" に対して使用できるソースがありません ”となります。(その他_swrite()など複数も同様)

自作も【cpp_ek_ra2a2_ep】プロジェクトもGNU Arm Cross C++ Linker設定のMiscellaneousのOther linker flagsに

”--specs=rdimon.specs”を追加しています。

GNU Arm Embedded Toolchainではシステムコールの詳細を実装していない部分があり、実装の必要があると記事で見ました。

https://qiita.com/takahashim/items/120d69a44a80d08b70e7

手動で実装する代わりにrdimonを使うことで解決するとのことで、”--specs=rdimon.specs”を追加しています。

”--specs=rdimon.specs”を追加しないと、別途ビルドエラーが発生してしまいます。

これが何か関係あるのか不明ですが、情報として記載しておきます。

 

以上、手詰まりとなってしまい、ここに投稿させていただきました。

原因と解決策のアドバイスをお願いいたします。

  • FSPの設定(歯車アイコン,Configuration.xml)を開き、BSPタブのプロパティ

    Heap size(デフォルト0)が0の場合は、上記ハードコピーと同じ場所で止まりました。

    Heap sizeを確保して実行すると、今度はデフォルトハンドラに飛んできました(スタックオーバフロー)。

    そこで、次に、Main stack size(デフォルト0x400)を増やすと、hal_entry()まで飛んできました。

    (手元には、RA2A2のボードは無かったので他のマイコンでの試行です。)

    RA2A2(RAM48kB)ですと、0x4000+0x4000はちょっとメモリを食い過ぎだと思いますが(どこまで削れるかは試していません)、デフォルト設定ですと、ヒープとスタックメモリが足りていないという話なのではないかと思いました。

  • stdio関数、特にprintf系は大き目のヒープを要求するので避けられるものなら避けた方が良いです。
    大規模な関数はスタックも食いますし。
    coutだと更に迂遠な処理になるのでリソースの消費も処理時間も大きくなるはず。
    自前の文字列処理関数を作るか、代償を支払って楽をするかは状況次第ですが。

    rdimon.specs(でリンクされるライブラリ)にはstdioで参照される関数のスタブも含まれるので、指定しないとリンクエラーが出るのは不思議なことではありません。

  • こんにちは、hira です。

    組み込み環境で STL を使う場合、特に標準入出力を使う場合、非常に巨大なメモリを、RAM、ROM共に消費します。

    なので、実質的に利用しない方が良いと思えます、以下のリンクはRXマイコンの場合ですが、同じような状況と思います。

    https://qiita.com/hira_kuni_45/items/790d379034c747e66d40

    自分も同じような問題にぶつかり、printf を使いたくないので、自前の実装に至りました。

    gcc 環境の場合、文字を入出力する場合、POSIX の標準関数を実装して、その中から、シリアル入出力に繋げる仕組みを実装する必要はあります。(統合環境の場合、内部のRUNタイムで自動で行っている場合があります)

    ここで解説している「format.hpp」はインクルードするだけで使え、他の環境でも同じように使えます。(RL78/gcc、R8C/gcc、MSYS2/gcc/clang、VisualStudio)

    POSIXの実装は、「syscalls.c」を参照して下さい。

    github.com/.../syscalls.c

  • GCCのIO処理をする部分は開発環境で特別にサポートでもしていなければ未実装になっています。_close, _exit, _fstat, _getpid, _isatty, _kill, _lseek, _read, _writeの中身を作らないと標準出力は使えません。

    そもそも、あなたのボードの標準出力ってどのデバイスですか?SCI0チャンネルですか?それともUSBのCDCデバイスですか?それとも液晶デバイスへの表示ですか?私なら組み込み用途で許されるメモリサイズを考えるとiostreamは使いません。newlibのstdio.h、printf (floatサポートなし)が現実的だと思います。

  • FSPの環境ですとデフォルトでは、"Use newlib-nano"が有効になっています。UARTで文字出力する時にsprintfで%dとかは使います。この場合は、ヒープメモリを確保しなくても動きますね。%fは、サクッと無視される(出力からは抜け落ちる)という動作であったかと思います。リンカオプションで、"Use float with nano printf"にチェックを入れて、ヒープメモリを確保すると、%fも使えます。個人的には浮動小数点数の表示フォーマットには自作関数を使っています。

  • 皆様、返答ありがとうございます。ここの返信にてまとめてお礼させていただきますこと、ご了承ください。

    デバッグ時にe2studioのコンソール出力に文字を表示できればなと思ったのが、coutを使用しようとしたきっかけです。

    皆様のアドバイスを参考に組み込みではメモリ容量が限られていますので、

    今回はcout および printfなどの標準出力、 そもそもSTL はよほどのことがない限り使用しない方向とします。

    改めまして、ありがとうございました。

  • これをもう少し読んでみるといいと思います。
    ja.na4.teamsupport.com/.../17797636