こんにちは。NoMaYです。別スレッド『Amazon AWSのFreeRTOS Kernel Developer GuideのサンプルコードをRenesas RX SimulatorのDebug Consoleで試せるようにしてみた』で気付いたことですが、FreeRTOSでは、ポートレイヤーの実装に内蔵周辺のソフトウェア割り込み機能(これはCPUのソフトウェア割り込み命令のことでは無いです)を使用することで、素朴に簡単に割り込みルーチンからFreeRTOS APIを呼び出せるようになることに気付きました。そこで、FreeRTOS v10.2.1 RL78ポートレイヤーをそのように改変してみました。以下、プロジェクトのファイル一式です。(CC-RL版はCS+ V8.01/e2 stuiod v7.40+CC-RL V1.02でビルド(e2 studio用.project/.cproject等を同梱))(GNURL78版はe2 studio v7.40+GNURL78 2019q2(4.9.2.201902)でビルド)(共にzipファイルをe2 studioに直接インポート可能) プロジェクト構造は極力RX版と同じにしてあります。([追記] すみません。以下に含まれるMAPファイルが別のものでした。タスク側のクリティカルセクションが以前のままのものでした。この投稿の末尾に追加したMOTファイルのzipファイルには訂正版を入れてあります。)sim_rl78_freertos_full_demo_ccrl_c_csplus_20190705.zip 628KBsim_rl78_freertos_full_demo_gnurl78_c_e2v740_20190705.zip 582KBそのスレッドに投稿していたRL78ポートレイヤー(これもFreeRTOS v10.2.1 RL78ポートレイヤーを改変したものです)では、割り込みルーチンからFreeRTOS APIを呼び出すには以下のような特別なおまじないを記述する必要がありました。(以下はCC-RLの場合のものですがGNURL78でも同様です。)
#pragma interrupt r_intc3_interrupt(vect=INTP3)/* Start user code for pragma. Do not edit comment generated here */R_PRAGMA_FREERTOS_INTERRUPT(r_intc3_interrupt)#define r_intc3_interrupt _r_intc3_interrupt/* End user code. Do not edit comment generated here */
そのスレッドにはRXポートレイヤーの改変についても投稿していたのですが、その時、最初に書いたことに気付きました。RL78の内蔵周辺には専用のソフトウェア割り込み機能はありませんが、以下のハードウェアマニュアルに記載されている通り、プログラムで割り込み要求フラグをセットすると割り込みを発生させることが出来ますので、実質的に任意の空き割り込みをソフトウェア割り込み機能として使うことが出来ます。(今回は、とりあえず、ウォッチドッグタイマのオーバフロー時間の75%到達のインターバル割り込みを使用してみました。) RL78/G13 ユーザーズマニュアル ハードウェア編からの抜粋www.renesas.com/ja-jp/doc/products/mpumcu/doc/rl78/r01uh0146jj0340_rl78g13.pdfなお、今回のRL78ポートレイヤーの改変で、先ほどの特別なおまじないを記述する必要は無くなりますが、割り込みルーチンからFreeRTOS APIを呼び出してブロック解除待ちタスクをブロック解除する場合のタスク切り替えの遅延時間が以下のRenesas RL78 SimulatorのSimulator GUIの画面コピーのように数十クロックほど(32MHz動作では600nsほど)延びます。(以下はCC-RLの場合のものですがGNURL78でも同様(ただし数百nsほど長い)です。) ちなみに、タスク側のクリティカルセクション(その区間では割り込み禁止となる)への出入りによるタイミングへの影響を避ける為、今回はクリティカルセクションとして扱うことしていませんので、以下の画面コピーでは別スレッドの画面コピーよりもポート出力トグルの速さが速くなっています。今回の改変前:今回の改変後:以下、今回のRL78ポートレイヤの改変内容です。コメントの訂正や不要になったルーチンの削除は省略しています。(以下はCC-RLの場合のものですがGNURL78でも同様です。)src/FreeRTOS/Source/portable/Renesas/RL78/portmacro.h今回の改変前:
/* Task utilities. */#define portYIELD() __brk()#define portYIELD_FROM_ISR( xHigherPriorityTaskWoken ) if( xHigherPriorityTaskWoken ) vTaskSwitchContext()#define portNOP() __nop()
今回の改変後: 赤文字行を追加/変更
#include "iodefine.h"
/* Task utilities. */#define portYIELD() do{ WDTIIF = 1; } while (0)#define portYIELD_FROM_ISR( xHigherPriorityTaskWoken ) if( xHigherPriorityTaskWoken ) portYIELD()#define portNOP() __nop()
src/FreeRTOS/Source/portable/Renesas/RL78/port.c今回の改変後: 赤文字行を追加
BaseType_t xPortStartScheduler( void ){ /* Setup the hardware to generate the tick. Interrupts are disabled when this function is called. */ configSETUP_TICK_INTERRUPT(); /* Setup the hardware to generate the yield interrupt. */ WDTIPR1 = 1; WDTIPR0 = 1; WDTIMK = 0; /* Restore the context of the first task that is going to run. */ vPortStartFirstTask(); /* Execution should not reach here as the tasks are now running! */ return pdTRUE;}
src/FreeRTOS/Source/portable/Renesas/RL78/portasm.asm今回の改変前:
_vPortYield: portSAVE_CONTEXT ; Save the context of the current task. call@ _vTaskSwitchContext ; Call the scheduler to select the next task. portRESTORE_CONTEXT ; Restore the context of the next task to run. retb
_vPortYield .VECTOR 0x7E
今回の改変後: 赤文字行を変更
_vPortYield: portSAVE_CONTEXT ; Save the context of the current task. call@ _vTaskSwitchContext ; Call the scheduler to select the next task. portRESTORE_CONTEXT ; Restore the context of the next task to run. reti
_vPortYield .VECTOR 0x04
以下、今回のタスク側のプログラムです。先ほど書いた通り、今回は各タスクのポート出力をトグルさせる部分をクリティカルセクションとして扱うことしていません。(なお、src/frtos_config/FreeRTOSConfig.hの#define FREERTOS_USER_MAIN 0の行で0→1の変更を行うことで以下が実行されるようになります。)src/user_main.c
void main_task(void *pvParameters){ (void) pvParameters; while (1) { P1_bit.no6 = !P1_bit.no6; }}void second_task(void *pvParameters){ (void) pvParameters; while (1) { P1_bit.no5 = !P1_bit.no5; }}void third_task(void *pvParameters){ (void) pvParameters; while (1) { P1_bit.no4 = !P1_bit.no4; }}void intp3_task(void *pvParameters){ (void) pvParameters; R_INTC3_Start(); LED_INIT(); while (1) { xSemaphoreTake( xSemaphoreINTP3, portMAX_DELAY ); LED_BIT = !LED_BIT; }}
[追記]MOTファイルsim_rl78_freertos_full_demo_ccrl_c_csplus_20190705_mot.zip 2019/07/12追加sim_rl78_freertos_full_demo_gnurl78_c_e2v740_20190705_mot.zip 2019/07/24追加
こんにちは。NoMaYです。昨日のラッパーマクロですが、mapファイルの内容が少し分かり易くなるかなと思い、ちょっと変更してみました。あと、FreeRTOS kernelのAPI関数のスタックサイズの尺度は4バイト単位(RX)だったり2バイト単位(RL78)だったりするのですが、何ヶ月経っても慣れません(違和感が無くなりません)ので、1バイト単位の数値をFreeRTOS kernelの流儀の数値へ変換するマクロを考えてみました。src/frtos_startup/freertos_start.h (ラッパーマクロに以下の赤文字部分を追加)
#define xTaskCreateStatic_R_Helper(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask) \do{ \ static StaticTask_t pxTaskCode##_xTCBBuffer; \ static StackType_t pxTaskCode##_xStackBuffer[usStackDepth]; \ TaskHandle_t xCreatedTask; \ xCreatedTask = xTaskCreateStatic( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxTaskCode##_xStackBuffer, &pxTaskCode##_xTCBBuffer ); \ if (NULL != (TaskHandle_t *)pxCreatedTask) \ { \ *(TaskHandle_t *)pxCreatedTask = xCreatedTask; \ } \ (void) &xCreatedTask; \ [追記] コンパイル時のワーニング除去の為に作成途中では必要でしたが最終的には不要でした}while (0)
src/frtos_config/FreeRTOSConfig.h (以下の変換マクロを追加)
#define pdBYTES_TO_STACK_DEPTH( ulBytes ) ( ( ( uint32_t ) ( ulBytes ) + ( sizeof( StackType_t ) - 1 ) ) / sizeof( StackType_t ) )
src/frtos_startup/freertos_object_init.c (以下のように変更)
void Kernel_Object_init (void){ /************** task creation ****************************/ xTaskCreateStatic_R_Helper( main_task, "MAIN_TASK", pdBYTES_TO_STACK_DEPTH(1024), NULL, 1, NULL ); xTaskCreateStatic_R_Helper( task_LED0, "task_LED0", pdBYTES_TO_STACK_DEPTH(1024), NULL, 2, NULL ); xTaskCreateStatic_R_Helper( task_LED1, "task_LED1", pdBYTES_TO_STACK_DEPTH(1024), NULL, 2, NULL ); xTaskCreateStatic_R_Helper( task_CONIO, "task_CONIO", pdBYTES_TO_STACK_DEPTH(1024), NULL, 3, NULL); /************** semaphore creation ***********************/ /************** queue creation ***************************/ /************** software time creation **************************/ /************** event groups creation ********************/ /************** stream buffer creation *************************/ /************** message buffer creation *********************/} /* End of function Kernel_Object_init()*/
昨日のラッパーマクロでのmapファイル(CC-RLの場合)
FILE=DefaultBuild\freertos_object_init.obj 000f3f5a 000f5011 10b8 _xStackBuffer@1@Kernel_Object_init 000f3f5a 400 data ,l 1 _xTCBBuffer@2@Kernel_Object_init 000f435a 2e data ,l 1 _xStackBuffer@3@Kernel_Object_init 000f4388 400 data ,l 1 _xTCBBuffer@4@Kernel_Object_init 000f4788 2e data ,l 1 _xStackBuffer@5@Kernel_Object_init 000f47b6 400 data ,l 1 _xTCBBuffer@6@Kernel_Object_init 000f4bb6 2e data ,l 1 _xStackBuffer@7@Kernel_Object_init 000f4be4 400 data ,l 1 _xTCBBuffer@8@Kernel_Object_init 000f4fe4 2e data ,l 1FILE=DefaultBuild\freertos_start.obj 000f5012 000f50d5 c4 _xIdleTaskTCBBuffer@1@vApplicationGetIdleTaskMemory 000f5012 2e data ,l 1 _xIdleTaskStackBuffer@2@vApplicationGetIdleTaskMemory 000f5040 96 data ,l 1
今回のラッパーマクロでのmapファイル(CC-RLの場合)
FILE=DefaultBuild\freertos_object_init.obj 000f3f5a 000f5011 10b8 _main_task_xStackBuffer@1@Kernel_Object_init 000f3f5a 400 data ,l 1 _main_task_xTCBBuffer@2@Kernel_Object_init 000f435a 2e data ,l 1 _task_LED0_xStackBuffer@3@Kernel_Object_init 000f4388 400 data ,l 1 _task_LED0_xTCBBuffer@4@Kernel_Object_init 000f4788 2e data ,l 1 _task_LED1_xStackBuffer@5@Kernel_Object_init 000f47b6 400 data ,l 1 _task_LED1_xTCBBuffer@6@Kernel_Object_init 000f4bb6 2e data ,l 1 _task_CONIO_xStackBuffer@7@Kernel_Object_init 000f4be4 400 data ,l 1 _task_CONIO_xTCBBuffer@8@Kernel_Object_init 000f4fe4 2e data ,l 1FILE=DefaultBuild\freertos_start.obj 000f5012 000f50d5 c4 _xIdleTaskTCBBuffer@1@vApplicationGetIdleTaskMemory 000f5012 2e data ,l 1 _xIdleTaskStackBuffer@2@vApplicationGetIdleTaskMemory 000f5040 96 data ,l 1
昨日のラッパーマクロでのmapファイル(GNURL78の場合)
.bss.xTCBBuffer.3825 0x000f3f04 0x2e ./src/frtos_startup/freertos_object_init.o .bss.xStackBuffer.3826 0x000f3f32 0x400 ./src/frtos_startup/freertos_object_init.o .bss.xTCBBuffer.3822 0x000f4332 0x2e ./src/frtos_startup/freertos_object_init.o .bss.xStackBuffer.3823 0x000f4360 0x400 ./src/frtos_startup/freertos_object_init.o .bss.xTCBBuffer.3819 0x000f4760 0x2e ./src/frtos_startup/freertos_object_init.o .bss.xStackBuffer.3820 0x000f478e 0x400 ./src/frtos_startup/freertos_object_init.o .bss.xTCBBuffer.3816 0x000f4b8e 0x2e ./src/frtos_startup/freertos_object_init.o .bss.xStackBuffer.3817 0x000f4bbc 0x400 ./src/frtos_startup/freertos_object_init.o .bss.xIdleTaskStackBuffer.3828 0x000f4fbc 0x96 ./src/frtos_startup/freertos_start.o .bss.xIdleTaskTCBBuffer.3827 0x000f5052 0x2e ./src/frtos_startup/freertos_start.o
今回のラッパーマクロでのmapファイル(GNURL78の場合)
.bss.task_CONIO_xTCBBuffer.3825 0x000f3f04 0x2e ./src/frtos_startup/freertos_object_init.o .bss.task_CONIO_xStackBuffer.3826 0x000f3f32 0x400 ./src/frtos_startup/freertos_object_init.o .bss.task_LED1_xTCBBuffer.3822 0x000f4332 0x2e ./src/frtos_startup/freertos_object_init.o .bss.task_LED1_xStackBuffer.3823 0x000f4360 0x400 ./src/frtos_startup/freertos_object_init.o .bss.task_LED0_xTCBBuffer.3819 0x000f4760 0x2e ./src/frtos_startup/freertos_object_init.o .bss.task_LED0_xStackBuffer.3820 0x000f478e 0x400 ./src/frtos_startup/freertos_object_init.o .bss.main_task_xTCBBuffer.3816 0x000f4b8e 0x2e ./src/frtos_startup/freertos_object_init.o .bss.main_task_xStackBuffer.3817 0x000f4bbc 0x400 ./src/frtos_startup/freertos_object_init.o .bss.xIdleTaskStackBuffer.3832 0x000f4fbc 0x96 ./src/frtos_startup/freertos_start.o .bss.xIdleTaskTCBBuffer.3831 0x000f5052 0x2e ./src/frtos_startup/freertos_start.o