こんにちは。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連投の1つ目です。自作のRX-TBのFreeRTOS Sample Programを移植しようとしているのですが、ちょっと欲張って、チョコさんのリングバッファを使ってみようとか、(DMAが無いのだから)DTCを使ってみようとか、しているうちに年末になってしまいました。(コーディングまではしたものの、デバッグはこれからです。) もう暫く掛かってしまいそうですので、ひとまず、このスレッドの最初の投稿でやっていた、Renesas RL78 Simulatorで動作させていたRL78 FreeRTOS Full DemoプログラムとAmazon AWSのFreeRTOS Kernel Developer GuideのサンプルコードをG13→G14へ変更(+α)しましたので、まず、それを投稿します。以下、プロジェクトのファイル一式です。(CC-RL版はCS+ V8.02/e2 stuiod 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に似せてあります。rl78g14fpb_freertos_full_demo_ccrl_c_csplus_20191225.zip (*1,*2) 668KBrl78g14fpb_freertos_full_demo_gnurl78_c_e2v760_20191225.zip (*1,*2,*3) 591KB*1:LED(やSW)のポートはRL78/G14 Fast Prototyping Boardと同じにしてありますので、FreeRTOS Full Demoの方は実機でもLED点滅の確認が出来ます。(ですが、FreeRTOS Kernel Developer Guideのサンプルコードの方は実機対応のvPrintString()出力ルーチンを作っていませんので、実機では確認が出来ないです。))*2:実機用のデバッガプロパティ設定(CS+)や.launchファイル設定(e2 studio)は当方特有の事情でオンボードエミュレータが使えない為に未確認です。(ひと通りは設定してあります。)*3:リンカスクリプトには別スレッド「GNURL78でconst領域/Mirror領域をちょっと安全に使えるようにlinker scriptのASSERT()で小技(TIPS)を考えてみた」に投稿した内容を反映してあります。今回、FreeRTOS Full DemoのLEDやSWのポートのアサインは以下のようになっています。(赤文字箇所を追加しました。) なお、src/FreeRTOSフォルダ以下は、この箇所を除いて、このスレッドのこれまでのソースと同じです。src/FreeRTOS/Demo/demo_specific_io.h
/* * FreeRTOS Kernel V10.2.1 * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * 。。。省略。。。 * * 1 tab == 4 spaces! */#ifndef LED_IO_H#define LED_IO_H/* Include the register definition file that is correct for the hardware beingused. The C and assembler pre-processor must have one of the following boarddefinitions defined to have the correct register definition header fileincluded. Alternatively, just manually include the correct files here. */ /* Prevent the files being included from the FreeRTOS port layer assembly source files. */ #ifndef __ASSEMBLER__ #if defined(__CCRL__) || defined(__GNUC__) #include "iodefine.h" #if defined(__GNUC__) #include "iodefine_ext.h" #endif /* defined(__GNUC__) */ #endif /* defined(__CCRL__) || defined(__GNUC__) */ #ifdef AE_R5F100LGAFB #if defined(__IAR_SYSTEMS_ICC__) && !defined(__CCRL__) && !defined(__CNV_IAR__) #include "ior5f100lg.h" #include "ior5f100lg_ext.h" #endif /* defined(__IAR_SYSTEMS_ICC__) && !defined(__CCRL__) && !defined(__CNV_IAR__) */ /* P5.0 is compatible with LED_BUILTIN of GR-KURUMI and GR-COTTON */ #define LED_BIT ( P5_bit.no0 ) #define LED_INIT() do{ P5 &= 0xFE; PM5 &= 0xFE; }while (0) #endif /* AE_R5F100LGAFB */ #ifdef RL78G14FPB #if defined(__IAR_SYSTEMS_ICC__) && !defined(__CCRL__) && !defined(__CNV_IAR__) #include "ior5f104ml.h" #include "ior5f104ml_ext.h" #endif /* defined(__IAR_SYSTEMS_ICC__) && !defined(__CCRL__) && !defined(__CNV_IAR__) */ #define LED_BIT ( P4_bit.no3 ) #define LED_INIT() do{ P4 &= 0xF7; PM4 &= 0xF7; P4 |= 0x10; PM4 &= 0xEF; }while (0) #endif /* RL78G14FPB */ #ifdef YRPBRL78G13 #if defined(__IAR_SYSTEMS_ICC__) && !defined(__CCRL__) && !defined(__CNV_IAR__) #include "ior5f100le.h" #include "ior5f100le_ext.h" #endif /* defined(__IAR_SYSTEMS_ICC__) && !defined(__CCRL__) && !defined(__CNV_IAR__) */ #define LED_BIT ( P7_bit.no7 ) #define LED_INIT() P7 &= 0x7F; PM7 &= 0x7F #endif /* YRPBRL78G13 */ 。。。省略。。。 #ifndef LED_BIT #error The hardware platform is not defined #endif #endif /* INCLUDED_FROM_FREERTOS_ASM_FILE */#endif /* LED_IO_H */
また、今回、RXマイコンのFITのBSPモジュールにあるplatform.hというファイル名を借用して、それっぽいような以下のヘッダファイルを作ってみました。src/platform.h
#ifndef PLATFORM_H#define PLATFORM_H#ifdef __cplusplusextern "C" {#endif#include "r_cg_macrodriver.h"#include "r_cg_userdefine.h"#if defined(__CCRL__) && !defined(_STDINT_H)#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"#if defined(__CCRL__) && (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L))#define bool _Bool#define true 1#define false 0#define __bool_true_false_are_defined 1#else#include <stdbool.h>#endif#include <stdio.h>#include <stddef.h>#include <string.h>#if defined(__GNUC__)#define BRK() asm("brk")#endif#define di() DI()#define ei() EI()#define halt() HALT()#define nop() NOP()#define stop() STOP()#define brk() BRK()#define INTERNAL_NOT_USED(p) ((void)(p))#if defined(__CCRL__)#define R_CG_DEFAULT_ISR_UNUSED(name)\ static void __near name##_UNUSED(void);\ void _##name##_UNUSED(void){name##_UNUSED();}#define R_CG_REDEFINE_ISR(name)\ static void __near name(void);#elif defined(__GNUC__)#define R_CG_DEFAULT_ISR_UNUSED(name)\ void name##_UNUSED(void) __attribute__ ((unused));#define R_CG_REDEFINE_ISR(name)\ void name(void) __attribute__ ((interrupt));#endif#if defined(RENESAS_SIMULATOR_DEBUGGING)#include "RenesasSimDebug/sim_debug_mode_hook.h"#endif#ifdef __cplusplus}#endif#endif /* PLATFORM_H */
なお、このヘッダファイルをコード生成機能で自動生成されるソースでいちいち#includeするのが面倒に思われましたので、以下のようにr_cg_userdefine.hのユーザ記述部で#includeするようにしてみました。(ですが、この投稿を書いていて、platform.hとr_cg_userdefine.hでインクルードが循環していることに気付きました。インクルードガードにより問題は起きないですが、、、)src/r_cg_userdefine.h
#ifndef _USER_DEF_H#define _USER_DEF_H/******************************************************************************User definitions******************************************************************************//* Start user code for function. Do not edit comment generated here */#include "platform.h"/* End user code. Do not edit comment generated here */#endif
この後、2投目、3投目は以下の通りです。2投目 (ひたすら画面コピーです)・プロジェクト構造 極力RX-TBの自作のFreeRTOSプロジェクトもどきSample Programに似せてあります。・Renesas RL78 SimulatorでのRL78 FreeRTOS Full Demoの実行例・Renesas RL78 SimulatorでのAmazon AWSのFreeRTOS Kernel Developer Guideのサンプルコードの実行例3投目 (ひたすら画面コピーです)・CC-RL/GNURL78の最適化オプション設定(及びGNURL78でのアーキテクチャ設定) 未使用の変数/関数を削除する等の実行速度を低下させない範囲でのサイズ削減設定をしています。 (GNURL78では-fltoオプションも指定したかったのですが、e2 studioのスタック解析ビューが表示されなくなってしまった為、今回は指定しませんでした。)・コンパイルオプションにて設定しているマクロ定義