RX72N Envision Kit+e2studio+GCCでCoreMark®


今回の目的

RXマイコンはCoreMarkの性能が売りの一つということで、RX72N Envision Kitで実際に計測してみました。

Coremarkのソースはgitで入手できるようになり、元々低かった敷居が更に下がっています。
https://github.com/eembc/coremark

RX72Nへの導入も簡単だろうと踏んでいましたが、今回の試行で色々詰まる所がある割に説明資料が少ないかなと感じました。

アプリケーションノート(RX100系)

APNはRX111+IARがベースで、他のマイコンにも適用可能という記述があります。
今回はこのAPNの手順を踏襲したうえで、e2studioにてCoremarkの実行環境を構築した試行錯誤の結果を書き残します。

ファイルの構成

新規プロジェクトを立ち上げ、上記gitとRX111のサンプルコードを中心にファイルを揃えました。

メイン関数

ツールが変わった場合にも対応しやすいようにメイン関数からcore_main.cのmain(core_mainに改名)を呼び出しています。

coremark_e2_test.c(main抜粋)
int main(void) {

    //System Init
    SYSTEM.PRCR.WORD = 0xA503;              //PRC1,0 Write Enable
    clk_init();

    //SCI Init
    serial_init();

    //user LED init&On (RX72N Envision Kit)
    PORT4.PODR.BYTE = 0x00;         //P40:"H" (LED on)
    PORT4.PDR.BYTE = 0x01;          //P40:output

    //ee_printf("START\n");

    //RUN Coremark
    core_main();

    //user LED OFF (RX72N Envision Kit)
    PORT4.PODR.BYTE = 0x01;         //P40:"H" (LED off)

return 0;
}

クロック設定、ログ転送用のSCIの初期設定の後CoreMarkの演算を行っています。
KitのユーザLEDを演算中かどうかのインジケータとしました。

coremark_e2_test.c(クロック設定)
int clk_init(void) {

    int i,j;

    //MOSC ON                               //Envision kit has 16MHz OSC.
    SYSTEM.MOSCCR.BYTE = 0x00;
    for (i=0;i<1000;i++) {}
    do {j = (SYSTEM.OSCOVFSR.BYTE) & 0x01;
    } while(j == 0x00);                     // wait for stable flag

    //PLL ON
    SYSTEM.PLLCR.WORD = 0x1D00;             // x15.0, 1:1, source:MOSC(16MHz@RX72N Envision Kit)
    SYSTEM.PLLCR2.BYTE = 0x00;              // PLL enable
    for (i=0;i<1000;i++) {}
    do {j = (SYSTEM.OSCOVFSR.BYTE) & 0x04;
    } while(j == 0x00);                     // wait for stable flag

    //Change Source Clock (LOCO to PLL)
    SYSTEM.MEMWAIT.BYTE = 0x01;             // 1wait
    SYSTEM.SCKCR3.WORD = 0x0400;            // source:PLL
    SYSTEM.SCKCR.LONG = 0x00003444;         // PCLKA=ICLK/8 (240/8=30MHz) PCKB,C,D=ICLK/16 (240/16=15MHz) //MTU1,2は120MHzでは早すぎてカウンタが一周する

    return 0;
}

精度重視のためPLLのクロックソースはHOCOでなくMOSCとしました。逓倍設定でRX72Nの最大設定の240MHzに合わせます。
周辺回路のクロックはMTUは30MHz,SCIは15MHzとしました。当初PCKAの最大設定となる120MHzにしたところ、カスケード接続したMTU1,2のカウントがオーバーフローしてしまったためあえて落としました。

serial_init()の中身は前回のエントリーで書いた設定と同じく、オンボードでUSB-UART変換が可能なSCI2(P12,P13)を使用します。
https://qiita.com/schuji_o/items/c2e85e3d695672a9a0f5

core_portme

環境やマイコンに合わせて各自書き換える必要のあるcore_portme.cと.hですが、ここはAPNを参考に変更を加えました。

#include "rx72n_mtu.h"
...
#define ITERATIONS  8500
#define FLAGS_STR   "-O3 -flto"     
...
#define NSECS_PER_SEC 30000000          //chg for RX Timer clock frequency: PCKA=30MHz
...
void start_time(void) {
    //GETMYTIME(&start_time_val );
    timer_init();                       //MTU1,2 initialize
    start_time_val = timer_start();     //MTU1,2 Start
}
...
void stop_time(void) {
    //GETMYTIME(&stop_time_val );
    stop_time_val = timer_stop();       //MTU1,2 Stop
}
...

NSECS_PER_SECはmain側で定義したPCKAの周波数に合わせて設定、ITERATIONSは何回か試行して10秒を超えるそこそこの値を結果論で入れました。演算時間が10秒を超えないとベンチの規格を満たさずエラーとなりますので、それよりは長くしています。

rx72n_mtu

MTU1,2のカスケード接続でPCKAのクロックをカウントする制御を行います。
UHMのMTU1,2の機能を確認し、上記APNのサンプルプログラムのレジスタのシンボルのリネームのみでそのまま使えると判断しました。

rx72n_mtu.c
...
  //MSTP(MTU) = 0;                  //chg
  SYSTEM.MSTPCRA.BIT.MSTPA9 = 0;    //chg
...

以下、レジスタ名を置換。

  • TSTR/TSYR → TSTRA/TSYRA
  • TMDR → TMDR1

.hの方はそのままで問題ありませんでした。

ee_printf

アルゴリズムの実行よりも結果やエラーメッセージをどのように表示するかがマイコン使用時の課題となりますが、今回も時間を取られました。

Knowledge Baseに下記がありまずはこちらを試しました。
https://ja.na4.teamsupport.com/knowledgeBase/17797636

  • Dynamic printfを使用する方法

 環境依存が強い/修正が大変/遅い/いつの間にかずれると色々ありましたが、ee_printf()中に環境変数や関数呼び出しがあるとエラーとなって処理が進まなくなるのが一番のネックです。

ee_printf("CoreMark 1.0 : %f / %s %s",default_num_contexts*results[0].iterations/time_in_secs(total_time),COMPILER_VERSION,COMPILER_FLAGS);

一旦変数に渡せば表示は可能ですが、core_mainの文中に手を入れるのを出来れば避けたくて別の方法をとることにしました。

  • 低水準入出力関数を実装する方法

上記リンクでガイドされていますが、GCCではプロジェクト作成時にチェックを入れる項目が見当たらなかったのとFITからファイルをコピーしてコンパイルするとエラーが散発したため、こちらも見送りました。

  • ググって良さそうなライブラリを使わせてもらう

APNではee_printf.c/hの置き換えは行われていなかったのですが、barebones下のee_printf.c/hを用いたシリアル転送時の文字変換を行うのが最もツール依存が少なく、実装も早いというところに落ち着きました。以下は検索した際に上位に来たもので、今回はこちらを流用させて貰いました。

シリアル通信部のみ各マイコンに合わせて修正する必要があります。1文字送ればよいので、シンプルに下記を追加しました。

...
#include "iodefine.h"   //add for RX
...
void uart_send_char(char c) {
...
    while(SCI2.SSR.BIT.TDRE == 0);
    SCI2.TDR = c;
    while(SCI2.SSR.BIT.TEND == 0);
}
...

APNでの使用ツールはIARでしたのでprintf周りが特に問題にはならなかったのだと思います。e2studioはprintfやscanfに工夫が要りますね。

実行結果

主だった修正内容は以上となります。
それではビルドして実行結果を確認します。最適化のオプションは下記の2点をデフォルトから変更しました。
* Optimizationを-O0から-O3に変更
* Link-time optimizer(-flto)にチェック

ビルド後に実行します。結果は以下となりました。

ICLK=240MHzですので、上記の結果では3.41Coremark/MHzということになります。
RX72Nの製品のHPではCoremarkのスコアは1300超えとなっていましたので、それに比べると低めですが普通にコンパイルしてこの数字が出る5000円未満のマイコンボードというのはそうあるものではないでしょう。
こうなるとCC-RXやIARでのコンパイル結果も気になってきます。

補足

プログラム設定が正しいかどうかの確証が得られているわけではありませんので、製品の性能評価は各自の環境で実施願います。もし間違いがあればご教示いただけると大変ありがたいです。