ルネサスの低消費電力8/16ビットマイコン【RL78シリーズ】の開発環境には、コード生成機能が用意されています。
コード生成を使うと、煩雑なレジスタ操作から解放され、コードの流用性も高まります。
この記事では、コード生成の方法や生成されたコードの使い方を説明します。長い記事なので、使う予定の機能の項目を抜粋して読んでいただければと思います。
環境とデバイス
この記事では、下記の環境とデバイスを前提条件として説明します。
- デバイス: R5F100LGAFB (RL78/G13 64ピン)
- 開発環境: e2studio Version: 2021-04 (21.4.0)
- コンパイラ: GCC
コード生成機能は他の開発環境CS+でも同じ機能なので、参考になると思います。
まだ環境構築をしていない方は下記の記事を参考にして開発環境構築をしてみてください。
コード生成の共通事項
まずは、どの機能ブロックのコード生成にも共通してしている内容をまとめます。
ファイルは3種類生成される
コード生成では、各機能ブロック毎に3種類のファイルが生成されます。
タイマー機能を例にすると下記のようなファイル名になります。
- ヘッダーファイル (r_cg_timer.h)
- Cソースファイル (r_cg_timer.c)
- Cソースファイル (r_cg_timer._user.c)
ヘッダーファイルは、その機能ブロックを使用する時に”#include”するためのものです。内容を編集/追記する必要性は無いはずです。
Cソースファイル(_user無し)には、各機能ブロックの実装がされています。具体的な動作を把握する為に内容を確認することはありますが、編集/追記する必要性は無いはずです。
Cソースファイル(_user有り)には、割り込みなどのコールバック関数が記述されており、ユーザーが追記するための場所も確保されています。割り込み時の処理は、このファイル内に記述していく事になります。
コード追記場所が指定されている
自動生成されたコードには、下記のようなコメントが記載されている場所があります。
/* Start user code for *****. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
ユーザーがコードを追記するのは、このコメントの間だけにするべきです。
このコメントの外に追記したコードは、再度コード生成を行った時に削除されてしまいます。
**Create()関数
各機能ブロックの生成コードには、”***_Create(void)”という名前の関数が生成されています。
この関数は、自動生成される初期化コードの中でコールされています。ユーザーがコールする必要は無いですし、別の場所で使用することもありません。
クロック発生回路
RL78でコード生成機能を使う場合には、まず最初にクロック発生回路の設定が必要です。設定画面を開くとタブが7つも付いていて大変そうですが、結局毎回同じような設定になるので一度覚えてしまえばそんなに困ることはないです。
端子割り当て設定
PIORレジスタの値を設定して、各端子に割り当てることが可能なペリフェラル機能を設定します。
回路図を確認しながら慎重に設定してください。設定は一度行うと変更できません。間違えたらプロジェクト作り直しです。
クロック設定
こちらも回路図を確認しながら設定していきます。確認ポイントは2か所。
- マイコンの電源電圧範囲
- マイコンに接続される発振子、クロックの有無。有るならばその周波数。
とりあえず最初は内蔵のオシレータクロックを使うように設定しておいても良いと思います。それで機能を満たせるのならば、外部クロックを削除してコストダウン出来ますから。
ブロック図
何も設定する項目はありません。クロック発生回路のブロック図が表示されるので、他タブの設定する際の確認用で参照したりします。
オンチップ・デバッグ設定
基本的には、オンチップ・デバッグ動作設定を【使用する】にチェックを入れて、エミュレータ設定で持っているデバッガにチェックを入れれば良いです。
セキュリティIDは、リバースエンジニアリングを気にされるならば設定しておきましょう。違うIDでは接続できなくなったり、プログラムを消去したりできるようになります。
リセット要因確認
チェックを入れておくと、マイコン初期化の途中でリセット・コントロール・フラグ・レジスタ(RESF)のデータを確認する関数をコールしてくれます。
この関数内でにコードを記述すれば、リセット要因によって初期化処理を分岐させることが可能となります。必要ならばチェックを入れておきましょう。
安全機能
RL78には、特定のRAMやレジスタを書き換えることが出来ないように設定できます。この機能は、マイコンの暴走やプログラムバグによって深刻な動作不良を起こさない為に用意されています。
ここでは、これら安全機能の有効/無効の設定が出来ます。
有効にした安全機能は、初期化中に”IAWCTL”レジスタを編集することで設定します。
データ・フラッシュ
電源を落とした時にも保存したいデータを保存しておく領域として、データ・フラッシュが用意されています。データ・フラッシュを使用する場合に設定をしておいてください。
データ・フラッシュ・ライブラリ自体は自動生成されません。メーカのダウンロードサイトよりダウンロードしてください。ライブラリの使い方などのドキュメントもこちらで入手できます。
データ・フラッシュ・ライブラリが対応しているコンパイラは下記の2つです。
- CC-RL
- CA78K0R
GCC非対応ですので注意してください。
ポート
GPIOポートの機能設定を行います。
チェックBOXにチェックするだけで、1ピン毎にGPIOの設定を行う事が出来ます。!マークが付いているポートは、他のペリフェラル機能が割り付けられてGPIOとして使えないポートになります。直感的に分かりやすくなっていますが、1点大きな落とし穴があります。
出力設定でN-chオープン・ドレイン出力モードにしか出来ないポートに、その事が記載されていません。
「正しく設定してあるのにHigh出力にならない」と思っていたらプルアップ抵抗が付いてなかった、というような事が無いように注意してください。
GPIOの読み書きするのに、”r_cg_port.h”をインクルードする必要はありません。”iodefine.h”ファイルに定義されている各ポートのレジスタを読み書きすれば良いです。
例えば、P0ポートにバイト単位で書き込む場合は、
P0 = 0xA5;
P01ポートにビット単位で書き込む場合は、
P0_bit.no1 = 1;
割り込み
この項目における割り込みとは、端子状態の変化によって発生する割り込みの事になり、”外部割込み”と”キー入力割り込み”の2つがあります。この2つの割り込みを設定します。
タイマーやシリアル受信などの割り込みについては、各機能ブロックで設定が可能です。
生成されたコードの使い方は簡単です。”**_Start()”関数をコールして割り込みを有効にします。割り込み発生時の制御は、”**_user.c”の中に用意されているコールバック関数の中に記述していきます。
外部割込み
1個の割り込み端子の状態変化によって割り込みを発生させる機能になります。
有効にしたいCHと有効にするエッジ、割り込みの優先順位を設定できます。
キー入力割り込み
キー入力割り込みとは、有効にしているCHのすべてがLowになった場合に割り込みを発生させる機能です。
有効にしたいCHと割り込みの優先順位を設定できます。
シリアル
3線シリアル(SPI)、UART、I2Cといったシリアル通信の設定を行います。
上段タブの”SAU0/SAU1”はシリアルアレイユニットです。3線シリアル(SPI)、UART、簡易I2Cの3機能が使用できます。”IICA0”はシリアル・インタフェースIICAで、I2C機能が使用できます。
3線シリアル(SPI)
コード生成ではCSIと表示されている機能です。いわゆるSPIです。SAU0/SAU1で使用できます。
設定は、通信先デバイスの仕様書を確認しつつ行ってください。
SPIを行う方法は、“R_CSI**_Start()“関数をコールしてから, “R_CSI00_Send()“, “R_CSI10_Receive()“, “R_CSI00_Send_Receive()“のいずれかを使用すれば良いです。どのHALが出力されるかは、有効にしたのが送信/受信/両方のどれかで決まります。
UART
UART機能は、SAU0/SAU1で使用できます。
設定は、接続先デバイスとの仕様を確認しつつ行ってください。
UARTを使うには、”R_UART*_Start()”関数をコールしてUART機能を有効にします。送信は”R_UART2_Send()”関数, 受信は”R_UART2_Receive()“関数を使用します。
受信関数がコールされていない場合に受信端子に入力されたデータは取りこぼしてしまいますので注意してください。常に受信できないといけない通信仕様の場合は、受信完了割り込み関数内で再度”R_UART2_Receive()”関数をコールするのが良いと思います。
I2C
I2Cは、”SAU0/SAU1”の簡易I2Cでマスタ動作が行えます。”IICA0”ではマスタ/スレーブの両方が使用出来ます。
設定は、接続先デバイスとの仕様を確認しつつ行ってください。
使用する場合は、”***_Start()”関数をコールした後に、下記の関数を使用すればOKです。
- R_IIC00_Master_Send
- R_IIC00_Master_Receive
- R_IICA0_Slave_Send
- R_IICA0_Slave_Receive
A/Dコンバータ
A/Dコンバータの設定を行います。
コンパレータ動作設定は、初期化完了時点でのコンパレータの停止/許可を設定します。初期化完了後に設定を切り替えたい場合は、”R_ADC_Set_OperationOn()”関数と”R_ADC_Set_OperationOff()”関数をコールすれば良いです。
分解能設定は、ADCの分解能を設定します。VREF±設定は基準電圧を何にするか設定します。内部基準電圧を使う場合は、分解能を8ビットにしないといけません。
トリガ・モード設定は、ADC開始のトリガを設定します。ソフトはユーザーコードで起動、ハードウェアトリガは、指定した割り込み発生でADCを開始します。開始をすぐ行うのか、A/D電源安定時間待つかも選択できます。
動作モード設定は、動作モードとADCのCHを設定できます。動作モードは下記のようになっています。
- 連続セレクト :選択した1CHを連続してA/D変換します
- 連続スキャン :連続した4CHのA/D変換を順番に、連続して行います。
- ワンショット・セレクト :選択した1CHを1回だけA/D変換します
- ワンショット・スキャン :連続した4CHのA/D変換を順番に、1回だけ行います。
変換時間設定では、変換時間モードと変換時間の設定を行います。サンプリング時間が短すぎると、ADC精度が悪化する可能性があるので、できるだけ遅めに設定しておくのがベターです。
変換結果上限/下限設定は、ADCの割り込みを発生させる有効範囲を指定できます。割り込みが発生しない場合は、ADCRレジスタにADC結果の格納も行われません。
A/Dコンバータを使用するのは、”R_ADC_Start()”関数と”R_ADC_Set_OperationOn()”関数をコールして変換の開始とコンパレータの有効化を行います。A/D変換結果は”R_ADC_Get_Result()”で取得できます。
連続セレクトモードであれば、A/D変換結果が欲しいタイミングで”R_ADC_Get_Result()”をコールすれば良いです。
他のモードだと、変換CHの管理や変換終了を検出しないといけません。A/D変換完了割り込みを使って管理するのが良いと思います。
タイマ
RL78には、16ビットのカウンタを備えたタイマが8CHあります。それらを単独で、もしくは複数使って様々な機能を実現できます。それぞれの機能と設定方法を説明します。
使い方については難しくありません。下記4点を抑えておけばOKです。
- “R_TAU*_Channel*_Start()“関数でカウンタ動作開始
- ”R_TAU*_Channel*_Stop()”関数でカウンタ動作を停止します。
- 入力パルス間隔測定、入力信号のハイ/ロウ・レベル幅測定機能では”R_TAU*_Channel*_Get_PulseWidth()”関数で測定値を取得できます。
- タイマ割り込み発生時の処理は”r_cg_timer_user.c”のコールバック関数内に記述します。
インターバル・タイマ
一定の間隔で割り込みを発生させる機能です。
設定もインターバル時間と割り込みだけで非常にシンプルです。
RL78には、インターバル・タイマにしか使えない12ビット・インターバル・タイマという機能もあり、基本的にはこちらを優先して使うのが良いと思います。ここで紹介しているタイマは高機能なので、他の用途に残しておいた方が良いです。
方形波出力
一定の間隔でタイマ出力端子を反転させて、Duty50%の方形波を出力する機能です。
設定は、方形波幅/出力初期値/割り込みだけで非常にシンプルです。
RL78には、方形波出力にしか使えないクロック出力/ブザー出力という機能もあります。かなり限定的な設定しかできませんが、こちらで十分な用途ならば優先して使うのが良いと思います。ここで紹介しているタイマは高機能なので、他の用途に残しておいた方が良いです。
外部イベント・カウンタ
タイマ入力端子に入力される信号の立上り/立下りエッジの回数を数えて、規定回数で割り込みを発生させる機能です。
設定は、入力端子のノイズフィルタ使用/エッジ選択/カウント値/割り込みを行います。
タイマ入力端子には、ノイズフィルタの使用を設定できます。設定すると、入力端子の状態が2CLK連続して同じロジックレベルになった時に採用されるようになります。一瞬のノイズで端子状態が化けてしまっても、誤動作する可能性が多少下がります。
入力パルス間隔測定
タイマ入力端子に入力される信号のパルス間隔を計測する機能になります。
測定するのは間隔なので、CLKやPWMの周期を測定するような用途になります。信号のパルス幅を測定したい場合は、後述の入力信号のハイ/ロウレベル幅測定を使用してください。
設定は、測定可能なパルス間隔/ノイズフィルタ使用/エッジ選択/割り込みを行います。
入力信号のハイ/ロウ・レベル幅測定
タイマ入力端子に入力される信号のパルス幅を計測する機能になります。
測定するのはパルス幅です。信号の間隔を測定したい場合は、前述の入力パルス間隔測定を使用してください。
設定は、測定可能なパルス間隔/ノイズフィルタ使用/幅測定のレベル選択/割り込みを行います。
ディレイカウント機能
タイマ入力端子に入力される信号のエッジからカウントを開始して、規定時間経過後に割り込みを発生させる機能になります。
設定は、ノイズフィルタ/外部イベント・エッジ/ディレイ時間/割り込みを行います。
PWM出力
任意の周期/DutyでPWM信号を出力する機能です。この機能はタイマを2CH使用します。
マスタCHでは、PWMの周期/割り込みを設定します。スレーブCHでは、PWMのDuty/初期値/割り込みを設定します。
PWM出力を停止する時に注意が必要です。出力を停止するのは”R_TAU*_Channel*_Stop()”関数をコールすれば良いのですが、その時の端子出力レベルは出力停止した瞬間の状態を保持します。Lo/Highのどちらかに確定させたい場合は、”R_TAU*_Channel*_Stop()”関数をコールした後にタイマ出力レジスタ”TO*”に希望の出力状態を書き込んでください。
ワンショットパルス出力(ソフトウェア・トリガ)
一回だけ任意の幅のパルスを出力する機能になります。この機能はタイマを2CH使用します。出力はソフトで指定できます。
マスタCHでは、ソフトウェアトリガからパルス出力までの時間を設定します。スレーブCHでは、パルス幅/出力論理を設定します。
ワンショットパルス出力(外部トリガ)
一回だけ任意の幅のパルスを出力する機能になります。この機能はタイマを2CH使用します。出力はマスターCHの入力端子でトリガされます。
マスタCHでは、入力端子のノイズフィルタ使用/有効エッジ/トリガからパルス出力までの時間を設定します。スレーブCHでは、パルス幅/出力論理を設定します。
多重PWM出力
PWM出力の機能拡張になります。1つのマスタCHと複数のスレーブCHを使用して、周期一定で任意のDutyのPWM信号を最大7つ出力できます。
マスタCHでは、PWMの周期/割り込みを設定します。各スレーブCHでは、そのCHのPWMのDuty/初期値/割り込みを設定します。
ウォッチドッグ・タイマ
ウォッチドッグ・タイマ(以降WDT)の機能設定を行います。
HALT/STOP/SNOOZEモード時の動作設定とは、これらのスタンバイ状態でもWDTが機能するかの設定です。
オーバーフロー時間設定とは、カウントスタートからWDTリセット発生までの時間を設定します。設定した時間までのWDTカウンタをクリアしないと
ウィンドウ・オープン期間とは、WDTカウンタクリア可能な「窓」の大きさを設定できます。例えば、オーバーフロー時間100msでウィンドウ・オープン期間40%とした場合、カウントスタートから60ms以降でないとカウンタクリアが出来ません。60ms以前にカウンタクリアをした場合、マイコンがリセットされますので注意してください。
割り込み設定では、WDTリセットの少し前(75%経過時点)に割り込みを発生させる設定です。WDTリセットの前にしておかないといけない処理が有る場合は有効にしておきましょう。
WDT機能の使い方は、しかるべき場所でカウンタのリスタート関数”R_WDT_Restart()”をコールするだけで良いです。WDTを開始/停止させるようなHAL関数はありません。
プロジェクト作成時のデフォルト設定が有効になっています。失念していると、なぜかマイコンが頻繁にリセットされるという状況になります。無駄な時間を浪費しないためにも注意しておきましょう。
リアルタイム・クロック
年・月・曜日・日・時・分・秒のカウンタで、実時間を管理することができるリアルタイム・クロックの機能設定が出来ます。
時刻の管理方式(12時間/24時間)や初期値の時間設定、アラームの設定などが出来ますが、これらはHAL関数でも設定が出来ます。「時計」の特性上、ここでの設定はそれほど重要ではなく、ユーザーが便利に設定できるようにすることが重要かと思います。
”r_cg_rtc.h”ファイルには、HAL関数以外にも実時間やアラームを管理するのに便利な構造体が宣言されています。ユーザープログラムでも、これらの構造体でアプリケーションを記述するのが良いと思います。HAL関数がこれらの構造体を引数に取りますし。
リアルタイム・クロックを使うには、サブシステム・クロック(XT1,XT2/EXCLKS端子)への32.768kHzクロックの入力が必要です。使用前に回路図を確認してください。
また、”クロック発生回路”のクロック設定タブで、サブシステム・クロック(fSUB)設定を動作にチェックしてください。
12ビット・インターバル・タイマ
一定間隔で割り込みを発生させる機能を設定します。
RL78にはこれ以外にもタイマー機能がありますが、こちらはPWM出力やカウンターなどの様々な機能にも使用できます。一定間隔で割り込みを発生させるのは機能がシンプルな12ビット・インターバル・タイマで行うのが効率的だと思います。
インターバル時間で割り込みを発生させる間隔を設定します。
割り込みは、チェックを入れないことは無いはずです。優先順位のみ検討して設定してください。
使用方法もシンプルです。”R_IT_Start()”関数をコールして機能動作を開始、割り込み処理は”r_cg_it_user.c”ファイル内のコールバック関数に記述します。
クロック出力/ブザー出力
PCLBUZ*端子から方形波を出力する設定をします。
メインCLKで8通り、サブCLKで8通りの周波数設定しかできません。非常にシンプルな機能です。より細かな周波数を設定したり、Dutyを変えたい場合には、より高機能なタイマー機能を使います。
出力クロック設定で方形波の周波数が設定できます。
使い方は、”R_PCLBUZ*_Start()”関数で出力開始、”R_PCLBUZ*_Stop()”関数で出力を止めます。
DMAコントローラ
DMAを使って、周辺ハードウェアのレジスタ(SFR)と内蔵RAM間のデータ転送をマイコンを介さずに自動で行う設定をします。
転送方向設定で、SFR→内蔵RAM か 内蔵RAM→SFR か、データ転送を行う方向を設定します。
転送データ・サイズ設定で、1回の転送が8ビットか16ビットか設定します。
アドレス・転送回数設定で、SFRアドレス/RAMアドレス/転送回数を指定します。転送回数が複数の場合、RAMアドレスを1つ(16ビットなら2つ)インクリメントしてから次の転送を行います。SFRアドレスはインクリメントされずに固定です。
※RAMアドレス設定の際は下記のCHECKも参照。
起動要因設定は、DMAの起動トリガを設定します。トリガとして指定できるのは、ソフトウェア起動/AD変換完了/タイマー/シリアル送受信完了になります。
割り込み設定で、DMA終了時に割り込みを発生させるのか、割り込みの優先順位について設定が出来ます。
DMA機能を使うには、”R_DMAC*_Start()”関数でDMAを有効にして、起動トリガとなる機能(タイマー割り込みなど)を開始すれば良いです。トリガが発生したらDMA転送が行われるます。
ここまでは簡単なのですが、再度DMAを有効にして使用する場合(ほとんどのケースがそうだと思いますが、、)には配慮が必要です。DMA完了時点のDMA機能レジスタ状態は、下記のような状態になっているのでこれらを再設定しなければいけません。
- DMA完了フラグ有効
- 転送RAMアドレスがインクリメントされている
- データ転送回数 = 0
再設定するのは、DMA完了割り込み内が良いと思います。同じDMA設定を繰り返す場合は、”R_DMAC*_Create()”と”R_DMAC*_Start()”関数をコールすればOKです。条件を変える場合はレジスタ(DRA*,DBC*,DRC*)を直接設定することになります。
DMAの設定UI画面でRAMアドレスをどうやって入力すれば良いのでしょうか?なかなか難しい問題です。対応としては2案考えられます。
- UIでは無意味な値を設定しておく。ユーザーコード内で設定する。
- UIで設定したRAMアドレスに変数を配置する。
通常は1.が簡単だと思います。”R_DMAC*_Start()”関数をコールする直前に下記のようなコードを記述すればOKです。
uint16_t dma_ram = 0;
DRC0 = 0x80; //DMA機能へのCLK供給を行う。DMAは未開始
DRA0 = (uint16_t)(&dma_ram); //変数のアドレス下位16bitを設定
R_DMAC0_Start();
2.についてはコンパイラがCS+かGCCかで対応が変わってきますし、リンカスクリプトの編集なども必要なのであまりお勧めできません。
電圧検出回路
マイコンの電源電圧を監視して、規定値以下になった時にリセットや割り込みを発生させる機能を設定します。
動作モードは、リセット/割り込み/両方から設定できます。
検出電圧は最大14種類から選択できます。リセット/割り込みの両方を設定する場合は、リセット電圧よりも高い電圧しか割り込み電圧に設定できません。
リセットに関する動作は、オプション・バイト(マイコン起動時に自動的に参照されるデータ領域)に定義されるので、プログラムでは何もする必要がありません。割り込みについては、”R_LVD_InterruptMode_Start()”関数をコールして有効にする必要があります。割り込み発生時の処理は、”r_cg_lvd_user.c”ファイル内のコールバック関数に記述します。
コメント