こんにちは。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です。#3連投の2つ目です。受信リングバッファ版のCONIOタスクのソースは以下の通りです。今回も前回同様、FreeRTOSのAPI関数(のラッパー関数)をタスク側ソースではなくコード生成側ソースで呼ぶようにしています。(コード生成側ソースの関数を呼び出している箇所を青文字にしています。また、割り込みのみ版やDTC版に対して受信リングバッファ版に特有の部分を赤文字にしています。)freertos_sampleprog3_gnurl78_c/src/frtos_skeleton/task_CONIO.c
void task_CONIO(void * pvParameters){/* ...略... */ volatile uint8_t recv_buff[CON_RECV_DEMO_SIZE + 1]; volatile uint8_t err_type; MD_STATUS status; uint32_t cnt; INTERNAL_NOT_USED( pvParameters ); U_UART3_Using_RecvRingBuff_Start(); cnt = 0; for (;;) { memset( (char *)recv_buff, 0, CON_RECV_DEMO_SIZE + 1 ); if (0 == cnt) { status = U_UART3_Send_Receive_Wait( (uint8_t *)CON_START_MESSAGE, sizeof(CON_START_MESSAGE), recv_buff, CON_RECV_DEMO_SIZE, &err_type, CON_RECV_TIMEOUT_MS ); } else { status = U_UART3_Receive_Wait( recv_buff, CON_RECV_DEMO_SIZE, &err_type, CON_RECV_TIMEOUT_MS ); } cnt++; nop(); /* for breakpoint, check timing chart on Simulator GUI */ if (MD_OK == status) { taskENTER_CRITICAL(); vPrintString( "Received Message: " ); vPrintString( (char *)recv_buff ); vPrintString( "\n" ); taskEXIT_CRITICAL(); } else { if (MD_RECV_TIMEOUT == status) { vPrintString( "Recv Timeout Error\n" ); } else if (MD_RECV_ERROR == status) { if (SCI_EVT_RXBUF_OVFL & err_type) { vPrintString( "Ring Buffer Overflow Error\n" ); } if (SCI_EVT_FRAMING_ERR & err_type) { vPrintString( "Framing Error\n" ); } if (SCI_EVT_PARITY_ERR & err_type) { vPrintString( "Parity Error\n" ); } if (SCI_EVT_OVFL_ERR & err_type) { vPrintString( "Overrun Error\n" ); } } g_task_CONIO_error = true; LED1 = LED_ON; while (true == g_task_CONIO_error) { vTaskDelay( LED1_ERROR_BLINK_FREQUENCY_MS ); LED1 = ~LED1; } LED1 = LED_OFF; U_UART3_Receive_ClearError(); /* if not called, will be called internally */ cnt = 0; continue; } status = U_UART3_Send_Wait( (uint8_t *)recv_buff, CON_RECV_DEMO_SIZE ); nop(); /* for breakpoint, check timing chart on Simulator GUI */ }/* ...略... */}
チョコさんのリングバッファのソースの変更点は、以下のソース比較ツールの画面コピーの通りです。もともとのソースがUART番号依存していないことを利用してUART[番号].cに以下の#defineを記述してUART3対応にしてみました。(なお、もともとはr_cg_serial_user.cのr_uart[番号]_callback_softwareoverrun()に記述されていた処理を、UART[番号].cにuartx_callback_receivedata()を作成して、そちらへ移しています。)
#define init_bf u_uart3_init_bf#define chk_status u_uart3_chk_status#define get_data u_uart3_get_data#define get_blk u_uart3_get_blk#define g_rx_buff g_uart3_rx_buff#define g_rx_rdpt g_uart3_rx_rdpt#define g_rx_dtno g_uart3_rx_dtno#define g_rx_status g_uart3_rx_status#define uartx_callback_receivedata u_uart3_callback_receivedata#define RX_BUFF_SIZE UART3_RX_BUFF_SIZE#define RX_DTPT_MASK (UART3_RX_BUFF_SIZE - 1)
こんにちは。NoMaYです。#3連投の3つ目です。以下、Renesas RL78 Simulatorでの実行例の画面コピーです。正常系 (CC-RL+CS+の場合) (シリアル送信データファイルはsim_rl78_serial_data_ok_3.serを使用)正常系 (GNURL78+e2 studioの場合) (シリアル送信データファイルはsim_rl78_serial_data_ok_3.serを使用)異常系 (CC-RL+CS+場合) (シリアル送信データファイルはsim_rl78_serial_data_err_overrun.serを使用)異常系 (GNURL78+e2 studioの場合) (シリアル送信データファイルはsim_rl78_serial_data_err_overrun.serを使用)なお、今回、Renesas RL78 Simulatorのトレース機能を使用して、もっとも割り込み禁止時間が長くなっていると思われる、ソフトウェア割り込み(もどき)でのタスク切り替え処理用割り込みの時間を調べてみたところ、4μs強の時間が掛かっていました。今回のUART通信では、ボーレートが2Mbpsで1バイトが11ビット(start:1,data:8,parity:1,stop1)ですので、1バイトの転送時間が5.5μsなのですが、残念ながら、連続転送させるとオーバーランエラーが発生します。先ほどの割り込み禁止時間が4μs強ですので間に合っても良さそうですが、今になって拙かったかなと思ったのは、多重割り込みは使用していないものの割り込み禁止期間中に割り込みが複数発生することはありますので、今回は割り込み優先順位が以下の通りになっている為に受信割り込みの受付がもっとも後回しにされてしまっている筈であり、そのせいでオーバーランエラーが発生してしまうのかな、と思い始めています。割り込み優先順位: 役割表記(上側)と割り込み要求名表記(下側)ソフトウェア割り込み(もどき)でのタスク切り替え処理用割り込み > ティック割り込み > 送信割り込み > 受信割り込みINTWDTI > INTIT > INTST3 > INTSR3以下、トレース表示の画面コピーです。019ms153us406ns - 019ms149us031ns = 4us375nsまた、今回、Renesas RL78 Simulatorのカバレッジ機能を使用してみましたが、ソースウィンドウで未実行箇所が容易に分かるのはちょっといいかも、と思いました。(ちなみに、コンパイラの最適化オプションが最適化ありのままですと、ソース行とコンパイルされたコードの対応関係が崩れて訳が分からなくなりますので、コンパイラの最適化オプションをデバッグ優先に変更しておく必要があります。)以下、カバレッジ表示の画面コピーです。その1:sim_rl78_serial_data_ok_3.ser ⇒ if文内に未実行箇所ありsim_rl78_serial_data_ok_3.ser + sim_rl78_serial_data_err_overrun.ser ⇒ if文内にまだ未実行箇所ありsim_rl78_serial_data_ok_3.ser + sim_rl78_serial_data_err_overrun.ser + sim_rl78_serial_data_err_timeout.ser ⇒ 全て実行その2:sim_rl78_serial_data_ok_3.ser ⇒ if文内に未実行箇所ありsim_rl78_serial_data_ok_3.ser + sim_rl78_serial_data_err_timeout.ser ⇒ if文内にまだ未実行箇所ありsim_rl78_serial_data_ok_3.ser + sim_rl78_serial_data_err_timeout.ser + sim_rl78_serial_data_err_uart_format.ser ⇒ 全て実行その他:コンパイラの最適化オプションで未使用の変数/関数を削除する最適化を実施しているのでコードの全く無い関数もありますCS+のヘルプの画面コピー[追記]なお、3連投の1つ目は、こちらです。
こんにちは。NoMaYです。FreeRTOSのタスク通知のAPIには、0以外の32ビット値を割り込み処理側から通常処理側(タスク処理側)へ通知することが出来る以下の関数があるのですが、それを使って先日投稿したSample Programをちょっと書き換えてみました。割り込み処理側(送り側)(今回から使用)
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken );
通常処理側(タスク処理側)(受け側)(以前から使用)
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
以下、プロジェクトのファイル一式です。(CC-RL版はCS+ V8.03/e2 studio v7.6.0+CC-RL V1.02でビルド(e2 studio用.project/.cproject等を同梱)(当方特有の事情でCC-RL V1.02を使用))(GNURL78版はe2 studio v7.6.0+GNURL78 2019q4(4.9.2.201904)でビルド)(共にzipファイルをe2 studioに直接インポート可能) プロジェクト構造は極力RX-TBの自作のFreeRTOSプロジェクトもどきSample Programに似せてあります。(なお、タスク通知に絡んだ変更の他にも、FreeRTOS kernelのソースをv10.2.1→v10.3.1へ更新したり、UART送信の転送モードやUART受信割り込み/UART受信エラー割り込みの優先順位、あれこれ細かな部分、等の変更も行っています。)rl78g14fpb_freertos_sampleprog1_ccrl_c_csplus_20200407.zip (*1) 456KBrl78g14fpb_freertos_sampleprog2_ccrl_c_csplus_20200407.zip (*1) 447KBrl78g14fpb_freertos_sampleprog3_ccrl_c_csplus_20200407.zip (*1) 507KBrl78g14fpb_freertos_sampleprog1_gnurl78_c_e2v760_20200407.zip (*1,*2) 422KBrl78g14fpb_freertos_sampleprog2_gnurl78_c_e2v760_20200407.zip (*1,*2) 413KBrl78g14fpb_freertos_sampleprog3_gnurl78_c_e2v760_20200407.zip (*1,*2) 474KBsampleprog1: UART送受信をDTCで行う版sampleprog2: UART送受信を割り込みのみで行う版sampleprog3: UART受信をリングバッファで行いUART送信を割り込みのみで行う版*1:実機用のデバッガプロパティ設定(CS+)や.launchファイル設定(e2 studio)は当方特有の事情でオンボードエミュレータが使えない為に未確認です。(ひと通りは設定してあります。)*2:リンカスクリプトには別スレッド『GNURL78でconst領域/Mirror領域をちょっと安全に使えるようにlinker scriptのASSERT()で小技(TIPS)を考えてみた』に投稿した内容を反映してあります。今回使ったAPI関数の日本語ドキュメントは以下にあります。xTaskNotifyFromISR() (今回から使用)docs.aws.amazon.com/ja_jp/freertos-kernel/latest/dg/task-notification.html#xtasknotify-and-xtasknotifyfromisr-api-functionsulTaskNotifyTake() (以前から使用)docs.aws.amazon.com/ja_jp/freertos-kernel/latest/dg/task-notification.html#ultasknotifytake-api-functionこれを以下のように使ってみました。(直接は使わずにラッパー関数を作って使うようにしました。)freertos_sampleprog2_ccrl_c/src/frtos_startup/freertos_start.c (sampleprog1,3も同じ)
BaseType_t xTaskNotifyFromISR_R_Helper(TaskHandle_t *pxTask, uint32_t ulValue){ if (NULL != *pxTask) { BaseType_t sHigherPriorityTaskWoken = pdFALSE; /* Notify the task that the interrupt/callback is complete. */ xTaskNotifyFromISR( *pxTask, ulValue, eSetValueWithOverwrite, &sHigherPriorityTaskWoken ); /* There are no interrupt/callback in progress, so no tasks to notify. */ *pxTask = NULL; portYIELD_FROM_ISR( sHigherPriorityTaskWoken ); } return pdTRUE;} /* End of function xTaskNotifyFromISR_R_Helper() */
uint32_t ulTaskNotifyTake_R_Helper(TickType_t xTicksToWait){ /* Wait to be notified that the interrupt/callback is complete. */ return ulTaskNotifyTake( pdTRUE, xTicksToWait );} /* End of function ulTaskNotifyTake_R_Helper() */
freertos_sampleprog2_ccrl_c/src/r_cg_serial_user.c (sampleprog1,3も同様)
static void r_uart3_callback_receiveend(void){ /* Start user code. Do not edit comment generated here */ if (0U == g_uart3_rx_error_type) { U_UART3_Receive_Stop(); g_uart3_rx_ready_flag = true; xTaskNotifyFromISR_R_Helper( &g_uart3_rx_task, 0x10000 | MD_OK ); } /* End user code. Do not edit comment generated here */}
static void r_uart3_callback_error(uint8_t err_type){ /* Start user code. Do not edit comment generated here */ U_UART3_Receive_Stop(); g_uart3_rx_error_type = err_type; xTaskNotifyFromISR_R_Helper( &g_uart3_rx_task, 0x10000 | (err_type << 8) | MD_RECV_ERROR ); /* End user code. Do not edit comment generated here */}
freertos_sampleprog2_ccrl_c/src/r_cg_serial.c (sampleprog1,3も同様)
MD_STATUS U_UART3_Receive_Wait(volatile uint8_t * rx_buf, uint16_t rx_num, volatile uint8_t * p_err_type, TickType_t rx_wait){ MD_STATUS status = MD_OK; uint32_t value; if (rx_num < 1U) { status = MD_ARGERROR; } else { g_uart3_rx_task = xTaskGetCurrentTaskHandle_R_Helper(); U_UART3_Receive( rx_buf, rx_num ); /* Wait for a notification from the interrupt/callback */ value = ulTaskNotifyTake_R_Helper( rx_wait ); if (0U == value) { /* Timeout */ U_UART3_Receive_Stop(); g_uart3_rx_task = NULL; /* Check an unhandled notification from timeout till stop */ value = ulTaskNotifyTake_R_Helper( 0 ); } if (0U != value) { /* Normal receive end or receive error */ *p_err_type = (value >> 8) & 0xFFU; status = value & 0xFFU; } else { /* Timeout */ *p_err_type = SCI_EVT_RXWAIT_TMOT; status = MD_RECV_TIMEOUT; } } return status;}
なお、以下の点を鑑み、UART受信割り込み/UART受信エラー割り込みの優先順位変更(sampleprog1,2,3)とUART送信の転送モード変更(sampleprog2,3)を行っています。本スレッドjapan.renesasrulz.com/cafe_rene/f/forum21/5845/rl78-freertos-api-cc-rl-gnurl78/34294#34294「今になって拙かったかなと思ったのは、多重割り込みは使用していないものの割り込み禁止期間中に割り込みが複数発生することはありますので、今回は割り込み優先順位が以下の通りになっている為に受信割り込みの受付がもっとも後回しにされてしまっている筈であり、そのせいでオーバーランエラーが発生してしまうのかな、と思い始めています。割り込み優先順位: 役割表記(上側)と割り込み要求名表記(下側)ソフトウェア割り込み(もどき)でのタスク切り替え処理用割り込み > ティック割り込み > 送信割り込み > 受信割り込みINTWDTI > INTIT > INTST3 > INTSR3」チョコさんが以前に指摘されていたRL78コード生成機能によるCSI連続送信の終了の割り込みコードの問題を調べていますjapan.renesasrulz.com/cafe_rene/f/forum18/6217/rl78-csi/34513#34513「今回の割り込みコードの問題はCSI連続送信でしたが、他のタイプの連続転送に関しても、コードを生成させて、生成コードを確認してみました。不具合原因のコードから推測すると、問題点の(2)の該当/非該当は以下の表のようになると思います。...略...SAU UART連続送信モード(繰り返し送信モード) 該当?...略...」以下、上記に関してコード生成機能の設定を変更した箇所の画面コピーです。(以下の画面コピーはCC-RL+CS+のものですが、CC-RL+e2 studioでもGNURL78+e2 studioでも、同様です。)sampleprog1(UART送受信をDTCで行う版)sampleprog2(UART送受信を割り込みのみで行う版)とsample3(UART受信をリングバッファで行いUART送信を割り込みのみで行う版)
こんにちは。NoMaYです。これまで投稿してきたSample Programでは、コンパイラの最適化オプションで未使用の変数/関数を削除する最適化を実施してデータサイズ/コードサイズを削減していたのですが、今回、FreeRTOSConfig.hを以下のファイル比較ツールの画面コピーの通りに変更してみたところ、更に削減することが出来ました。例えば、sampleprog2(UART送受信を割り込みのみで行う版)では、CC-RLで表示されるPROGRAM SECTIONのサイズが8247(2037H)→4274(10b2H)へ、GNURL78で表示されるtextセクションのサイズが11240→5898へ、となりました。(ちなみに、CC-RLとGNURL78では集計の発想が異なる為、双方を直接は比較出来ません。)
sampleprog1: UART送受信をDTCで行う版sampleprog2: UART送受信を割り込みのみで行う版sampleprog3: UART受信をリングバッファで行いUART送信を割り込みのみで行う版なお、今回試したFreeRTOSConfig.hとビルドした結果のmapファイル等を以下のzipファイルに固めました。rl78g14fpb_freertos_sampleprogs_issue_20200413.zip以下、画面コピーです。zipファイル内のファイル一覧FreeRTOSConfig.hの変更内容: 今まで(左側ペイン)と今回(右側ペイン)サイズ比較結果例: sampleprog2: CC-RL: 今まで(左側ペイン)と今回(右側ペイン)サイズ比較結果例: sampleprog2: GNURL78: 今まで(左側ペイン)と今回(右側ペイン)
こんにちは。NoMaYです。FreeRTOSConfig.hを変更して、FreeRTOS kernel内で動的メモリ確保が行われないようにしてみました。(ちなみに、FreeRTOS kernelのメモリマネージャのheap_1.cをビルドから除外したり、xTaskCreate()の代わりにxTaskCreateStatic()を使用したり、vApplicationGetIdleTaskMemory()を実装したり、といった変更もする必要があります。)なお、今回試したFreeRTOSConfig.h等のソースとビルドした結果のmapファイル等を以下のzipファイルに固めました。rl78g14fpb_freertos_sampleprogs_issue_20200414.zipソースの主な変更箇所は以下の通りです。src/frtos_config/FreeRTOSConfig.h (以下の設定を追加)
#define configSUPPORT_DYNAMIC_ALLOCATION 0#define configSUPPORT_STATIC_ALLOCATION 1
src/frtos_startup/freertos_start.h (xTaskCreateStatic()を呼び出すラッパーマクロを用意)
#define xTaskCreateStatic_R_Helper(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask) \do{ \ static StaticTask_t xTCBBuffer; \ static StackType_t xStackBuffer[usStackDepth]; \ TaskHandle_t xCreatedTask; \ xCreatedTask = xTaskCreateStatic( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, xStackBuffer, &xTCBBuffer ); \ if (NULL != (TaskHandle_t *)pxCreatedTask) \ { \ *(TaskHandle_t *)pxCreatedTask = xCreatedTask; \ } \ (void) &xCreatedTask; \}while (0)
src/frtos_startup/freertos_object_init.c (TaskCreate()の代わりにxTaskCreateStatic()を上記ラッパーマクロ経由で使用)
void Kernel_Object_init (void){ /************** task creation ****************************/ xTaskCreateStatic_R_Helper(main_task, "MAIN_TASK", 512, NULL, 1, NULL); xTaskCreateStatic_R_Helper(task_LED0, "task_LED0", 512, NULL, 2, NULL); xTaskCreateStatic_R_Helper(task_LED1, "task_LED1", 512, NULL, 2, NULL); xTaskCreateStatic_R_Helper(task_CONIO, "task_CONIO", 512, 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()*/
src/frtos_startup/freertos_start.c (vApplicationGetIdleTaskMemory()を実装)
#if( configSUPPORT_STATIC_ALLOCATION != 0 )void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ){ static StaticTask_t xIdleTaskTCBBuffer; static StackType_t xIdleTaskStackBuffer[configMINIMAL_STACK_SIZE]; *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; *ppxIdleTaskStackBuffer = xIdleTaskStackBuffer; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;} /* End of vApplicationGetIdleTaskMemory() */#endif /* configSUPPORT_STATIC_ALLOCATION != 0 */
なお、上記ソースでスタックサイズをconfigMINIMAL_STACK_SIZEとしたのは、以下のFreeRTOS kernelのソースでconfigMINIMAL_STACK_SIZEとなっていたので、単にそれを踏襲したからです。src/FreeRTOS/Source/tasks.c
void vTaskStartScheduler( void ){BaseType_t xReturn; /* Add the idle task at the lowest priority. */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) { StaticTask_t *pxIdleTaskTCBBuffer = NULL; StackType_t *pxIdleTaskStackBuffer = NULL; uint32_t ulIdleTaskStackSize; /* The Idle task is created using user provided RAM - obtain the address of the RAM then create the idle task. */ vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); xIdleTaskHandle = xTaskCreateStatic( prvIdleTask, configIDLE_TASK_NAME, ulIdleTaskStackSize, ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ pxIdleTaskStackBuffer, pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ ...略... } #else { /* The Idle task is being created using dynamically allocated RAM. */ xReturn = xTaskCreate( prvIdleTask, configIDLE_TASK_NAME, configMINIMAL_STACK_SIZE, ( void * ) NULL, portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ } #endif /* configSUPPORT_STATIC_ALLOCATION */ ...略...}
以下、画面コピーです。FreeRTOS kernelのメモリマネージャのheap_1.cをビルドから除外zipファイル内のファイル一覧FreeRTOSConfig.hの変更内容: 前回(左側ペイン)と今回(右側ペイン)freertos_object_init.cの変更内容: 前回(左側ペイン)と今回(右側ペイン)サイズ比較結果例: sampleprog2: CC-RL: 前回(左側ペイン)と今回(右側ペイン)サイズ比較結果例: sampleprog2: GNURL78: 前回(左側ペイン)と今回(右側ペイン)
こんにちは。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
こんにちは。NoMaYです。Call Walker (CC-RL+CS+)でガチにスタック使用量を見積もってみました。(なお、見積もりの妥当性の検証は今からやろうとしているところです。) Call Walkerには以下の使用制限がありますので、Call Walkerを起動した後に、Call WalkerのGUI上で、手作業で、関数/サブルーチンの情報を修正しました。・ 関数ポインタで関数呼び出しする箇所では、その箇所から呼ばれる関数/サブルーチンの追跡をしない・ アセンブラソースのサブルーチン(Cスタートアップルーチンも含む)に関しては、スタック使用量を不明としている・ アセンブラソースのサブルーチン(Cスタートアップルーチンも含む)に関しては、関数/サブルーチンの追跡をしない・ 上記の影響で、アセンブラソースのみから呼ばれる関数/サブルーチンが、どこからも呼ばれないものとして扱われる・ アセンブラソースのサブルーチン(Cスタートアップルーチンも含む)の単なる分岐先ラベルがサブルーチン扱いされる以下、修正前と修正後のCall Walkerのcalファイルと画面コピーです。修正前freertos_sampleprog2_ccrl_c.cal修正後freertos_sampleprog2_ccrl_c.Editing.cal関数/サブルーチンの情報を修正するには、Call WalkerのGUIの「Add...」「Modify...」「Delete」、および、ドラッグアンドドロップ操作による移動、の機能を使用しました。ただ、困ったことに、Undo機能がありませんので、操作を間違えた時、そのあとの操作でうまく修復できないケースもあり、最初から修正をやり直すことを何度か繰り返す必要がありました。加えて、一度修正しても、プログラムはどんどん変更されていきますので、何度も何度も修正を繰り返さないといけないかも知れません。その手間を減らす為のMerge機能があるようなのですが、今のところ、使い方のコツを修得出来ていません。(ちなみに、修正を行う時、表示ツリーの状態が強制的に全展開状態になってしまうのですが、これには大変閉口しています、、、毎回、展開レベルを1に戻すことで対処していますが、、、)「Add...」「Modify...」「Delete」のメニュー/ツールバー/ダイアログ展開レベルを1に戻す小技なお、スタック使用量が不明となっていた(スタック使用量が0となっていた)アセンブラソースのサブルーチン(Cスタートアップルーチンも含む)で値を設定(値を修正)したのは以下の通りです。以下、Call Walkerのヘルプ画面の幾つかです。
こんにちは。NoMaYです。Call Walker (CC-RL+CS+)で見積もったスタック使用量の妥当性を検証してみました。なお、そもそも(RTOS未使用時においても)Call Walker (CC-RL+CS+)によるスタック使用量の見積もりは適切ではないですよね。あまりに当たり前過ぎて、皆さん不問に付しているのだとは思うのですが、(少なくとも多重割り込みを使用していない場合において、)必要スタックサイズの値は以下ではないかと思うのですが、その点が考慮されてませんよね、、、本来の必要スタックサイズの見積もり(多重割り込みを使用していない場合):必要サイズ = Cスタートアップルーチンから数えて通常処理で最も深くなるサイズ + 割り込み処理の内で最も深くなるサイズCall Walker (CC-RL+CS+)での必要スタックサイズの見積もり:必要サイズ = 通常処理も割り込み処理も区別することなく、単に最も深くなるサイズですので、私も、そうした点は手計算するものとして検証しました。ですが、検証といっても、大したことをする訳でもなく、デバッガ上で、ブレークポイントを設定してブレークさせたり、ステップ実行させたりして、最も深くなる位置でのSP(スタックポインタ)の値をウォッチウィンドウで確認してみただけです。また、しらみつぶしに確認した訳ではなく、事例を絞って確認しました。あと、ルネサスRL78シミュレータで確認しました。確認結果:(A) 見積もりと実動作は概ね一致ただし(B) 関数/サブルーチンの最後のCALL命令をBR命令に置き換える最適化が行われた箇所(および、CALL命令をBR命令で置き換えた後の分岐先が連続していたのでBR命令さえ削除された箇所)の影響により実動作の方がサイズが小さかった(SPの値としては大きかった)という不一致あり(実害は無い)また(C) 所望の実行経路を今回のサンプルプログラムですぐに実現することが出来なかったので断念したものありさらに(D) スタック渡し引数で使用されるスタックが、呼び出し元の関数に計上されるのか、呼び出し先の関数に計上されるのか、調べてみたところ、(少なくともCC-RL V1.02では)呼び出し元の関数に計上されていたので、このことは見積もりの方がサイズが大きくなる方向に作用すると思います確認事例:(1) main_task(レジスタ渡し引数有り+戻り番地+自動変数無し、関数/サブルーチン呼び出し無し)での確認 ⇒ 一致(2) r_intc0_interrupt(割り込み処理)から数えて最も深くなる場所での確認 ⇒ 一致(3) _start(Cスタートアップルーチンのアセンブラ)から数えて通常処理で最も深くなる場所での確認 ⇒ 不一致(実害無し)(4) _vPortYield(FreeRTOSポートレイヤのアセンブラの割り込み処理の1つ)から数えて最も深くなる場所での確認 ⇒ 一致(5) _vPortTickISR(FreeRTOSポートレイヤのアセンブラの割り込み処理の1つ)から数えて最も深くなる場所での確認 ⇒ 断念(6) スタック渡し引数がある関数を記述してmain_taskから呼び出してみた時の例また、今回、確認がやり易くなるかと考えて、各タスクの優先順位を以下の通りに変更してみました。(実質、main_task実行中にr_intc0_interruptが実行されるケースが多くなる、ようにしてみました。)src/frtos_startup/freertos_object_init.c (赤文字箇所を変更)
void Kernel_Object_init (void){ ...略... 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, 0/*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, 0/*3*/, NULL); ...略...} /* End of function Kernel_Object_init()*/
ちなみに、mapファイルで調べたmain_taskのスタック領域は 0x0f3f5a ~ 0x0f435a となっていました。あと、_startのスタック領域は 0x0f510e ~ 0x0ffe20 となっていました。DefaultBuild/freertos_sampleprog2_ccrl_c.map
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
Absolute value symbolsFILE=rlink_generates_05... __STACK_ADDR_START 000ffe20 0 none ,g 1 __STACK_ADDR_END 000f510e 0 none ,g 1
以下、それぞれの場合のCS+のルネサスRL78シミュレータでの実行結果の画面コピーです。なお、今回、Call Walkerの表示設定は以下の通りに変更しています。あと、CS+のビルドツールのプロパティを変更して、アセンブラソースを出力させるようにしています。[View]→[Show Used Stack]をチェック[View]→[Show All Symbols]をチェック[アセンブリソースファイルにコメントを出力する]を[いいえ]に設定(デフォルト設定) (画面コピーの大きさを少し小さくする為)[アセンブリソースファイルを出力する]を[はい(-asm_path)]に設定(1) main_task(レジスタ渡し引数有り+戻り番地+自動変数無し、関数/サブルーチン呼び出し無し)での確認SP期待値: 0x0f4356 (0x0f435a - 4)SP確認値: 0x0f4356 ⇒ OK(一致)(2) r_intc0_interrupt(割り込み処理)から数えて最も深くなる場所での確認SP期待値: 0x0f432e (0x0f435a - 4 - 40) : 4 = main_taskでの使用量、40 = r_intc0_interruptでの使用量SP確認値: 0x0f432e ⇒ OK(一致)(3) _start(Cスタートアップルーチンのアセンブラ)から数えて通常処理で最も深くなる場所での確認SP期待値: 0x0ffe10 (0x0ffe20 - 16)SP確認値: 0x0ffe18 ⇒ △(不一致だが実害無し)(4) _vPortYield(FreeRTOSポートレイヤのアセンブラの割り込み処理の1つ)から数えて最も深くなる場所での確認SP期待値: 0x0f4344 (0x0f435a - 4 - 22) : 4 = main_taskでの使用量、22 = _vPortYield割り込みでの使用量SP確認値: 0x0f4340 ⇒ OK(一致)(5) _vPortTickISR(FreeRTOSポートレイヤのアセンブラの割り込み処理の1つ)から数えて最も深くなる場所での確認SP期待値: 0x0f4330 (0x0f435a - 4 - 38) : 4 = main_taskでの使用量、38 = _vPortTickISR割り込みでの使用量SP確認値: Unknown(所望の実行経路を今回のサンプルプログラムですぐに実現することが出来なかったので断念)(6) スタック渡し引数がある関数を記述してmain_taskから呼び出してみた時の例スタック渡し引数で使用されるスタックは呼び出し元の関数のスタックサイズに計上されていました。このことは見積もり値の方が大きくなる方向に作用すると思います。main_task.c
uint16_t foo3(uint16_t a, uint16_t b, uint16_t c);uint16_t foo4(uint16_t a, uint16_t b, uint16_t c, uint16_t d);uint16_t foo3(uint16_t a, uint16_t b, uint16_t c){ return a + b + c;}uint16_t foo4(uint16_t a, uint16_t b, uint16_t c, uint16_t d){ return a + b + c + d;}uint16_t a, b, c, d;volatile uint16_t r;void main_task(void *pvParameters){ INTERNAL_NOT_USED(pvParameters); while(1) { r = foo3( a, b, c ); r = foo4( a, b, c, d ); }}
main_task.asm
_foo3: .STACK _foo3 = 4 addw ax, bc addw ax, de ret_foo4: .STACK _foo4 = 4 movw hl, ax movw ax, [sp+0x04] addw ax, de movw de, ax movw ax, hl addw ax, bc addw ax, de ret_main_task: .STACK _main_task = 6.BB@LABEL@3_1: ; bb11 movw de, !LOWW(_c) movw bc, !LOWW(_b) movw ax, !LOWW(_a) call $!_foo3 ⇒ ここから先の呼び出しが深くなった時にスタック使用量に +2 のゲタが発生する movw !LOWW(_r), ax movw ax, !LOWW(_d) push ax movw de, !LOWW(_c) movw bc, !LOWW(_b) movw ax, !LOWW(_a) call $!_foo4 ⇒ ここから先の呼び出しではそのようなゲタは発生しない pop hl movw !LOWW(_r), ax br $.BB@LABEL@3_1
こんにちは。NoMaYです。Call Walker (CC-RL+CS+)でのスタック使用量の見積もりは妥当だと感じましたので、最終的に、必要スタックサイズが幾つなのか計算してみました。ただ、以前に別スレッド『e2 studio v7.5.0のFreeRTOS ProjectでVisual Expression+Renesas RX Simulator/TB-RX65Nで試せるSample Programを作ってみた』で思ったことですが、ソースレベルデバッグ時には最適化無しにすると思いますが、そのことはスタックは最適化無しの場合でも足りるサイズを確保しておかざるを得ない、ことになるのだと思います、、、必要スタックサイズを見積もる為のCall Walker (CC-RL+CS+)によるスタック使用量の見積もり値(元データ)
最終的な必要スタックサイズの見積もり値
以下、最適化無しの場合の修正前と修正後のCall Walkerのcalファイルと画面コピーです。修正前freertos_sampleprog2_ccrl_c.Onothing.cal修正後freertos_sampleprog2_ccrl_c.Onothing.Editing.cal
こんにちは。NoMaYです。今回、Call Walker (CC-RL+CS+)上で、PowerON_Reset_PC、Tasks、TaskExitError、Interruptsの4つのダミーのシンボルを定義して、以下の画面コピーのように、それぞれの下に関数/サブルーチンの情報をグループ化してみました。(どう運用するのが良いのか、試行錯誤している内の、思い付きの1つです。) なお、今まで意識していませんでしたが、e2 studioのスタック解析ビューには、関数/サブルーチンの情報を修正する機能が無いですね、、、あと、以前に別スレッド『e2 studio v7.5.0のStack Analysis ViewはGNURXでは1箇所でも関数ポインタで関数呼び出しするとERRORになって使えませんね』で思ったことでもあるのですが、今回のサンプルプログラムのGNURL78版でも、main_taskのスタック使用量の表示が0ですので、(少なくとも)戻り番地の分は計上されていないみたいですね、、、最適化無しの場合の今回修正後のcalファイルとCall Walkerの画面コピーfreertos_sampleprog2_ccrl_c.Onothing.Editing.calデフォルト最適化の場合の今回修正後のcalファイルとCall Walkerの画面コピーfreertos_sampleprog2_ccrl_c.Editing.calダミーのシンボルは以下の画面コピーの通りに定義しました。(なお、アドレスは単なる仮の値ですが、値が重複してはいけないようです。)PowerON_Reset_PCTasksTaskExitErrorInterrupts以下、e2 studio v7.8.0のスタック解析ビューの画面コピーです。CC-RLで最適化無し(-Onothing)CC-RLでデフォルト最適化(デフォルト)GNURL78でデバッグ優先最適化(-Og)GNURL78でサイズ優先最適化(-Os)ちなみに、e2 studio v7.8.0のバグリストでも、スタック使用量の表示の件はStack Analysis Viewのバグとして挙がっていないみたいです。e²studio 7.8 Known Issues ListList generated on 30/03/2020 15:14:31www2.renesas.eu/_custom/software/ree_eclipse/e2studio7/docs/releasenotes/7.8.0/openissues.htm