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です。

    (今度もRenesas RL78 Simulatorですが、、、) 先日の、DMAでUART受信しながらタイムアウトエラーやフレーミングエラー/パリティエラー/オーバーランエラーを検出するようにしてみたプログラムの変な挙動ですが、受信エラー割り込みが複数回発生しないようにするやり方でも対処してみました。また、同様のやり方で、割り込みでUART受信しながらこれらのエラーを検出するプログラムも作ってみました。以下、プロジェクトのファイル一式です。

    sim_rl78_freertos_ccrl_c_csplus_DMA_20190701.zip    664KB
    sim_rl78_freertos_gnurl78_c_e2v740_DMA_20190701.zip    615KB

    sim_rl78_freertos_ccrl_c_csplus_INT_20190701.zip    654KB
    sim_rl78_freertos_gnurl78_c_e2v740_INT_20190701.zip    607KB

    今回、以下のグルー関数を作成/使用し、受信エラー割り込みが複数回発生しないようにしてみました。(CC-RLの場合のものですがGNURL78でも同様です。)

    ●DMA受信版

    src/r_cg_serial.c

    void U_UART0_DMAC0_Receive_Stop(void)
    {
        SREMK0 = 1U;   /* disable INTSRE0 interrupt */
        R_DMAC0_Stop();
    }

    src/r_cg_serial_user.c

    #pragma interrupt r_uart0_interrupt_send(vect=INTST0)
    #pragma interrupt r_uart0_interrupt_receive(vect=INTSR0)
    #pragma interrupt r_uart0_interrupt_error(vect=INTSRE0)
    /* Start user code for pragma. Do not edit comment generated here */
    R_PRAGMA_FREERTOS_INTERRUPT(r_uart0_interrupt_error)
    #define r_uart0_interrupt_error _r_uart0_interrupt_error
    /* End user code. Do not edit comment generated here */
    static void r_uart0_callback_error(uint8_t err_type)
    {
        /* Start user code. Do not edit comment generated here */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        /* return SSR01 error type instead of RXD0 data.
         */
        *gp_uart0_rx_address = err_type;

        /* Prevent from unexpected error callback more than once.
         * Such unexpected multiple callback causes unexpected multiple semaphore give operation.
         */
        U_UART0_DMAC0_Receive_Stop();

        /* 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 */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        /* Prevent from unexpected error callback more than once.
         * Such unexpected multiple callback causes unexpected multiple semaphore give operation.
         */
        U_UART0_DMAC0_Receive_Stop();

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

    ●割り込み受信版

    src/r_cg_serial.c

    void U_UART0_Receive_Stop(void)
    {
        SRMK0 = 1U;    /* disable INTSR0 interrupt */
        SREMK0 = 1U;   /* disable INTSRE0 interrupt */
    }

    src/r_cg_serial_user.c

    #pragma interrupt r_uart0_interrupt_send(vect=INTST0)
    #pragma interrupt r_uart0_interrupt_receive(vect=INTSR0)
    #pragma interrupt r_uart0_interrupt_error(vect=INTSRE0)
    /* Start user code for pragma. Do not edit comment generated here */
    R_PRAGMA_FREERTOS_INTERRUPT(r_uart0_interrupt_receive)
    #define r_uart0_interrupt_receive _r_uart0_interrupt_receive
    R_PRAGMA_FREERTOS_INTERRUPT(r_uart0_interrupt_error)
    #define r_uart0_interrupt_error _r_uart0_interrupt_error
    /* End user code. Do not edit comment generated here */
    static void r_uart0_callback_receiveend(void)
    {
        /* Start user code. Do not edit comment generated here */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        /* Prevent from unexpected error callback after receive end.
         * Such unexpected callback causes unexpected semaphore give operation.
         */
        U_UART0_Receive_Stop();

        /* End user code. Do not edit comment generated here */
    }
    static void r_uart0_callback_error(uint8_t err_type)
    {
        /* Start user code. Do not edit comment generated here */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        *gp_uart0_err_type = err_type;

        /* Prevent from unexpected error callback more than once.
         * Such unexpected multiple callback causes unexpected multiple semaphore give operation.
         */
        U_UART0_Receive_Stop();

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

    以下、タスク側のソースと他のグルー関数のソースです。

    ●DMA受信版

    src/user_main.c

    void uart_recv_demo_task(void *pvParameters)
    {
        ...略...

        U_UART0_Start();

        for (;;)
        {
            ...略...

            U_UART0_DMAC0_Receive_Start( recv_buff, UART_RECV_DEMO_SIZE, &err_type );

            /* --- Waiting for a transmission of serial data on the Simulator GUI --- */
            ret = xSemaphoreTake( xSemaphoreINTDMA0_INTSRE0, pdMS_TO_TICKS(100) );
            if (pdPASS == ret && 0 == err_type)
            {
                taskENTER_CRITICAL();
                LED_B = LED_ON;
                vPrintString( "Received Message: " );
                vPrintString( (char *)recv_buff );
                vPrintString( "\n" );
                taskEXIT_CRITICAL();
            }
            else
            {
                taskENTER_CRITICAL();
                LED_R = LED_ON;
                if (pdFAIL == ret)
                {
                    U_UART0_DMAC0_Receive_Stop();
                    LAB_TIMEOUT_ERROR = LAB_SHOW;
                    vPrintString( "Timeout Error\n" );
                }
                else
                {
                    ...略...
                }
                taskEXIT_CRITICAL();
            }

            NOP();  /* for breakpoint, check timing chart on Simulator GUI */
        }
    }

    src/r_cg_serial.c

    void U_UART0_DMAC0_Start(void)
    {
        R_UART0_Start();
        SRMK0 = 1U;    /* disable INTSR0 interrupt */
    }
    void U_UART0_DMAC0_Receive_Start(volatile uint8_t * const rx_buf, uint16_t const rx_num, 
                                     volatile uint8_t * const p_err_type)
    {
        (void) RXD0;        /* dummy read */
        SIR01 = 0x0007U;    /* clear UART0 error flags */
        *p_err_type = 0;    /* clear UART0 error flags buffer */
        R_UART0_Receive( (uint8_t *) p_err_type, 1 );    /* for INTSRE0 interrupt */
        U_DMAC0_UserInit( rx_buf, rx_num );
        SREIF0 = 0U;   /* clear INTSRE0 interrupt flag */
        SREMK0 = 0U;   /* enable INTSRE0 interrupt */
        R_DMAC0_Start();
    }

    ●割り込み受信版

    src/user_main.c

    void uart_recv_demo_task(void *pvParameters)
    {
        ...略...

        U_UART0_Start();

        for (;;)
        {
            ...略...

            U_UART0_Receive_Start( recv_buff, UART_RECV_DEMO_SIZE, &err_type );

            /* --- Waiting for a transmission of serial data on the Simulator GUI --- */
            ret = xSemaphoreTake( xSemaphoreCBRECEIVEEND_CBERROR, pdMS_TO_TICKS(100) );
            if (pdPASS == ret && 0 == err_type)
            {
                taskENTER_CRITICAL();
                LED_B = LED_ON;
                vPrintString( "Received Message: " );
                vPrintString( (char *)recv_buff );
                vPrintString( "\n" );
                taskEXIT_CRITICAL();
            }
            else
            {
                taskENTER_CRITICAL();
                LED_R = LED_ON;
                if (pdFAIL == ret)
                {
                    U_UART0_Receive_Stop();
                    LAB_TIMEOUT_ERROR = LAB_SHOW;
                    vPrintString( "Timeout Error\n" );
                }
                else
                {
                    ...略...
                }
                taskEXIT_CRITICAL();
            }

            NOP();  /* for breakpoint, check timing chart on Simulator GUI */
        }
    }

    src/r_cg_serial.c

    void U_UART0_Start(void)
    {
        R_UART0_Start();
        U_UART0_Receive_Stop();
    }
    void U_UART0_Receive_Start(volatile uint8_t * const rx_buf, uint16_t const rx_num, 
                               volatile uint8_t * const p_err_type )
    {
        (void) RXD0;        /* dummy read */
        SIR01 = 0x0007U;    /* clear UART0 error flags */
        *p_err_type = 0;    /* clear UART0 error flags buffer */
        gp_uart0_err_type = p_err_type;
        R_UART0_Receive( (uint8_t *) rx_buf, rx_num );
        SRIF0 = 0U;    /* clear INTSR0 interrupt flag */
        SREIF0 = 0U;   /* clear INTSRE0 interrupt flag */
        SRMK0 = 0U;    /* enable INTSR0 interrupt */
        SREMK0 = 0U;   /* enable INTSRE0 interrupt */
    }

    それから、Renesas RL78 Simulatorで、Simulator GUIのタイミングチャートウィンドウでポート出力トグルとUART受信の波形を表示させてみました。割り込み受信版は、受信割り込みの影響で、ポート出力トグルの波形に乱れがありますね。

    ●DMA受信版


    ●割り込み受信版

Reply
  • こんにちは。NoMaYです。

    (今度もRenesas RL78 Simulatorですが、、、) 先日の、DMAでUART受信しながらタイムアウトエラーやフレーミングエラー/パリティエラー/オーバーランエラーを検出するようにしてみたプログラムの変な挙動ですが、受信エラー割り込みが複数回発生しないようにするやり方でも対処してみました。また、同様のやり方で、割り込みでUART受信しながらこれらのエラーを検出するプログラムも作ってみました。以下、プロジェクトのファイル一式です。

    sim_rl78_freertos_ccrl_c_csplus_DMA_20190701.zip    664KB
    sim_rl78_freertos_gnurl78_c_e2v740_DMA_20190701.zip    615KB

    sim_rl78_freertos_ccrl_c_csplus_INT_20190701.zip    654KB
    sim_rl78_freertos_gnurl78_c_e2v740_INT_20190701.zip    607KB

    今回、以下のグルー関数を作成/使用し、受信エラー割り込みが複数回発生しないようにしてみました。(CC-RLの場合のものですがGNURL78でも同様です。)

    ●DMA受信版

    src/r_cg_serial.c

    void U_UART0_DMAC0_Receive_Stop(void)
    {
        SREMK0 = 1U;   /* disable INTSRE0 interrupt */
        R_DMAC0_Stop();
    }

    src/r_cg_serial_user.c

    #pragma interrupt r_uart0_interrupt_send(vect=INTST0)
    #pragma interrupt r_uart0_interrupt_receive(vect=INTSR0)
    #pragma interrupt r_uart0_interrupt_error(vect=INTSRE0)
    /* Start user code for pragma. Do not edit comment generated here */
    R_PRAGMA_FREERTOS_INTERRUPT(r_uart0_interrupt_error)
    #define r_uart0_interrupt_error _r_uart0_interrupt_error
    /* End user code. Do not edit comment generated here */
    static void r_uart0_callback_error(uint8_t err_type)
    {
        /* Start user code. Do not edit comment generated here */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        /* return SSR01 error type instead of RXD0 data.
         */
        *gp_uart0_rx_address = err_type;

        /* Prevent from unexpected error callback more than once.
         * Such unexpected multiple callback causes unexpected multiple semaphore give operation.
         */
        U_UART0_DMAC0_Receive_Stop();

        /* 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 */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        /* Prevent from unexpected error callback more than once.
         * Such unexpected multiple callback causes unexpected multiple semaphore give operation.
         */
        U_UART0_DMAC0_Receive_Stop();

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

    ●割り込み受信版

    src/r_cg_serial.c

    void U_UART0_Receive_Stop(void)
    {
        SRMK0 = 1U;    /* disable INTSR0 interrupt */
        SREMK0 = 1U;   /* disable INTSRE0 interrupt */
    }

    src/r_cg_serial_user.c

    #pragma interrupt r_uart0_interrupt_send(vect=INTST0)
    #pragma interrupt r_uart0_interrupt_receive(vect=INTSR0)
    #pragma interrupt r_uart0_interrupt_error(vect=INTSRE0)
    /* Start user code for pragma. Do not edit comment generated here */
    R_PRAGMA_FREERTOS_INTERRUPT(r_uart0_interrupt_receive)
    #define r_uart0_interrupt_receive _r_uart0_interrupt_receive
    R_PRAGMA_FREERTOS_INTERRUPT(r_uart0_interrupt_error)
    #define r_uart0_interrupt_error _r_uart0_interrupt_error
    /* End user code. Do not edit comment generated here */
    static void r_uart0_callback_receiveend(void)
    {
        /* Start user code. Do not edit comment generated here */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        /* Prevent from unexpected error callback after receive end.
         * Such unexpected callback causes unexpected semaphore give operation.
         */
        U_UART0_Receive_Stop();

        /* End user code. Do not edit comment generated here */
    }
    static void r_uart0_callback_error(uint8_t err_type)
    {
        /* Start user code. Do not edit comment generated here */

        BaseType_t sHigherPriorityTaskWoken = pdFALSE;

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

        *gp_uart0_err_type = err_type;

        /* Prevent from unexpected error callback more than once.
         * Such unexpected multiple callback causes unexpected multiple semaphore give operation.
         */
        U_UART0_Receive_Stop();

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

    以下、タスク側のソースと他のグルー関数のソースです。

    ●DMA受信版

    src/user_main.c

    void uart_recv_demo_task(void *pvParameters)
    {
        ...略...

        U_UART0_Start();

        for (;;)
        {
            ...略...

            U_UART0_DMAC0_Receive_Start( recv_buff, UART_RECV_DEMO_SIZE, &err_type );

            /* --- Waiting for a transmission of serial data on the Simulator GUI --- */
            ret = xSemaphoreTake( xSemaphoreINTDMA0_INTSRE0, pdMS_TO_TICKS(100) );
            if (pdPASS == ret && 0 == err_type)
            {
                taskENTER_CRITICAL();
                LED_B = LED_ON;
                vPrintString( "Received Message: " );
                vPrintString( (char *)recv_buff );
                vPrintString( "\n" );
                taskEXIT_CRITICAL();
            }
            else
            {
                taskENTER_CRITICAL();
                LED_R = LED_ON;
                if (pdFAIL == ret)
                {
                    U_UART0_DMAC0_Receive_Stop();
                    LAB_TIMEOUT_ERROR = LAB_SHOW;
                    vPrintString( "Timeout Error\n" );
                }
                else
                {
                    ...略...
                }
                taskEXIT_CRITICAL();
            }

            NOP();  /* for breakpoint, check timing chart on Simulator GUI */
        }
    }

    src/r_cg_serial.c

    void U_UART0_DMAC0_Start(void)
    {
        R_UART0_Start();
        SRMK0 = 1U;    /* disable INTSR0 interrupt */
    }
    void U_UART0_DMAC0_Receive_Start(volatile uint8_t * const rx_buf, uint16_t const rx_num, 
                                     volatile uint8_t * const p_err_type)
    {
        (void) RXD0;        /* dummy read */
        SIR01 = 0x0007U;    /* clear UART0 error flags */
        *p_err_type = 0;    /* clear UART0 error flags buffer */
        R_UART0_Receive( (uint8_t *) p_err_type, 1 );    /* for INTSRE0 interrupt */
        U_DMAC0_UserInit( rx_buf, rx_num );
        SREIF0 = 0U;   /* clear INTSRE0 interrupt flag */
        SREMK0 = 0U;   /* enable INTSRE0 interrupt */
        R_DMAC0_Start();
    }

    ●割り込み受信版

    src/user_main.c

    void uart_recv_demo_task(void *pvParameters)
    {
        ...略...

        U_UART0_Start();

        for (;;)
        {
            ...略...

            U_UART0_Receive_Start( recv_buff, UART_RECV_DEMO_SIZE, &err_type );

            /* --- Waiting for a transmission of serial data on the Simulator GUI --- */
            ret = xSemaphoreTake( xSemaphoreCBRECEIVEEND_CBERROR, pdMS_TO_TICKS(100) );
            if (pdPASS == ret && 0 == err_type)
            {
                taskENTER_CRITICAL();
                LED_B = LED_ON;
                vPrintString( "Received Message: " );
                vPrintString( (char *)recv_buff );
                vPrintString( "\n" );
                taskEXIT_CRITICAL();
            }
            else
            {
                taskENTER_CRITICAL();
                LED_R = LED_ON;
                if (pdFAIL == ret)
                {
                    U_UART0_Receive_Stop();
                    LAB_TIMEOUT_ERROR = LAB_SHOW;
                    vPrintString( "Timeout Error\n" );
                }
                else
                {
                    ...略...
                }
                taskEXIT_CRITICAL();
            }

            NOP();  /* for breakpoint, check timing chart on Simulator GUI */
        }
    }

    src/r_cg_serial.c

    void U_UART0_Start(void)
    {
        R_UART0_Start();
        U_UART0_Receive_Stop();
    }
    void U_UART0_Receive_Start(volatile uint8_t * const rx_buf, uint16_t const rx_num, 
                               volatile uint8_t * const p_err_type )
    {
        (void) RXD0;        /* dummy read */
        SIR01 = 0x0007U;    /* clear UART0 error flags */
        *p_err_type = 0;    /* clear UART0 error flags buffer */
        gp_uart0_err_type = p_err_type;
        R_UART0_Receive( (uint8_t *) rx_buf, rx_num );
        SRIF0 = 0U;    /* clear INTSR0 interrupt flag */
        SREIF0 = 0U;   /* clear INTSRE0 interrupt flag */
        SRMK0 = 0U;    /* enable INTSR0 interrupt */
        SREMK0 = 0U;   /* enable INTSRE0 interrupt */
    }

    それから、Renesas RL78 Simulatorで、Simulator GUIのタイミングチャートウィンドウでポート出力トグルとUART受信の波形を表示させてみました。割り込み受信版は、受信割り込みの影響で、ポート出力トグルの波形に乱れがありますね。

    ●DMA受信版


    ●割り込み受信版

Children
No Data