UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

UMEHOSHI IT (my_sys.cと.my_sys.h)

my_sys.hのソース

#ifndef _MY_SYS_H    /* Guard against multiple inclusion */
#define _MY_SYS_H

#include "my_beep.h"

extern int core_once_count1_val; // 0になるまでコアタイマでダウンカウント
extern int core_once_count2_val; 
extern int core_once_count3_val; 

void init_main();
void init_interrupt();

#endif /* _MY_SYS_H */

my_sys.cのソース

/*
 * ウメ・エディット・プログラム実現用のシステム部分
 * 起動関連の処理
 * タイマ関連 割り込み関連の初期指定
 * PWMの初期化ルーチン
 * ADコンバータの初期化ルーチン
 */

#include <xc.h>
#include <stdio.h>
#include <proc/p32mx270f256b.h>
#include "my_app.h" 
#include "my_usb_cmd.h" 
#include "my_adc.h" 
#include "my_uart.h"
#include "my_sys.h"
#include "common.h"

/*****************************************************
 *  グローバル変数
 ****************************************************/
unsigned int temp;// デバック確認用

// ESP32-WROOM-32Dの起動時のメッセージ出力を止める細工を20201005に追加
int core_once_count1_val = 880; // 0になるまでコアタイマでダウンカウント(1秒)
int core_once_count2_val = 1760; // 0になるまでコアタイマでダウンカウント(2秒)
int core_once_count3_val = 2640; // 0になるまでコアタイマでダウンカウント(3秒)
int core_once_count4_val = 3520; // 0になるまでコアタイマでダウンカウント(4秒)

// 割り込みルーチンとウメシステム情報のテーブル
void (*handlers_table[(0x1000>>2)-4])(void) __attribute__ (( persistent, address(_PTR_HANDLERS) ));

// RAMのプログラミングや情報記憶域領域
char ram_area1[0x3000] __attribute__ (( persistent, address(_PTR_RAM_AREA1) ));
char ram_area2[0x1000] __attribute__ (( persistent, address(_PTR_RAM_AREA2) ));
char ram_area3[0x0F00] __attribute__ (( persistent, address(_PTR_RAM_AREA3) ));

// 割り込みルーチンとウメシステム情報のテーブルの先頭ポインタ
void (**handlers)(void)= (void (**)(void) )handlers_table;

static int led_D1=0;//LED D1の初期値

int power_on_flag = 0; // パワーオンリセットで1、リセット時は0 追加[2023-4]

/* =============================================================================
 *  main内部の最初に呼ばれる。( SYS_Initialize ( NULL );の前で呼ばれる)
 * =============================================================================
 */
void init_main()
{
    //ANSELB:指定ビット0にするとデジタル、1でアナログ(デフォルト)として使う。
    ANSELBCLR =  0x0000E3BC; //15,14,13,9,8,7,5,4,3,2を0にする。
                             // 1110 0011 1011 1100
    ANSELBCLR = ~0x00000DB3; // 0への指定ビットをデジタルとして使う
    ODCB = 0x0; // オープンドレインを使わない。 

    // TRISB 1にすると入力、0にすると出力
    TRISBCLR =  0x0000E22C; // 出力指定 1110 0010 0010 1100
    TRISBSET =  0x00000190;//  入力指定 0000 0001 1001 0000
       
    // CPU 命令アクセスバスエラービット バスエラー例外を無効にする
    ((__BMXCONbits_t *)& BMXCON )->BMXERRIS = 0;
    
    // バスマトリクス調停モードビット モード0
    ((__BMXCONbits_t *)& BMXCON )->BMXARB = 0;
       
    // メモリ構成の設定 「0x80004000」?をプログラミング用に使う
    BMXDKPBA = 0x00004000;//16 KB のカーネルデータ 「0x80004000」    
    BMXDUDBA = BMXDKPBA+0x0000C000;//48 KB のカーネルプログラム
    BMXDUPBA = BMXDUDBA;//ユーザデータのサイズ = 0、ユーザプログラムのサイズ = 0 
    // メモリ構成の設定はここまで
    
    extern void init_handle_area ();//ハンドラ・テーブル と ユー・ラム・エリア 初期用 
    // このソースの最後で、「ウメ・エディットプログラム」インターフェイス用に定義!)
    init_handle_area (); // ハンドラ・テーブル と ユー・ラム・エリア 初期     
    //  (各種インターフェイス用記憶域、割込みテーブルの初期化などが初期化)
}
 
/*******************************************************************************
 * 
 *  各割込みのサンプル関数
 * 
 ******************************************************************************/

void dummy_function() {  }// ダミー関数

void dummy_init_function() {// handlers[_IDX_INIT_SUB_FUNC]デフォルト値
    _RB15 = led_D1; // D1 LED の初期設定
    asm("NOP");
}// ダミー関数

volatile unsigned int core_wait_down_count __attribute__((section("sfrs")));
//uint8_t core_wait_down_count;//割り込みで変更される変数は、上記の宣言が必要
// 上記を使った待機関数(コアタイマの割り込みでカウントされる変数を利用して待機する。)
void core_wait(int cnt0){
   if(core_wait_down_count == 0){
        core_wait_down_count= cnt0;
    }
    while(core_wait_down_count > 0){
    }
 }
 
// onに変化してからn回連続onが続いた時に1を、そうでなければ0を返す。
// また、それを記憶する変数(押し続けても、1回しかtrueにならない分、少し遅れる)
static int switch2 = 0;
int is_on_sw2(int n){ // default コアタイマで呼び出している。
    static int push = 0;
    static int cnt = 0;
    push = (PORTB & 0x80) == 0;
    if( switch2 != push ){
         cnt++;
    } else {
        cnt = 0;                    
    }
    if(cnt == n) {
        switch2 = push;//しっかり変化したと判断(n回分の遅れが生じる)
        return switch2;
    }
    return switch2;
}

// SW2の状態を返すグローバル関数 (押すと1になる)●
int get_switch2_state(){
    return switch2;
}

void core_timer_sub_1()// 初期サンプルのビープ振動処理, SW2チェック--------------
{    
    // 起動時時SW2操作の分岐や、ESP32-WROOM-32Dの起動時のメッセージ出力を止める細工
    if(core_once_count1_val != 0) core_once_count1_val--;
    if(core_once_count2_val != 0) core_once_count2_val--;
    if(core_once_count3_val != 0) core_once_count3_val--;
    if(core_once_count4_val != 0) core_once_count4_val--;
    if(core_wait_down_count != 0) core_wait_down_count--;
    
    //別途に1秒時にUART受信あれば、UARTへ改行を送信して2秒間のUART受信を無視している
    
    if(core_once_count3_val==1){//3秒のタイミングで1回だけ実行
        U1STAbits.OERR = 0;     

        if( _RB7 == 0 || _UME_THROUGH_MODE){//約2秒後の瞬間
            // _RB7 がLow(SW2が押されていいる)または、スルーモード指定がある?           
            
            _RB15 = ! _RB15;// // D1 LED 反転 (点燈から消灯へ)
            asm("NOP");     
                       
            // UARTスルーモードへ移行
            handlers[_IDX_MY_APP_TASKS] = (void *)My_APP_Tasks_Through;
            APP_State_Reset();
            init_outBuffers(); //USB出力用リングバッファ関連変数 の初期化
            ringbuf_reset(&uartSndBuf);
            ringbuf_reset(&uartRecBuf);
            clear_beep_code();
            
            // 下記のフロー制御を使うとESP32-WROOM-32Dのesptool.pyが使えない
            //U1MODEbits.RTSMD = 0; // UxRTS ピンモード選択をフロー制御モード
            //U1MODEbits.UEN = 2;//UxTX、UxRX、UxCTS、UxRTS ピンを有効にして使う
        }
    }

    if(core_once_count4_val==1 && _RB7 == 0){//_RB7 がLow(SW2が押されていいる)
        // UART のコマンドモードへ移行
        _RB15 = ! _RB15;// D1 LED 反転 
        asm("NOP");            
        handlers[_IDX_MY_APP_TASKS] = (void *)My_APP_Tasks;
        init_outBuffers(); //USB出力用リングバッファ関連変数 の初期化
        handlers[_IDX_DEF_POLLS_UART] = handlers[_IDX_CMD_POLLS_UART];
        
        // RN42のプログラム転送で、下記のフロー制御が必要
        U1MODEbits.RTSMD = 0; // UxRTS ピンモード選択をフロー制御モード
        U1MODEbits.UEN = 2;//UxTX、UxRX、UxCTS、UxRTS ピンを有効にして使う
    }
    
    void base_beep();// この関数内部で、ブザーの振動のON/OFF制御をしている。
    base_beep();// ビープ音の音色(グローバル変数beep_onでブザーをON、OFFしている。)
    
    void beep_code_switching();// グローバル変数beep_onを変更してON/OFF指示
    beep_code_switching();// 4bitコードを音にする。 (初期は440Hzビープ)
    
    int is_on_sw2(int n);    
    is_on_sw2(50);  // スイッチ SW2の監視関数
    //temp = get_switch2_state();  //SW2の状態取得可能。
}

// コアタイマーサンプル関数-------------------------------------------------------
void core_timer_umeFunc_1(){
    unsigned long ct_count = _CP0_GET_COUNT();
    unsigned long period = _UM_CP0_SET_COMPARE;  
    handlers[_IDX_CORE_TIMER_SUB_FUNC](); // 上記core_timer_sub_1()がデフォルト.    
    // update the Compare period
    period += ct_count;
    _CP0_SET_COMPARE(period);

    IFS0CLR = _IFS0_CTIF_MASK; // 割り込み要求フラグをクリア
}


//  Timer1 の割り込みから呼びだされるサンプル関数----------------------------------
void timer1_umeFunc1_1(){
    IFS0CLR = 0x00000010; // Clear the timer interrupt status flag

    void beep_cycle_switching();
    beep_cycle_switching();  // サウンド再生時の音の長さ制御がデフォルト
}

//  Timer2 の割り込みから呼びだされるサンプル関数----------------------------------
void timer2_umeFunc1_1(){
    IFS0CLR = 0x00000200; // Clear the timer interrupt status flag
}

// 各コンペアの割り込み関数
void compare5_umeFunc(){   
    IFS0CLR= _IFS0_OC5IF_MASK; // Clear the OC5 interrupt flag
}
void compare1_umeFunc(){   
    IFS0CLR= _IFS0_OC1IF_MASK; // Clear the OC1 interrupt flag
}
void compare3_umeFunc(){   
    IFS0CLR= _IFS0_OC3IF_MASK; // Clear the OC3 interrupt flag
}
void compare4_umeFunc(){   
    IFS0CLR= _IFS0_OC4IF_MASK; // Clear the OC4 interrupt flag
}

//  Timer4 の割り込みから呼びだされるサンプル関数---------------------------------
void timer4_sample()//デファオルと0.05ミリ秒
{
    static int count=0;
    if(++count == 10000){//0.5秒ごと
        _RB15 = ! _RB15;//点滅周期:1秒.
        count = 0;
    }
}

//  Timer5 の割り込みから呼びだされるサンプル関数---------------------------------
void timer5_sample()//デファオルと0.05ミリ秒
{
    static int count=0;
    if(++count == 10000){//0.5秒ごと
        _RB15 = ! _RB15;//点滅周期:1秒.
        count = 0;
    }
}

/*******************************************************************************
 * 
 *   割込みの初期化関数
 * 
 ******************************************************************************/

// コアタイマーサンプル用初期化---------------------------------------------------
void init_core_timer_1(){
    _CP0_SET_COUNT(0);//コアタイマを0にセット(CP0の9番レジスタ)
    _CP0_SET_COMPARE(_UM_CP0_SET_COMPARE);// コンペアレジスタに値設定(コアタイマがそれに達すると割り込み)  
    _CP0_BIC_DEBUG(_CP0_DEBUG_COUNTDM_MASK);// halt core timer and program at a debug breakpoint
    IFS0CLR = _IFS0_CTIF_MASK;// clear core timer interrupt flag
    IPC0SET = (7 << _IPC0_CTIP_POSITION);// set core time interrupt priority of 7
    IPC0SET = (3 << _IPC0_CTIS_POSITION);// set core time interrupt subpriority of 0
    IEC0CLR = _IEC0_CTIE_MASK;
    IEC0SET = (1 << _IEC0_CTIE_POSITION);// enable core timer interrupt
        
   	IEC0CLR = _IEC0_CTIE_MASK;// disable interrupt
    IEC0SET = _IEC0_CTIE_MASK;	// Enable(割込み許可)
}

// Timer1 の初期化 -----デフォルトで音符の長さ指定に使用---------------------------
void init_timer_1(){
    T1CON =0x00000000;//typeA,16bit, [1:1プリスケール
    TMR1=0x00000000; //16bitタイマの設定値(レジスタがカウントアップ)
    PR1=20000-1; // 0.0005 = 200000*(1/40e6) -1これは約0.5ミリ秒
    IPC1SET = 0x0000000C; // Set priority level = 3
    IPC1SET = 0x00000001; // Set sub-priority level = 1
    IFS0CLR = 0x00000010; // Clear the timer interrupt status flag
    IEC0SET = 0x00000010;//T1IE Timer1 Enable(割込み許可)
    //T1CONSET =0x8000; // Start timer1
}

// Timer2 の初期化 ------デフォルトでPWMのタイミングカウンターに使用----------------
void init_timer_2(){
    T2CONbits.ON = 0;// typeBでON
    T2CONbits.SIDL = 0;// デバイスがアイドルモードに移行しても動作を継続する
    T2CONbits.TGATE = 0;// ゲート時間積算を無効にする
    T2CONbits.TCKPS = 0;// タイマ入力クロック [1:1]プリスケール値
                            // TCKPS 3bit:111
    T2CONbits.T32 = 0;//TMRxとTMRyは別々の16ビットタイマを構成する
    T2CONbits.TCS = 0;//内部の周辺モジュール用クロック
    T2CON =0x00000000;//typeB,16bit, [1:1]プリスケール   
    //T2CON =0x00000070;//typeB,16bit, [1:256]プリスケール
    TMR2=0x0000; //16bitタイマの設定値(レジスタがカウントアップ)
    PR2=0x0FFFF; //16bit周期レジスタビット設定
    IPC2SET = 0x0000000C; // Set priority level = 3
    IPC2SET = 0x00000001; // Set sub-priority level = 1
    IFS0CLR = 0x00000200; // Clear the timer interrupt status flag
    IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)
    //T2CONSET =0x8000; // Start timer2
}

//モータ用パルス幅変調モードの初期設定(PWM の設定)
void init_compare()// IDX_INIT_PWD
{
    //CN6(左側)前方向デューティ比用Output Compare Output5 の設定
    RPB2Rbits.RPB2R = 0x6; // RB2をOC5の出力にする。
    OC5CONbits.SIDL = 0; // アイドルモード中も動作を継続する
    OC5CONbits.OC32 = 0; //OCxR<15:0> およびOCxRS<15:0> を使って16 ビットタイマ源と比較する
    OC5CONbits.OCTSEL = 0; // Timer2 をこの出力コンペア モジュールのクロック源として使う
    OC5CONbits.OCM = 6; // OC1 をPWM モードにし、フォルトピンを無効にする
    IPC5bits.OC5IP = 5;// Set OC1 interrupt priority to 5
    IPC5bits.OC5IS = 2;// Set Subpriority to 3, maximum
    IFS0CLR= _IFS0_OC5IF_MASK; // Clear the OC5 interrupt flag
    //IEC0SET= _IEC0_OC5IE_MASK; // Enable Interrupt
            
    //CN6(左側)後ろ方向デューティ比用Output Compare Output1 の設定
    RPB3Rbits.RPB3R = 0x5; // RB3をOC1の出力にする
    OC1CONbits.SIDL = 0; // アイドルモード中も動作を継続する
    OC1CONbits.OC32 = 0; //OCxR<15:0> およびOCxRS<15:0> を使って16 ビットタイマ源と比較する
    OC1CONbits.OCTSEL = 0; // Timer2 をこの出力コンペア モジュールのクロック源として使う
    OC1CONbits.OCM = 6; // OC1 をPWM モードにし、フォルトピンを無効にする
    IPC1bits.OC1IP = 5;// Set OC1 interrupt priority to 5
    IPC1bits.OC1IS = 2;// Set Subpriority to 3, maximum
    IFS0CLR= _IFS0_OC1IF_MASK; // Clear the OC1 interrupt 
    //IEC0SET= _IEC0_OC1IE_MASK; // Enable Interrupt
    
    //CN7(右側)前方向デューティ比用Output Compare Output4 の設定
    RPB13Rbits.RPB13R = 0x5; // RB13をOC4の出力にする。
    OC4CONbits.SIDL = 0; // アイドルモード中も動作を継続する
    OC4CONbits.OC32 = 0; //OCxR<15:0> およびOCxRS<15:0> を使って16 ビットタイマ源と比較する
    OC4CONbits.OCTSEL = 0; // Timer2 をこの出力コンペア モジュールのクロック源として使う
    OC4CONbits.OCM = 6; // OC1 をPWM モードにし、フォルトピンを無効にする
    IPC4bits.OC4IP = 5;// Set OC1 interrupt priority to 5
    IPC4bits.OC4IS = 2;// Set Subpriority to 3, maximum
    IFS0CLR= _IFS0_OC3IF_MASK; // Clear the OC3 interrupt 
    //IEC0SET= _IEC0_OC3IE_MASK; // Enable Interrupt
    
    //CN7(右側)後ろ方向デューティ比用Output Compare Output3 の設定
    RPB14Rbits.RPB14R = 0x5; // RB14をOC3の出力にする。
    OC3CONbits.SIDL = 0; // アイドルモード中も動作を継続する
    OC3CONbits.OC32 = 0; //OCxR<15:0> およびOCxRS<15:0> を使って16 ビットタイマ源と比較する
    OC3CONbits.OCTSEL = 0; // Timer2 をこの出力コンペア モジュールのクロック源として使う
    OC3CONbits.OCM = 6; // OC1 をPWM モードにし、フォルトピンを無効にする
    IPC3bits.OC3IP = 5;// Set OC1 interrupt priority to 5
    IPC3bits.OC3IS = 2;// Set Subpriority to 3, maximum
    IFS0CLR= _IFS0_OC4IF_MASK; // Clear the OC4 interrupt flag
    //IEC0SET= _IEC0_OC4IE_MASK; // Enable Interrupt

    OC5R = 0;//_UME_CN6_OC5R;//0;//出力コンペアx コンペアレジスタ・・
    OC5RS = _UME_CN6_OC5RS;//出力コンペアx セカンダリコンペアレジスタ設定用(デューティー比 )
    OC1R = 0;//_UME_CN6_OC1R;//出力コンペアx コンペアレジスタ・・
    OC1RS = _UME_CN6_OC1RS;//出力コンペアx セカンダリコンペアレジスタ設定用(デューティー比 )
    OC4R = 0;//_UME_CN7_OC4R;//0;//出力コンペアx コンペアレジスタ・・
    OC4RS = _UME_CN7_OC4RS;//出力コンペアx セカンダリコンペアレジスタ設定用(デューティー比 )
    OC3R = 0;//_UME_CN7_OC3R;//0;//出力コンペアx コンペアレジスタ・・
    OC3RS = _UME_CN7_OC3RS;//出力コンペアx セカンダリコンペアレジスタ設定用(デューティー比 )
    
    //各出力コンペア モジュールを有効にする
    OC5CONbits.ON = 1; // RB2のOC5の出力をON(CN6の前方向)
    OC1CONbits.ON = 1; // RB3のOC1の出力をON(CN6の後ろ方向)
    OC4CONbits.ON = 1; // RB13のOC4の出力をON(CN7の前方向)
    OC3CONbits.ON = 1; // RB14のOC3の出力をON(CN7の後ろ方向)
}

// 現在未使用( PWM を使わないでモータを前進させる初期化)
void init_not_compare(){
    // ビット操作命令をポートに対して行う場合、ポートから全ての bit を読み出し、
    // 指定のビットをセットしてから、ポートに書き戻す。
    // その直後にビット操作命令がきた場合、ポートに書き戻したデータが確定しない
    // まま読み出しが起こり、ビットが反転する可能性がある。よって間にNOPを追加する。
    OC5CONbits.ON = 0; // RB2のOC5の出力をON(CN6)
    OC1CONbits.ON = 0; // RB3のOC1の出力をON(CN6)
    OC4CONbits.ON = 0; // RB13のOC4の出力をON(CN7)
    OC3CONbits.ON = 0; // RB14のOC3の出力をON(CN7)
    _RB2 = 0;// CN6 1-2
    __asm__("NOP");
    _RB3 = 0;// CN6 3-4 
    asm("NOP");
    _RB14 = 0;// CN7 1-2
    asm("NOP");
    _RB13 = 0;// CN7 3-4
    // 上記でNOPをなくすと、上記は動作しなかった。
    // 上記は、下記のように作る方が良い。
    PORTBCLR = 0x600c;//0b0110 0000 0000 1100;  
    //PORTBSET = 0x2004;//0b0010 0000 0000 0100;  
}




// Timer4,5 の初期化 -------------------------------------------------------------
void init_timer_4_5(){
    // ---- Timer4を使う指定 ここから
    T4CON =0x00000000;//typeB,16bit, [1:1]プリスケール
    TMR4=0x00000000; //16bitタイマの設定値(レジスタがカウントアップ)
    PR4=1999; // =0.0005/(1/40e6)-1 これは0.05ミリ秒
    IPC4bits.T4IP = 6; // Set priority level = 6(2番に大きな優先度)
    IPC4bits.T4IS = 0;// Set sub-priority level = 3(最大値)
    IFS0bits.T4IF = 0;// Clear the timer interrupt status flag
    IEC0bits.T4IE = 1;// Timer4 Enable(割込み許可)
    //T4CONbits.ON = 1;// Start timer4
    // ---- Timer4を使う指定 ここまで
    
    // ---- Timer5を使う指定 ここから
    T5CON =0x00000000;//typeB,16bit, [1:1]プリスケール
    TMR5=0x00000000; //16bitタイマの設定値(レジスタがカウントアップ)
    PR5=2000-1; // =0.0005/(1/40e6) -1これは約0.05ミリ秒
    IPC5bits.T5IP = 1; // Set priority level = 1(最小値)
    IPC5bits.T5IS = 3;// Set sub-priority level = 0(最小値)
    IFS0bits.T5IF = 0;// Clear the timer interrupt status flag
    IEC0bits.T5IE = 1;// Timer5 Enable(割込み許可)
    //T5CONbits.ON = 1;// Start timer5
    // ---- Timer5を使う指定 ここまで
}

// CN6 CN7 をPWMモードで使うかの切り替え
void set_pwd_mode(int flag){
    if(flag){
        handlers[_IDX_INIT_COMPARE] = init_compare; // PWM 関連の初期化
        
    } else {
        handlers[_IDX_INIT_COMPARE] = init_not_compare;// PWM を使わない設定
        
    }
    handlers[_IDX_INIT_COMPARE]();
}

/* =============================================================================
 * 割り込みハンドラなどの初期化ルーチンをまとめた関数
 * main()関数内のループ直前で呼ばれる。(SYS_Initialize ( NULL );の後で呼ばれる。))
 */
void init_interrupt()
{ 
    //コアタイマに関する初期化 init_core_timer_1();のような処理が登録が実行される。
    handlers[_IDX_INIT_CORE_TIMER]();
    
    // Timer1 初期化 
    handlers[_IDX_INIT_TIMER_1]();

    // Timer2 初期化 PWD の周期設定
    handlers[_IDX_INIT_TIMER_2]();// init_timer_2();
    
    // モータなどで使うPWMなど Output Compare Outputの初期化 
    _init_compare(); //handlers[_IDX_INIT_COMPARE]();

    // Timer3、ADC 初期化 
    handlers[_IDX_INIT_ADC_1]();
    handlers[_IDX_INIT_TIMER_3]();

    // Timer4,5 初期化 
    handlers[_IDX_INIT_TIMER_4_5]();
 
    // UART1 の設定init_uart()
    handlers[_IDX_INIT_UART1]();
    
    _RB9 = 0; // RTS(Request to Send (送信要求) ) の出力端子
    asm("nop");

    _RB8 = 0; // CTS(Clear to Send (送信可) ) の入力端子
    asm("nop");
    
    // 以下を1にすると、スルーモードで起動する。
    _UME_THROUGH_MODE = 0;
    
    //_UME_THROUGH_MODE = 1;// 実験の為スルーモード指定
    //(ESP32-WROOM-32D取り付け時,上記設定でSW2を押す操作を押さないと、Basicが起動  )
    
    // PB2にクロックを出力させて、周波数測定する時の設定
    // RPB2Rbits.RPB2R=0x07;// PB2を REFCLKO (50000Hz)に、ピン割り当てする。
    // REFOCONbits.OE = 1;  // REFERENCE OSCILLATOR CONTROL REGISTER

    if( power_on_flag == 1){//追加[2023-4]
        power_on_start();//追加[2023-4]
    }
    else //追加[2023-4]-----以下から
    {   // パワーオンでない場合(リセット)で実行する関数
        void (* func)(void) = (void *) 0x9D020000;
        if( *((uint32_t *)func) != 0xffffffff ){// EEPROMの記憶内容が0xffでない?
            func();
        }
    }   //追加[2023-4]-----以上までから

     //UMEHOSHI ITA アプリ用「初期ルーチン」デフォルトでは dummy_init_function関数 
    _init_sub_func(); //  handlers[_IDX_INIT_SUB_FUNC]の実行
    
} // end of void init_interrupt()
// main()関数内のループ直前で呼ばれる。(SYS_Initialize ( NULL );の後で呼ばれる。))


/* =============================================================================
 * 割り込みハンドラ
 * =============================================================================
/*
 *  優先度が同じで副優先度がより高い割り込みが発生しても、
 * サービス中の副優先度の低い割り込みは保留されません。
 * しかし、同じ優先度を持つ2つの割り込みが保留中である場合、
 * 副優先度が高い方の割り込みが先に処理されます
 */
// ------ コアタイマの割込みベクタの定義
// (下記のIPL7SOFTが優先度で、このソースでは、「IPC0SET」の設定と連動が必要な設定)
void __ISR(_CORE_TIMER_VECTOR, IPL7SOFT) CTInterruptHandler(void)
{   // システムクロック2つで、1カウントするカウンターが使われる。
    handlers[_IDX_CORE_TIMER_FUNC](); // デフォルトは440Hzのビープスイッチング
}

void __ISR(_TIMER_1_VECTOR,IPL3SOFT)Timer1Handler(void)
{
    handlers[_IDX_TIMER_1_FUNC](); // 音符長制御 
}

void __ISR(_TIMER_2_VECTOR,IPL3SOFT)Timer2Handler(void)
{
    //UMEHOSHI ITA アプリ用Timer2ルーチン デフォルトでは dummy関数がセット
    handlers[_IDX_TIMER_2_FUNC]();
}

// RB5 CN6[1-2]
void __ISR(_OUTPUT_COMPARE_5_VECTOR, IPL5SOFT) OC5_IntHandler (void)
{
    // コンペア割り込み OC5用
    handlers[_IDX_COMPARE_5_FUNC]();
}

// RB3 CN6[3-4]
void __ISR(_OUTPUT_COMPARE_1_VECTOR, IPL5SOFT) OC1_IntHandler (void)
{
    handlers[_IDX_COMPARE_1_FUNC]();
}

// RB14 CN7[1-2]
void __ISR(_OUTPUT_COMPARE_3_VECTOR, IPL5SOFT) OC3_IntHandler (void)
{
    handlers[_IDX_COMPARE_3_FUNC]();
}

// RB13[3-4]
void __ISR(_OUTPUT_COMPARE_4_VECTOR, IPL5SOFT) OC4_IntHandler (void)
{
    handlers[_IDX_COMPARE_4_FUNC]();    
}

void __ISR(_TIMER_3_VECTOR,IPL6SOFT)Timer3Handler(void)
{
   ((void (*)(struct ADC_BUFF*))handlers[_IDX_TIMER_3_FUNC])(p_buff);
}

void __ISR(_ADC_VECTOR,IPL7SOFT)ADC1Handler(void)
{
    ((void (*)(struct ADC_BUFF*))handlers[_IDX_ADC_1_FUNC])( p_buff );
}

void __ISR(_TIMER_4_VECTOR, IPL6SOFT) Timer4Handler(void)
{
    IFS0bits.T4IF = 0; // Clear the OC4 interrupt flag(この設定は次の割込みを可能にする).
    handlers[_IDX_TIMER_4_FUNC](); //timer4_sample()//デファオルと0.05ミリ秒
}

void __ISR(_TIMER_5_VECTOR, IPL1SOFT) Timer5Handler(void)
{
    IFS0bits.T5IF = 0; // Clear the OC5 interrupt flag(この設定は次の割込みを可能にする)
    handlers[_IDX_TIMER_5_FUNC](); // timer5_sample()//デファオルと0.05ミリ秒
}
// _TIMER_45_VECTOR と_TIMER_5_VECTOR は同じ20の番号になっているので、下記を定義するとエラー
//void __ISR(_TIMER_45_VECTOR, IPL7SOFT) Timer45Handler(void)
//{
//    IFS0bits.T5IF = 0; // Clear the OC5 interrupt flag(この設定は次の割込みを可能にする)
//    handlers[_IDX_TIMER_5_FUNC](); // timer5_sample()//デファオルと0.05ミリ秒
//}


/* =============================================================================
 * 起動時(リセット)直後に実行する。
 * ウメ・エディット・プログラムを実現するハンドラの初期化
 * 各種インターフェイス用記憶域、割込みテーブルの初期化
 * =============================================================================
 */

//void init_handlers (){//以前
void init_handle_area ()
{
    __RCONbits_t *rcon = (__RCONbits_t*) & RCON;//RCON: リセット制御レジスタ
    
    uint32_t t32 = (uint32_t) handlers;// 0xA0004000が記憶
    temp = sizeof(handlers[0]);//4が記憶
    temp = sizeof(handlers);//4が記憶
    t32  = (uint32_t) ram_area1;// 0xA0005000が記憶
    temp = sizeof(ram_area1);//0x3000がセット
    ram_area1[sizeof(ram_area1)-1]=0;//←これを行わないと、ram_area1領域ができない。
    ram_area2[sizeof(ram_area2)-1]=0;
    ram_area3[sizeof(ram_area3)-1]=0;
    
    led_D1 = 0; // D1 LED の初期点灯の予約

    // EEPROM操作関連 追加[2023-4]
    handlers[_IDX_NVM_ERASE_PAGE]=(void *)NVM_erase_page;
    handlers[_IDX_NVM_WRITE_WORD]=(void *)NVM_write_word;
   
    if (_RB7 == 0 || rcon->POR == 1) {//パワーオン時(リセット無関係)処理======= 
        // SW2 (RB7)が押されている。または、パワーオン リセットが発生
        // (リセットだけでは実行しない処理)    
        // 起動時(リセット)直後でSW2を押すことでも実行。
        core_once_count1_val = 880; // 0になるまでコアタイマでダウンカウント(1秒)
        core_once_count2_val = 1760; // 0になるまでコアタイマでダウンカウント(2秒)
        core_once_count3_val = 2640; // 0になるまでコアタイマでダウンカウント(3秒)
        
        // コア・タイマーの初期化    
        handlers[_IDX_INIT_CORE_TIMER] = init_core_timer_1;
        handlers[_IDX_CORE_TIMER_FUNC] = core_timer_umeFunc_1;//コア・タイマー処理
        _UM_CP0_SET_COMPARE = 22727u;//1/40e6*22727*2=0.00113635秒周期(440Hzブザー用)
        handlers[_IDX_CORE_TIMER_SUB_FUNC] = core_timer_sub_1;

        // スイッチ SW2 状態取得 ---------------------------------------------------
        handlers[_IDX_SWITCH2_STATE] = (void (*)(void) ) get_switch2_state;
        handlers[_IDX_CORE_WAIT] = (void (*)(void) ) core_wait;
        
        _UME_THROUGH_MODE = 0; // スルーモード 
        _UME_USB_CDC_DATE = 115200;//USB のボーレート
        
        // BEEP関連
        extern uint8_t my_beep_area[];
        _UM_PTR_BEEP_AREA = my_beep_area;
        _UM_PTR_GOTO_BEEP = my_beep_area;
        
        // Timer関連        
        handlers[_IDX_TIMER_1_FUNC] = timer1_umeFunc1_1;//TIMER1
        handlers[_IDX_INIT_TIMER_1] = init_timer_1;
        handlers[_IDX_TIMER_4_FUNC] = timer4_sample;
        handlers[_IDX_TIMER_5_FUNC] = timer5_sample;
        handlers[_IDX_INIT_TIMER_4_5] = init_timer_4_5;
        //_HANDLES[_IDX_INIT_TIMER_4_5] = init_timer_4_5;
        
        // compare関連
        handlers[_IDX_COMPARE_1_FUNC] =compare1_umeFunc;
        handlers[_IDX_COMPARE_3_FUNC] =compare3_umeFunc;
        handlers[_IDX_COMPARE_4_FUNC] =compare4_umeFunc;    
        handlers[_IDX_COMPARE_5_FUNC] =compare5_umeFunc;

        // PWM関連の初期設定 & Timer2
        //_UME_CN6_OC5R = 0;         
        _UME_CN6_OC5RS = 0;//0x0ffff;   // CN6 PWM 前方向へのデューティー比 
        //_UME_CN6_OC1R =0;
        _UME_CN6_OC1RS = 0;  // CN6 PWM 後ろ方向へのデューティー比 
        //_UME_CN7_OC4R = 0;
        _UME_CN7_OC4RS = 0;//0x0ffff;     // CN7 PWM 前方向へのデューティー比 
        //_UME_CN7_OC3R = 0;
        _UME_CN7_OC3RS = 0x00;     // CN7 PWM 前方向へのデューティー比 
        handlers[_IDX_TIMER_2_FUNC] =  timer2_umeFunc1_1;
        handlers[_IDX_INIT_TIMER_2] = init_timer_2;
        handlers[_IDX_INIT_COMPARE] = init_not_compare;// PWM を使わない設定
        //handlers[_IDX_INIT_COMPARE] = init_compare; // PWM 関連の初期化

        _UME_CONFIG = 0x0006; // BEEP デフォルトON, エラーBEEP通知ON
        
        // ADC関連 & Timer3
        handlers[_IDX_ADC_1_FUNC] = adc_umeFunc1_1;
        handlers[_IDX_INIT_ADC_1] = init_adc;
        handlers[_IDX_TIMER_3_FUNC] =  (void *)adc_usb_out;
        handlers[_IDX_INIT_TIMER_3] = init_timer_3;
        handlers[_IDX_ENCODE_ADC_BUFF] = (void *)encode_adc_buff;
        
        // UART1 関連 
        handlers[_IDX_INIT_UART1] = init_uart;
        handlers[_IDX_RECV_UART1] = (void *)recv_uart1;
        handlers[_IDX_SEND_UART1] = (void *)send_uart1;
        handlers[_IDX_MY_APP_TASKS] = (void *)My_APP_Tasks;
        handlers[_IDX_DEF_POLLS_UART] = (void *)recive_and_send_uart_with_polling;
        handlers[_IDX_CMD_POLLS_UART] = (void *)uart_cmd_mode_polling;
        handlers[_IDX_ISR_POLLS_UART] = (void *)uart_isr_buff_polling;
        
        // この関数内の最後で実行する「_handls_user_set_func()」の初期化
        handlers[_IDX_HANDLE_USER_SET_FUNC] = dummy_function;//何もしない
        
        //ウメ・エディットプログラムの初期化(_init_sub_func();の実行)
        handlers[_IDX_INIT_SUB_FUNC] = dummy_init_function;

        // USBからの置き換え可能な受信処理--------------------------------------------
        _RECIVE_USB_FUNC = dummy_recive;

        // ADC関連 -----------------------------------------------------------------
        handlers[_IDX_GET_PTR_ADC_BUFF] = (void (*)(void) ) get_ptr_adc_buff;
        handlers[_IDX_SET_ADC_EXE] = (void (*)(void) ) set_adc_exe;
        handlers[_IDX_SET_ADC_MODE] = (void (*)(void) ) set_adc_mode; 

        // 以下は、「ウメ・エディットプログラム」での利用を可能にするためのマクロ     
        // USBを介した文字列出力関連 -------------------------------------------------
        handlers[_IDX_API_REQUEST_ACC_OUTBUFF] = (void (*)(void) ) request_acc_outbuff;
        handlers[_IDX_API_RELEASE_ACC_OUTBUFF] = (void (*)(void) ) release_acc_outbuff;
        handlers[_IDX_API_SEND_CHAR] = (void (*)(void) ) send_char;
        handlers[_IDX_API_SET_BREAK_BUFFER] = (void (*)(void) ) setBreakBuffer;    
        handlers[_IDX_API_SEND_STRING] = (void (*)(void) ) send_string;
        handlers[_IDX_API_SEND_HEX_LOW] = (void (*)(void) ) send_hex_low;
        handlers[_IDX_API_SEND_HEX_HI] = (void (*)(void) ) send_hex_hi;
        handlers[_IDX_API_SEND_DECIMAL] = (void (*)(void) ) send_decimal;
        handlers[_IDX_API_GET_CAPACITY] = (void (*)(void) ) get_capacity;
        handlers[_IDX_API_SEND_16BYTE] = (void (*)(void) ) send_16byte;
        handlers[_IDX_SEND_PADDING_UINT] = (void (*)(void) ) send_padding_uint;
        handlers[_IDX_SEND_FLOAT] = (void (*)(void) ) send_float;
        handlers[_IDX_SEND_EXPONENT] = (void (*)(void) ) send_exponent;
        handlers[_IDX_SEND_UME_ID] = (void (*)(void) ) send_ume_id;

        // UART1 関連 --------------------------------------------------------------
        handlers[_IDX_API_REQUEST_ACC_UARTBUFF] = (void (*)(void) ) request_acc_uartbuff;
        handlers[_IDX_API_RELEASE_ACC_UARTBUFF] = (void (*)(void) ) release_acc_uartbuff;
        handlers[_IDX_GET_UART_CAPACITY] = (void (*)(void) ) get_uart1_capacity;
        handlers[_IDX_SEND_STR_UART1] = (void (*)(void) ) send_string_to_uart1;

        // ブザー関連 --------------------------------------------------------------
        handlers[_IDX_SET_BEEP_PERIOD] = (void (*)(void) ) set_beep_period;
        void set_beep_sound_node(int , uint8_t ,uint8_t, uint8_t);
        handlers[_IDX_SET_BEEP_SOUND_NODE] = (void (*)(void) ) set_beep_sound_node;
        void set_switching_period(int period);
        handlers[_IDX_SET_SWITCHING_PERIOD] = (void (*)(void) ) set_switching_period;
        void set_beep_code(uint8_t );
        handlers[_IDX_SET_BEEP_CODE] = (void (*)(void) ) set_beep_code;
        void clear_beep_code();
        handlers[_IDX_CLEAR_BEEP_CODE] = (void (*)(void) ) clear_beep_code;
        handlers[_IDX_DEBUG_POINT] = (void (*)(void) ) debug_point;    
   
        // DEBUG 関連定義------------------------------------------------------------
        handlers[_IDX_DEBUG_COUNT]=(void (*)(void) ) debug_count;
        handlers[_IDX_DEBUG_HEX4]=(void (*)(void) ) debug_hex4;
        handlers[_IDX_DEBUG_HEX8]=(void (*)(void) ) debug_hex8;
        handlers[_IDX_DEBUG_HEX16]=(void (*)(void) ) debug_hex16;
        handlers[_IDX_DEBUG_HEX32]=(void (*)(void) ) debug_hex32;

        // -------------------------------------------------------------------------
        handlers[_IDX_SET_PWD_MODE]=(void (*)(void) ) set_pwd_mode; 

        rcon->POR = 0;
        //PORは、POWER ON 時に1になる。リセット時には1にならない。       
        // 上記を行った後、リセットでは上記を行わなないようにクリアする
        
        led_D1 = 1; // D1 LED の初期点灯の予約

        power_on_flag = 1;//追加[2023-4]

    }//パワーオン時(リセット無関係)処理==============================ここまで
    
    _handle_user_set_func(); // handlers設定関数

}