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

  • こんにちは。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 vPortYield
    static 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_DEBUGGING
    const 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に変更しました。

  • こんにちは。NoMaYです。

    GNURX(e2 studio)版もやってみました。今回、zipファイルにe2 studioプロジェクトを2つ入れてみました。また、GNURX版を作っていて気付いた点やGNURX版とCC-RX版でソースを同じにしたかった点を反映させて、CC-RX(CS+/e2 studio)版も作り直しました。以下、プロジェクトのファイル一式です。(GNURX版はe2 studio v7.40+GNURX 2019q2(4.8.4.201902)でビルド)(CC-RX版はCS+ V8.01/e2 stuiod v7.40+CC-RX V2.03でビルド(e2 studio用.project/.cproject等を同梱))(共にzipファイルをe2 studioに直接インポート可能)

    sim_rx65n_freertos_gnurx_c_e2v740_20190530.zip    915KB
    sim_rx65n_freertos_ccrx_c_csplus_20190529.zip    990KB

    以下、GNURX版とCC-RX版のそれぞれのzipファイルにe2 studioプロジェクトを2つ入れてみた画面です。

    インポート時



    インポート後



    以下、FreeRTOS kernelの開発者ガイドのCコード例の実行画面です。

    GNURX+e2 studio+ルネサスRXシミュレータで実行


    CC-RX+e2 studio+ルネサスRXシミュレータで実行


    ちなみにFreeRTOS kernelの開発者ガイドではFreeRTOS Windowsシミュレータで実行
    docs.aws.amazon.com/ja_jp/freertos-kernel/latest/dg/task-management.html


    以下、ルネサスRXシミュレータで実行させてみたCコード例です。(ルネサスFreeRTOSプロジェクトはmain()を呼び出しませんので、src/frtos_startup/freertos_start.cのProcessing_Before_Start_Kernel()をmain()の代わりに使っています。) 開発者ガイドの最初のCコード例ということで、タスク内ではRTOSのAPIを何も呼び出していないCコードですが、、、

    src/frtos_startup/freertos_start.c

    void vTask1( void *pvParameters )
    {
    const char *pcTaskName = "Task 1 is running\r\n";
    volatile uint32_t ul; /* volatile to ensure ul is not optimized away.*/

        /* Remove compiler warning about unused parameter. */
        ( void ) pvParameters;

        /* As per most tasks, this task is implemented in an infinite loop. */
        for( ;; )
        {
            /* Print out the name of this task. */
            vPrintString( pcTaskName );
            /* Delay for a period. */
            for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
            {
                 /* This loop is just a very crude delay implementation. There is
                 nothing to do in here. Later examples will replace this crude loop
                 with a proper delay/sleep function. */
            }
         }
    }
    void vTask2( void *pvParameters )
    {
    const char *pcTaskName = "Task 2 is running\r\n";
    volatile uint32_t ul; /* volatile to ensure ul is not optimized away.*/

        /* Remove compiler warning about unused parameter. */
        ( void ) pvParameters;

        /* As per most tasks, this task is implemented in an infinite loop. */
        for( ;; )
        {
            /* Print out the name of this task. */
            vPrintString( pcTaskName );
            /* Delay for a period. */
            for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
            {
                /* This loop is just a very crude delay implementation. There is
                nothing to do in here. Later examples will replace this crude loop
                with a proper delay/sleep function. */
            }
        }
    }
    void Processing_Before_Start_Kernel(void)
    {
        /* Create one of the two tasks. Note that a real application should check
        the return value of the xTaskCreate() call to ensure the task was created
        successfully. */
        xTaskCreate( vTask1, /* Pointer to the function that implements thetask. */
                     "Task 1",/* Text name for the task. This is to facilitate debugging only. */
                     1000, /* Stack depth - small microcontrollers will use much less stack than this. */
                     NULL, /* This example does not use the task parameter. */
                     1, /* This task will run at priority 1. */
                     NULL ); /* This example does not use the task handle. */

        /* Create the other task in exactly the same way and at the same priority. */
        xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL );

        /* Start the scheduler so the tasks start executing. */
        vTaskStartScheduler();

        /* If all is well then main() will never reach here as the scheduler will
        now be running the tasks. If main() does reach here then it is likely that
        there was insufficient heap memory available for the idle task to be created.
        For more information, see Heap Memory Management. */
        for( ;; );
    }

     

  • こんにちは。NoMaYです。#前の投稿の続きです

    今回、CC-RXのC言語拡張仕様からGNURXのC言語拡張仕様への置き換え以外に、以下のことも行っています。

    (1) RXスマートコンフィグレータがGNURX向けに生成したベクタ配列変数に自前で実装した割り込み関数を配置する小細工
    (2) RXスマートコンフィグレータがGNURX向けに生成したコードでRTOSサポートを有効にする為のr_bsp_config.hの小細工
    (3) resetprg.cに追加したrenesas_simulator_debugging_keyがconst volatileだとGNURXでROMに配置されないので変更
    (4) GNURXでのワーニング対策でFreeRTOSConfig.hでconfigENABLE_BACKWARD_COMPATIBILITYを0で定義(未定義時は1)
    (5) FreeRTOS kernelのRX600v2のGNURX版もCC-RX版のconfigINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_Hの切り分けを導入
    (6) FreeRTOS kernelのRX600v2のGNURX版もCC-RX版と同様なルネサスRXシミュレータ向けの無理矢理な代替実装を追加

    以下、詳細です。

    (1) RXスマートコンフィグレータがGNURX向けに生成したベクタ配列変数に自前で実装した割り込み関数を配置する小細工

    CC-RXでは、C/C++ソースで#pragma interrupt XXX(vect=NNN)のように記述してコンパイルすれば、リンカがベクタテーブルにベクタを埋め込んでくれるのですが、RXスマートコンフィグレータがGNURX向けに生成したコードは、生成したソースに記述されたベクタ配列変数にRXスマートコンフィグレータがベクタを配置するようになっています。そこで、この為だけにRXスマートコンフィグレータにソースを生成させて、生成させたソースの幾つかはビルドから除外するようにし、生成されたソースに以下のような記述を追加してみました。(赤文字箇所) (なお、CC-RX/GNURX/ICCRX共通化BSPがリリースされ、RXスマートコンフィグレータがGNURXが持っている、CC-RXと同様のコンパイラ/リンカ機能を使うようになれば、こういうことは不要になる筈です。)

    src/smc_gen/general/r_cg_vector_table.c

    #include "r_cg_macrodriver.h"
    /* Start user code for include. Do not edit comment generated here */
    #define r_Config_CMT3_cmi3_interrupt vTickISR
    #ifndef RENESAS_SIMULATOR_DEBUGGING
    #define r_Config_ICU_software_interrupt vSoftwareInterruptISR
    #define r_Config_CMT1_cmi1_interrupt undefined_interrupt_source_isr
    #else
    #define r_Config_ICU_software_interrupt undefined_interrupt_source_isr
    #define r_Config_CMT1_cmi1_interrupt vSoftwareInterruptISR
    #if FREERTOS_USER_MAIN == 2
    #define r_Config_TPU4_tgi4a_interrupt undefined_interrupt_source_isr
    #define r_Config_TPU5_tgi5a_interrupt undefined_interrupt_source_isr
    #endif
    #endif
    extern void vTickISR( void );
    extern void vSoftwareInterruptISR( void );
    /* End user code. Do not edit comment generated here */
    #include "r_cg_userdefine.h"
    void * const Reserved_Vector[] __attribute((section(".rvectors"))) =
    {
        /* 0x0000 Reserved */
        (void (*)(void))0xFFFFFFFF,
    ...略...
        /* 0x006C ICU SWINT */
        r_Config_ICU_software_interrupt,
    ...略...
        /* 0x0074 CMT1 CMI1 */
        r_Config_CMT1_cmi1_interrupt,
    ...略...
        /* 0x0204 PERIB INTB129 */
        r_Config_CMT3_cmi3_interrupt,
    ...略...
    }

    src/smc_gen/Config_CMT1/Config_CMT1.h

    /* Start user code for function. Do not edit comment generated here */

    /* The src/FreeRTOS/Source/portable/Renesas/ files have its own implementation for the CMT1. */
    #define R_Config_CMT1_Create() do{}while (0)

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

    src/smc_gen/Config_CMT3/Config_CMT3.h

    /* Start user code for function. Do not edit comment generated here */

    /* The src/frtos_startup/freertos_start.c has its own implementation for the CMT3. */
    #define R_Config_CMT3_Create() do{}while (0)

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

    src/smc_gen/Config_TPU4/Config_TPU4.h

    /* Start user code for function. Do not edit comment generated here */

    /* The src/FreeRTOS/Demo/Full_Demo/IntQueueTimer.c has its own implementation for the TPU4. */
    #define R_Config_TPU4_Create() do{}while (0)

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

    src/smc_gen/Config_TPU5/Config_TPU5.h

    /* Start user code for function. Do not edit comment generated here */

    /* The src/FreeRTOS/Demo/Full_Demo/IntQueueTimer.c has its own implementation for the TPU5. */
    #define R_Config_TPU5_Create() do{}while (0)

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

    (2) RXスマートコンフィグレータがGNURX向けに生成したコードでRTOSサポートを有効にする為のr_bsp_config.hの小細工

    CC-RX版でRのTOSサポートを有効にする為のr_bsp_config.hの小細工は、別スレッド「FreeRTOSをFITやCG(や追々PDG2でも?)と一緒に使うサンプルプログラムをCSplusでビルド出来るプロジェクトにしてみた」に投稿したものですが、GNURX版ではそれだけでは足りませんでしたので、以下のように小細工しました。(赤文字箇所)

    src/smc_gen/r_config/r_bsp_config.h

    変更前

    /* This macro lets other modules no if a RTOS is being used.
       0 = RTOS is not used.
       1 = RTOS is used.
    */
    #define BSP_CFG_RTOS_USED               (0) /* Generated value. Do not edit this manually */

    変更後

    /* This macro lets other modules no if a RTOS is being used.
       0 = RTOS is not used.
       1 = FreeRTOS is used.
       2 = embOS is used.(This is not available.)
       3 = MicroC_OS is used.(This is not available.)
       4 = RI600V4 or RI600PX is used.(This is not available.)
    */
    #if !defined(BSP_CFG_RTOS_USED) || (BSP_CFG_RTOS_USED == 0)
    #if defined(BSP_CFG_RTOS_USED)
    #undef BSP_CFG_RTOS_USED
    #endif
    #define BSP_CFG_RTOS_USED               (0) /* Generated value. Do not edit this manually */
    #endif
    /* This macro is used to select which CMT channel used for system timer of RTOS.
     * The setting of this macro is only valid if the macro BSP_CFG_RTOS_USED is set to a value other than 0. */
    #if (BSP_CFG_RTOS_USED != 0)
    /* Setting value.
     * 0      = CMT channel 0 used for system timer of RTOS (recommended to be used for RTOS).
     * 1      = CMT channel 1 used for system timer of RTOS.
     * 2      = CMT channel 2 used for system timer of RTOS.
     * 3      = CMT channel 3 used for system timer of RTOS.
     * Others = Invalid. */
    #define BSP_CFG_RTOS_SYSTEM_TIMER       (3)
    #endif
    /* As of today, the r_bsp.h in the R_BSP module which is generated by the RX Smart Configurator for GNURX project
       does not support RTOS. Therefore RTOS header files are included here. */
    #if BSP_CFG_RTOS_USED == 0      /* Non-OS */
    #elif BSP_CFG_RTOS_USED == 1    /* FreeRTOS */
    #include "FreeRTOS.h"
    #include "task.h"
    #include "semphr.h"
    #include "queue.h"
    #include "croutine.h"
    #include "timers.h"
    #include "event_groups.h"
    #include "freertos_start.h"
    #elif BSP_CFG_RTOS_USED == 2    /* SEGGER embOS */
    #elif BSP_CFG_RTOS_USED == 3    /* Micrium MicroC/OS */
    #elif BSP_CFG_RTOS_USED == 4    /* Renesas RI600V4 & RI600PX */
    #else
    #endif

    (3) resetprg.cに追加したrenesas_simulator_debugging_keyがconst volatileだとGNURXでROMに配置されないので変更

    修飾子の組み合わせがconst volatileの場合、、CC-RXではROMに配置されたのですが、GNURXではROMに配置されずにRAMに配置されたので、以下のように修正しました。(赤文字箇所)

    src/r_bsp_modified/resetprg.c

    前回の版

    /* Switch Key for Renesas Simulator Debugging */
    #ifdef RENESAS_SIMULATOR_DEBUGGING
    const 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
        ...略...
    }

    今回の版

    /* Switch Key for Renesas Simulator Debugging */
    #ifdef RENESAS_SIMULATOR_DEBUGGING
    const 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 (*(volatile uint32_t *)&renesas_simulator_debugging_key != 0x00000001)
        {
            operating_frequency_set();
        }
    #endif
        ...略...
    }

    (4) GNURXでのワーニング対策でFreeRTOSConfig.hでconfigENABLE_BACKWARD_COMPATIBILITYを0で定義(未定義時は1)

    未定義時は以下のワーニングが出ましたので、出ないようにする為に、以下を追加しました。(青文字箇所)

    出たワーニング

    rx-elf-gcc @"src/FreeRTOS/Demo/Common/Minimal/QueueSet.o.in"
    In file included from ../src/FreeRTOS/Demo/Common/Minimal/QueueSet.c:47:0:
    ../src/FreeRTOS/Demo/Common/Minimal/QueueSet.c: In function 'prvTestQueueOverwriteWithQueueSet':
    …略…\src\FreeRTOS\Source\include/FreeRTOS.h:924:23: warning: declaration of 'QueueHandle_t' shadows a global declaration [-Wshadow]
      #define xQueueHandle QueueHandle_t
                           ^
    ../src/FreeRTOS/Demo/Common/Minimal/QueueSet.c:613:15: note: in expansion of macro 'xQueueHandle'
     QueueHandle_t xQueueHandle = NULL, xReceivedHandle = NULL;
                   ^
    In file included from ../src/FreeRTOS/Demo/Common/Minimal/QueueSet.c:49:0:
    …略…\src\FreeRTOS\Source\include/queue.h:48:34: warning: shadowed declaration is here [-Wshadow]
     typedef struct QueueDefinition * QueueHandle_t;
                                      ^

    追加した内容
    src/frtos_config/FreeRTOSConfig.h

    /* When the FIT configurator or the Smart Configurator is used, platform.h has
    to be used. */
    #define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H  1

    /* Definitions to allow backward compatibility with FreeRTOS versions prior to
    V8 if desired. */
    #define configENABLE_BACKWARD_COMPATIBILITY             0

    (5) FreeRTOS kernelのRX600v2のGNURX版もCC-RX版のconfigINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_Hの切り分けを導入

    RXスマートコンフィグレータでコード生成させた場合に、e2 studioがiodefine.hがあるBSPモジュールのフォルダのパスをインクルードパスリストから削除してしまう点はGNURXでもCC-RXと同様なので、以下のようにFreeRTOS kernelのRX600v2のCC-RX版と同じになるように修正しました。(赤文字箇所)

    src/FreeRTOS/Source/portable/GCC/RX600v2/port.c

    /* Hardware specifics. */
    #if defined( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H ) && ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 )
        #include "platform.h"
    #else
        #include "iodefine.h"
    #endif

    (6) FreeRTOS kernelのRX600v2のGNURX版もCC-RX版と同様なルネサスRXシミュレータ向けの無理矢理な代替実装を追加

    以下の通りです。(青文字箇所)

    src/FreeRTOS/Source/portable/GCC/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 = 0;

            /* 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();
        }

        /* Should not get here. */
        return pdFAIL;
    }

    src/FreeRTOS/Source/portable/GCC/RX600v2/portmacro.h

    #if !defined(RENESAS_SIMULATOR_DEBUGGING) || RENESAS_SIMULATOR_DEBUGGING == 0
    /* Yield equivalent to "*portITU_SWINTR = 0x01; ( void ) *portITU_SWINTR;"
    where portITU_SWINTR is the location of the software interrupt register
    (0x000872E0).  Don't rely on the assembler to select a register, so instead
    save and restore clobbered registers manually. */
    #define portYIELD()                         \
        __asm volatile                          \
        (                                       \
            "PUSH.L R10                 \n"     \
            "MOV.L  #0x872E0, R10       \n"     \
            "MOV.B  #0x1, [R10]         \n"     \
            "MOV.L  [R10], R10          \n"     \
            "POP    R10                 \n"     \
        )
    #else
    #define portYIELD()                                                         \
        __asm volatile                                                          \
        (                                                                       \
            "PUSH.L R10                 \n"                                     \
    \
            /* Disable the timer 1 interrupt. */                                \
            /* _IEN( _CMT1_CMI1 ) = 0; */                                       \
            "MOV.L  #0x00087203, R10    \n"                                     \
            "BCLR   #0x05, [R10].B      \n"                                     \
            /* Read back and test to complete a write access here. */           \
            /* if( _IEN( _CMT1_CMI1 ) == 0 ){}else{} */                         \
            "BTST   #0x05, [R10].B      \n"                                     \
    \
            /* Enable interrupt on compare match. (Divide the PCLK by 8.) */    \
            /* CMT1.CMCR.WORD = 0x00C0; */                                      \
            "MOV.L  #0x00088008, R10    \n"                                     \
            "MOV.W  #0x00C0, [R10]      \n"                                     \
    \
            /* Wait for the timer 1 interrupt request. */                       \
            /* while( _IR( _CMT1_CMI1 ) == 0 ){} */                             \
            "MOV.L  #0x0008701D, R10    \n"                                     \
    "?:"    "BTST   #0x00, [R10].B      \n"                                     \
            "BEQ    ?-                  \n"                                     \
    \
            /* Disable interrupt on compare match. (Divide the PCLK by 8.) */   \
            /* CMT1.CMCR.WORD = 0x0080; */                                      \
            "MOV.L  #0x00088008, R10    \n"                                     \
            "MOV.W  #0x0080, [R10]      \n"                                     \
    \
            /* Enable the timer 1 interrupt. */                                 \
            /* _IEN( _CMT1_CMI1 ) = 1; */                                       \
            "MOV.L  #0x00087203, R10    \n"                                     \
            "BSET   #0x05, [R10].B      \n"                                     \
            /* Read back and test to complete a write access here. */           \
            /* if( _IEN( _CMT1_CMI1 ) == 1 ){}else{} */                         \
            "BTST   #0x05, [R10].B      \n"                                     \
    \
            "POP    R10                 \n"                                     \
        )
    #endif

    #define portYIELD_FROM_ISR( x ) if( x != pdFALSE ) portYIELD()

    あとそれから、以下はGNURXでFull Demoをビルドした時のe2 studioの画面コピーです。

  • NoMaYさん

    こんにちは、シェルティです。

    種々ご検討いただきありがとうございます。
    近日中にFITモジュール全般を更新してCC-RX/GCC/IAR対応となります。
    またスマートコンフィグレータとAmazon FreeRTOSの連携もある程度可能になります。
    各開発チームには可能な限りNoMaYさんのレスを確認して取り込めるアイデアを取り込んでほしいと
    依頼はしておりますが、各人温度差があると思いますので、どのくらいうまくAmazon FreeRTOSと
    スマートコンフィグレータが連携して、かつ、コンパイラ違いの環境でもコンフィグレーションが正しく
    働くかが正直なところ未知数です。
    継続して改善を続けていくことになりますので、引き続きご意見などをいただけますと幸いです。

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

    今度はRenesas RL78 Simulatorでやってみました。残念ながらデバッグコンソール機能はありませんので、CS+ではPrintf Action Event機能を、e2 studioではDynamic Printf機能を、それぞれ使用しました。また、Simulator GUIにはLEDやButtonなどのGUI部品を並べたパネルを作成する機能がありますので、コード生成機能+FreeRTOSで割り込みを扱う簡単なプログラムを作成して、動作確認してみました。(今回は実機での確認をしてません。)

    以下、プロジェクトのファイル一式です。(CC-RL版はCS+ V8.01/e2 stuiod v7.40+CC-RX V1.02でビルド(e2 studio用.project/.cproject等を同梱))(GNURL78版はe2 studio v7.40+GNURL78 2019q2(4.9.2.201902)でビルド)(共にzipファイルをe2 studioに直接インポート可能) プロジェクト構造は極力RX版と同じにしてみました。

    sim_rl78_freertos_ccrl_c_csplus_20190612.zip    580KB
    sim_rl78_freertos_gnurl78_c_e2v740_20190612.zip    677KB

    以下、Printf Action Eventでの実行結果、Dynamic Printfでの実行結果、Simulator GUIでLEDとButtonを配置したパネル、の画面コピーです。







    今回のプロジェクトのベースは、別スレッド『FreeRTOSをFITやCG(や追々PDG2でも?)と一緒に使うサンプルプログラムをCSplusでビルド出来るプロジェクトにしてみた』のCC-RL版GNURL78版ですが、以下の小細工を追加しています。(なお、長時間運転の件は1年放置してしまっています。すみません、、、)

    (1) コード生成されたr_cg_macrodriver.hとFreeRTOSが使用するstdint.hとのint8_t/uint8_t等のtypedefの衝突の回避(CC-RL)
    (2) コード生成されたr_cg_vector_table.cにFreeRTOSのvPortTickISRとvPortYieldをスクリプトで自動ベクタ登録する(GNURL78)

    また、作業していて、以下の点には留意しておいた方が良さそうな気がしました。

    (3) FreeRTOSのstream_buffer.cでCC-RLの「偶数アライメントのオブジェクトを指すポインタが奇数番地を保持しています」が出る
    (4) FreeRTOSのGNURL78版では割り込み用スタックが使用されるが多重割り込みに対応していない(他方CC-RL版では使用されない)

    以下、その詳細です。

    (1) コード生成されたr_cg_macrodriver.hとFreeRTOSが使用するstdint.hとのint8_t/uint8_t等のtypedefの衝突の回避(CC-RL)

    幸い、FreeRTOSが使用するint8_t/uint8_t等のtypedefはr_cg_macrodriver.hに記述されているもので足りるようでしたので、以下のように小細工しました。(赤文字箇所)

    src/frtos_startup/freertos_start.h

    #include "r_cg_macrodriver.h"
    #include "r_cg_userdefine.h"
    #if defined(__CCRL__)
    #define _STDINT_H
    #endif
    #include "FreeRTOS.h"
    #include "task.h"
    #include "semphr.h"
    #include "queue.h"
    #include "croutine.h"
    #include "timers.h"
    #include "event_groups.h"

    (2) コード生成されたr_cg_vector_table.cにFreeRTOSのvPortTickISRとvPortYieldをスクリプトで自動ベクタ登録する(GNURL78)

    今回、r_cg_vector_table.jsというスクリプトを作成して、ビルド時に自動的に実行されるようにしました。このスクリプトでr_cg_vector_table.cを以下のように書き換えます。FreeRTOSのvPortTickISRとvPortYieldの他にも利用出来るよう、ちょっと大げさに書き換えることにしました。

    src/r_cg_vector_table.c

    自動書き換え前

    #include "r_cg_macrodriver.h"
    #include "r_cg_userdefine.h"

    ...略...

    #define VECT_SECT          __attribute__ ((section (".vects")))
    const void *Vectors[] VECT_SECT  = {
        // Address 0x4
        R_Dummy,
        ...略...
        // Address 0x7E
        R_Dummy,
    };

    自動書き換え後

    #include "r_cg_macrodriver.h"
    #include "r_cg_userdefine.h"
    #include "r_cg_vector_table.h"

    ...略...
    #define VECT_SECT          __attribute__ ((section (".vects")))
    const void *Vectors[] VECT_SECT  = {
        // Address 0x4
        R_Vector_0x4,
        ...略...
        // Address 0x7E
        R_Vector_0x7E,
    };

    そして、新規追加したr_cg_vector_table.hで以下のように任意のベクタを登録出来るようにしてみました。

    src/r_cg_vector_table.h

    /* Defines for user */

    /*
     * INT_IT (0x38 or 0x3C)
     */
    #if INTIT_vect == 0x38

    #define R_Vector_0x38 vPortTickISR

    #elif INTIT_vect == 0x3C

    #define R_Vector_0x3C vPortTickISR

    #else

    #error Neither vector 0x38 nor vector 0x3C is available for the tick interrupt.

    #endif

    /*
     * INT_BRK_I (0x7E)
     */
    #define R_Vector_0x7E vPortYield

    void vPortTickISR(void) __attribute__ ((interrupt));
    void vPortYield(void) __attribute__ ((interrupt));

    /* Defines for default */

    #ifndef R_Vector_0x4
    #define R_Vector_0x4  R_Dummy
    #endif
    ...略...
    #ifndef R_Vector_0x7E
    #define R_Vector_0x7E R_Dummy
    #endif

    (3) FreeRTOSのstream_buffer.cでCC-RLの「偶数アライメントのオブジェクトを指すポインタが奇数番地を保持しています」が出る

    CC-RLでコンパイルすると以下のワーニングが出ます。(GNURL78では出ませんがチェックしていないからです。) もしstream_buffer.cの機能を使用するのであれば、問題無いかどうか確認してから使用する必要があります。(今回、ちょっと気力不足で、私はFreeRTOSのソースを調べていないです。)

    src\FreeRTOS\Source\stream_buffer.c(262):W0523082:偶数アライメントのオブジェクトを指すポインタが奇数番地を保持しています。
    src\FreeRTOS\Source\stream_buffer.c(275):W0523082:偶数アライメントのオブジェクトを指すポインタが奇数番地を保持しています。

    (4) FreeRTOSのGNURL78版では割り込み用スタックが使用されるが多重割り込みに対応していない(他方CC-RL版では使用されない)

    もともとFreeRTOS 10.2.1のソースにCC-RL版はありませんので正確にはCC-RL版のベースにしたIAR版では使用されていない、ということなのですが、それに対してGNURL78版では以下のように割り込み用スタックへの切り替えが行われています。FreeRTOSカーネル自体は多重割り込み対応だろうとは思っていますが、以下の部分が多重割り込みでは誤動作する(多重割り込みでスタックポインタが割り込み用スタックの初期値に戻ってしまう)ので、もしGNURL78版でFreeRTOS APIを多重割り込み内から呼び出すようなことをしたければ改造が必要です。

    src/FreeRTOS/Source/portable/GCC/RL78/isr_support.h

    /*
     * portSAVE_CONTEXT MACRO
     * Saves the context of the general purpose registers, CS and ES registers,
     * the usCriticalNesting Value and the Stack Pointer of the active Task
     * onto the task stack
     */
        .macro portSAVE_CONTEXT

        SEL     RB0

        /* Save the register bank 0. */
        PUSH    AX
        PUSH    BC
        PUSH    DE
        PUSH    HL
        /* Save CS register. */
        MOV     A, CS
        XCH     A, X
        /* Save ES register. */
        MOV     A, ES
        PUSH    AX
        /* Save the other register banks - only necessary in the GCC port. */
        ...略...
        /* Registers in bank 3 are for ISR use only so don't need saving. */
        SEL     RB0
        /* Save the usCriticalNesting value. */
        MOVW    AX, !_usCriticalNesting
        PUSH    AX
        /* Save the Stack pointer. */
        MOVW    AX, !_pxCurrentTCB
        MOVW    HL, AX
        MOVW    AX, SP
        MOVW    [HL], AX
        /* Switch stack pointers. */
        movw sp,#_stack /* Set stack pointer */

        .endm

    あと、以下は、dev guide debugの実行時、full demoの実行時、full demoのビルド時の画面コピーです。

    CC-RL + CS+ + ルネサスRL78シミュレータで実行




    CC-RL + e2 studio + ルネサスRL78シミュレータで実行




    GNURL78 + e2 studio + ルネサスRL78シミュレータで実行


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

    CS+のPrintf Action Event機能も、e2 studioのDynamic Printf機能も、GUIから設定出来ますが、今回は以下のようにして、自動的に設定されるようにしました。

    CS+: ダウンロード後のフック関数のPythonスクリプトを記述

    sim_rl78_freertos_dev_guide_debug.py / sim_rl78_freertos_full_demo.py

    ...略...
    def AfterDownload():
        ThrowExceptSave = common.ThrowExcept
        ViewOutputSave  = common.ViewOutput
        common.ThrowExcept = False
        common.ViewOutput  = False
        if debugger.DebugTool.GetType() == DebugTool.Simulator:
            for ae in debugger.ActionEvent.Information():
                if ae.Address == "sim_debugger_console.c#1":
                    break;
            else:
                ae = ActionEventCondition()
                ae.Address = "sim_debugger_console.c#1"
                ae.Output = "char *"
                ae.Expression = "message"
                ae.ActionEventType = ActionEventType.Printf
                ae_number = debugger.ActionEvent.Set(ae)
        common.ThrowExcept = ThrowExceptSave
        common.ViewOutput  = ViewOutputSave
        return

    e2 studio: デバッグ構成の[Starup]の[コマンドを実行]にGDBコマンドを記述

    dprintf sim_debugger_console.c:1,"%s",message
    clear sim_debugger_console.c:1
    dprintf sim_debugger_console.c:1,"%s",message

    また、上記での自動設定(において重複設定してしまうことの回避)がやりやすくなるよう、イベントを設定するソースを以下のようにしました。

    src/sim_debugger_console.c

    void sim_debugger_console(const char *message); void sim_debugger_console(const char *message) { (void) message; }
    /* This is a stub function to output a string to the debugger console
    using an Action Event of the CS+ or a Dynamic Printf of the e2 studio
    for the Renesas RL78 Simulator. */

    上記の関数は以下で呼び出されます。

    src/frtos_startup/freertos_start.c

    /******************************************************************************
    * Function Name: vPrintString
    * Description  : This function is used to write a string to a debug console.
    * Arguments    : None.
    * Return Value : None.
    ******************************************************************************/
    void vPrintString(const char *pcMessage)
    {
        /* Write the string to a debug console, using a critical section
        as a crude method of mutual exclusion. */

        extern void sim_debugger_console( const char *message );

        taskENTER_CRITICAL();
        {
            sim_debugger_console( pcMessage );
        }
        taskEXIT_CRITICAL();

    } /* End of function vPrintString() */

    Simulator GUIのパネルのLEDとButtonは以下の画面コピーの通りに設定にしました。また、この設定はCS+ではSimulator GUI起動時に自動的に再設定されたのですが、e2 studioでは再設定されませんでしたので、この設定を保存したファイルsim_rl78_visual_parts_panel.pnlをzipファイルに同梱しました。なお、LEDとButtonを接続する端子はGR-KURUMIで扱える端子を選択してみました。









    あと、以下は、Renesas RL78 Simulatorの起動設定の画面コピーです。

    CS+





    e2 studio


  • こんにちは。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が切り替わります。

      

  • NoMaYさん

    シェルティです、こんにちは。

    本件、面白そうですね。時間を見つけて私もトライしてみます。
    これまでのAmazon FreeRTOS関連のノウハウを最近GitHubのウィキに書き始めました。
    github.com/.../wiki

    シミュレータ動作の件も整理して載せてみたいと思います。

    今は私はOTA関連の情報まとめを進めています。
    github.com/.../OTAの活用

    以上です
  • こんにちは。NoMaYです。

    Renesas RL78 Simulatorですが、各タスクでポート出力をトグルさせ、それをSimulator GUIのタイミングチャートウィンドウに表示してやれば、タスクの切り替わりが見えるようになりそうな気がしましたので、やってみました。以下、プロジェクトのファイル一式です。(今回はプロジェクトは1つだけです。)

    sim_rl78_freertos_ccrl_c_csplus_20190615.zip    623KB
    sim_rl78_freertos_gnurl78_c_e2v740_20190615.zip    580KB

    以下、CS+での画面コピーです。(e2 studioでも同様です。) タスクが切り替わっていく様子が見えます。

    プリエンプションが起きていない場合


    プリエンプションが起きた場合


    以下、各タスクでポート出力をトグルさせるプログラムです。(なお、CC-RLとGNURL78が生成したコードを見てみたところ、トグルさせる部分をクリティカルセクションとして扱わなくても大丈夫なコード(ビット操作命令で代入操作が行われるコード)には成っていました。このソースのリストファイルもzipファイルに同梱しました。)

    src/user_main.c

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

        while (1)
        {
            taskENTER_CRITICAL();
            P1_bit.no6 = !P1_bit.no6;
            taskEXIT_CRITICAL();
        }
    }

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

        while (1)
        {
            taskENTER_CRITICAL();
            P1_bit.no5 = !P1_bit.no5;
            taskEXIT_CRITICAL();
        }
    }

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

        while (1)
        {
            taskENTER_CRITICAL();
            P1_bit.no4 = !P1_bit.no4;
            taskEXIT_CRITICAL();
        }
    }

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

        R_INTC3_Start();

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

     

  • こんにちは。NoMaYです。

    今度もRenesas RL78 Simulatorですが、2.5μsec毎に100回連続A/D変換させてDMAでデータを取り込んでみました。ベースにしたプロジェクトは以前に『RL78/G13で2.5μsec毎に100回連続A/D変換させてDMAでデータを取り込むコードをコード生成させてシミュレータと実デバイスで試してみた』に投稿したものです。以下、プロジェクトのファイル一式です。(今回もプロジェクトは1つだけです。) (また、今回も実機では確認してません。)

    sim_rl78_freertos_ccrl_c_csplus_20190619.zip    673KB
    sim_rl78_freertos_gnurl78_c_e2v740_20190619.zip    625KB

    以下、CS+での画面コピーです。(e2 studioでも同様です。)




    今回、以下の部分で割り込みの発生待ちをするようにしてみました。(赤文字箇所)

    src/user_main.c

    void intp_timer_adc_dmac_demo_task(void *pvParameters)
    {
        uint8_t count;
        
        (void) pvParameters;
        NOP();  /* for breakpoint, start singnal input on Simulator GUI */

        taskENTER_CRITICAL();
        LED_INIT();
        taskEXIT_CRITICAL();

        R_INTC3_Start();

        R_ADC_Set_OperationOn();
        for (count = 0U ; count < 32U ; count++)    /* Waiting for comparator stabilizing */
        {
            NOP();
        }

        for (;;)
        {
            /* --- Waiting for a click of button on Simulator GUI --- */
            xSemaphoreTake( xSemaphoreINTP3, portMAX_DELAY );

            taskENTER_CRITICAL();
            LED_BIT = !LED_BIT;
            taskEXIT_CRITICAL();

            R_DMAC0_UserInit();

            /* --- Start TAU and A/D Convert and DMA --- */
            R_DMAC0_Start();                        /* Enable DMA : Start waiting DMA trigger */
            R_ADC_Start();                          /* Enable A/D : Start waiting A/D trigger */
            R_TAU0_Channel1_Lower8bits_Start();     /* Start! */

            /* --- A/D converting now --- */
            xSemaphoreTake( xSemaphoreINTDMA0, portMAX_DELAY );

            /* --- Stop TAU and A/D Convert and DMA --- */
            R_TAU0_Channel1_Lower8bits_Stop();
            R_ADC_Stop();
            R_DMAC0_Stop();

            taskENTER_CRITICAL();
            LED_BIT = !LED_BIT;
            taskEXIT_CRITICAL();

            NOP();  /* for trace start, check timing chart on Simulator GUI
                    after trace full break */
        }
    }

    割り込みルーチンは以下の通りです。(CC-RLの場合のものですがGNURL78でも同様です。)

    src/r_cg_intc_user.c

    #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 */
    static void __near 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 */
    }

    src/r_cg_dma_user.c

    #pragma interrupt r_dmac0_interrupt(vect=INTDMA0)
    /* Start user code for pragma. Do not edit comment generated here */
    R_PRAGMA_FREERTOS_INTERRUPT(r_dmac0_interrupt)
    #define r_dmac0_interrupt _r_dmac0_interrupt
    /* End user code. Do not edit comment generated here */
    static void __near r_dmac0_interrupt(void)
    {
        /* Start user code. Do not edit comment generated here */

        short sHigherPriorityTaskWoken = pdFALSE;

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

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

    また、先日の投稿と同様に、各タスクでポート出力をトグルさせています。

    src/user_main.c

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

        while (1)
        {
            taskENTER_CRITICAL();
            P1_bit.no6 = !P1_bit.no6;
            taskEXIT_CRITICAL();
        }
    }

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

        while (1)
        {
            taskENTER_CRITICAL();
            P1_bit.no5 = !P1_bit.no5;
            taskEXIT_CRITICAL();
        }
    }

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

        while (1)
        {
            taskENTER_CRITICAL();
            P1_bit.no4 = !P1_bit.no4;
            taskEXIT_CRITICAL();
        }
    }