こんにちは。NoMaYです。#5連投の1つ目です。今は(今後も?)e2 studioでのみ作れるFreeRTOSプロジェクトですが、以下のプログラムを作ってみました。TB-RX65N用(1) TBボードのLED0を500ms毎にOn/Offする(FreeRTOS APIのvTaskDelay()を使用)(2) TBボードのSW1押下毎にLED1をOn/Offする(タスクでセマフォ待ちして割り込みでセマフォ待ち解除)(3) TBボードのSCI1で3文字受信毎に3文字エコーバックする(タスクでセマフォ待ちして割り込みで3文字毎にセマフォ待ち解除)Renesas RX Simulator用(1') Visual ExpressionのLED部品を50ms(但しシミュレーション上の時間)毎にOn/Offする(上の(1)の括弧内と同様)(2') Visual ExpressionのBUTTON部品押下毎にLED部品をOn/Offする(上の(2)の括弧内と同様)(3') Renesas Debug Virtual Console⇔SCI1で3文字受信毎に3文字エコーバックする(上の(3)の括弧内と同様)プロジェクトのファイル一式 (CC-RX V2.03でビルド、zipファイルをe2 studioに直接インポート可能)japan.renesasrulz.com/cafe_rene/m/sample_program/434sim_rx65n_freertos_proj_fit_scfg_ccrx_c_e2v750_20190924.zip 1.23MBsim_rx65n_freertos_proj_fit_scfg_ccrx_c_e2v760_20191019.zip 1.23MB (主にGNURX版との合わせ込みです)含まれるプロジェクトsim_rx65n_freertos_proj_fit_scfg ← こちら側にソースがあります(TB-RX65Nでも動作可)(*1,*2)tb_rx65n_freertos_proj_fit_scfg ← こちら側にソースは無いです(TB側はSIM側のソースフォルダをリンク機能で参照します)(*1,*2)x_DO_NOT_BUILD_rx65n_freertos_proj_fit_scfg_0 ← ソース編集前のRXスマートコンフィグレータ設定直後のソース(*3)*1:以前に別スレッド「RenesasさんからRXマイコンの低価格Target Boardが出たのでサンプルプログラムをCSplus projectへ変換してみようと思います」に投稿したプロジェクトと同じIDコードを設定しています。*2:実機用の.launchファイルは当方特有の事情でオンボードエミュレータが使えない為に未確認です。*3:RXスマートコンフィグレータの設定を行った直後にRXスマートコンフィグレータに生成させたソースがx_DO_NOT_BUILD_rx65n_freertos_proj_fit_scfg_0プロジェクトのsrcフォルダのソースです。ファイル比較ツールで比較することで、RXスマートコンフィグレータに生成させた後、どのように編集したか分かります。出来るだけ同じプログラムにしたかった/する為に、Renesas RX Simulator用に以下の#if~#else~#endifがあります。(私のパソコンの遅さゆえにそうしたものもあります。)(A) Visual ExpressionのBUTTON部品押下からのPORTB.PIDR.BIT.B1書き換えをポーリングしてIRQ4割り込みをエミュレート(B) Renesas Debug Virtual Consoleからの受信到着待ちをポーリングしてSCI1のRXI1割り込みをエミュレート(C) Renesas Debug Virtual Consoleへの送信可能待ちをポーリングしてSCI1のTXI1/TEI1(*3)割り込みをエミュレート(D) FreeRTOSのRX600v2ポートレイヤは別スレッドで試したRenesas RX Simulator用の無理矢理な代替実装を使用(実機動作可)(E) その別スレッドで試したr_bspモジュールのクロック切り替え時の無限ループ対処をフラッシュキャッシュ有効化時にも適用(F) TB-RX65N用では500msの点滅間隔をRenesas RX Simulator用では50ms(但しシミュレーション上の時間)の点滅間隔に変更(G) TB-RX65N用では10msのチャタリング除去待ち時間をRenesas RX Simulator用では待ち時間は無しに変更*3:もう少し正確に書くとTEI1の動作ではなくICUのGROUPBL0割り込みとGROUPBL0のビット6の動作に関してです。コーディング上の小技として以下のこともやってみました。(H) CGコンポーネント初期化用のr_cg_hardware_setup.cでFITモジュール端子設定関数を呼ぶStart user code~End user code内の記述(I) r_bspモジュールのソースを直接変更せずにRenesas RX Simulator用の無限ループ対処を組み込む#defineマクロFreeRTOS関連では以下のような設定変更や記述追加も行いました。(a) r_bsp_config.h(a-1) Uスタックサイズを0へ(FreeRTOS管理下のメモリがタスクのスタックに使われるので)(Iスタックはそのまま使われます)(a-2) Heapサイズを0へ(FreeRTOS管理下のメモリをFreeRTOSのスレッドセーフなAPIで操作する方が安全と思われますので)(b) FreeRTOSConfig.h(b-1) #define __TYPEDEF__ 1 を削除(b-2) #define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H 1 を追加(b-3) #define configENABLE_BACKWARD_COMPATIBILITY 0 を追加(c) freertos_start.c(c-1) 別スレッド同様にRenesas RX Simulator用のRX600v2ポートレイヤの無理矢理な代替実装で使うCMT1の重複エラーを追加(c-2) 別スレッド同様にAmazon AWSのFreeRTOS Kernel Developer Guideのサンプルコードを試せるようにvPrintString()を追加(c-3) vAssertCalled(), vApplicationMallocFailedHook(), vApplicationStackOverflowHook()でvPrintString()でメッセージを出力(c-4) vApplicationTickHook()でIRQ4やSIC1の割り込み動作エミュレート用の関数を呼び出す(ここが一番手っ取り早そうだった)(c-5) FreeRTOSプロジェクトでmain_task()がFreeRTOS Objectコンポーネント管理外なので対処(今回はmain_task()は空です)(c-1) Heapサイズを0にするとsbrk()が無いというリンクエラーになってしまうのでエラー処理のみのsbrk()を追加後日手を入れたいと思っていることに以下のことがあります。(イ) R_SCI_RXモジュールのAPI+FreeRTOS APIで受信エラーをタスク側で拾うにはどうすると良いか?(RL78ではこうしたけれど)(ロ) 最終的に使わなかったR_CMT_RXモジュールとRX600v2ポートレイヤの無理矢理な代替実装の両方でCMT1の使用が重複してしまう問題への対処(R_CMT_RXモジュールに手を入れるか?)この後、2投目~5投目は以下の通りです。2投目・IRQ4割り込みエミュレーションのソース (大げさなものでは無いです)・SCI1のRXI1/TXI1/TEI1(前述の*3を参照)割り込みエミュレーションのソース (大げさなものでは無いです)・CGコンポーネント初期化用のr_cg_hardware_setup.cでFITモジュール端子設定関数を呼ぶStart user code~End user code内の記述・r_bspモジュールのソースを直接変更せずにRenesas RX Simulator用の無限ループ対処を組み込む#defineマクロ3投目・FreeRTOSプロジェクトでmain_task()がFreeRTOS Objectコンポーネント管理外なので対処(今回はmain_task()は空です)・tb_rx65n_main.c, main_task.c, task_LED0.c, task_LED1.c, task_CONIO.cのソース4投目 (ひたすら画面コピーです)・Visual Expressionの部品の設定・Visual Expressionの設定・Renesas Debug Virtual Consoleの設定・コンソールのCOMポートの設定5投目 (ひたすら画面コピーです)・RXスマートコンフィグレータの設定以下、画面コピーと写真です。Renesas RX Simulatorで実行TB-RX65Nで実行RXスマートコンフィグレータに生成させた後に編集/追加したソース(右側のペイン)[履歴]sim_rx65n_freertos_proj_fit_scfg_ccrx_c_e2v750_20190924.zip・初版sim_rx65n_freertos_proj_fit_scfg_ccrx_c_e2v760_20191019.zip・MOTファイルは変わりません・VOLATILEマクロ追加(GNURX版との合わせ込み) 変更ファイル: src/smc_gen/r_config/r_bsp_config.h, src/sim_rx65n_int_emulation.c・machine.hファイル追加(CC-RX版では未使用)(GNURX版との合わせ込み) 追加ファイル: src/r_bsp_modified/GNURX_support/machine.h 変更ファイル: src/smc_gen/r_config/r_bsp_config.h・GNURX版でのワーニング対処の反映(GNURX版との合わせ込み) 変更ファイル: src/smc_gen/r_pincfg/Pin.c・スタック情報ファイルを生成するプロジェクト設定を追加 変更ファイル: .cproject・実機用の.lauchファイルを追加(当方特有の事情でオンボードエミュレータが使えない為に未確認です) 追加ファイル: "sim_rx65n_freertos_proj_fit HardwareDebug.launch", "tb_rx65n_freertos_proj_fit HardwareDebug.launch"等
こんにちは。NoMaYです。#5連投の2つ目です。今回のFreeRTOSプロジェクトの構造は以下の画面コピーの通りです。今回作成した割り込み動作エミュレート用の関数はRenesasRXSimDebugIntEmulation()ですが、以下のようにFreeRTOSのTickフックから呼び出すようにしました。これは、ここが一番手っ取り早そうだったのでそうしただけで、Tick割り込みでFreeRTOSのTickハンドラから戻って来たところで呼んでも良かったですし、あるいは別のタイマ割り込み(意図的にTick割り込みの1ms周期とは異なるようにして)から呼んでも良かったものです。src/frtos_startup/freertos_start.c
#if( configUSE_TICK_HOOK != 0 )void vApplicationTickHook(void){ /* Implement user-code for user own purpose. */#if defined(RENESAS_SIMULATOR_DEBUGGING) if (IsRenesasSimDebugMode()) { /* Renesas RX Simulator */ RenesasRXSimDebugIntEmulation(); }#endif} /* End of function vApplicationTickHook() */#endif /* configUSE_TICK_HOOK != 0 */
IRQ4割り込みは以下のようにエミュレートしました。完全なエミュレーションを行うつもりは無く、R_IRQ_RXモジュールが動けば良し(もしCGコンポーネントが動作しなかったら直す)、というレベルです。処理内容は、Visual ExpressionのBUTTON部品は押下時にメモリ/内蔵周辺レジスタの値を変更することしかしませんので、その値をチェックしてIRQ4のモードに応じて適宜int_exception( VECT(ICU, IRQ4) )を呼び出していることと、BUTTON部品は押下時(RELEASE→PUSH)しか値を変更しない(PUSH→RELEASEでは変更しない)ので、押されてから暫く経ったら、こちら側で値を戻していること、ぐらいです。(ちなみに、Visual ExpressionのLED部品は設定されたリフレッシュ間隔でメモリ/内蔵周辺レジスタの値を読み出して表示を変化させることしかしません。)src/sim_rx65n_int_emulation.c
static uint8_t PORTB_PIDR_BIT_B1_prev = 0; static uint16_t PORTB_PIDR_BIT_B1_time = 0; static bool PORTB_PIDR_BIT_B1_trig = false; switch (ICU.IRQCR[4].BIT.IRQMD) { case ICU_IRQCR_IRQMD_LOW_LEVEL: if (0 == PORTB.PIDR.BIT.B1) { PORTB_PIDR_BIT_B1_trig = true; } break; case ICU_IRQCR_IRQMD_FALLING_EDGE: if (1 == PORTB_PIDR_BIT_B1_prev && 0 == PORTB.PIDR.BIT.B1) { PORTB_PIDR_BIT_B1_trig = true; } break; case ICU_IRQCR_IRQMD_RISING_EDGE: if (0 == PORTB_PIDR_BIT_B1_prev && 1 == PORTB.PIDR.BIT.B1) { PORTB_PIDR_BIT_B1_trig = true; } break; case ICU_IRQCR_IRQMD_BOTH_EDGE: if (PORTB_PIDR_BIT_B1_prev != PORTB.PIDR.BIT.B1) { PORTB_PIDR_BIT_B1_trig = true; } break; default: /* Never come here */ break; } if (true == PORTB_PIDR_BIT_B1_trig && 0 != IEN(ICU, IRQ4)) { int_exception( VECT(ICU, IRQ4) ); PORTB_PIDR_BIT_B1_trig = false; } switch (ICU.IRQCR[4].BIT.IRQMD) { case ICU_IRQCR_IRQMD_LOW_LEVEL: case ICU_IRQCR_IRQMD_BOTH_EDGE: /* Keep the value of PORTB.PIDR.BIT.B1 */ break; case ICU_IRQCR_IRQMD_FALLING_EDGE: /* Invert the value of PORTB.PIDR.BIT.B1 automatically */ if (0 == PORTB.PIDR.BIT.B1) { if (VEDIAGRAM_BUTTON_AUTORECOVERY_TIME > PORTB_PIDR_BIT_B1_time) { PORTB_PIDR_BIT_B1_time++; } else if (VEDIAGRAM_BUTTON_AUTORECOVERY_TIME <= PORTB_PIDR_BIT_B1_time) { PORTB.PIDR.BIT.B1 = 1; PORTB_PIDR_BIT_B1_time = 0; } } break; case ICU_IRQCR_IRQMD_RISING_EDGE: /* Invert the value of PORTB.PIDR.BIT.B1 automatically */ if (1 == PORTB.PIDR.BIT.B1) { if (VEDIAGRAM_BUTTON_AUTORECOVERY_TIME > PORTB_PIDR_BIT_B1_time) { PORTB_PIDR_BIT_B1_time++; } else if (VEDIAGRAM_BUTTON_AUTORECOVERY_TIME == PORTB_PIDR_BIT_B1_time) { PORTB.PIDR.BIT.B1 = 0; PORTB_PIDR_BIT_B1_time = 0; } } break; default: /* Never come here */ break; } PORTB_PIDR_BIT_B1_prev = PORTB.PIDR.BIT.B1;
SCIのRXI1/TXI1/TEI1(前述の*3を参照)割り込みは以下のようにエミュレートしました。こちらも、完全なエミュレーションを行うつもりは無く、R_SCI_RXモジュールが動けば良し(もしCGコンポーネントが動作しなかったら直す)、というレベルです。処理内容は、Renesas Debug Virtual Consoleへ送信可能な状態ならばint_exception( VECT(SCI1, TXI1) )を呼び出した後にTDRを読んで値を送信して、Renesas Virtual Debug Consoleから受信到着の状態ならば、受信した値をRDRに書いた後にint_exception( VECT(SCI1, RXI1) )を呼び出して、というものです。また、送信終了割り込み許可ならばint_exception( VECT(ICU, GROUPBL0) )をIS6ビットを操作しながら呼び出すことも行っています。src/sim_rx65n_int_emulation.c
while (0 == (BSP_PRV_E1_DBG_PORT.dbgstat & BSP_PRV_TXFL0EN)) { if (0 != SCI1.SCR.BIT.TE && 0 != SCI1.SCR.BIT.TIE && 0 != IEN(SCI1, TXI1)) { int_exception( VECT(SCI1, TXI1) ); if (0 != SCI1.SCR.BIT.TIE) { BSP_PRV_E1_DBG_PORT.tx_data = (int32_t)SCI1.TDR; } } else { break; } } if (0 != SCI1.SCR.BIT.TE && 0 != SCI1.SCR.BIT.TEIE && 0 != IEN(ICU, GROUPBL0) && 0 != ICU.GENBL0.BIT.EN6) { ICU.GRPBL0.BIT.IS6 = 1; int_exception( VECT(ICU, GROUPBL0) ); if(0 == SCI1.SCR.BIT.TE || 0 == SCI1.SCR.BIT.TEIE) { ICU.GRPBL0.BIT.IS6 = 0; } } while (0 != (BSP_PRV_E1_DBG_PORT.dbgstat & BSP_PRV_RXFL0EN)) { if(0 != SCI1.SCR.BIT.RE && 0 != SCI1.SCR.BIT.RIE && 0 != IEN(SCI1, RXI1)) { SCI1.RDR = (uint8_t)BSP_PRV_E1_DBG_PORT.rx_data; int_exception( VECT(SCI1, RXI1) ); } else { break; } }
話は変わって、今回どうしたものかと思ったのは、FITモジュール端子設定関数をどこで呼ぼうかという点です。FreeRTOSプロジェクトでなければmain()の先頭で呼べば良いと思うのですが、FreeRTOSプロジェクトではmain()がありません。Processing_Before_Start_Kernel()内で呼び出すというのも、この関数ではFreeRTOSのスケジューラ起動前の処理を行うものという感があり、ちょっとしっくり来ません。CGコンポーネント初期化用のr_cg_hardware_setup.c内で、CGコンポーネント初期化関数を呼び出している近辺で呼び出したいところですが、ちょうどよいStart user code~End user codeがありません。そこで以下のように記述してみました。(赤文字の行で#defineマクロによる小細工をしています。)src/general/r_cg_hardware_setup.c
#include "r_cg_macrodriver.h"#include "r_smc_cgc.h"#include "r_smc_interrupt.h"/* Start user code for include. Do not edit comment generated here */#include "r_gpio_rx_if.h"#include "r_pinset.h"/* End user code. Do not edit comment generated here */#include "r_cg_userdefine.h" /* Start user code for global. Do not edit comment generated here *//* Workaround for missing a place to initialize pin settings for FIT modules */void R_Systeminit1(void);void R_Systeminit2(void);void R_Systeminit(void){ R_Systeminit1(); R_Systeminit2();}#define R_Systeminit R_Systeminit1/* End user code. Do not edit comment generated here */ void R_Systeminit(void){ /* Enable writing to registers related to operating modes, LPC, CGC and software reset */ SYSTEM.PRCR.WORD = 0xA50BU; /* Enable writing to MPC pin function control registers */ MPC.PWPR.BIT.B0WI = 0U; MPC.PWPR.BIT.PFSWE = 1U; /* Initialize clocks settings */ R_CGC_Create(); /* Register undefined interrupt */ R_BSP_InterruptWrite(BSP_INT_SRC_UNDEFINED_INTERRUPT,(bsp_int_cb_t)r_undefined_exception); /* Disable writing to MPC pin function control registers */ MPC.PWPR.BIT.PFSWE = 0U; MPC.PWPR.BIT.B0WI = 1U; /* Enable protection */ SYSTEM.PRCR.WORD = 0xA500U;}/* Start user code for adding. Do not edit comment generated here */void R_Systeminit2(void){ /* Initialize pin settings for FIT modules */ /* GPIO for LED0 and LED1 */ R_GPIO_PinWrite(GPIO_PORT_D_PIN_6, GPIO_LEVEL_HIGH); // for the initial level ...略... R_GPIO_PinWrite(GPIO_PORT_D_PIN_7, GPIO_LEVEL_HIGH); // for the initial level ...略... R_GPIO_PinDirectionSet(GPIO_PORT_D_PIN_6, GPIO_DIRECTION_OUTPUT); R_GPIO_PinDirectionSet(GPIO_PORT_D_PIN_7, GPIO_DIRECTION_OUTPUT); /* GPIO for SW1 */ R_GPIO_PinDirectionSet(GPIO_PORT_B_PIN_1, GPIO_DIRECTION_INPUT ); /* Others */ R_ICU_PinSet(); R_SCI_PinSet_SCI1();}/* End user code. Do not edit comment generated here */
それから、#defineマクロによる小細工つながりで、r_bspモジュールのソースを直接変更せずにRenesas RX Simulator用の無限ループ対処を組み込む(小細工というよりパズル的な)#defineマクロが思い浮かんだので使ってみました。Renesas RX Simulatorでデバッグしようとすると、r_bspモジュール内のoperating_frequency_set()内とrom_cache_function_set()内で、無限ループしてしまうので、以下の#defineマクロを使って、それらの呼び出しがバイパスされるようにしました。ミソは、それらを呼び出している/定義しているmcu_clock.cもhwsetup.cも変更すること無しにバイパスされるようになる、という点です。(なお、この(小細工というよりパズル的な)#defineマクロは引数がvoidである関数に対してしか使えません。)src/r_bsp_modified/sim_debug_mode_hook.h
#define operating_frequency_set(...) operating_frequency_setXXX##__VA_ARGS__()#define operating_frequency_setXXX() do{ if (!IsRenesasSimDebugMode()) { operating_frequency_set(); } }while(0)#define operating_frequency_setXXXvoid() operating_frequency_set(void)#define rom_cache_function_set(...) rom_cache_function_setXXX##__VA_ARGS__()#define rom_cache_function_setXXX() do{ if (!IsRenesasSimDebugMode()) { rom_cache_function_set(); } }while(0)#define rom_cache_function_setXXXvoid() rom_cache_function_set(void)
このヘッダファイルは以下のようにr_bsp_config.hでインクルードされるようにしてあります。src/smc_gen/r_config/r_bsp_config.h
/* For Renesas RX Simulator Debugging. */#if defined(RENESAS_SIMULATOR_DEBUGGING)#include "r_bsp_modified/sim_debug_mode_hook.h"#include "sim_rx65n_int_emulation.h"#endif
こんにちは。NoMaYです。#5連投の3つ目です。今回のFreeRTOSプロジェクトのタスクは以下の画面コピーの通りです。但し、ちょっとmain_task()は例外的であり、もともと、FreeRTOSプロジェクト生成時にメインのソース内に出力されたmain_task()が存在しており、かつ、その時点で、main_task()の生成処理もfreertos_start.c内のProcessing_Before_Start_Kernel()内に記述されていて、RXスマートコンフィグレータのFreeRTOS Objectと別扱いになっています。(FreeRTOSオブジェクトの場合は、各タスクのソースはfrtos_skeletonフォルダ内のタスク名.cに出力されており、また、各タスクの生成処理はfrtos_startupフォルダ内のfreertos_object_init.c内に出力されています。) とはいえ、main_task()も他タスクと同様にRXスマートコンフィグレータにFreeRTOS Objectとして表示させたいので、今回は、以下のように対処することにしました。src/frtos_skeleton/main_task.c
#include "task_function.h"/* Start user code for import. Do not edit comment generated here */#if 0/* End user code. Do not edit comment generated here */void main_task(void * pvParameters){/* Start user code for function. Do not edit comment generated here *//* End user code. Do not edit comment generated here */}/* Start user code for other. Do not edit comment generated here */#endif /* #if 0 *//* End user code. Do not edit comment generated here */
src/frtos_startup/freertos_start.c
void Processing_Before_Start_Kernel(void){#if 0 BaseType_t ret;#endif /* #if 0 */略#if 0 /************** task creation ****************************/ /* Main task. */ ret = xTaskCreate(main_task, "MAIN_TASK", 512, NULL, 3, NULL); if (pdPASS != ret) { while(1) { /* Failed! Task can not be created. */ } }#endif /* #if 0 */} /* End of function Processing_Before_Start_Kernel() */
但し、今回は、main_task()は以下の通りに空となっています。(空とは言え、CPU時間は消費しています。)src/tb_rx65n_main.c
#include "task_function.h" #include "freertos_start.h" #include "platform.h" void main_task(void *pvParameters) { INTERNAL_NOT_USED(pvParameters); /* Create all other application tasks here */ while(1); /* vTaskDelete(NULL); */ }
#include "task_function.h" /* Start user code for import. Do not edit comment generated here */ #include "freertos_start.h" #include "platform.h" #include "tbrx65ndef.h" /* End user code. Do not edit comment generated here */ void task_LED0(void * pvParameters) { /* Start user code for function. Do not edit comment generated here */ INTERNAL_NOT_USED( pvParameters ); LED0 = LED_ON; for (;;) { #if defined(RENESAS_SIMULATOR_DEBUGGING) if (IsRenesasSimDebugMode()) { /* Renesas RX Simulator */ vTaskDelay( pdMS_TO_TICKS( 50/*ms(as of the simulation time)*/ ) ); } else #endif { /* Hardware */ vTaskDelay( pdMS_TO_TICKS( 500/*ms*/ ) ); } LED0 = ~LED0; } /* End user code. Do not edit comment generated here */ } /* Start user code for other. Do not edit comment generated here */ /* End user code. Do not edit comment generated here */
#include "task_function.h" /* Start user code for import. Do not edit comment generated here */ #include "freertos_start.h" #include "platform.h" #include "r_irq_rx_if.h" #include "r_irq_rx_config.h" #include "tbrx65ndef.h" static void my_irq4_callback( void *pdata ); /* End user code. Do not edit comment generated here */ void task_LED1(void * pvParameters) { /* Start user code for function. Do not edit comment generated here */ INTERNAL_NOT_USED( pvParameters ); irq_err_t my_error_code; irq_handle_t my_irq4_handle; my_error_code = R_IRQ_Open( IRQ_NUM_4, IRQ_TRIG_FALLING, IRQ_PRI_2, &my_irq4_handle, my_irq4_callback ); if (IRQ_SUCCESS != my_error_code) { for(;;); /* TODO: Handle an error */ } LED1 = LED_OFF; for (;;) { xSemaphoreTake( semaphore_handle_SW1_PUSH, portMAX_DELAY ); /* Remove mechanical switch chattering */ #if defined(RENESAS_SIMULATOR_DEBUGGING) if (IsRenesasSimDebugMode()) { /* Renesas RX Simulator */ /* Nothing to do */ } else #endif { /* Hardware */ vTaskDelay( pdMS_TO_TICKS( 10/*ms*/ ) ); } xSemaphoreTake( semaphore_handle_SW1_PUSH, 0 ); if (SW1_PUSH == SW1) { LED1 = ~LED1; } } /* End user code. Do not edit comment generated here */ } /* Start user code for other. Do not edit comment generated here */ void my_irq4_callback(void *pdata) { INTERNAL_NOT_USED( pdata ); BaseType_t sHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR( semaphore_handle_SW1_PUSH, &sHigherPriorityTaskWoken ); portYIELD_FROM_ISR( sHigherPriorityTaskWoken ); } /* End user code. Do not edit comment generated here */
#include "task_function.h" /* Start user code for import. Do not edit comment generated here */ #include "freertos_start.h" #include "platform.h" #include "r_sci_rx_if.h" #include "r_sci_rx_config.h" #include "r_byteq_if.h" static uint16_t my_sci_rx_length = 0; static volatile uint16_t my_sci_rx_count = 0; static void my_sci_callback(void *pArgs); /* End user code. Do not edit comment generated here */ void task_CONIO(void * pvParameters) { /* Start user code for function. Do not edit comment generated here */ INTERNAL_NOT_USED( pvParameters ); sci_err_t my_sci_err; sci_hdl_t my_sci_handle; sci_cfg_t my_sci_config; uint8_t my_char[3]; my_sci_config.async.baud_rate = 115200; my_sci_config.async.clk_src = SCI_CLK_INT; my_sci_config.async.data_size = SCI_DATA_8BIT; my_sci_config.async.parity_en = SCI_PARITY_OFF; my_sci_config.async.parity_type = SCI_EVEN_PARITY; my_sci_config.async.stop_bits = SCI_STOPBITS_1; my_sci_config.async.int_priority = 3; // 1=lowest, 15=highest my_sci_err = R_SCI_Open(SCI_CH1, SCI_MODE_ASYNC, &my_sci_config, my_sci_callback, &my_sci_handle); if (SCI_SUCCESS != my_sci_err) { for(;;); /* TODO: Handle an error */ } for (;;) { taskENTER_CRITICAL(); // or taskDISABLE_INTERRUPTS() { // FIXME: This is a super ultra tentative code :( my_sci_rx_length = 3; my_sci_rx_count = 0; } taskEXIT_CRITICAL(); // or taskENABLE_INTERRUPTS() xSemaphoreTake( semaphore_handle_CON_RX_READY, portMAX_DELAY ); my_sci_err = R_SCI_Receive(my_sci_handle, my_char, my_sci_rx_length); if (SCI_SUCCESS != my_sci_err) { for(;;); /* TODO: Handle an error */ } my_sci_err = R_SCI_Send(my_sci_handle, my_char, my_sci_rx_length); if (SCI_SUCCESS != my_sci_err) { for(;;); /* TODO: Handle an error */ } } /* End user code. Do not edit comment generated here */ } /* Start user code for other. Do not edit comment generated here */ void my_sci_callback(void *pArgs) { sci_cb_args_t *args; args = (sci_cb_args_t *)pArgs; if (args->event == SCI_EVT_RX_CHAR) { /* From RXI interrupt; received character data is in args->byte */ my_sci_rx_count++; if (my_sci_rx_count == my_sci_rx_length) { BaseType_t sHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR( semaphore_handle_CON_RX_READY, &sHigherPriorityTaskWoken ); portYIELD_FROM_ISR( sHigherPriorityTaskWoken ); } else if (my_sci_rx_count > my_sci_rx_length) { /* Prevent from doing xSemaphoreGiveFromISR() more than once */ /* Nothing to do */ } } #if SCI_CFG_CH1_DATA_MATCH_INCLUDED else if (args->event == SCI_EVT_RX_CHAR_MATCH) { /* From RXI interrupt; received match character data is in args->byte */ nop(); } #endif #if SCI_CFG_TEI_INCLUDED else if (args->event == SCI_EVT_TEI) { /* From TEI interrupt; transmitter is idle Possibly disable external transceiver here */ nop(); } #endif else if (args->event == SCI_EVT_RXBUF_OVFL) { /* From RXI interrupt; rx queue is full; 'lost' data is in args->byte You will need to increase buffer size or reduce baud rate */ nop(); } else if (args->event == SCI_EVT_OVFL_ERR) { /* From receiver overflow error interrupt; error data is in args->byte Error condition is cleared in calling interrupt routine */ nop(); } else if (args->event == SCI_EVT_FRAMING_ERR) { /* From receiver framing error interrupt; error data is in args->byte Error condition is cleared in calling interrupt routine */ nop(); } else if (args->event == SCI_EVT_PARITY_ERR) { /* From receiver parity error interrupt; error data is in args->byte Error condition is cleared in calling interrupt routine */ nop(); } } /* End user code. Do not edit comment generated here */
こんにちは。NoMaYです。#5連投の4つ目です。以下、Renesas RX Simulator用のVisual ExpressionとRenesas Debug Virtual Consoleの設定、TB-RX65N用のコンソールのCOMポートの設定です。(ひたすら画面コピーです。) ちなみに、Visual Expressionの設定は、以下のファイルに自動的に保存され、デバッグ開始時に自動的に復元されるようになっていました。sim_rx65n_freertos_proj_fit_scfg/.settings/vediagram.xml
<?xml version="1.0"?> <Elements> <DIAGRAM> <VEModelDiagram.BackgroundGridLinesOption>true</VEModelDiagram.BackgroundGridLinesOption> <VEModelDiagram.BackgroundImageOption></VEModelDiagram.BackgroundImageOption> <VEModelDiagram.BackgroundImageStretchOption>true</VEModelDiagram.BackgroundImageStretchOption> </DIAGRAM> <IMAGE> <VEModelChildElement.LocationX>26</VEModelChildElement.LocationX> <VEModelChildElement.LocationY>26</VEModelChildElement.LocationY> <VEModelChildElement.SizeCX>124</VEModelChildElement.SizeCX> <VEModelChildElement.SizeCY>124</VEModelChildElement.SizeCY> <VEModelChildElement.expressionTitleVisible>true</VEModelChildElement.expressionTitleVisible> <VEModelChildElement.minRange>0.0</VEModelChildElement.minRange> <VEModelChildElement.maxRange>100.0</VEModelChildElement.maxRange> <VEModelChildElement.expressionName>PORTD.PODR.BIT.B6</VEModelChildElement.expressionName> <VEModelChildElement.expressionUpdatesDisabled>false</VEModelChildElement.expressionUpdatesDisabled> <VEModelChildElement.foregroundColor>16777215</VEModelChildElement.foregroundColor> <VEModelChildElement.backgroundColor>0</VEModelChildElement.backgroundColor> <VEModelImage.stretchImagesToFit>true</VEModelImage.stretchImagesToFit> <VEModelImage.rangeInputNumberFormat>Decimal</VEModelImage.rangeInputNumberFormat> <VEModelImage.rangeValues>1|To|1|icons/imageelement/LEDType1_square_grey.png|false</VEModelImage.rangeValues> <VEModelImage.rangeValues>0|To|0|icons/imageelement/LEDType1_square_green.png|false</VEModelImage.rangeValues> </IMAGE> <IMAGE> <VEModelChildElement.LocationX>176</VEModelChildElement.LocationX> <VEModelChildElement.LocationY>26</VEModelChildElement.LocationY> <VEModelChildElement.SizeCX>125</VEModelChildElement.SizeCX> <VEModelChildElement.SizeCY>124</VEModelChildElement.SizeCY> <VEModelChildElement.expressionTitleVisible>true</VEModelChildElement.expressionTitleVisible> <VEModelChildElement.minRange>0.0</VEModelChildElement.minRange> <VEModelChildElement.maxRange>100.0</VEModelChildElement.maxRange> <VEModelChildElement.expressionName>PORTD.PODR.BIT.B7</VEModelChildElement.expressionName> <VEModelChildElement.expressionUpdatesDisabled>false</VEModelChildElement.expressionUpdatesDisabled> <VEModelChildElement.foregroundColor>16777215</VEModelChildElement.foregroundColor> <VEModelChildElement.backgroundColor>0</VEModelChildElement.backgroundColor> <VEModelImage.stretchImagesToFit>true</VEModelImage.stretchImagesToFit> <VEModelImage.rangeInputNumberFormat>Decimal</VEModelImage.rangeInputNumberFormat> <VEModelImage.rangeValues>1|To|1|icons/imageelement/LEDType1_square_grey.png|false</VEModelImage.rangeValues> <VEModelImage.rangeValues>0|To|0|icons/imageelement/LEDType1_square_green.png|false</VEModelImage.rangeValues> </IMAGE> <PUSHBUTTON> <VEModelChildElement.LocationX>326</VEModelChildElement.LocationX> <VEModelChildElement.LocationY>25</VEModelChildElement.LocationY> <VEModelChildElement.SizeCX>124</VEModelChildElement.SizeCX> <VEModelChildElement.SizeCY>125</VEModelChildElement.SizeCY> <VEModelChildElement.expressionTitleVisible>true</VEModelChildElement.expressionTitleVisible> <VEModelChildElement.minRange>0.0</VEModelChildElement.minRange> <VEModelChildElement.maxRange>100.0</VEModelChildElement.maxRange> <VEModelChildElement.expressionName>PORTB.PIDR.BIT.B1</VEModelChildElement.expressionName> <VEModelChildElement.expressionUpdatesDisabled>false</VEModelChildElement.expressionUpdatesDisabled> <VEModelChildElement.foregroundColor>15790320</VEModelChildElement.foregroundColor> <VEModelChildElement.backgroundColor>0</VEModelChildElement.backgroundColor> <VEModelChildElement.numberFormat>Natural</VEModelChildElement.numberFormat> <VEModelPushButton.buttonName>BUTTON</VEModelPushButton.buttonName> <VEModelPushButton.injectionValue>0</VEModelPushButton.injectionValue> </PUSHBUTTON> </Elements>
こんにちは。NoMaYです。#5連投の5つ目です。以下、RXスマートコンフィグレータの設定です。(ひたすら画面コピーです。)
こんにちは。NoMaYです。e2 studioインストール時に一緒にStateViewerというツール(プラグイン)をインストールすることが出来るのですが、FreeRTOSのタスクやキューやタイマの状態を表示することが出来るので表示させてみたところ、以下の画面コピーのように表示されました。(なお、キューやタイマは使っていませんので表示は空です。)開き方は以下の画面コピーの通りです。(SafeRTOS Viewerの方ではなくOpenRTOS Viewerの方になります。)
こんにちは。NoMaYです。以下のAWSドキュメントによると、EclipseではFreeRTOSを使ったアプリケーションのデバッグの為のツール(プラグイン)としてStateViewer以外にもThreadSpyというもの(有償製品)が紹介されていたので、評価版をe2 studioにインストールしてみました。どうも、RX600自体には対応しているようなのですが、残念ながら、以下の画面コピーの通り、e2 studioのRenesas GDB Hardware DebuggingやRenesas Simulator Debuggingと組み合わせることは出来ないようです。開発者サポート - AWS ドキュメント » FreeRTOS Kernel » 開発者ガイド » docs.aws.amazon.com/ja_jp/freertos-kernel/latest/dg/developer-support.htmlThreadSpyはRemote FreeRTOS Applicationというデバッグ構成からしか使えないようでした
こんにちは。NoMaYです。e2 studioのスタック解析ウィンドウを開いてみました。(投稿したプロジェクトに対しリンクオプションを変更する必要があります。) この小さいサンプルプログラムでも350個程の関数(やアセンブラのシンボル)が表示されるので、ちょっと面食らいました。なお、以下はRenesas RX Simulator用プロジェクトのものですが、こちらの方は最適レベル0でコンパイルされたものです。(もう一方のTB-RX65N用プロジェクトは最適化レベル2でコンパイルされます。) ちなみに、関数情報の「属性」の意味は以下の通りです。・R (Runtime Library) 実行時ルーチン・O (Created by Optimization) 最適化作成関数・I (Interrupt) 割り込み関数・S (Static) 静的関数・V (Virtual) 仮想関数・L (Use Local Stack) ローカル・スタック使用関数画面コピーテキスト出力sim_rx65n_freertos_proj_fit_scfg_stackinfo.txtsim_rx65n_freertos_proj_fit_scfg_stackinfo_20190927.txtちゃんとした考察は後でやってみようと思いますが、差し当たり気になるのは以下の関数でしょうか、、、PowerON_Reset_PCtask_LED0task_LED1task_CONIOirq4_isrsci1_rxi1_isrsci1_txi1_isrgroup_bl0_handle_isrmy_irq4_callbackmy_sci_callback
こんにちは。NoMaYです。e2 studioのスタック解析ウィンドウに表示されるサンプルプログラムのスタック使用量ですが、コンパイル時の最適化レベルとして、最適化無し(レベル0)と最適化有り(レベル2)で、それぞれに対し、ちょっと値をメモしてみました。(ちゃんとした考察は後で(GNURX版のサンプルプログラムを作った後に)やってみようかと思っています。)直感的には最適化無しよりも最適化有りの方がスタック使用量は少なくなるだろうと思っていたのですが、例外(以下の表の赤文字箇所)もあるのですね。それと、あぁ、と思ったのが、ソースレベルデバッグ時には最適化無しにすると思いますが、そのことは(以下の赤文字箇所のような例外はあるけれども)結局のところ、スタックは最適化無しでのサイズを確保しておかざるを得ないのだよなぁ、、、ということでした。スタック解析ウィンドウ表示されたスタック使用量 (赤文字箇所は最適化無しよりも最適化有りの方が多い)
TB版
こんにちは。NoMaYです。RL78/G14 Fast Prototyping Boardで、同じようなSample Programを、チョコさんのリングバッファのソースコードを使って作ろうとしていたところ、RTOS使用時は、そのソースの通常処理側と割り込み処理側の排他制御のやり方を変えないと拙い、ということに気付きました。そして、それはFITでも同様な筈なのでは、と気付きました。(FITには、以前からFreeRTOSパッケージがありますが、その時点から対策されていなかったのでは無いでしょうか、、、)RTOS未使用時は大丈夫だけれどもRTOS使用時は拙い排他制御のやり方(通常処理側と割り込み処理側の排他制御)・個別の割り込みマスクフラグを使用して割り込み一旦禁止と割り込み再度許可を行う理由・RTOSによるタスク切り替えが上記による割り込み禁止期間中に発生すると禁止期間がミリ秒オーダーになってしまう(タスク切り替えにより暫くの間は他タスクに行ってしまうから)対応・RTOS側で用意されているクリティカルセクションへの出入り関数(FreeRTOSならtaskENTER_CRITICAL()とtaskEXIT_CRITICAL()など)を使用するように手を加える具体的には、チョコさんのリングバッファのソースコードですと、以下のような置き換えをする必要があります。(以下の場所以外にもあります。なお、RL78のFreeRTOSでは両出入り関数はDIとEIに帰着されるので、以下のように単純化してあります。他マイコンなどでは、可能性として、割り込み優先順位を操作することで、クリティカルセクション内でも通信割り込みを受け付けられるようにする実装も有り得ると思います。その場合は、以下のような単なる置き換えにならないこともあるかと思います。)RL78のUARTへのリングバッファ追加/UART_3/UART0.c
/******************************************************************************** Function Name: get_blk* Description : リングバッファから指定されたデータを読み出す(転送)* Arguments : 格納ポインタ,データ数* Return Value : 残りデータ数*******************************************************************************/uint8_t get_blk(uint8_t * const buff, uint8_t number){ uint8_t work; uint8_t cnt; /* 転送用カウンタ */ uint8_t * gp_buff; /* 転送用ポインタ */ work = number; /* 要求データ数をセット */ if ( ( 0 != number ) && ( 0 != g_rx_dtno ) ) { /* 転送データがある場合 */ gp_buff = buff; /* 転送先ポインタを設定 *//* --------------------------------------------------------------------------- 転送データ数を算出----------------------------------------------------------------------------*/ if ( number < g_rx_dtno ) { /* 要求数がデータ量以下の場合 */ cnt = number; /* 転送データ数をセット */ work = 0; /* 残りデータ数は0にする */ } else { /* 要求数がデータ量以上の場合 */ cnt = g_rx_dtno; /* 転送数はバッファ内の全て */ work = number - g_rx_dtno; /* 残りデータ数を算出 */ }/* --------------------------------------------------------------------------- データを転送----------------------------------------------------------------------------*/ for ( ; cnt > 0 ; cnt-- ) { *gp_buff = g_rx_buff[g_rx_rdpt]; /* リングバッファから転送 */ SRMK0 = 1; /* INTSR0との排他制御 */ taskENTER_CRITICAL(); g_rx_rdpt++; /* 読み出しポインタを更新 */ g_rx_rdpt &= 0x0F; g_rx_dtno--; /* データ数を-1 */ SRMK0 = 0; /* INTSR0との排他制御終了 */ taskEXIT_CRITICAL(); gp_buff++; /* 転送ポインタを更新 */ } } return( work );}
また、FITのR_SCI_RXモジュールにも同様な場所があります。r_sci_rx/src/r_sci_rx.c
#if (SCI_CFG_ASYNC_INCLUDED)/****************************************************************************** Function Name: sci_receive_async_data* Description : This function determines if the rx byte queue of the channel * referenced by the handle, the requested number of bytes * is available, and get the data from the rx byte queue.* Arguments : hdl -* handle for channel (ptr to chan control block)* p_dst -* ptr to buffer to load data into* length - * number of bytes to read* Return Value : SCI_SUCCESS -* requested number of byte loaded into p_dst* SCI_ERR_INSUFFICIENT_DATA -* rx queue does not contain requested amount of data******************************************************************************/static sci_err_t sci_receive_async_data(sci_hdl_t const hdl, uint8_t *p_dst, uint16_t const length){ sci_err_t err = SCI_SUCCESS; uint16_t cnt; byteq_err_t byteq_err = BYTEQ_SUCCESS; /* CHECK FOR SUFFICIENT DATA IN QUEUE, AND FETCH IF AVAILABLE */ R_BYTEQ_Used(hdl->u_rx_data.que, &cnt); if (cnt < length) { return SCI_ERR_INSUFFICIENT_DATA; } /* Get bytes from rx queue */ /* WAIT_LOOP */ for (cnt = 0; cnt < length; cnt++) { /* Disable RXI Interrupt */ DISABLE_RXI_INT; byteq_err = R_BYTEQ_Get(hdl->u_rx_data.que, p_dst++); ENABLE_RXI_INT; if (BYTEQ_SUCCESS != byteq_err) { err = SCI_ERR_INSUFFICIENT_DATA; break; } } return err;} /* End of function sci_receive_async_data() */#endif /* SCI_CFG_ASYNC_INCLUDED */
r_sci_rx\src\targets\rx65n/r_sci_rx65n_private.h
/* Macros to enable and disable ICU interrupts */#define ENABLE_RXI_INT (*hdl->rom->icu_rxi |= hdl->rom->rxi_en_mask)#define DISABLE_RXI_INT (*hdl->rom->icu_rxi &= (uint8_t)~hdl->rom->rxi_en_mask)#define ENABLE_TXI_INT (*hdl->rom->icu_txi |= hdl->rom->txi_en_mask)#define DISABLE_TXI_INT (*hdl->rom->icu_txi &= (uint8_t)~hdl->rom->txi_en_mask)#define ENABLE_ERI_INT (*hdl->rom->icu_grp |= hdl->rom->eri_ch_mask)#define DISABLE_ERI_INT (*hdl->rom->icu_grp &= ~hdl->rom->eri_ch_mask)#define ENABLE_TEI_INT (*hdl->rom->icu_grp |= hdl->rom->tei_ch_mask)#define DISABLE_TEI_INT (*hdl->rom->icu_grp &= ~hdl->rom->tei_ch_mask)
ここは、以下のようにする必要があったのかな、と思います。(たぶんRXI以外は、取りこぼし、という話は無さそうに思いますので、そのままでよさそうに思います。なお、通信割り込みの優先順位を上げていると、以下のような単なる置き換えにならないこともあるかと思います。)r_sci_rx\src\targets\rx65n/r_sci_rx65n_private.h
/* Macros to enable and disable ICU interrupts */#if BSP_CFG_RTOS_USED == 0 /* Non-OS */#define ENABLE_RXI_INT (*hdl->rom->icu_rxi |= hdl->rom->rxi_en_mask)#define DISABLE_RXI_INT (*hdl->rom->icu_rxi &= (uint8_t)~hdl->rom->rxi_en_mask)#elif BSP_CFG_RTOS_USED == 1 /* FreeRTOS */#define ENABLE_RXI_INT taskEXIT_CRITICAL()#define DISABLE_RXI_INT taskENTER_CRITICAL()#elif BSP_CFG_RTOS_USED == 2 /* SEGGER embOS */#error#elif BSP_CFG_RTOS_USED == 3 /* Micrium MicroC/OS */#error#elif BSP_CFG_RTOS_USED == 4 /* Renesas RI600V4 & RI600PX */#error#endif#define ENABLE_TXI_INT (*hdl->rom->icu_txi |= hdl->rom->txi_en_mask)#define DISABLE_TXI_INT (*hdl->rom->icu_txi &= (uint8_t)~hdl->rom->txi_en_mask)#define ENABLE_ERI_INT (*hdl->rom->icu_grp |= hdl->rom->eri_ch_mask)#define DISABLE_ERI_INT (*hdl->rom->icu_grp &= ~hdl->rom->eri_ch_mask)#define ENABLE_TEI_INT (*hdl->rom->icu_grp |= hdl->rom->tei_ch_mask)#define DISABLE_TEI_INT (*hdl->rom->icu_grp &= ~hdl->rom->tei_ch_mask)
[追記]単にヘッダファイルのマクロを置き換えるというのは、ちょっと横着だったかも知れません。Cファイル側で以下のような記述を追加して、RTOS毎に切り替えるのが良いのかも知れません。(RZマイコンのOS Abstraction layerとか、どうしているのかな、、、)r_sci_rx/src/r_sci_rx.c
#if (SCI_CFG_ASYNC_INCLUDED)...略...static sci_err_t sci_receive_async_data(sci_hdl_t const hdl, uint8_t *p_dst, uint16_t const length){ ...略... /* Get bytes from rx queue */ /* WAIT_LOOP */ for (cnt = 0; cnt < length; cnt++) { /* Disable RXI Interrupt */ BSP_CFG_RTOS_ENTER_CRITICAL_FUNCTION(); DISABLE_RXI_INT; byteq_err = R_BYTEQ_Get(hdl->u_rx_data.que, p_dst++); ENABLE_RXI_INT; BSP_CFG_RTOS_EXIT_CRITICAL_FUNCTION(); if (BYTEQ_SUCCESS != byteq_err) { err = SCI_ERR_INSUFFICIENT_DATA; break; } } ...略...} /* End of function sci_receive_async_data() */#endif /* SCI_CFG_ASYNC_INCLUDED */
r_config/r_bsp_config.h
#if BSP_CFG_RTOS_USED == 0 /* Non-OS */#define BSP_CFG_RTOS_ENTER_CRITICAL_FUNCTION() /* nothing */#define BSP_CFG_RTOS_EXIT_CRITICAL_FUNCTION() /* nothing */#elif BSP_CFG_RTOS_USED == 1 /* FreeRTOS */#define BSP_CFG_RTOS_ENTER_CRITICAL_FUNCTION() taskENTER_CRITICAL()#define BSP_CFG_RTOS_EXIT_CRITICAL_FUNCTION() taskEXIT_CRITICAL()#elif BSP_CFG_RTOS_USED == 2 /* SEGGER embOS */#error#elif BSP_CFG_RTOS_USED == 3 /* Micrium MicroC/OS */#error#elif BSP_CFG_RTOS_USED == 4 /* Renesas RI600V4 & RI600PX */#error#endif