RL78/G1Eでのタイマー関数

お世話になります初心者IKUZOと申します
プログラム中でタイミング遅延を正確にする関数を作成したいと思うのですが
サンプル等教えていただけませんでしょうか?
タイマー等のサンプルはあるみたいですが
LEDを割込みで変化させるようなものが見当たりますが
RXシリーズでやっていた以下のようなものが欲しいです
///////////////////////////////////////////////////////////////////////
//CMT0を使用したタイマ
///////////////////////////////////////////////////////////////////////
void R_CMT_Wait(unsigned short cnt)
{
/* ---- Stop CMT0 counting ---- */
/* CMSTR0 - Compare Match Timer Start Register 0
b15:b2 Reserved - The write value should be 0.
b1 STR1 - Count Start 1 - CMT1.CMCNT count is stopped.
b0 STR0 - Count Start 0 - CMT0.CMCNT count is stopped. */
CMT.CMSTR0.BIT.STR0 = 0; /* CMT0 count is stopped. */

/* ---- Clear the CMT0 count ---- */
/* CMCNT - Compare Match Timer Counter */
CMT0.CMCNT = 0x0000;

/* ---- Wait time set is other than 0? ---- */
if (0 != cnt)
{
/* ---- Decrement the wait time ---- */
cnt = cnt - 1;
}

/* ---- Set the CMT0 wait time ---- */
/* CMCOR - Compare Match Timer Constant Register */
CMT0.CMCOR = cnt;

/* ---- Clear the CMT0 interrupt request ---- */
while (1 == IR(CMT0,CMI0))
{
IR(CMT0,CMI0) = 0; /* CMT0.CMI0 interrupt request is cleared. */
}

/* ---- Start CMT0 counting ---- */
/* CMSTR0 - Compare Match Timer Start Register 0
b0 STR0 - Count Start 0 - CMT0.CMCNT count is started. */
CMT.CMSTR0.BIT.STR0 = 1;

/* ---- CMI0 interrupt request generated? ---- */
while (0 == IR(CMT0,CMI0))
{

}

/* ---- Stop CMT0 counting ---- */
/* CMSTR0 - Compare Match Timer Start Register 0
b0 STR0 - Count Start 0 - CMT0.CMCNT count is stopped. */
CMT.CMSTR0.BIT.STR0 = 0;

/* Clear IR flag */
IR(CMT0,CMI0) = 0;
}
///////////////////////////////////////////////////////////////////////
//CMT0を使用したタイマ
///////////////////////////////////////////////////////////////////////
割込みは使用しない方法が良いです。

Parents
  • チョコです。

    RXの方の細かいところは分からないので,適当に作ってみました。

    タイマはTM01をインターバルタイマとして使用します。インターバルは特に気にしなかったので,デフォルトの100usそのままです。使いたい時間に変更して下さい。

    割り込みは使用しないに設定します。

    これで,コード生成します。

    後は,r_main.cのmain関数を以下のようにして1秒の時間待ちを行うようにしてみました。

        while (1U)
        {
            R_CMT_Wait( 10000 );    /* 1秒待ち              */
            NOP();
        }

    ここで使用しているR_CMT_Wait関数は以下のようにしています。

    /***********************************************************************************************************************
    * Function Name: R_CMT_Wait
    * Description  : TM01(インターバルタイマ)を用いて指定した時間を待つ
    * Arguments    : 100us単位での待ち時間
    * Return Value : None
    ***********************************************************************************************************************/
    void R_CMT_Wait( uint16_t cnt )
    {
        R_TAU0_Channel1_Start();        /* TM01スタート         */

        for ( ; cnt > 0  ; cnt-- )
        {
            while ( TMIF01 == 0 )       /* 100us経過を待つ      */
            {
                NOP();
            }
            TMIF01 = 0;                 /* 割り込みフラグクリア */  
        }
        R_TAU0_Channel1_Stop();         /* TM01停止             */
    }

    この関数では,最初にTM01に起動を掛けて,カウント完了の割り込みTMIF01がセットされるのを待っています。

    TMIF01がセットされ,whileループを抜けたらTMIF01をクリアします。

    この処理を引数で渡された回数ループすることで,指定された時間を待ってからTM01を停止して戻ります。

     

    こんなところではどうでしょう。空いている(入出力で使用しない)チャネルを使って,時間は適当に変更して下さい。

    追記

    待ちたい時間の仕様が分からないので,100us単位での時間測定にしてしまいましたが,細かい(CPUのクロック単位での)

    指定が必要なら,下のようにTDR01レジスタにカウント値を設定して,forの部分を削除してください。

    void R_CMT_Wait( uint16_t cnt )
    {
        TDR01 = cnt;

        R_TAU0_Channel1_Start();        /* TM01スタート         */

            while ( TMIF01 == 0 )       /* 100us経過を待つ      */
            {
                NOP();
            }
            TMIF01 = 0;                 /* 割り込みフラグクリア */  
        R_TAU0_Channel1_Stop();         /* TM01停止             */
    }

  • チョコさんいつもお世話になっています
    ありがとうございます、
    これをそのまま使用させてください。
  • チョコさんいつもお世話になっています
    やってみましたが
    どうも腑に落ちなくて
    うまくいっていないようです
    原因がどうもわかりません、
    単位が100uSにならないようです
    コンパイラーの最適化でループが無視されているのでしょうか?
    画面はmain();からTAU1_Wait(100);を呼び出しています
    ///////////////////////////////////////////////////////////////////////
    //TAU1
    ///////////////////////////////////////////////////////////////////////
    //100=4uSになります
    //1000=32uSになります
    //10000=313uSになります
    //33333=だいたい1mSぐらい
    void TAU1_Wait( uint16_t cnt )
    {
    P5 |=0x02;//LED2消灯(オシロで監視)
    TDR01=cnt;
    TAU0_Channel1_Start
    while(TMIF01==0){
    NOP();
    }
    TMIF01=0;
    TAU0_Channel1_Stop
    P5 &=~0x02;//LED2点灯(オシロで監視)
    }
    ///////////////////////////////////////////////////////////////////////
    //TAU1
    ///////////////////////////////////////////////////////////////////////

    初期設定は

    // Channel 1 used as interval timer
    TMR01 = _0000_TAU_CLOCK_SELECT_CKM0 | _0000_TAU_CLOCK_MODE_CKS | _0000_TAU_16BITS_MODE |
    _0000_TAU_TRIGGER_SOFTWARE | _0000_TAU_MODE_INTERVAL_TIMER | _0000_TAU_START_INT_UNUSED;
    TDR01 = _0C7F_TAU_TDR01_VALUE;です。

  • チョコです。
    >コンパイラーの最適化でループが無視されているのでしょうか?
    100usはハードウェア(TM01のインターバルタイマ)で実現しているので,コンパイラとは無関係です。
    このプログラム(cntをTDR01に代入する)では,カウントしたいクロック数(-1)を引数にします。
    100usを実現するには,初期設定でセットしている0x0C7F(3199)を引数にすればいいはずですが。
  • チョコさんいつもお世話になっています
    「コンパイラとは無関係」わかりました、
    他をみるのですが、原因がつかめなくて、

    #define TAU0_Channel1_Start \
    TS0 |= _0002_TAU_CH1_START_TRG_ON;


    #define TAU0_Channel1_Stop \
    TT0 |= _0002_TAU_CH1_STOP_TRG_ON;


    void TAU1_Wait( uint16_t cnt );


    ///////////////////////////////////////////////////////////////////////
    //TAU設定
    ///////////////////////////////////////////////////////////////////////
    TAU0EN = 1U; // supplies input clock
    TPS0 = _0000_TAU_CKM0_FCLK_0 | _0000_TAU_CKM1_FCLK_0 | _0000_TAU_CKM2_FCLK_1 | _0000_TAU_CKM3_FCLK_8;
    // Stop all channels
    TT0 = _0001_TAU_CH0_STOP_TRG_ON | _0002_TAU_CH1_STOP_TRG_ON | _0004_TAU_CH2_STOP_TRG_ON |
    _0008_TAU_CH3_STOP_TRG_ON | _0010_TAU_CH4_STOP_TRG_ON | _0020_TAU_CH5_STOP_TRG_ON |
    _0040_TAU_CH6_STOP_TRG_ON | _0080_TAU_CH7_STOP_TRG_ON | _0200_TAU_CH1_H8_STOP_TRG_ON |
    _0800_TAU_CH3_H8_STOP_TRG_ON;
    // Mask channel 0 interrupt
    TMMK00 = 1U; // disable INTTM00 interrupt
    TMIF00 = 0U; // clear INTTM00 interrupt flag
    // Mask channel 1 interrupt
    TMMK01 = 1U; // disable INTTM01 interrupt
    TMIF01 = 0U; // clear INTTM01 interrupt flag
    // Mask channel 1 higher 8 bits interrupt
    TMMK01H = 1U; // disable INTTM01H interrupt
    TMIF01H = 0U; // clear INTTM01H interrupt flag
    // Mask channel 2 interrupt
    TMMK02 = 1U; // disable INTTM02 interrupt
    TMIF02 = 0U; // clear INTTM02 interrupt flag
    // Mask channel 3 interrupt
    TMMK03 = 1U; // disable INTTM03 interrupt
    TMIF03 = 0U; // clear INTTM03 interrupt flag
    // Mask channel 3 higher 8 bits interrupt
    TMMK03H = 1U; // disable INTTM03H interrupt
    TMIF03H = 0U; // clear INTTM03H interrupt flag
    // Mask channel 4 interrupt
    TMMK04 = 1U; // disable INTTM04 interrupt
    TMIF04 = 0U; // clear INTTM04 interrupt flag
    // Mask channel 5 interrupt
    TMMK05 = 1U; // disable INTTM05 interrupt
    TMIF05 = 0U; // clear INTTM05 interrupt flag
    // Mask channel 6 interrupt
    TMMK06 = 1U; // disable INTTM06 interrupt
    TMIF06 = 0U; // clear INTTM06 interrupt flag
    // Mask channel 7 interrupt
    TMMK07 = 1U; // disable INTTM07 interrupt
    TMIF07 = 0U; // clear INTTM07 interrupt flag
    // Set INTTM00 low priority
    TMPR100 = 1U;
    TMPR000 = 1U;
    // Set INTTM04 low priority
    TMPR104 = 1U;
    TMPR004 = 1U;
    // Set INTTM07 low priority
    TMPR107 = 1U;
    TMPR007 = 1U;
    // Channel 0 used as square output function
    TMR00 = _0000_TAU_CLOCK_SELECT_CKM0 | _0000_TAU_CLOCK_MODE_CKS | _0000_TAU_COMBINATION_SLAVE |
    _0000_TAU_TRIGGER_SOFTWARE | _0000_TAU_MODE_INTERVAL_TIMER | _0000_TAU_START_INT_UNUSED;
    TDR00 = _027F_TAU_TDR00_VALUE;
    TO0 |= _0001_TAU_CH0_OUTPUT_VALUE_1;
    TOE0 |= _0001_TAU_CH0_OUTPUT_ENABLE;

    // Channel 1 used as interval timer
    TMR01 = _0000_TAU_CLOCK_SELECT_CKM0 | _0000_TAU_CLOCK_MODE_CKS | _0000_TAU_16BITS_MODE |
    _0000_TAU_TRIGGER_SOFTWARE | _0000_TAU_MODE_INTERVAL_TIMER | _0000_TAU_START_INT_UNUSED;
    TDR01 = _0C7F_TAU_TDR01_VALUE;

    // Channel 4 used as square output function
    TMR04 = _0000_TAU_CLOCK_SELECT_CKM0 | _0000_TAU_CLOCK_MODE_CKS | _0000_TAU_COMBINATION_SLAVE |
    _0000_TAU_TRIGGER_SOFTWARE | _0000_TAU_MODE_INTERVAL_TIMER | _0000_TAU_START_INT_UNUSED;
    TDR04 = _0C7F_TAU_TDR04_VALUE;
    TOM0 &= ~_0010_TAU_CH4_OUTPUT_COMBIN;
    TOL0 &= ~_0010_TAU_CH4_OUTPUT_LEVEL_L;
    TO0 &= ~_0010_TAU_CH4_OUTPUT_VALUE_1;
    TOE0 |= _0010_TAU_CH4_OUTPUT_ENABLE;
    // Channel 7 is used to measure input pulse interval
    TMR07 = _0000_TAU_CLOCK_SELECT_CKM0 | _0000_TAU_COMBINATION_SLAVE | _0000_TAU_CLOCK_MODE_CKS |
    _0100_TAU_TRIGGER_TIMN_VALID | _0000_TAU_TIMN_EDGE_FALLING | _0004_TAU_MODE_CAPTURE |
    _0000_TAU_START_INT_UNUSED;
    TOM0 &= ~_0080_TAU_CH7_OUTPUT_COMBIN;
    TOL0 &= ~_0080_TAU_CH7_OUTPUT_LEVEL_L;
    TO0 &= ~_0080_TAU_CH7_OUTPUT_VALUE_1;
    TOE0 &= ~_0080_TAU_CH7_OUTPUT_ENABLE;
    NFEN1 &= (uint8_t)~_80_TAU_CH7_NOISE_ON; // disable using noise filter of TI07 pin input signal
    // Set TO00 pin
    P0 &= 0xFDU;
    PM0 &= 0xFDU;
    // Set TO04 pin
    P4 &= 0xFBU;
    PM4 &= 0xFBU;
    // Set TI07 pin
    PMC4 &= 0xFDU;
    PM4 |= 0x02U;
    ///////////////////////////////////////////////////////////////////////
    //TAU設定
    ///////////////////////////////////////////////////////////////////////

  • チョコです。
    >//100=4uSになります
    >//1000=32uSになります
    >//10000=313uSになります
    >//33333=だいたい1mSぐらい
    と言うのは,main関数でTAU1_Wait関数を呼び出すときの引数ですよね。
    また,TAU1_Wait関数は以前のコメントで追記した部分のプログラムですよね。
    このプログラムは,短い時間間隔を待てるように,TM01のインターバルを直接指定する(時間の単位はCPUの動作クロックの周期で約33ns)ものです。これは,1クロック単位で約2msまでカウントできます。

    100us単位にするには,最初に書いていた以下のようにすべきです。この場合には,TM01のカウントは3200カウントで100usごとにTMIF01がセットされるので,これをカウントして,目的の時間待ちます。

    void TAU1_Wait( uint16_t cnt )
    {
    R_TAU0_Channel1_Start(); /* TM01スタート */

    for ( ; cnt > 0 ; cnt-- )
    {
    while ( TMIF01 == 0 ) /* 100us経過を待つ */
    {
    NOP();
    }
    TMIF01 = 0; /* 割り込みフラグクリア */
    }
    R_TAU0_Channel1_Stop(); /* TM01停止 */
    }

    この関数を呼び出して,LEDを制御するポートを反転させるプログラムで1秒ごとに点灯/消灯しています。(RL78/G13ですが。)
  • チョコさんいつもお世話になっています
    main();に以下のように設定しまして1mSの波形が観測できました、
    正常に動作しています、先の高解像度のほうとともに使用させていただきます、
    P5 &=~0x02;//LED2点灯
    TAU1_Wait(10);
    P5 |=0x02;//LED2消灯
    TAU1_Wait(10);
    P5 &=~0x02;//LED2点灯

Reply
  • チョコさんいつもお世話になっています
    main();に以下のように設定しまして1mSの波形が観測できました、
    正常に動作しています、先の高解像度のほうとともに使用させていただきます、
    P5 &=~0x02;//LED2点灯
    TAU1_Wait(10);
    P5 |=0x02;//LED2消灯
    TAU1_Wait(10);
    P5 &=~0x02;//LED2点灯

Children
No Data