忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

RL78のコード生成を使う(PWM編)

前回でコード生成の準備が整ったのでコード生成でPWMを設定してみます。

関連:
コード生成(準備編)
コード生成(AD編)
コード生成(UART編)
・I2Cスレーブ(現象対策

今回は10Y47でPWMを3ポート分出力する設定を行います。
RL78G10の場合、PWMのマスタとスレーブを設定します。
 マスタ:繰り返し周期などの全体の設定
 スレーブ:実際に出力するデューティー比の設定
となっている様です。
マスタは周期等の管理を行うだけでPWMの波形は出力されません。

PWMの周波数を独立して設定する場合は
PWM出力(マスタ)PWM出力(スレーブ)の組み合わせを使います。
10Y47の場合、PWM出力(スレーブ)は最大2ポートになります。

なるべくPWM出力のポート数を稼ぎたい場合は
多重PWM出力(マスタ)、多重PWM出力(スレーブ)の組み合わせを使います。
10Y47の場合、多重PWM出力(スレーブ)は最大3ポートになります。

出力端子の設定

なるべくPWM出力のポート数を稼ぎたいので、多重PWMとして設定します。
コード生成→周辺機能→タイマ・アレイ・ユニット→一般設定のタブから
多重PWM出力(マスタ)、多重PWM出力(スレーブ)×3に設定します。


周期などが標準状態に設定されるので、好みに合わせて設定を変更します。
チャンネル0がマスターなので、チャンネル0のタブから各種設定を行います。
PWM周期1kHz、初期状態のデューティー比を25%、50%、75%に設定してみます。

PWM周期
・チャンネル0(マスタ):1kHz→1ms


デューティー
・チャンネル1(スレーブ):25%
・チャンネル2(スレーブ):50%
・チャンネル3(スレーブ):75%


コード生成を実行すればPWMの基本設定ができます。


生成されたコードの実行

ここで生成されたコードを見てみます。
 ファイル→コード生成→r_cg_tau.c


PWMのコード生成により3つの関数が作成されました。

void R_TAU0_Create(void)
PWMの初期化関数です
SH等で作成したinit_pwm()に相当します。

void R_TAU0_Channel0_Start(void)
PWMの処理開始関数です。

void R_TAU0_Channel0_Stop(void)
PWMの処理開始停止です。

ハードウェアマニュアルを見ると
R_TAU0_CreateR_TAU0_Channel0_Startの順で実行するように書いてありますが、
R_TAU0_Createrg_cg_systemint.cR_Systeminitで実行されるように自動的に
設定されます。
また、R_Systeminithdwinitで実行され、hdwinitもどこかで自動実行されるようです。

という事で、R_TAU0_Channel0_Startを実行すれば1kHzで
チャンネル1→TO01→P04 デューティー比25%
チャンネル2→TO02→P05 デューティー比50%
チャンネル3→TO03→P07 デューティー比75%
が出力されるようになります。

自作メイン関数でR_TAU0_Channel0_Startを実行させます。
<設定>
#include "iodefine.h"    //端子の基本設定読み込み
#include "r_cg_macrodriver.h"    //uint16_tとか読み込み
#include "r_cg_wdt.h"    //ウォッチドッグタイマー
#include "r_cg_tau.h"    //PWM設定

void user_main(void){
    R_TAU0_Channel0_Start();    //PWM開始
    while(1){
        R_WDT_Restart();    //ウォッチドッグタイマーリセット
    }
}

ビルドして書込んで(E1,シリアル)実行し、TO01からデューティー比25%でPWMが出力されれば
ひとまず成功です。

デューティー比の変更

デューティー比固定では使えないので、デューティー比を変更してみます。
コード生成機能がしてくれるのはここまでです。
ここから先はハードウェアマニュアル等を確認しながらの作業が必要です。
ルネサスのページからRL78/G10の資料をダウンロードしておきます。
https://www.renesas.com/jp/ja/products/microcontrollers-microprocessors/rl78/rl78g1x/rl78g10.html

※ダウンロードには登録(無料)が必要です。

r_cg_tau.cR_TAU0_Create内で初期設定されているので見てみます。
PWMの周期
    TDR00H = _4E_TAU_TDR00H_VALUE;
    TDR00L = _1F_TAU_TDR00L_VALUE;
に対して、PWM1のON時間
    TDR01H = _13_TAU_TDR01H_VALUE;
    TDR01L = _88_TAU_TDR01L_VALUE;
でデューティー比が決まります。
周期0x4E1F(19999)に対して0x1388(5000)でデューティー比が25%に設定されています。
従って、TDR0*HおよびTDR0*Lを変更すればデューティー比を変更できます。

これに基づいて、チャンネル1のデューティー比を変更してみます。

<設定>
#include "iodefine.h"    //端子の基本設定読み込み
#include "r_cg_macrodriver.h"    //uint16_tとか読み込み
#include "r_cg_wdt.h"    //ウォッチドッグタイマー
#include "r_cg_tau.h"    //PWM設定

void user_main(void){
    unsigned short duty1;    //デューティー比 0-1000
    unsigned long pwm_out1;    //出力
    unsigned short pwm_max=TDR00H*0x100+TDR00L;
    R_TAU0_Channel0_Start();    //PWM開始
    while(1){
        duty1=700;    //デューティー比を設定(70%)
        pwm_out1=(long)duty1*pwm_max/1000;            //設定値を計算
        pwm_out1=(pwm_out1>pwm_max)?pwm_max:pwm_out1;//設定上限
        TDR01H=(unsigned char)(pwm_out1/0x100);        //上位8bitを格納
        TDR01L=(unsigned char)(pwm_out1&0x00FF);    //下位8bitを格納
        R_WDT_Restart();    //ウォッチドッグタイマーリセット
    }
}

これでデューティー比を変更可能になりました。
チャンネル2、チャンネル3を設定する場合は同様の方法で
 チャンネル2:TDR02H、TDR02L
 チャンネル3:TDR03H、TDR03L
へ設定値を書き込みます。
あとは必要に応じて関数化して使いましょう。

<関数化の例>(2020/08/15変数型式修正)
#include "iodefine.h"    //端子の基本設定読み込み
#include "r_cg_macrodriver.h"    //uint16_tとか読み込み
#include "r_cg_tau.h"    //PWM設定

void set_pwm(int port,short duty){
    unsigned short pwm_out;        //設定値
    unsigned short pwm_max=TDR00H*0x100+TDR00L;    //最大値
    volatile unsigned char *pwm_H;    //H格納先(ポインタ)
    volatile unsigned char *pwm_L;    //L格納先(ポインタ)   

    switch(port){
        case 1:
            pwm_H=&TDR01H;    //格納先を指定
            pwm_L=&TDR01L;    //格納先を指定
            break;
        case 2:
            pwm_H=&TDR02H;    //格納先を指定
            pwm_L=&TDR02L;    //格納先を指定
            break;
        case 3:
            pwm_H=&TDR03H;    //格納先を指定
            pwm_L=&TDR03L;    //格納先を指定
            break;
        default:    //該当なし
            return;
    }

    pwm_out=(unsigned short)((long)duty*pwm_max/1000);            //設定値を計算
    pwm_out=(pwm_out>pwm_max)?pwm_max:pwm_out;    //設定上限

    *pwm_H=(unsigned char)(pwm_out/0x100);        //上位8bitを格納
    *pwm_L=(unsigned char)(pwm_out&0x00FF);        //下位8bitを格納
}

<実行例>
#include "iodefine.h"    //端子の基本設定読み込み
#include "r_cg_macrodriver.h"    //uint16_tとか読み込み
#include "r_cg_wdt.h"    //ウォッチドッグタイマー

void user_main(void){
    unsigned short duty1,duty2,duty3;    //デューティー比 0-1000

    R_TAU0_Channel0_Start();    //PWM開始

    while(1){
        duty1=250;    //デューティー比を設定
        duty2=500;    //デューティー比を設定
        duty3=750;    //デューティー比を設定

        set_pwm(1,duty1);    //TO01へPWM出力
        set_pwm(2,duty2);    //TO02へPWM出力
        set_pwm(3,duty3);    //TO03へPWM出力
        R_WDT_Restart();    //ウォッチドッグタイマーリセット
    }
}


タイマー機能

SHおよびRXはPWMとタイマーが独立した機能になっていました。
RL78(G10)はPWMもタイマーもTAU(タイマ・アレイ・ユニット)へ集約されています。
で、PWMを優先して使用すると純粋なタイマーへ割り振るカウンターが残りません。
しかし、タイマーが無いとそれはそれで困ります。
そこで、チャンネル0のカウント機能をタイマー機能として使用します。

PWMの周期設定で周期を1msに設定した場合、1msごとにチャンネル0の割り込み
が発生します。コード生成を利用するとr_cg_tau_user.cのr_tau0_channel0_interrupt
として割込み機能が生成されています。
r_tau0_channel0_interruptへ1msごとに実行したい処理を記述しておきます。
今まで通り_systimerを作成し、システム時刻として利用します。
とりあえず内容はr_cg_tau_user.cへ記述していきます。

<設定>(2020/08/15誤記修正)
/********************************************************************************************
Global variables and functions
*********************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
static unsigned long _systime=0;
/* End user code. Do not edit comment generated here */



static void __near r_tau0_channel0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
    _systime++;    //1msを前提とした場合
    /* End user code. Do not edit comment generated here */
}



/* Start user code for adding. Do not edit comment generated here */
unsigned long getsystime(void){
    return _systime;
}
/* End user code. Do not edit comment generated here */


プロトタイプ宣言はとりあえずr_cg_tau.hに書いておきます。
/* Start user code for function. Do not edit comment generated here */
unsigned long getsystime(void);
/* End user code. Do not edit comment generated here */

これでシステム時刻を利用できます。
とりあえずr_cg_tau_user.cへ記述しましたが、作成した関数を他のプロジェクトでも
流用したい場合は自動生成されるr_cg_tau_user.cを移植するのは危険なので、各種
自作関数は自作のソースファイルで管理し、実行したい処理をまとめた自作関数
自動生成された割込み関数で実行するのが良いと思います。

周期を20ms等に設定した場合は割り込みの発生が20msなのでそのままでは1msの分解能
を得る事ができませんが、内部カウント値TCR00H,TCR00Lの情報を利用すれば1ms程度
の分解能を得ることもできます。
PR

コメント

プロフィール

HN:
ぼんどF博士
性別:
男性
自己紹介:

最新コメント