こんにちは。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です。実機(秋月電子さんのRL78基板+LED)で試してみましたが、CC-RL版のFullDemoで3日連続運転することが出来ました。(1年以上前に試していたものは、今も1日連続運転出来ませんでした。)
こんにちは。NoMaYです。GNURL78版のFullDemoも実機(秋月電子さんのRL78基板+LED)で試してみると、3日連続運転することが出来ました。これで、1年以上前に試していた時より状況は良くなっているなぁ、というところですが、今のところ好転した契機として思い浮かぶのは、以下の項目のどれかかなぁ、といったところです。(1) FreeRTOSのバージョン(デモのソースを含む)をv10.0.1→10.2.1へ上げた(2) FreeRTOSConfig.hの変更(特に16bit tick→32bit tickとしたことが気になります)(3) ポートレイヤでのレジスタのPUSH/POPの順番を変えた(これは関係ないと思いますが)(4) Yieldの実装方法をBRK命令を使うやり方からソフトウェア割り込み機能もどきを使うやり方へ変えたどれが原因かは調べてみたい気持ちはありますが、最近、CA78K0Rを使用しているスレッドにリプライすることが何度かありましたので、CA78K0Rにも移植してみたい気持ちもあります、、、
こんにちは。NoMaYです。ルネサスさんからRL78/G14 Fast Prototyping Boardという安い評価ボードが出たのですが、私も購入してみたので、これに自作の以下のRX-TBのFreeRTOS Sample Programを移植してみようかと思います。LEDの数とSWの数がRX-TBと同じなので、、、(RL78にはFITがありませんのでCGで、、、)CSplusでFreeRTOSプロジェクトもどきSample Programを作ってRenesas RX Simulator/TB-RX65Nで試せるようにしてみたjapan.renesasrulz.com/cafe_rene/f/forum21/5980/csplus-freertos-sample-program-renesas-rx-simulator-tb-rx65ne2 studio+GNURXでFreeRTOSプロジェクトもどきSample Programを作ってRenesas RX Simulator/TB-RX65Nで試せるようにしてみたjapan.renesasrulz.com/cafe_rene/f/forum21/6012/e2-studio-gnurx-freertos-sample-program-renesas-rx-simulator-tb-rx65n「(1) TBボードのLED0を500ms毎にOn/Offする(FreeRTOS APIのvTaskDelay()を使用)(2) TBボードのSW1押下毎にLED1をOn/Offする(タスクでセマフォ待ちして割り込みでセマフォ待ち解除)(3) TBボードのSCI1で3文字受信毎に3文字エコーバックする(タスクでセマフォ待ちして割り込みで3文字毎にセマフォ待ち解除)」[関連スレッド]RL78の安い評価ボードが発売されています。japan.renesasrulz.com/cafe_rene/f/forum18/6086/rl78
こんにちは。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のスタック解析ビューが表示されなくなってしまった為、今回は指定しませんでした。)・コンパイルオプションにて設定しているマクロ定義
こんにちは。NoMaYです。#3連投の2つ目です。プロジェクト構造は以下の画面コピーの通りです。極力RX-TBの自作のFreeRTOSプロジェクトもどきSample Programに似せてあります。CC-RL+CS+の場合CC-RL+e2 studioの場合GNURL78+e2 studioの場合Renesas RL78 SimulatorでのRL78 FreeRTOS Full Demoの実行例は以下の画面コピーの通りです。CC-RL+CS+の場合CC-RL+e2 studioの場合GNURL78+e2 studioの場合Renesas RL78 SimulatorでのAmazon AWSのFreeRTOS Kernel Developer Guideのサンプルコードの実行例は以下の画面コピーの通りです。CC-RL+CS+の場合CC-RL+e2 studioの場合GNURL78+e2 studioの場合
こんにちは。NoMaYです。#3連投の3つ目です。CC-RL/GNURL78の最適化オプション設定(及びGNURL78でのアーキテクチャ設定)は以下の画面コピーの通りです。未使用の変数/関数を削除する等の実行速度を低下させない範囲でのサイズ削減設定をしています。なお、GNURL78では-fltoオプションも指定したかったのですが、e2 studioのスタック解析ビューが表示されなくなってしまった為、今回は指定しませんでした。また、コンパイルオプションにてRL78G14FPBとRENESAS_SIMULATOR_DEBUGGING=1のマクロ定義を設定しています。CC-RL+CS+の場合CC-RL+e2 studioの場合GNURL78+e2 studioの場合
こんにちは。NoMaYです。#4連投の1つ目です。自作の以下のRX-TBのFreeRTOS Sample ProgramをRL78/G14 Fast Prototyping Boardへ移植してみました。実は何パターンか実装するつもりでいて、今回、まず、UART送受信をDTCで行う版を投稿します。(後で、UART受信にチョコさんのリングバッファのソースコードを使用する版とか(デバッグ中)、UART送受信をコード生成機能が生成した割り込み処理のソースコードを素朴に使用する版とか(まだ未着手)、投稿してみようと思っています。)CSplusでFreeRTOSプロジェクトもどきSample Programを作ってRenesas RX Simulator/TB-RX65Nで試せるようにしてみたhttps://japan.renesasrulz.com/cafe_rene/f/forum21/5980/csplus-freertos-sample-program-renesas-rx-simulator-tb-rx65ne2 studio+GNURXでFreeRTOSプロジェクトもどきSample Programを作ってRenesas RX Simulator/TB-RX65Nで試せるようにしてみたjapan.renesasrulz.com/cafe_rene/f/forum21/6012/e2-studio-gnurx-freertos-sample-program-renesas-rx-simulator-tb-rx65n「(1) TBボードのLED0を500ms毎にOn/Offする(FreeRTOS APIのvTaskDelay()を使用)(2) TBボードのSW1押下毎にLED1をOn/Offする(タスクでセマフォ待ちして割り込みでセマフォ待ち解除)(3) TBボードのSCI1で3文字受信毎に3文字エコーバックする(タスクでセマフォ待ちして割り込みで3文字毎にセマフォ待ち解除)」RL78/G14 Fast Prototyping BoardではRX65NのSCI1の置き換えとしてRL78/G14のUART3を使用また、このスレッドの前に投稿していた以下のスレッドで、RL78/G13ですが、UART受信をDMAで行う際に受信エラーを返せるようにしたFreeRTOSサンプルプログラムを投稿したことがありましたので、今回、それを基に、受信エラー処理として以下の(3')の処理を追加しました。また、その時の投稿と同様に、Renesas RL78 Simulatorで読み込めるシリアル送信データファイル(.serファイル)も同梱しています。(なお、今回、.serファイルを1つ追加しています。)Amazon AWSのFreeRTOS Kernel Developer GuideのサンプルコードをRenesas RX SimulatorのDebug Consoleで試せるようにしてみたjapan.renesasrulz.com/cafe_rene/f/forum21/5790/amazon-aws-freertos-kernel-developer-guide-renesas-rx-simulator-debug-console/32271#32271これに投稿したRL78/G13のFreeRTOSサンプルプログラムを基に今回追加した動作『(3') 受信エラーを検出したらLED1を200ms毎にOn/OffさせるようにしてSW1が押下されたら受信エラー状態をクリアする 検出する受信エラー:パリティエラー、フレーミングエラー、オーバーランエラー、タイムアウト(60秒)』以下、プロジェクトのファイル一式です。(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_sampleprog1_ccrl_c_csplus_20200106.zip (*1) 406KBrl78g14fpb_freertos_sampleprog1_gnurl78_c_e2v760_20200106.zip (*1,*2) 372KB*1:実機用のデバッガプロパティ設定(CS+)や.launchファイル設定(e2 studio)は当方特有の事情でオンボードエミュレータが使えない為に未確認です。(ひと通りは設定してあります。)*2:リンカスクリプトには別スレッド「GNURL78でconst領域/Mirror領域をちょっと安全に使えるようにlinker scriptのASSERT()で小技(TIPS)を考えてみた」に投稿した内容を反映してあります。この後、2投目~4投目は以下の通りです。2投目ソースコードの記述でちょっと特殊なことをしている点(1) コード生成機能が生成した割り込み関数を自前の割り込み関数で置き換える(2) コード生成機能が生成した関数で使用すると都合が悪くなる関数を使用不可にする(3) Renesas RL78 SimulatorがN-chオープンドレイン出力でLEDを駆動する方法に未対応であることへの対処(4) DTC転送時の送信開始処理と送信終了判定処理(5) DTC保留命令によりタスク切り替えが起きなくなってしまったことへの対処3投目・各タスクのソース task_LED0 task_LED1 task_CONIO・Renesas RL78 Simulatorでシリアル送信データのファイルを使った実行例の画面コピー CC-RL+CS+ sim_rl78_serial_data_ok_2.ser(今回追加)を使用 sim_rl78_serial_data_err_uart_format.serを使用 GNURL78+e2 studio (CC-RL+e2 studioも同様) sim_rl78_serial_data_ok_2.ser(今回追加)を使用 sim_rl78_serial_data_err_uart_format.serを使用4投目・コード生成機能の設定の画面コピー DTC設定(転送元アドレスと転送先アドレスは単に仮の値) シリアル設定 外部割込み設定(かふぇルネの他の投稿にありましたが単なるSW入力ぐらいでは外部割り込みは使われないようです) ポート設定 ウォッチドッグタイマ設定(単に使用しない設定) 安全機能設定(単に使用しない設定) リセット要因確認設定(単に確認関数を出力しない設定) 端子割り当て設定 クロック設定・GNURL78+e2 studio+コード生成機能でDTCを使用する場合のGNURL78のobjcopyコマンドの設定の画面コピー (MOTファイルにRAM領域のレコードが直接出力されてしまうことへの対処です)以下、実機で実行中の写真と画面コピーですRL78/G14 Fast Prototyping Boardの今回のSample Programで使用したUART3のArduioソケット端子の位置RxD3 : J7-D0TxD3 : J7-D1GND : J8-GCC-RL+CS+の場合GNURL78+e2 studioの場合 (CC-RL+e2 studioの場合も同様です)
こんにちは。NoMaYです。#4連投の2つ目です。今回、ソースコードの記述でちょっと特殊なことをしている点は、以下の通りです。(1) コード生成機能が生成した割り込み関数を自前の割り込み関数で置き換えるCC-RL/GNURL78の最適化オプションで未使用の変数/関数を削除する最適化を実施することを前提にして、以下のマクロを定義して使用してみました。src/platform.h
#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
src/r_cg_serial_user.c
/* Start user code for global. Do not edit comment generated here */...略...R_CG_DEFAULT_ISR_UNUSED(r_uart3_interrupt_receive)R_CG_DEFAULT_ISR_UNUSED(r_uart3_interrupt_error)R_CG_DEFAULT_ISR_UNUSED(r_uart3_interrupt_send)#define r_uart3_interrupt_receive r_uart3_interrupt_receive_UNUSED#define r_uart3_interrupt_error r_uart3_interrupt_error_UNUSED#define r_uart3_interrupt_send r_uart3_interrupt_send_UNUSED/* End user code. Do not edit comment generated here */static void __near r_uart3_interrupt_receive(void) ← コード生成機能が生成した割り込み関数{...略...}static void __near r_uart3_interrupt_error(void) ← コード生成機能が生成した割り込み関数{...略...}static void __near r_uart3_interrupt_send(void) ← コード生成機能が生成した割り込み関数{...略...}static void r_uart3_callback_receiveend(void){ /* Start user code. Do not edit comment generated here */ ...略... /* End user code. Do not edit comment generated here */}static void r_uart3_callback_softwareoverrun(uint16_t rx_data){ /* Start user code. Do not edit comment generated here */ ...略... /* End user code. Do not edit comment generated here */}static void r_uart3_callback_sendend(void){ /* Start user code. Do not edit comment generated here */ ...略... /* End user code. Do not edit comment generated here */}static void r_uart3_callback_error(uint8_t err_type){ /* Start user code. Do not edit comment generated here */ ...略... /* End user code. Do not edit comment generated here */}/* Start user code for adding. Do not edit comment generated here */#undef r_uart3_interrupt_receive#undef r_uart3_interrupt_error#undef r_uart3_interrupt_sendR_CG_REDEFINE_ISR(r_uart3_interrupt_receive)R_CG_REDEFINE_ISR(r_uart3_interrupt_error)R_CG_REDEFINE_ISR(r_uart3_interrupt_send)static void __near r_uart3_interrupt_receive(void) ← 自前の割り込み関数{...略...}static void __near r_uart3_interrupt_error(void) ← 自前の割り込み関数{...略...}static void __near r_uart3_interrupt_send(void) ← 自前の割り込み関数{...略...}/* End user code. Do not edit comment generated here */
ちなみに、いっそのこと、コード生成機能でコールバック関数を生成しないように設定しておき、以下のように#if 0~#endifで括ってしまう手もあったなぁ、と投稿の下書きを書いていて思いました。
/* Start user code for global. Do not edit comment generated here */...略...#if 0 /* NOT USED *//* End user code. Do not edit comment generated here */static void __near r_uart3_interrupt_receive(void) ← コード生成機能が生成した割り込み関数{...略...}static void __near r_uart3_interrupt_error(void) ← コード生成機能が生成した割り込み関数{...略...}static void __near r_uart3_interrupt_send(void) ← コード生成機能が生成した割り込み関数{...略...}/* Start user code for adding. Do not edit comment generated here */#endif /* NOT USED */static void __near r_uart3_interrupt_receive(void) ← 自前の割り込み関数{...略...}static void __near r_uart3_interrupt_error(void) ← 自前の割り込み関数{...略...}static void __near r_uart3_interrupt_send(void) ← 自前の割り込み関数{...略...}/* End user code. Do not edit comment generated here */
(2) コード生成機能が生成した関数で使用すると都合が悪くなる関数を使用不可にするCC-RL/GNURL78の最適化オプションで未使用の変数/関数を削除する最適化を実施することを前提にして、以下の記述をしてみました。(こちらに関してはマクロの定義はしていません。)src/r_cg_serial.c
/* Start user code for global. Do not edit comment generated here */...略...#define R_UART3_Receive R_UART3_Receive_DO_NOT_USE#define R_UART3_Send R_UART3_Send_DO_NOT_USEMD_STATUS R_UART3_Receive(uint8_t * const rx_buf, uint16_t rx_num);MD_STATUS R_UART3_Send(uint8_t * const tx_buf, uint16_t tx_num);/* End user code. Do not edit comment generated here */
(3) Renesas RL78 SimulatorがN-chオープンドレイン出力でLEDを駆動する方法に未対応であることへの対処LEDを駆動する方法としては一般的な「N-chオープンドレイン出力ポート+LED+抵抗+VDD」ですが、Renesas RL78 Simulatorの入出力パネルでN-chオープンドレイン出力ポートにアクティブロウ設定でLEDを接続しても、残念ながらLEDを点灯させることが出来ませんでした。ただ、以下の画面コピーのようにRenesas RL78 Simulatorの端子設定でN-chオープンドレイン出力ポートをPull Up設定すれば、点灯させることが出来ます。(これは、上記の一般的な接続とは異なるもの、ですが。)ちょっと厄介なのは、上記のPull Up設定がRenesas RL78 Simulatorのどの環境設定ファイルにも保存されないので、e2 studioでは毎回手動で設定しなければならないことです。(CS+ではmtpjファイルに記憶されます。) そこで、以下のようにソースコードを記述をして、(CS+の場合であっても)Renesas RL78 Simulatorでデバッグする時(Renesas RL78 Simulatorにダウンロードした時)には、N-chオープンドレイン出力ポートが通常のCMOS出力ポートに設定されるようにしました。src/r_cg_port.c
/* Start user code for global. Do not edit comment generated here */#if defined(RENESAS_SIMULATOR_DEBUGGING)/* Workaround for a problem that the Renesas RL78 simulator does not work expectedly * for a wiring such as "N-ch Open Drain Output Port <--> LED <--> R <--> VDD" */void R_PORT_Create1(void);void R_PORT_Create2(void);void R_PORT_Create(void){ R_PORT_Create1(); R_PORT_Create2();}#define R_PORT_Create R_PORT_Create1#endif/* End user code. Do not edit comment generated here */void R_PORT_Create(void){ P4 = _08_Pn3_OUTPUT_1 | _10_Pn4_OUTPUT_1; PU4 = _00_PUn0_PULLUP_OFF; PU14 = _08_PUn3_PULLUP_ON; POM4 = _08_POMn3_NCH_ON | _10_POMn4_NCH_ON; PM4 = _01_PMn0_NOT_USE | _02_PMn1_NOT_USE | _04_PMn2_NOT_USE | _00_PMn3_MODE_OUTPUT | _00_PMn4_MODE_OUTPUT | _20_PMn5_NOT_USE | _C0_PM4_DEFAULT;}/* Start user code for adding. Do not edit comment generated here */#if defined(RENESAS_SIMULATOR_DEBUGGING)/* Workaround for a problem that the Renesas RL78 simulator does not work expectedly * for a wiring such as "N-ch Open Drain Output Port <--> LED <--> R <--> VDD" */void R_PORT_Create2(void){ if (IsRenesasSimDebugMode()) { POM4 &= ~(_08_POMn3_NCH_ON | _10_POMn4_NCH_ON); }}#endif/* End user code. Do not edit comment generated here */
なお、IsRenesasSimDebugMode()マクロは以下のようにrenesas_simulator_debugging_key変数を参照するようになっていて、そのrenesas_simulator_debugging_key変数はシミュレータデバッグのダウンロード時にPythonスクリプト(CS+)やDBGコマンド(e2 studio)によって自動的に書き換えるようにしています。src/RenesasSimDebug/sim_debug_mode_hook.h
#if defined(RENESAS_SIMULATOR_DEBUGGING)extern const unsigned short renesas_simulator_debugging_key;#define IsRenesasSimDebugMode() (0x0001 == renesas_simulator_debugging_key)#endif
src/RenesasSimDebug/sim_debug_mode_hook.c
#if defined(RENESAS_SIMULATOR_DEBUGGING)/* Switch Key for Renesas Simulator Debugging * * non 0x0001 : Emulator or No debugger * 0x0001 : Renesas RL78 Simulator */const unsigned short renesas_simulator_debugging_key = 0xFFFF;#endif
CS+の場合: ダウンロード後のフック関数にPythonスクリプトを記述freertos_sampleprog1_ccrl_c.py
...略...def AfterDownload():...略... # Set the switch key variable in case of simulator. if debugger.DebugTool.GetType() == DebugTool.Simulator: debugger.Watch.SetValue('renesas_simulator_debugging_key', 0x0001) return
e2 studioの場合: デバッグ構成の[Starup]の[コマンドを実行]にGDBコマンドを記述
set renesas_simulator_debugging_key=0x0001
もっとも、環境設定が一括でmtpjファイルに記憶されるCS+とは異なり、e2 studioでは各種環境設定ファイルを毎回手動で読み込む必要がありますので、僅か2つのPull Up設定を毎回手動で行うことを気にしても仕方無かったかもしれないなぁ、と投稿の下書きを書いていて思いました。(4) DTC転送時の送信開始処理と送信終了判定処理DTC転送時の送信開始処理と送信終了判定処理は、以下の通りにしました。RL78マイコンのSAUでは、RXマイコンのCSIとは異なり、送信バッファエンプティ割り込みと送信終了割り込みが共通になっており(どちらにするかSAUのレジスタで切り替える)、また、同様にRXマイコンのCSIとは異なり、送信終了割り込みはエッジ検出なのではないかと思われます。src/r_cg_serial.c
MD_STATUS U_UART3_DTC_Send(uint8_t * tx_buf, uint16_t tx_num){ MD_STATUS status = MD_OK; if (tx_num < 1U && 256U < tx_num) { status = MD_ARGERROR; } else { if (1 < tx_num) { U_DTCD1_UserInit( tx_buf + 1, tx_num - 1 ); R_DTCD1_Start(); SMR12 |= _0001_SAU_BUFFER_EMPTY; } else { SMR12 &= ~_0001_SAU_BUFFER_EMPTY; } STIF3 = 0U; /* clear INTST3 interrupt flag */ STMK3 = 0U; /* enable INTST3 interrupt */ TXD3 = *tx_buf; /* also raise INTST3 interrupt */ } return status;}
static void __near r_uart3_interrupt_send(void){ /* DTC has finished data transfer operation. (i.e. The last data has been * written to SDR register.) But the data may stay in either SDR register * or shift register. */ /* It is preferred that next interrupt will be a transmission end interrupt * (i.e. not only SDR register but also shift register become empty) than * a SDR register empty interrupt. */ SMR12 &= ~_0001_SAU_BUFFER_EMPTY; /* In normal case of interrupt, UART has just finished data transmission * operation at 2nd interrupt. But in abnormal case of after long or very * long time pending of data transfer completion interrupt, though at 1st * interrupt, SDR register may already become empty or, moreover, shift * register may already have finished data transmission operation. In the * latter case, it is not clear whether data transmission end interrupt * will occur or not, so the following check is useful. */ if ((SSR12 & _0040_SAU_UNDER_EXECUTE) == 0U) { /* UART has finished data transmission operation. Note that one more * interrupt may occur by above change of SMR register setting unless * transmission interrupt becomes disabled. */ STMK3 = 1U; r_uart3_callback_sendend(); } /* If ((SSR12 & _0040_SAU_UNDER_EXECUTE) == 0U) changes from false to true * just here, changing SMR register setting at the following timing may * lose data transmission end interrupt. * * SMR12 &= ~_0001_SAU_BUFFER_EMPTY; */}
以下、RL78/G14のユーザーズマニュアルのハードウェア編の画面コピーと私のメモの書き込みです。www.renesas.com/jp/ja/search/keyword-search.html#genre=document&q=r01uh0186r01uh0186jj0330-rl78g14.pdf(5) DTC保留命令によりタスク切り替えが起きなくなることへの対処以下のRL78/G14のユーザーズマニュアルのハードウェア編の画面コピーの通り、幾つかの命令の実行時にDTC転送が保留されることがあるのですが、DTC転送が保留されている間は割り込みも保留されることになっています。不運にも、移植元のRX-TBのサンプルプログラムでは、タイマ割り込み(FreeRTOSのTick割り込み)によってタスク切り替えが起きることを前提に、単なるタスクの一例として、以下のタスクを記述していました。このタスクのwhile(1);の部分はRL78ではBR $$となり、これはDTC保留命令になります。しかも、この命令が実行され続けますので、DTC転送が保留され続けてしまうと同時に、タイマ割り込み(FreeRTOSのTick割り込み)も保留され続けてしまいます。結局、タスク切り替えが起きなくなり、サンプルプログラムが動作しなくなってしまいました。そこで、以下の通り、NOPを挿入することにして回避しました。src/rl78g14_fpb_main.c修正前
void main_task(void *pvParameters){ INTERNAL_NOT_USED(pvParameters); /* Create all other application tasks here */ while(1); /* vTaskDelete(NULL); */}
修正後
void main_task(void *pvParameters){ INTERNAL_NOT_USED(pvParameters); /* Create all other application tasks here */ while(1) { /* The nop prevents infinite DTC pending caused by BR $$. * (Moreover, such DTC pending causes infinite interrupt pending. * Furthermore, such interrupt pending prevents task switching. * So, in case of without nop, task switching never occur.) */ nop(); } /* vTaskDelete(NULL); */}
ちなみに、修正前のソースでもRenesas RL78 Simulatorでは動作してしまいましたので、実機で動作させようとした途端に動作しなくなってしまったことに関して、暫く原因について思い悩みました。以下、RL78/G14のユーザーズマニュアルのハードウェア編の画面コピーです。
こんにちは。NoMaYです。#4連投の3つ目です。以下、各タスクのソースの通りです。(ヘッダ等は省略しています。また、ソース中に/* Start user code …略… */や/* End user code …略… */の記述がありますが、移植元のRX-TBの時にRXスマートコンフィグレータで生成されたタスクのスケルトンのソースに出力されていたものです。RL78コード生成機能では、タスクのスケルトンのソースは生成されません。)src/frtos_skeleton/task_LED0.c
#include "task_function.h" /* Start user code for import. Do not edit comment generated here */ #include "freertos_start.h" #include "platform.h" #include "rl78g14fpbdef.h" #if defined(RENESAS_SIMULATOR_DEBUGGING) /* Hardware or Renesas RL78 Simulator */ #define LED0_BLINK_FREQUENCY_MS pdMS_TO_TICKS( !IsRenesasSimDebugMode() ? 500 : 50 ) #else /* Hardware */ #define LED0_BLINK_FREQUENCY_MS pdMS_TO_TICKS( 500 ) #endif /* End user code. Do not edit comment generated here */ void task_LED0(void * pvParameters) { /* Start user code for function. Do not edit comment generated here */ INTERNAL_NOT_USED( pvParameters ); LED0 = LED_ON; for (;;) { vTaskDelay( LED0_BLINK_FREQUENCY_MS ); LED0 = ~LED0; } /* End user code. Do not edit comment generated here */ }
#include "task_function.h" /* Start user code for import. Do not edit comment generated here */ #include "freertos_start.h" #include "platform.h" #include "r_cg_intc.h" #include "rl78g14fpbdef.h" extern volatile bool g_task_CONIO_error; #if defined(RENESAS_SIMULATOR_DEBUGGING) /* Hardware or Renesas RL78 Simulator */ #define SW1_REMOVE_CHATTERING_PERIOD_MS pdMS_TO_TICKS( !IsRenesasSimDebugMode() ? 10 : 0 ) #else /* Hardware */ #define SW1_REMOVE_CHATTERING_PERIOD_MS pdMS_TO_TICKS( 10 ) #endif /* End user code. Do not edit comment generated here */ void task_LED1(void * pvParameters) { /* Start user code for function. Do not edit comment generated here */ INTERNAL_NOT_USED( pvParameters ); LED1 = LED_OFF; for (;;) { R_INTC0_Start(); xSemaphoreTake( semaphore_handle_SW1_PUSH, portMAX_DELAY ); /* Remove mechanical switch chattering */ vTaskDelay( SW1_REMOVE_CHATTERING_PERIOD_MS ); if (true == g_task_CONIO_error) { /* Clear error */ g_task_CONIO_error = false; } else { /* Toggle LED1 */ if (SW1_PUSH == SW1) { LED1 = ~LED1; } } } /* End user code. Do not edit comment generated here */ }
#include "task_function.h" /* Start user code for import. Do not edit comment generated here */ #include "freertos_start.h" #include "platform.h" #include "r_cg_serial.h" #include "rl78g14fpbdef.h" volatile bool g_task_CONIO_error = false; #define CON_RECV_DEMO_SIZE 3 #if defined(RENESAS_SIMULATOR_DEBUGGING) /* Hardware or Renesas RL78 Simulator */ #define LED1_ERROR_BLINK_FREQUENCY_MS pdMS_TO_TICKS( !IsRenesasSimDebugMode() ? 200 : 20 ) #define CON_RECV_TIMEOUT_MS pdMS_TO_TICKS( !IsRenesasSimDebugMode() ? 60 * 1000UL : 600L ) //#define CON_RECV_TIMEOUT_MS pdMS_TO_TICKS( !IsRenesasSimDebugMode() ? 60 * 1000UL : portMAX_DELAY ) /* for debug */ //#define CON_RECV_TIMEOUT_MS pdMS_TO_TICKS( !IsRenesasSimDebugMode() ? 60 * 1000UL : 0 ) /* for debug */ #else /* Hardware */ #define LED1_ERROR_BLINK_FREQUENCY_MS pdMS_TO_TICKS( 200 ) #define CON_RECV_TIMEOUT_MS pdMS_TO_TICKS( 60 * 1000UL ) #endif /* End user code. Do not edit comment generated here */ void task_CONIO(void * pvParameters) { /* Start user code for function. Do not edit comment generated here */ volatile uint8_t recv_buff[CON_RECV_DEMO_SIZE + 1]; volatile uint8_t err_type; BaseType_t ret; INTERNAL_NOT_USED( pvParameters ); U_UART3_ASYNC_Start( semaphore_handle_CON_TX_READY, semaphore_handle_CON_RX_READY ); for (;;) { memset( (char *)recv_buff, 0, CON_RECV_DEMO_SIZE + 1 ); U_UART3_DTC_Receive( recv_buff, CON_RECV_DEMO_SIZE, &err_type ); ret = xSemaphoreTake( semaphore_handle_CON_RX_READY, CON_RECV_TIMEOUT_MS ); nop(); /* for breakpoint, check timing chart on Simulator GUI */ if (pdPASS == ret && 0 == err_type) { taskENTER_CRITICAL(); vPrintString( "Received Message: " ); vPrintString( (char *)recv_buff ); vPrintString( "\n" ); taskEXIT_CRITICAL(); } else { if (pdFAIL == ret) { U_UART3_DTC_Receive_Abort(); /* or Retry U_UART3_DTC_Receive() */ vPrintString( "Timeout Error\n" ); } else { if (SCI_EVT_FRAMING_ERR & err_type) { vPrintString( "Framing Error\n" ); } if (SCI_EVT_PARITY_ERR & err_type) { vPrintString( "Parity Error\n" ); } if (SCI_EVT_OVFL_ERR & err_type) { vPrintString( "Overrun Error\n" ); } } g_task_CONIO_error = true; LED1 = LED_ON; while (true == g_task_CONIO_error) { vTaskDelay( LED1_ERROR_BLINK_FREQUENCY_MS ); LED1 = ~LED1; } LED1 = LED_OFF; continue; } U_UART3_DTC_Send( (uint8_t *)recv_buff, CON_RECV_DEMO_SIZE ); ret = xSemaphoreTake( semaphore_handle_CON_TX_READY, portMAX_DELAY ); nop(); /* for breakpoint, check timing chart on Simulator GUI */ } /* End user code. Do not edit comment generated here */ }
こんにちは。NoMaYです。#4連投の4つ目です。コード生成機能の設定は以下の画面コピーの通りです。(以下の画面コピーはCC-RL+CS+のものですが、CC-RL+e2 studioでもGNURL78+e2 studioでも、同様です。)DTC設定(転送元アドレスと転送先アドレスは単に仮の値)シリアル設定外部割込み設定(かふぇルネの他の投稿にありましたが単なるSW入力ぐらいでは外部割り込みは使われないようです)ポート設定ウォッチドッグタイマ設定(単に使用しない設定)安全機能設定(単に使用しない設定)リセット要因確認設定(単に確認関数を出力しない設定)端子割り当て設定クロック設定なお、GNURL78+e2 studio+コード生成機能でDTCを使用する場合には、GNURL78のobjcopyコマンドのコマンドラインオプションに以下の画面コピーのオプションを追加しておくと良いと思います。そうしないと、DTCを使用する場合にコード生成機能によってリンカスクリプトに追加された設定により、MOTファイルにRAM領域のレコードが出力されるようになってしまいますので、最近のRenesas Flash Programmerでは以下の画面コピーのようにエラーになってしまうからです。GNURL78のobjcopyコマンドのコマンドラインオプションに追加するオプション-R .dtc_vectortable -R .dtc_controldata_*オプションを追加しない場合には最近のRenesas Flash Programmerではエラーになる