LoginSignup
2

More than 1 year has passed since last update.

posted at

updated at

Renesas RA:環境構築~シリアル出力時計開発

本記事ではRenesas RAの環境構築からちょっとしたアプリケーション作成まで紹介します。

非常に簡単に組込みシステムを構築できるので、思いついたシステムを直ぐに実機に落とすことができると思います。

内容自体には面白みがありませんが、皆さんの開発に役にたてばと思います👍。

今回はRenesas RA familyのBluetooth 5.0 Low Energyにも対応したRA4W1のEvaluation Kitを使用します。

参考:Qiita記事「Renesas RA開発で困ったらここを見ろ!

EK-RA4W1 ↓
EK_RA4W1.JPG

※注記:この記事にて生じた損害に関し一切の責任を負いません。


Outline

本記事は以下の構成で記載しています。
Renesas RAとは
準備
 ボードの購入・ソフトウェア/ドキュメントの入手
環境構築
 Renesas FSPのインストール
動作確認
 Blinkyプロジェクトで動作確認
シリアル出力時計開発
 FSPを使用したちょっとしたアプリケーション開発を紹介します。


Renesas RAとは

Renesas RAはルネサスエレクトロニクスが開発/販売する32ビットMCU製品ファミリーのことです。RAファミリーはM&A案件で最近世間を騒がしているARM社のCortex-Mを搭載したMCUです。産業分野にマッチした優れたパフォーマンス、低消費電力動作、高セキュリティを実現しています。詳しくはこちら

またRenesas RAはユーザの組込みシステム開発を支援するFlexible Software Package (FSP)を提供しています。ユーザはMCUの制御レジスタ等を意識することなく周辺モジュールを活用したシステムを作成することができます。

RAを紹介した記事はこちら


準備

ボードの購入、ソフトウェア/ドキュメントの入手を紹介します。

ボードの購入

【2021/03/25 注記】ルネサスHPのリニューアルに伴い、ボード掲載ページが大幅に変更となっています。ボードのページは各MCUのページの末尾、「ボード&キット」から見つけてください。

まずはボードを入手する必要があります。
ルネサスサイトのRAファミリー概要ページの下に評価キットの紹介が載っていますのでお好きなボードを選択します。筆者はBLEの開発も試せるEK-RA4W1を購入しました。
renesas_RA_kits.PNG

各キットのページに移動したら、ご購入タブを選択します。
ご購入ページには以下のように購入可能サイトのリンクが記載されています。筆者はマルツオンライン経由で購入しましたが、執筆時は入荷待ちのようです。入手しやすいところから購入すると良いでしょう。
renesas_RA_EK_RA4W1.PNG

ソフトウェアの入手

ボードの購入手続きor入手ができましたらソフトウェアを入手します(ボードが手に入っていなくてもソフトは入手し試せますが。。。)。

Renesas RA familyが提供するソフトウェアはFSP(Flexible Software Package)といいます。FSPにはHALドライバやFree RTOSにインテグレートされたミドルウェアが含まれています。詳細はこちら
また後ほど紹介しますが、スマートコンフィギュレータやデベロッパアシスタントなどのツールが用意されており、ユーザが実際に行うコーディング作業は最小限で済みます。

FSPの入手は以下のようにFSPサイトの「最新バージョン...をダウンロードする」から行えます。ダウンロードには時間がかかりますので、時間があるときに行っておくといいでしょう。
renesas_FSP.PNG

ドキュメントの入手

開発にあたり必要となるドキュメントは以下から入手できます。
・RA4W1 ユーザーズマニュアル ハードウェア:RA4W1のドキュメントページ
・EK-RA4W1 ユーザーズマニュアル:EK-RA4W1のドキュメントページ
・EK-RA4W1 回路図等:EK-RA4W1のダウンロードページ
・FSP ユーザーズマニュアル:FSPのドキュメントページ
・FSP サンプルプログラム(EK-RA4W1用):EK-RA4W1のダウンロードページ or github


環境構築

ここまでの準備ができましたら環境構築を行います。
詳細は公式のFSPユーザーズマニュアルを参考にしてください。

・ダウンロードしたインストール実行ファイル(setup_fsp_v2_1_0_e2s_v2020-10.exe等)をダブルクリックしてください。
言い忘れましたが、今回はFSPをe2studioと合わせて一括インストールします。すでにe2studioをインストール済みの方もいらっしゃると思いますが、別々にインストールしたほうが他のバージョンと競合しないでいいと思います。

クリック後、ファイルの解凍とインストールするユーザ選択を行います。windowsの変更許可を求めてきますが、快く許可してあげてください。

・まず初めになにをしたいか聞いてきます。筆者の場合、FSP v1.3.0が既にインストールされているようで、「別の場所にインストール」を選択しました。Nextをクリック。
FSP_install_1.PNG

・次にインストールタイプを聞いてきます。特にこだわりわないのでQuick installを選択。Nextをクリック。
FSP_install_2.PNG

・インストールに必要な条件を調べます。少し待ちます。
緑色のチェックがすべて付けば、インストールの準備完了です。
何をインストールするか(コンパイラ等)はスクロールすると下の方に書かれています。

※インストール場所を変更したい場合は青矢印の「変更」をクリックして変更してください。変更したら再度条件チェックが走ります。

Nextをクリック。
FSP_install_3.PNG

・ライセンス/規約を読み、同意します。Nextをクリック。
FSP_install_4.PNG

・ショートカットを選択します。
筆者はショットカットを必要としないのでチェックを外しました。
準備完了なら、インストールをクリックします。
FSP_install_5.PNG

・インストールが開始します。☕でも飲んで待ちましょう。

・以下の画面が表示されればインストール完了です。リリースノート等、読みたいドキュメントがあればチェックを入れOKをクリックしてください。
FSP_install_6.PNG

・環境構築を完了するにはもう1つ大事なことがあります。ツールチェーンの登録です。
インストール完了の画面の「Launch e2studio?」にチェックを入れてOKを押すかインストールフォルダ内のe2studio.exeを選択してLauncherを起動します。

起動するとワークスペースの場所を指定する画面が出てきますので、適当な場所にワークスペースを作成し選択してください。Launchをクリック。
e2studio_launcher.PNG

そうすると以下のようにルールチェインを登録する画面が出てきます。筆者は既にいくつかのGNU toolchainをインストール済みなので複数表示されました。チェックをつけて登録をクリック。完了したら「登録しました」と表示されます。
※この作業はインストール後最初の1回のみ行います。
e2studio_toolchain.PNG

以上で環境構築は完了です。お疲れさまでした。

・アンインストール方法
ちなみにアンインストールはコントロールパネルの「プログラムと機能」から行うか、
インストールフォルダ(デフォルトではC:\Renesas\RA)内のアンインストール実行ファイル(uninstall.exe)で行えます。


動作確認

環境構築が行えたらプロジェクト作成の紹介がてら動作確認を行っておきます。

・e2studioを起動します。Welcomeページは使わないのでクローズします。

・プロジェクトを生成します。Project Explorer内の「Create a new C or C++ project」をクリック。
e2studio_c.PNG

・生成したいプロジェクトを選択します。今回はRA用のプロジェクトを生成したいので「Renesas RA C/C++ Project」を選択します。Nextをクリック。
e2studio_create_project_1.PNG

・プロジェクト名を入力します。入力後、Nextをクリック。
e2studio_create_project_2.PNG

・デバイス/ツールを選択します。今回はEK-RA4W1を使用するのでBoardにEK-RA4W1を選択します。その他必要に応じて設定を変更します。Nextをクリック。
e2studio_create_project_3.PNG

・生成物/RTOSを選択します。今回はRTOSは使用しないのでNo RTOSを選択します。Nextをクリック。
e2studio_create_project_4.PNG

・FSPに同梱のBlinkyプロジェクト(Bare Metal - Blinky)を選択します。Blinkyプロジェクト以外のプロジェクトを作成したいときは「Bare Metal-Minimal」を選択します。Finishをクリック。
e2studio_create_project_5.PNG

・プロジェクトが生成されたら以下のようなメッセージが表示されます。パースペクティブとはe2studioの画面構成のことです。RAプロジェクトを生成するとスマートコンフィギュレータ用のパースペクティブが選択され切り替えられるため、確認のためのメッセージが出ます。
※パースペクティブの切り替えはe2studio右上のボタンで行うことができます。
e2studio_create_project_6.PNG

・生成されたプロジェクトを確認します。
画面左側のProject Explorer内に先程選択したプロジェクト名のプロジェクトが生成されています。
メインのソースプログラムはsrcフォルダのhal_entry.cのhal_entry関数内に記載されています。
※今回はFSP同梱のサンプルプロジェクトであり、ユーザがコードを書き加える必要はありません。

・生成されたプロジェクトをビルドします。
まずスマートコンフィギュレータ内の「Generate Project Content」をクリックします。その後、赤矢印の部分にビルドしたいプロジェクトが選択されていることを確認し、左上の🔨ボタンをクリックします。

下の青矢印のように「Build Finished. 0 errors」と表示されればビルド完了です。
e2studio_create_project_7.PNG

・ダウンロード/実行します。
PCとEK-RA4W1(外側のUSBポート:ECN1)をUSBケーブルで接続してください。
左上の緑虫ボタンをクリックすると、ダウンロード/デバッグが開始します。パースペクティブ切り替えメッセージが出ますがSwitchをクリック。
ボードへの最初の書き込みの際にオンボードj-linkのファームウェアアップグレード確認メッセージが出る場合がありますが、してもしなくてもいいです。
e2studio_debug_1.PNG

・デバッグを再開します。
ダウンロード/デバッグ開始が完了するとリセットハンドラの最初で停止します。
黄色と緑三角のボタン(再開)をクリックすると次のブレイクポイントまで実行します。メイン処理を開始させるには複数回(筆者の環境では2回)クリックする必要があります。

ちなみにこの画面構成はDebugです。画面右上のDebugが青くなっているのが分かります。ソース編集、スマートコンフィギュレータ編集、Debugのそれぞれの作業に応じてパースペクティブを変更すると作業効率が上がると思います。
e2studio_debug_2.PNG

・ボード中央のLED0とLED1が1秒おきに点滅すれば正常に動作しています。
EK_RA4W1.JPG

・デバッグの停止は再開ボタンの2つ右隣の赤い■ボタンを押すことでできます。プログラムは既にマイコン内蔵のFlashメモリに書き込まれているので、電源を再投入してあげればデバッガを繋がなくても動作可能です。

 
以上で動作確認は完了です。お疲れさまでした。
(記事も長くなってきました。ちょっと休憩しましょう。)


シリアル出力時計開発

ちょっと簡単なアプリケーション開発としてシリアル出力時計を開発します。
今回はEK-RA4W1をベースにシステムを開発しますが、使用するモジュールのチャンネルなどを合わせればどのボードでも実装可能と思います。使用するFSPのバージョンはv2.1.0です。

概要

以下の図のようにシリアル通信を使用して1秒おきに時計データを出力します。初期設定やスタートコマンド受信のため、双方向通信とします。
serial_clock_overview.PNG

機能
・UART通信(SCI)でRTCの初期値を受信。
・UART通信によるスタートコマンド受信で時計開始。
・RTCで時計計測を実行。
・1secおき(RTCのperiodicイベント)にUART通信で時刻を送信。

使用する入出力ポートは以下の通りです。
・RA4W1 P205 (SCI4.TX) --> PC RX
・RA4W1 P206 (SCI4.RX) <-- PC TX
・RA4W1 P106 (GPIO) --> LED0 (初期化中にON)
・RA4W1 P404 (GPIO) --> LED1 (1secごとに点滅)

作業手順
・プロジェクト作成
・ポート設定
・周辺モジュール設定
・コード作成
・動作確認

※以降はGIF画像を用いて紹介します。初めて使うので分かりづらい部分があるかと思いますが、ご了承下さい。

プロジェクト作成

プロジェクトを生成します。方法は上で紹介した通りです。
project_create_pjt.gif

Pin設定

スマートコンフィギュレータを用いてPinの設定をします。EKボードを使用する場合、ある程度想定できる部分は既に設定されています。以下のgif画像では設定を確認しています。
project_pin_setting.gif

周辺モジュール設定

モジュールのドライバ追加と各種設定を行います。
このアプリケーションではRTCとSCI4を使います。
作業手順:SCI4ドライバ追加 -> SCI4設定 -> RTCドライバ追加 -> RTC設定
project_module_setting.gif

コード作成

コードを生成します。すべてを紹介するのは大変なので、GUIでできる部分を中心に一部のみ紹介します。

デベロッパアシスタントを用いてモジュールのOpen関数と割り込み関数を設置します。設置したいAPIをドラッグ・アンド・ドロップで追加することができます。このAPIにはスマートコンフィギュレータで設定した値が自動的に適用されるのでユーザは設置するだけでよいです。
project_code_generate.gif

割り込み関数内を設定します。
project_code_generate2.gif

説明は以上です。以降は添付するソースコードを参考に実装してみて下さい。

以下はソースコードです。筆者が記述した部分のみ添付してあります。以下のコードをFSPが生成したサンプルプロジェクトの適切な場所に置くことで、使用することができます。

【2021/02/27追記】 github上にプロジェクトファイルを公開しました。インポート方法は、FSP User's manualの"2.2.12 Importing an Existing Project into e2 studio"をご参照ください.

main.c
#define LED0_ON     R_PORT1->PCNTR3_b.PORR = (1 << 6)
#define LED0_OFF    R_PORT1->PCNTR3_b.POSR = (1 << 6)
#define LED1_ON     R_PORT4->PCNTR3_b.PORR = (1 << 4)
#define LED1_OFF    R_PORT4->PCNTR3_b.POSR = (1 << 4)

rtc_time_t set_time;
rtc_time_t get_time;

volatile bool uart_recv_flag = false;
volatile bool rtc_periodic_flag = false;
volatile bool uart_send_complete_flag = false;
volatile bool led_status = false;

unsigned char recv_data[2];
unsigned char send_data[30];
unsigned char send_buff[40];

fsp_err_t uart_recv_time_value(rtc_time_t* _time);

void hal_entry(void) {
    LED0_ON;
    fsp_err_t status = FSP_SUCCESS;

    /* Initialize SCI */
    status = R_SCI_UART_Open(&g_uart4_ctrl, &g_uart4_cfg);
    if(FSP_SUCCESS != status) __BKPT();

    /* Initialize RTC */
    status = R_RTC_Open(&g_rtc0_ctrl, &g_rtc0_cfg);
    if(FSP_SUCCESS != status) __BKPT();

    /* Receive RTC time value */
    status = uart_recv_time_value(&set_time);
    if(FSP_SUCCESS != status) __BKPT();

    /* Send massage */
    sprintf(send_buff, "Please push s to start timer.\n");
    status = R_SCI_UART_Write(&g_uart4_ctrl, send_buff, 30);
    if(FSP_SUCCESS != status) __BKPT();
    while(uart_send_complete_flag == false){}
    uart_send_complete_flag = false;

    /* Wait until receive start command */
    status = R_SCI_UART_Read(&g_uart4_ctrl, &recv_data[0], 1);
    if(FSP_SUCCESS != status) __BKPT();
    while(uart_recv_flag == false){}
    uart_recv_flag = false;

    if(recv_data[0] == 's'){
        sprintf(send_buff, "Start timer.\n");
        status = R_SCI_UART_Write(&g_uart4_ctrl, send_buff, 13);
        while(uart_send_complete_flag == false){}
        uart_send_complete_flag = false;
    }else{
        sprintf(send_buff, "invalid input data.\n");
        status = R_SCI_UART_Write(&g_uart4_ctrl, send_buff, 20);
        while(uart_send_complete_flag == false){}
        uart_send_complete_flag = false;
        __BKPT();
    }

    /* Set RTC time value */
    status = R_RTC_CalendarTimeSet(&g_rtc0_ctrl, &set_time);
    if(FSP_SUCCESS != status) __BKPT();

    /* Set RTC periodic irq */
    status = R_RTC_PeriodicIrqRateSet(&g_rtc0_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);
    if(FSP_SUCCESS != status) __BKPT();

    LED0_OFF;

    while(1){
        LED1_OFF;

        if(rtc_periodic_flag){
            rtc_periodic_flag = false;

            /* Get RTC time */
            status = R_RTC_CalendarTimeGet(&g_rtc0_ctrl, &get_time);
            if(FSP_SUCCESS != status) __BKPT();

            /* Send time */
            sprintf(send_data, "time %4d/%2d/%2d %2d:%2d:%2d\n", get_time.tm_year + 1900, get_time.tm_mon + 1, get_time.tm_mday, get_time.tm_hour, get_time.tm_min, get_time.tm_sec);
            status = R_SCI_UART_Write(&g_uart4_ctrl, send_data, 30);
            if(FSP_SUCCESS != status) __BKPT();

            LED1_ON;
            R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
        }
    }
}

fsp_err_t uart_recv_time_value(rtc_time_t* _time){
    unsigned char _recv_buff2[2];
    unsigned char _recv_buff4[4];
    unsigned char _send_buff[30];

    fsp_err_t status = FSP_SUCCESS;

    sprintf(_send_buff, "Enter time value!!");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 18);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    //////// YEAR ////////
    sprintf(_send_buff, "\n     Year > ");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 13);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    status |= R_SCI_UART_Read(&g_uart4_ctrl, &_recv_buff4, 4);
    while(!uart_recv_flag){}
    uart_recv_flag = false;

    _time->tm_year = atoi(_recv_buff4) - 1900;

    //////// MONTH ////////
    sprintf(_send_buff, "\n     MONTH > ");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 14);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    status |= R_SCI_UART_Read(&g_uart4_ctrl, &_recv_buff2, 2);
    while(!uart_recv_flag){}
    uart_recv_flag = false;

    _time->tm_mon = atoi(_recv_buff2) - 1;

    //////// DAY ////////
    sprintf(_send_buff, "\n     DAY > ");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 12);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    status |= R_SCI_UART_Read(&g_uart4_ctrl, &_recv_buff2, 2);
    while(!uart_recv_flag){}
    uart_recv_flag = false;

    _time->tm_mday = atoi(_recv_buff2);

    //////// HOUR ////////
    sprintf(_send_buff, "\n     HOUR > ");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 13);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    status |= R_SCI_UART_Read(&g_uart4_ctrl, &_recv_buff2, 2);
    while(!uart_recv_flag){}
    uart_recv_flag = false;

    _time->tm_hour = atoi(_recv_buff2);

    //////// MIN ////////
    sprintf(_send_buff, "\n     MIN > ");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 12);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    status |= R_SCI_UART_Read(&g_uart4_ctrl, &_recv_buff2, 2);
    while(!uart_recv_flag){}
    uart_recv_flag = false;

    _time->tm_min = atoi(_recv_buff2);

    //////// SEC ////////
    sprintf(_send_buff, "\n     SEC > ");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 12);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    status |= R_SCI_UART_Read(&g_uart4_ctrl, &_recv_buff2, 2);
    while(!uart_recv_flag){}
    uart_recv_flag = false;

    _time->tm_sec = atoi(_recv_buff2);

    //////// Finish ////////
    sprintf(_send_buff, "\n");
    status |= R_SCI_UART_Write(&g_uart4_ctrl, _send_buff, 1);
    while(!uart_send_complete_flag){}
    uart_send_complete_flag = false;

    return status;
}

void user_uart_callback(uart_callback_args_t *p_args)
{
    if(p_args->event == UART_EVENT_RX_COMPLETE)
    {
        uart_recv_flag = true;
    }else if(p_args->event == UART_EVENT_TX_COMPLETE)
    {
        uart_send_complete_flag = true;
    }
}

void rtc0_callback(rtc_callback_args_t *p_args)
{
    if(p_args->event == RTC_EVENT_PERIODIC_IRQ){
        rtc_periodic_flag = true;
    }
}

【2021/03/25 Rulzで疑問を持たれている方がいたので補足】
上記のコードで使用している__BKPT()はソフトウェアブレイクポイントを意味し、GCCコンパイラによって定義されています。 __BKPT()をエラー箇所にセットすることで、ツール上で簡単にエラー箇所を特定することができます。ソフトウェアブレイクポイントはソースコードに埋め込むことになるので、ハードウェアブレイクポイントやフラッシュブレイクポイントのように「ツール間のプロジェクトの移動で再設定しないといけない」といったことはなくなります。使用できる数に制限がないのもメリットでしょうか。ですが、ソースコードに埋め込むことになるので、スタンドアロン(単体動作)の時でも有効になります。止まっているようだけど、どの行で止まっているわからないなんてことにならないように注意が必要です。デバッグ時に使用してください。本来のシステムだと、エラー時は何かしらのエラー処理を実装すると思うので、必然と使用しないと思います。。。

動作確認

PCとEK-RA4W1を接続しターミナルソフトを用いて初期値とスタートコマンド('s')を入力すると1秒おきに時間データを送信します。
またボード上のLED1が1秒おきに点滅すれば動作確認完了です。

お疲れさまでした!!
serial_clock_teraterm.PNG

※EK-RA4W1は出荷時の状態では外部クロック発振器が取り付けられてなく、内部クロックのみで動作しします。これに伴い、RTCの時間にズレが発生します。これはRA4W1の問題ではなく、マイコン/半導体では当たり前の動作と考えてください。正確な時刻を刻みたい場合は、ユーザーズマニュアルに従って発振器を取り付ける必要があります。


まとめ

以上、環境構築からアプリケーション開発まで長々と紹介してきましたが、いかがだったでしょうか??

ArduinoやRPiなどのコミュニティが発達し環境が整っているものと比べると少し手間と感じてしまう部分があると思いますが、これまでの汎用マイコンの開発作業と比べれば非常に簡単になっていることを感じてもらえたと思います。

特にGUIで設定が行えるようになることで、マイコンが持つ多彩な機能を誰でも簡単に使うことができるようになっています。

今後もRAマイコンはこれらを提供し続け、ユーザの開発を大きく後押ししてくれるのではないでしょうか。


参考資料

上記記載のドキュメント類。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2