Amazon AWSのFreeRTOS Kernel Developer GuideのサンプルコードをRenesas RX SimulatorのDebug Consoleで試せるようにしてみた

こんにちは。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

Parents
  • こんにちは。NoMaYです。#3連投の3つ目です。

    今回、コード生成機能+FreeRTOSで割り込みを扱い易くする為、以下のR_PRAGMA_FREERTOS_INTERRUPT()というマクロを作成してみました。(また、このマクロと整合するようにFreeRTOSのポートレイヤーでのレジスタのPUSH/POPの順番を改変しています。ちなみにRXでは特別なことをしなくても扱えます(筈)が、RL78でもそのように出来ないものだろうかとポートレイヤーを改変出来ないか思案しているところです、、、)

    src/frtos_startup/freertos_isr.h

    #if defined(__CCRL__)

    extern void vPortFreeRTOSInterruptCommonHandler_C(void);

    #pragma inline_asm vPortFreeRTOSInterruptCommonHandler_C_Helper

    static void __near vPortFreeRTOSInterruptCommonHandler_C_Helper(void)
    {
        pop bc
    #if defined(__RL78_SMALL__)
        br !_vPortFreeRTOSInterruptCommonHandler_C
    #elif defined(__RL78_MEDIUM__)
        br !!_vPortFreeRTOSInterruptCommonHandler_C
    #else
        #error Unknown memory model.
    #endif
    }

    #define R_PRAGMA_FREERTOS_INTERRUPT(function) \
        static void __near _##function(void); \
        void __near function(void) \
        { \
            /* vPortFreeRTOSInterruptCommonHandler_C() will not return here. */ \
            void (__near * volatile p)() = _##function; \
            vPortFreeRTOSInterruptCommonHandler_C_Helper(); \
            /* The following is intended to remove the epilogue code. */ \
            while (1) {} \
        }

    #elif defined(__GNUC__)

    extern void vPortFreeRTOSInterruptCommonHandler_C(void);

    #define R_PRAGMA_FREERTOS_INTERRUPT(function) \
        void _##function(void); \
        void function(void) __attribute__((interrupt, noreturn)); \
        void function(void) \
        { \
            /* vPortFreeRTOSInterruptCommonHandler_C() will not return here. */ \
            __asm volatile \
            ( \
                "movw bc, #__" #function "\n" \
                "br !!_vPortFreeRTOSInterruptCommonHandler_C\n" \
            ); \
            /* The following is intended to remove the epilogue code. */ \
            while (1) {} \
        } \

    #endif

    このマクロを以下のように使用することで、コード生成機能の割り込み処理ルーチンからFreeRTOS APIを不便無く(コード生成する度にコード生成されたソースを書き直すこと無く)呼び出すことが出来るようになります。

    src/r_cg_intc_user.c

    CC-RLの場合

    /******************************************************************************
    Includes
    ******************************************************************************/
    #include "r_cg_macrodriver.h"
    #include "r_cg_intc.h"
    /* Start user code for include. Do not edit comment generated here */
    #include "freertos_start.h"
    #include "freertos_isr.h"
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"

    /******************************************************************************
    Pragma directive
    ******************************************************************************/
    #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 */

    GNURL78の場合

    /******************************************************************************
    Includes
    ******************************************************************************/
    #include "r_cg_macrodriver.h"
    #include "r_cg_intc.h"
    /* Start user code for include. Do not edit comment generated here */
    #include "freertos_start.h"
    #include "freertos_isr.h"
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"

    /******************************************************************************
    Global variables and functions
    ******************************************************************************/
    /* Start user code for global. 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 */

    呼び出し例(CC-RL/GNURL78共通)

    /******************************************************************************
    * Function Name: r_intc3_interrupt
    * Description  : This function is INTP3 interrupt service routine.
    * Arguments    : None
    * Return Value : None
    ******************************************************************************/
    void r_intc3_interrupt(void)
    {
        /* Start user code. Do not edit comment generated here */

        short sHigherPriorityTaskWoken = pdFALSE;

        xSemaphoreGiveFromISR( xSemaphoreINTP3, &sHigherPriorityTaskWoken );
        portYIELD_FROM_ISR( sHigherPriorityTaskWoken );

        /* End user code. Do not edit comment generated here */
    }

    zipファイルのプロジェクトでは、full demo プロジェクトでFreeRTOSConfig.hのFREERTOS_USER_MAINを以下のように1にすると、以下のタスクを生成した状態での割り込み処理動作をSimulator GUIのパネルで試すことが出来ます。

    frtos_config/FreeRTOSConfig.h

    /* Set FREERTOS_USER_MAIN to one to run an user main other than test/demo main.
    Project file may set this to two by compiler command line option to run one of
    examples which can be obtained in the FreeRTOS Kernel Developer Guide from AWS,
    https://docs.aws.amazon.com/ja_jp/freertos-kernel/latest/dg/task-management.html */
    #ifndef FREERTOS_USER_MAIN
    #define FREERTOS_USER_MAIN                    1
    #endif

    src/user_main.c

    void main_task(void *pvParameters)
    {
        (void) pvParameters;

        while (1)
        {
        }
    }

    void second_task(void *pvParameters)
    {
        (void) pvParameters;

        while (1)
        {
        }
    }

    void third_task(void *pvParameters)
    {
        (void) pvParameters;

        while (1)
        {
        }
    }

    void intp3_task(void *pvParameters)
    {
        (void) pvParameters;

        R_INTC3_Start();

        LED_INIT();
        while (1)
        {
            xSemaphoreTake( xSemaphoreINTP3, portMAX_DELAY );
            LED_BIT = !LED_BIT;
        }
    }

    frtos_startup/freertos_start.c

    void Processing_Before_Start_Kernel(void)
    {
        BaseType_t ret;

        /************** semaphore creation ***********************/
        xSemaphoreINTP3 = xSemaphoreCreateBinary();
        if (xSemaphoreINTP3 == NULL)
        {
            while(1)
            {
                /* Failed! Semaphore can not be created. */
            }
        }

        /************** mutex creation ***************************/


        /************** queues creation **************************/


        /************** event groups creation ********************/


        /************** mailbox creation *************************/


        /************** memory pool creation *********************/


        Kernel_Object_init();

        /************** task creation ****************************/
        /* Main task. */
        ret = xTaskCreate(main_task, "MAIN_TASK", 512, NULL, 1, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

        /* Second task. */
        ret = xTaskCreate(second_task, "2ND_TASK", 512, NULL, 1, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

        /* Third task. */
        ret = xTaskCreate(third_task, "3RD_TASK", 512, NULL, 1, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

        /* INTP3 task. */
        ret = xTaskCreate(intp3_task, "INTP3_TASK", 512, NULL, 3, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

    } /* End of function Processing_Before_Start_Kernel() */

    Simulator GUIでは、パネル上でボタン(プッシュボタン)を押すごとにLEDのOn/Offが切り替わります。

      

Reply
  • こんにちは。NoMaYです。#3連投の3つ目です。

    今回、コード生成機能+FreeRTOSで割り込みを扱い易くする為、以下のR_PRAGMA_FREERTOS_INTERRUPT()というマクロを作成してみました。(また、このマクロと整合するようにFreeRTOSのポートレイヤーでのレジスタのPUSH/POPの順番を改変しています。ちなみにRXでは特別なことをしなくても扱えます(筈)が、RL78でもそのように出来ないものだろうかとポートレイヤーを改変出来ないか思案しているところです、、、)

    src/frtos_startup/freertos_isr.h

    #if defined(__CCRL__)

    extern void vPortFreeRTOSInterruptCommonHandler_C(void);

    #pragma inline_asm vPortFreeRTOSInterruptCommonHandler_C_Helper

    static void __near vPortFreeRTOSInterruptCommonHandler_C_Helper(void)
    {
        pop bc
    #if defined(__RL78_SMALL__)
        br !_vPortFreeRTOSInterruptCommonHandler_C
    #elif defined(__RL78_MEDIUM__)
        br !!_vPortFreeRTOSInterruptCommonHandler_C
    #else
        #error Unknown memory model.
    #endif
    }

    #define R_PRAGMA_FREERTOS_INTERRUPT(function) \
        static void __near _##function(void); \
        void __near function(void) \
        { \
            /* vPortFreeRTOSInterruptCommonHandler_C() will not return here. */ \
            void (__near * volatile p)() = _##function; \
            vPortFreeRTOSInterruptCommonHandler_C_Helper(); \
            /* The following is intended to remove the epilogue code. */ \
            while (1) {} \
        }

    #elif defined(__GNUC__)

    extern void vPortFreeRTOSInterruptCommonHandler_C(void);

    #define R_PRAGMA_FREERTOS_INTERRUPT(function) \
        void _##function(void); \
        void function(void) __attribute__((interrupt, noreturn)); \
        void function(void) \
        { \
            /* vPortFreeRTOSInterruptCommonHandler_C() will not return here. */ \
            __asm volatile \
            ( \
                "movw bc, #__" #function "\n" \
                "br !!_vPortFreeRTOSInterruptCommonHandler_C\n" \
            ); \
            /* The following is intended to remove the epilogue code. */ \
            while (1) {} \
        } \

    #endif

    このマクロを以下のように使用することで、コード生成機能の割り込み処理ルーチンからFreeRTOS APIを不便無く(コード生成する度にコード生成されたソースを書き直すこと無く)呼び出すことが出来るようになります。

    src/r_cg_intc_user.c

    CC-RLの場合

    /******************************************************************************
    Includes
    ******************************************************************************/
    #include "r_cg_macrodriver.h"
    #include "r_cg_intc.h"
    /* Start user code for include. Do not edit comment generated here */
    #include "freertos_start.h"
    #include "freertos_isr.h"
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"

    /******************************************************************************
    Pragma directive
    ******************************************************************************/
    #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 */

    GNURL78の場合

    /******************************************************************************
    Includes
    ******************************************************************************/
    #include "r_cg_macrodriver.h"
    #include "r_cg_intc.h"
    /* Start user code for include. Do not edit comment generated here */
    #include "freertos_start.h"
    #include "freertos_isr.h"
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"

    /******************************************************************************
    Global variables and functions
    ******************************************************************************/
    /* Start user code for global. 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 */

    呼び出し例(CC-RL/GNURL78共通)

    /******************************************************************************
    * Function Name: r_intc3_interrupt
    * Description  : This function is INTP3 interrupt service routine.
    * Arguments    : None
    * Return Value : None
    ******************************************************************************/
    void r_intc3_interrupt(void)
    {
        /* Start user code. Do not edit comment generated here */

        short sHigherPriorityTaskWoken = pdFALSE;

        xSemaphoreGiveFromISR( xSemaphoreINTP3, &sHigherPriorityTaskWoken );
        portYIELD_FROM_ISR( sHigherPriorityTaskWoken );

        /* End user code. Do not edit comment generated here */
    }

    zipファイルのプロジェクトでは、full demo プロジェクトでFreeRTOSConfig.hのFREERTOS_USER_MAINを以下のように1にすると、以下のタスクを生成した状態での割り込み処理動作をSimulator GUIのパネルで試すことが出来ます。

    frtos_config/FreeRTOSConfig.h

    /* Set FREERTOS_USER_MAIN to one to run an user main other than test/demo main.
    Project file may set this to two by compiler command line option to run one of
    examples which can be obtained in the FreeRTOS Kernel Developer Guide from AWS,
    https://docs.aws.amazon.com/ja_jp/freertos-kernel/latest/dg/task-management.html */
    #ifndef FREERTOS_USER_MAIN
    #define FREERTOS_USER_MAIN                    1
    #endif

    src/user_main.c

    void main_task(void *pvParameters)
    {
        (void) pvParameters;

        while (1)
        {
        }
    }

    void second_task(void *pvParameters)
    {
        (void) pvParameters;

        while (1)
        {
        }
    }

    void third_task(void *pvParameters)
    {
        (void) pvParameters;

        while (1)
        {
        }
    }

    void intp3_task(void *pvParameters)
    {
        (void) pvParameters;

        R_INTC3_Start();

        LED_INIT();
        while (1)
        {
            xSemaphoreTake( xSemaphoreINTP3, portMAX_DELAY );
            LED_BIT = !LED_BIT;
        }
    }

    frtos_startup/freertos_start.c

    void Processing_Before_Start_Kernel(void)
    {
        BaseType_t ret;

        /************** semaphore creation ***********************/
        xSemaphoreINTP3 = xSemaphoreCreateBinary();
        if (xSemaphoreINTP3 == NULL)
        {
            while(1)
            {
                /* Failed! Semaphore can not be created. */
            }
        }

        /************** mutex creation ***************************/


        /************** queues creation **************************/


        /************** event groups creation ********************/


        /************** mailbox creation *************************/


        /************** memory pool creation *********************/


        Kernel_Object_init();

        /************** task creation ****************************/
        /* Main task. */
        ret = xTaskCreate(main_task, "MAIN_TASK", 512, NULL, 1, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

        /* Second task. */
        ret = xTaskCreate(second_task, "2ND_TASK", 512, NULL, 1, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

        /* Third task. */
        ret = xTaskCreate(third_task, "3RD_TASK", 512, NULL, 1, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

        /* INTP3 task. */
        ret = xTaskCreate(intp3_task, "INTP3_TASK", 512, NULL, 3, NULL);
        if (pdPASS != ret)
        {
            while(1)
            {
                /* Failed! Task can not be created. */
            }
        }

    } /* End of function Processing_Before_Start_Kernel() */

    Simulator GUIでは、パネル上でボタン(プッシュボタン)を押すごとにLEDのOn/Offが切り替わります。

      

Children