Article #263

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.

FM-7 ROM吸出し器の改版(8)

posted by sakurai on May 26, 2020 #263

タイマーの設定

今回はTimer2を用いて割り込みをかけるので、Timer2の設定を行います。表261.1にある組み合わせであればどれでも良いのですが、ここでは62.5 usecの割込みを入れ、割込みルーチン内で4回の*REFCKを発行するものとします。

まず、図263.1のようにモジュール設定でIntterrupt moduleを選択し(①)、右の画面でTMR2をイネーブル(②)とします。

図%%.1
図263.1 Interrupt module

最後にタイマーの設定を行います。モジュール設定でTMR2を選択(①)します。周期に62.5 usと記入(②)します。プリスケーラ、ポストスケーラとも1:1(③)とします。割込み何回に一回コールバックするかを設定(④)します。

図%%.2
図263.2 TMR2 module

コード生成

これで設定が完了したので、Generateでコード生成を行います。様々なCソースやヘッダファイルが生成されます。例えば、device.cが生成され、その内容は、

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = OFF    // Watchdog Timer Enable->WDT disabled
#pragma config PWRTE = OFF    // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = ON    // MCLR Pin Function Select->MCLR/VPP pin function is MCLR
#pragma config CP = OFF    // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config BOREN = ON    // Brown-out Reset Enable->Brown-out Reset enabled
#pragma config CLKOUTEN = OFF    // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
// CONFIG2
#pragma config WRT = OFF    // Flash Memory Self-Write Protection->Write protection off
#pragma config STVREN = ON    // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset
#pragma config BORV = LO    // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LPBOR = OFF    // Low-Power Brown Out Reset->Low-Power BOR is disabled
#pragma config LVP = ON    // Low-Voltage Programming Enable->Low-voltage programming enabled

となっています。次にinterrupt_manager.cの内容は、

#include "interrupt_manager.h"
#include "mcc.h"
void __interrupt() INTERRUPT_InterruptManager (void)
{
    // interrupt handler
    if(INTCONbits.PEIE == 1)
    {
        if(PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1)
        {
            TMR2_ISR();
        } 
        else
        {
            //Unhandled Interrupt
        }
    }      
    else
    {
        //Unhandled Interrupt
    }
}

のように、TMR2_ISR()を呼び出しています。mcc.cは各種初期化関数の集合であり、

#include "mcc.h"
void SYSTEM_Initialize(void)
{
    PIN_MANAGER_Initialize();
    OSCILLATOR_Initialize();
    WDT_Initialize();
    TMR2_Initialize();
}
void OSCILLATOR_Initialize(void)
{
    // SCS FOSC; IRCF 16MHz_HF; 
    OSCCON = 0x78;
    // SBOREN disabled; BORFS disabled; 
    BORCON = 0x00;
}
void WDT_Initialize(void)
{
    // WDTPS 1:65536; SWDTEN OFF; 
    WDTCON = 0x16;
}

となっています。pin_manager.cは、

#include "pin_manager.h"
void PIN_MANAGER_Initialize(void)
{
    /**
    LATx registers
    */
    LATA = 0x00;
    /**
    TRISx registers
    */
    TRISA = 0x32;
    /**
    ANSELx registers
    */
    ANSELA = 0x00;
    /**
    WPUx registers
    */
    WPUA = 0x00;
    OPTION_REGbits.nWPUEN = 1;
    /**
    APFCONx registers
    */
    APFCON = 0x00;
}

のように、ピン(ポート)の設定です。最後にtmr2.cはtimer2の各種関数の集合であり、左下のNavigatorウインドウに生成された関数一覧が確認できます。ここでは、

  • TMR2_CallBack()
  • TMR2_DefaultInterruptHandler()
  • TMR2_ISR()
  • TMR2_Initialize()
  • TMR2_InterruptHandler
  • TMR2_LoadPeriodRegister(uinit8_t periodVal)
  • TMR2_ReadTimer()
  • TMR2_SetInterruptHandler(void(*InterruptHandler)()
  • TMR2_StartTimer()
  • TMR2_StopTimer()
  • TMR2_WriteTimer(uint8_t timerVal)

が生成されました。interrupt_managerからTMR2_ISR()がコールされ、そこからTMR2_CallBack()がコールされ、そこではTMR_InterruptHandler()がコールされます。

ISR

以下のコメント部が示すように、TMR2_DefaultInterruptHandlerに割込み処理を書くようです。以下に内容を示します。

void TMR2_DefaultInterruptHandler(void){
    // add your TMR2 interrupt custom code
    // or set custom function using TMR2_SetInterruptHandler()
}

前稿での割込み処理内容は

もしZ80W=Lなら
1. Rfreq=H、Xrefck=Hを出力 //リフレッシュ要求
2. Rfgnt=Hを待つ
3. Rfreq=H、Xrefck=Lを出力
4. Rfreq=H、Xrefck=Hを出力 (3, 4を4回繰り返す)
5. Rfreq=L、Xrefck=Hを出力
6. リターン

であったので、そのままプログラムします。以下のピン名から始まる各種の関数はマクロとして、生成されたpin_manager.hで定義されています。

void TMR2_DefaultInterruptHandler(void){
    if (Z80W_GetValue() == 0) {
        XREFCK_SetHigh();
        RFREQ_SetHigh();
        while (RFGNT_GetValue() == 0);
        XREFCK_SetLow();  XREFCK_SetHigh();
        XREFCK_SetLow();  XREFCK_SetHigh();
        XREFCK_SetLow();  XREFCK_SetHigh();
        XREFCK_SetLow();  XREFCK_SetHigh();
        RFREQ_SetLow();
    }
}

TMR2_Initialize()の内容は、

void TMR2_Initialize(void)
{
    // Set TMR2 to the options selected in the User Interface
    // PR2 249; 
    PR2 = 0xF9;
    // TMR2 0; 
    TMR2 = 0x00;
    // Clearing IF flag before enabling the interrupt.
    PIR1bits.TMR2IF = 0;
    // Enabling TMR2 interrupt.
    PIE1bits.TMR2IE = 1;
    // Set Default Interrupt Handler
    TMR2_SetInterruptHandler(TMR2_DefaultInterruptHandler);
    // T2CKPS 1:1; T2OUTPS 1:1; TMR2ON on; 
    T2CON = 0x04;
}

のようになっています。また、main()は、

#include "mcc_generated_files/mcc.h"
/*
                         Main application
 */
void main(void)
{
    // initialize the device
    SYSTEM_Initialize();
    // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
    // Use the following macros to:
    // Enable the Global Interrupts
    INTERRUPT_GlobalInterruptEnable();
    // Enable the Peripheral Interrupts
    INTERRUPT_PeripheralInterruptEnable();
    while (1)
    {
        // Add your application code
    }
}

のように、初期設定がされているため、以下のようにタイマーの開始を追加します。while ループ内の処理はありません。

    TMR2_StartTimer();

左矢前のブログ 次のブログ右矢

Leave a Comment

Your email address will not be published.

You may use Markdown syntax.

Please enter the letters as they are shown in the image above.
Letters are not case-sensitive.