こんにちは。NoMaYです。別スレッドで、AWSドキュメントサイト内にFreeRTOS kernelの開発者ガイドの日本語版が載っていることに気付いたのですが、その中に含まれているCコード例をルネサスRXシミュレータで試せたら面白そうだと思い、やってみました。まずはCC-RX(CS+/e2 studio)版です。後日GNURX(e2 studio)版もやろうと思います。以下、プロジェクトのファイル一式です。(CS+ V8.01+CC-RX V2.03でビルド)(e2 studio用.project/.cproject等を同梱(zipファイルをe2 studioに直接インポート可能))sim_rx65n_freertos_ccrx_c_csplus_20190526.zipやったこと(主なもの)(1) FreeRTOS kernelがルネサスRXシミュレータの未対応機能を使っていたので無理矢理に対応機能のみ使うように小細工(2) Full DemoからルネサスRXシミュレータの未対応機能を使っている項目を除外(3) ルネサスRXシミュレータではBSPモジュール内で無限ループしてしまう点を回避(4) 開発者ガイドのCコード例で使われているvPrintString()をDebug Consoleへ出力するように作成(5) Full Demo/Simple Blinky Demo/Cコード例でvAssertCalled()呼び出し時にDebug Consoleへメッセージを出力(6) Full Demo/Simple Blinky DemoでLEDのOn/OffのタイミングでDebug ConsoleへOn/Offのメッセージを出力(7) 開発者ガイドのCコード例が動くようにルネサスRXシミュレータの起動設定を変更(私の個人的な好みを含む)(8) 開発者ガイドのCコード例をビルドする時には不要なデモソースをビルドから除外したプロジェクトを作成(CS+のみ)(9) 開発者ガイドのCコード例をビルドするプロジェクトではコンパイル時の最適化レベルを0に変更(CS+のみ)以下、FreeRTOS kernelの開発者ガイドのCコード例をルネサスRXシミュレータで動かした時の画面コピーです。(上記の(8)のプロジェクトです。)FreeRTOS kernelの開発者ガイドではFreeRTOS Windowsシミュレータで実行docs.aws.amazon.com/ja_jp/freertos-kernel/latest/dg/task-management.htmlルネサスRXシミュレータで実行ビルドした時のビルド設定とビルド結果zipファイルには、開発者ガイドのCコード例をビルドするプロジェクト(CS+のみ)の他に、別スレッドに投稿した、RX65N TBボードで動く(といってもデバッグ中ではありますが)Full Demo/Simple Blinky Demoをビルドするプロジェクトも含まれています。(上記の(2)で除外している項目はありますが。) 以下、それらの画面コピーです。CS+e2 studio
こんにちは。NoMaYです。#前の投稿の続きです以下、やったこと(主なもの)の詳細です。(1) FreeRTOS kernelがルネサスRXシミュレータの未対応機能を使っていたので無理矢理に対応機能のみ使うように小細工FreeRTOS kernelではRXマイコンのSWINT割り込みを使っていますが、ルネサスRXシミュレータでは未対応となっています。そこで、ルネサスRXシミュレータが対応してるCMT割り込みの1つで無理矢理代替しました。(以下の青文字部分) なお、この無理矢理な代替実装ですが、一応、実機でも動きます。zipファイル内のMOTファイルは、この代替実装でFull Demo(除外項目あり)をビルドしたものです。RX65N TBボードで動きます。src/FreeRTOS/Source/portable/Renesas/RX600v2/port_asm.src
.if RENESAS_SIMULATOR_DEBUGGING == 0 .RVECTOR 27, _vSoftwareInterruptEntry.else .RVECTOR 29, _vSoftwareInterruptEntry.endif
src/FreeRTOS/Source/portable/Renesas/RX600v2/port.c
BaseType_t xPortStartScheduler( void ){extern void vApplicationSetupTimerInterrupt( void ); /* Use pxCurrentTCB just so it does not get optimised away. */ if( pxCurrentTCB != NULL ) { /* Call an application function to set up the timer that will generate the tick interrupt. This way the application can decide which peripheral to use. A demo application is provided to show a suitable example. */ vApplicationSetupTimerInterrupt();#if !defined(RENESAS_SIMULATOR_DEBUGGING) || RENESAS_SIMULATOR_DEBUGGING == 0 /* Enable the software interrupt. */ _IEN( _ICU_SWINT ) = 1; /* Ensure the software interrupt is clear. */ _IR( _ICU_SWINT ) = 0; /* Ensure the software interrupt is set to the kernel priority. */ _IPR( _ICU_SWINT ) = configKERNEL_INTERRUPT_PRIORITY;#else /* The Renesas Simulator for RX does not support the software interrupt. Therefore the CMT channel 1 interrupt is used for the yield interrupt. */ /* Protect off. */ SYSTEM.PRCR.WORD = 0xA502; /* Enable the compare match timer 1. */ MSTP( CMT1 ) = 0; /* Protect on. */ SYSTEM.PRCR.WORD = 0xA500; /* Stop the timer 1. */ CMT.CMSTR0.BIT.STR1 = 0; /* Set the compare match value. */ CMT1.CMCOR = 1; /* Clear counter. */ CMT1.CMCNT = 0; /* Disable interrupt on compare match. (Divide the PCLK by 8.) */ CMT1.CMCR.WORD = 0x0080; /* Ensure the timer 1 interrupt is set to the kernel priority. */ IPR(CMT1, CMI1) = configKERNEL_INTERRUPT_PRIORITY; /* Ensure the timer 1 interrupt is clear. */ IR(CMT1, CMI1) = 0; /* Enable the timer 1 interrupt. */ IEN(CMT1, CMI1) = 1; /* Start the timer 1. */ CMT.CMSTR0.BIT.STR1 = 1;#endif /* Start the first task. */ prvStartFirstTask(); } /* Just to make sure the function is not optimised away. */ ( void ) vSoftwareInterruptISR(); /* Should not get here. */ return pdFAIL;}
src/FreeRTOS/Source/portable/Renesas/RX600v2/portmacro.h
#pragma inline_asm vPortYieldstatic void vPortYield( void ){#if !defined(RENESAS_SIMULATOR_DEBUGGING) || RENESAS_SIMULATOR_DEBUGGING == 0 /* Save clobbered register - may not actually be necessary if inline asm functions are considered to use the same rules as function calls by the compiler. */ PUSH.L R5 /* Set ITU SWINTR. */ MOV.L #553696, R5 MOV.B #1, [R5] /* Read back to ensure the value is taken before proceeding. */ MOV.L [R5], R5 /* Restore clobbered register to its previous value. */ POP R5#else /* Disable the timer 1 interrupt. */ /* _IEN( _CMT1_CMI1 ) = 0; */ MOV.L #00087203H, R14 BCLR #05H, [R14].B /* Read back and test to complete a write access here. */ /* if( _IEN( _CMT1_CMI1 ) == 0 ){}else{} */ BTST #05H, [R14].B /* Enable interrupt on compare match. (Divide the PCLK by 8.) */ /* CMT1.CMCR.WORD = 0x00C0; */ MOV.L #00088008H, R15 MOV.W #00C0H, [R15] /* Wait for the timer 1 interrupt request. */ /* while( _IR( _CMT1_CMI1 ) == 0 ){} */ MOV.L #0008701DH, R5?: BTST #00H, [R5].B BEQ ?- /* Disable interrupt on compare match. (Divide the PCLK by 8.) */ /* CMT1.CMCR.WORD = 0x0080; */ MOV.W #0080H, [R15] /* Enable the timer 1 interrupt. */ /* _IEN( _CMT1_CMI1 ) = 1; */ BSET #05H, [R14].B /* Read back and test to complete a write access here. */ /* if( _IEN( _CMT1_CMI1 ) == 1 ){}else{} */ BTST #05H, [R14].B#endif}#define portYIELD() vPortYield()#define portYIELD_FROM_ISR( x ) if( x != pdFALSE ) portYIELD()
(2) Full DemoからルネサスRXシミュレータの未対応機能を使っている項目を除外Full Demoの中にRXマイコンのTPUを使って実装されている項目がありますが、ルネサスRXシミュレータではTPUは未対応となっていますので、その項目を除外しました。(以下の青文字部分) src/FreeRTOS/Demo/Full_Demo/main_full.c
void main_full( void ){ ...略...#if !defined(RENESAS_SIMULATOR_DEBUGGING) || RENESAS_SIMULATOR_DEBUGGING == 0 vStartInterruptQueueTasks();#endif ...略...}
static void prvCheckTask( void *pvParameters ){ ...略... for( ;; ) { ...略...#if !defined(RENESAS_SIMULATOR_DEBUGGING) || RENESAS_SIMULATOR_DEBUGGING == 0 if( xAreIntQueueTasksStillRunning() != pdTRUE ) { pcStatusMessage = "Error: IntQueue"; }#endif ...略... }}
(3) ルネサスRXシミュレータではBSPモジュール内で無限ループしてしまう点を回避ルネサスRXシミュレータはクロック系の内蔵周辺機能にも未対応ですが、そのことによりBSPモジュールのresetprg.cのoperating_frequency_set()内で無限ループしてしまいます。今回の無理矢理な代替実装でも実機で動きますので、単に条件コンパイルでoperating_frequency_set()呼び出しを除外するのではなく、以下のようにrenesas_simulator_debugging_keyという変数で動的に呼び出しを除外出来るようにしておき、デバッガでのルネサスRXシミュレータへのダウンロード時にデバッガの機能で変数の値を書き換えてしまうやり方を取ってみました。src/r_bsp_modified/resetprg.c
/* Switch Key for Renesas Simulator Debugging */#ifdef RENESAS_SIMULATOR_DEBUGGINGconst volatile uint32_t renesas_simulator_debugging_key = 0xFFFFFFFF; // non 0x00000001 is emulator, 0x00000001 is simulator#endif
void PowerON_Reset_PC(void){ ...略... /* Switch to high-speed operation */#ifndef RENESAS_SIMULATOR_DEBUGGING operating_frequency_set();#else if (renesas_simulator_debugging_key != 0x00000001) { operating_frequency_set(); }#endif ...略...}
CS+でダウンロード時に値を書き換えるにはダウンロード後のフック関数にPythonスクリプトを記述します。sim_rx65n_freertos_dev_guide_debug.py / sim_rx65n_freertos_full_demo.py
...略...def AfterDownload(): if debugger.DebugTool.GetType() == DebugTool.Simulator: debugger.Watch.SetValue('renesas_simulator_debugging_key', 0x00000001) return
e2 studioでダウンロード時に値を書き換えるにはデバッグ構成の[Starup]の[コマンドを実行]にGDBコマンドを記述します。
set renesas_simulator_debugging_key=0x00000001
(4) 開発者ガイドのCコード例で使われているvPrintString()をDebug Consoleへ出力するように作成
BPSモジュールではcharput()がDebug Consoleへ出力するようになっていますので以下のように記述しました。src/frtos_startup/freertos_start.c
void vPrintString(const char *pcMessage){ /* Write the string to the Debug Console, using a critical section as a crude method of mutual exclusion. *///#ifdef RENESAS_SIMULATOR_DEBUGGING //if( renesas_simulator_debugging_key == 0x00000001 ) { taskENTER_CRITICAL(); { while( *pcMessage ) { charput(*pcMessage++); } } taskEXIT_CRITICAL(); }//#endif} /* End of function vPrintString() */
(5) Full Demo/Simple Blinky Demo/Cコード例でvAssertCalled()呼び出し時にDebug Consoleへメッセージを出力vAssertCalled()に以下を追加しました。(青文字部分)src/frtos_startup/freertos_start.c
void vAssertCalled(void){ volatile unsigned long ul = 0; taskENTER_CRITICAL(); { vPrintString( "Assertion failed!\r\n" ); /* Use the debugger to set ul to a non-zero value in order to step out of this function to determine why it was called. */ while( 0 == ul ) { portNOP(); } } taskEXIT_CRITICAL();} /* End of function vAssertCalled() */
(6) Full Demo/Simple Blinky DemoでLEDのOn/OffのタイミングでDebug ConsoleへOn/Offのメッセージを出力vParTestInitialise()とvParTestSetLED()に以下を追加しました。(青文字部分)src/FreeRTOS/Demo/ParTest.c
void vParTestInitialise( void ){ /* First set the data levels. */ LED0 = LED_OFF; LED1 = LED_OFF; vPrintString( "LED0 off\r\n" ); vPrintString( "LED1 off\r\n" );}
void vParTestSetLED( unsigned long ulLED, signed long xValue ){ if( ulLED < partestNUM_LEDS ) { if( xValue != 0 ) { /* Turn the LED on. */ taskENTER_CRITICAL(); { switch( ulLED ) { case 0: LED0 = LED_ON; vPrintString( "LED0 on\r\n" ); break; case 3: LED1 = LED_ON; vPrintString( "LED1 on\r\n" ); break; default:/* No LEDs to do */ break; } } taskEXIT_CRITICAL(); } else { /* Turn the LED off. */ taskENTER_CRITICAL(); { switch( ulLED ) { case 0: LED0 = LED_OFF; vPrintString( "LED0 off\r\n" ); break; case 3: LED1 = LED_OFF; vPrintString( "LED1 off\r\n" ); break; default:/* No LEDs to do */ break; } } taskEXIT_CRITICAL(); } }}
(7) 開発者ガイドのCコード例が動くようにルネサスRXシミュレータの起動設定を変更(私の個人的な好みを含む)以下、画面コピーです。CS+ (トレース機能/カバレッジ機能はデバッグ画面の右下のボタンで容易にOn/Offが可能)e2 studio ([トレース・キャプチャー]というのが何のことか分からないのでデフォルトの[はい]のまま)(8) 開発者ガイドのCコード例をビルドする時には不要なデモソースをビルドから除外したプロジェクトを作成(CS+のみ)CS+のsim_rx65n_freertos_dev_guide_debugプロジェクトではsrc/FreeRTOS/Demo/フォルダから下を丸ごとビルドから除外しました。(9) 開発者ガイドのCコード例をビルドするプロジェクト(CS+のみ)ではコンパイル時の最適化レベルを0に変更実は、自分自身、デバッグする時に嵌ってしまっていたのでコンパイル時の最適化レベルを0に変更しました。