PIC32MXで長時間タイマーを作る(1)

こんにちは。お久しぶりです。

今回はMicrochip社製の32bitマイコンPIC32MX250F128Bを使用して1時間や12時間といった長時間タイマーを作製しようとしました。
負荷を12時間おきにON,OFFしたいというのが目標です。それとなるべくコストをカットすること。
主に備忘録。

ということで、開発環境はMPLAB XとMPLAB Harmonyを使用しました。またデバッカはPICKIT3を使用しました。
また回路エディタはKiCadです。
インストールとプロジェクトファイルの作り方、基本操作は以下のページが分かりやすかったです。
http://www.ys-labo.com/MPLAB%20Harmony/2016/Led%20FreeRun-NOP%20sum.html

今回の大まかな流れです。
1.MPLAB Harmonyプロジェクトを作成し、各種設定を行う。
2.app.cとsystem_interrupt.cにプログラムを追加する。
3.ブレッドボードで試作。
今回はここまで----------------------------------------------------
4.基板設計。
5.フリー基板に実装。
6.Elecrowに発注。


1.MPLAB Harmonyプロジェクトを作成し、各種設定を行う
と、その前に簡単な仕様を決める必要がありますね。
長時間をマイコンでカウントする方法としては
マイコンのシステムクロックを使用したタイマー機能
・外部クロックを用いたRTC
辺りが一般的だと思います。
精度をもっと求める場合は
GPSモジュールの1sパルスをカウントする
・インターネットに接続する(NTP)
が考えられますが、今回はGPSもNTPも使用しません。
よってタイマーモジュールを使うか、RTCを使うかの二択となりましたが、今回実装部品を減らしたいのでマイコンは内部発振及び内部PLLをシステムクロックとしますので、
発振精度が悪いです。そのためカウントをし続けると誤差がどんどん蓄積され、まともな値となりません。

そのため今回は32.768kHzの水晶発振器を外付けし、PICに内蔵されているRTCモジュールを動作させることにしました。

そんなわけでMPLAB HarmonyのClock Diagramは以下のように設定しました。

f:id:TomoC:20200306112947j:plain
Clock Diagram1
f:id:TomoC:20200306112951j:plain
Clock Diagram2

OptionsではMPLAB Harmony&Application Configuration→Harmony Framework Configuration→System Service→RTCCの順に開き、以下のようにしました。

f:id:TomoC:20200306113234j:plain
RTCC設定

Pin SettingsとPin Diagramは次の通り。RTCCピンの設定と、GPIO_OUTを各一つ設定しました。

f:id:TomoC:20200306113412j:plain
Pin settings
f:id:TomoC:20200306113430j:plain
Pin Diagram


2.app.cとsystem_interrupt.cにプログラムを追加する。

Generate Codeボタンを押すとコードが自動的に作製されます。なんかいっぱい出てきますが、編集するのはSource Files→app.cとSource Files→System_config→Default→system_interrupt.cだけです。

ソースファイルが出てきたら、app.cに以下のコードを追加します。以下のページを参考にしました。変数名はそのページのまま使用しております。挿入箇所等もわかりやすく記されているため、
そちらを参照してください。
http://www.ys-labo.com/Shop/Referrence/PIC32MZ/1704/32MZ%20RTCC%20Time%20Alarm%20LCD%20sum.html
またデバックしやすいように12時間ではなく、RTCCアラームを1min、60回アラームを検出したらGPIO反転(60min)というプログラムにしてあります。
データシートを参照し、RTCALRMレジスタのAMASKビットを操作することで時間が変更できます。またそのアラームのカウント回数を変化させれば任意の時間が作製できるかと思います。

#include <stdio.h>
#include "app.h"
#include "peripheral/rtcc/plib_rtcc.h"

extern int AlarmOccurrence;

int date = 0x17022802;//date = 5 March 2017 Monday
int time= 0x23594500;//time = 23h59m45s

void APP_Initialize ( void )に追加

void APP_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    appData.state = APP_STATE_INIT;

    
    /* TODO: Initialize your application's state machine and other
     * parameters.
     */
    //XXXbits.YY=ZZ //bits select
    PLIB_RTCC_RTCDateSet(RTCC_ID_0, date);  //Defalt set
    PLIB_RTCC_RTCTimeSet(RTCC_ID_0, time);  //Defalt set
    RTCCONbits.RTSECSEL =0b0;//RTCC Alarm Pulse output for the RTCC pin
    RTCALRMbits.ALRMEN  =0b1;//Alarm ON
    RTCALRMbits.CHIME   =0b1;//Alarm Kurikaesi
    //RTCALRMbits.PIV     =0b0;//RTCpin Output Defalt_0
    //RTCALRMbits.AMASK   =0b0101;//1h
    RTCALRMbits.AMASK   =0b0011;//1min
    RTCCONbits.CAL      =0b1111111010;//RTC calibration bits 1111111111=minimum negative djustment
    
    LATBbits.LATB2 = 1;//portB2出力 レジスタ直打ち
}

RTCCONbits.CALに関してはクロック補正用レジスタです。必要に応じて補正値を打ち込みます。1minごとにこのレジスタが読み込まれるそうです。
トライ&エラーで手打ち補正しました。

void APP_Tasks ( void )に追加

void APP_Tasks ( void )
{

    /* Check the application's current state. */
    switch ( appData.state )
    {
        /* Application's initial state. */
        case APP_STATE_INIT:
        {
            bool appInitialized = true;
       
        
            if (appInitialized)
            {
            
                appData.state = APP_STATE_SERVICE_TASKS;
            }
            break;
        }

        case APP_STATE_SERVICE_TASKS:
        {
            if(AlarmOccurrence == 1){
                Hour++;
                AlarmOccurrence = 0;
            }
            if(Hour == 60){
                LATBbits.LATB2 = 0;
            }
            if(Hour == 120){
                LATBbits.LATB2 = 1;
                Hour = 0;
            }
            
            break;
        }

        /* TODO: implement your application state machine.*/
        

        /* The default state should never be executed. */
        default:
        {
            /* TODO: Handle error in application's state machine. */
            break;
        }
    }
}

1hごとにGPIOピンを反転させるように設定しました。
編集が完了したら、プロジェクトをビルドし、エラーが出ないことを確認します。
これでプログラムの準備はOKです。

3.ブレッドボードで試作
適当にPICKIT3とPIC、水晶発振子そしてLEDをOUTPUTピンに接続し、準備完了です。MPLAB Xの書き込みボタンを押してPICへプログラムを書き込みます。
ここで回路にPICKIT3から電源を供給するように設定ができます。必要であれば画面左下のDashboardウインドウの左上のスパナマークをクリック→出てきたウインドウ左上のPICKIT3→Option categories
→Powerの順に操作し、Power target circuit form PICKit3にチェック、電圧は3.25Vに設定しておけば大丈夫です。
必要に応じて設定します。
書き込み時にターゲットデバイスが見つかりません!とういエラーは配線ミスか、電源供給がされておらず、PICの電源が入っていないことのどちらかが多いように思います。

RTCCピンは指定した時間でHighとLowを繰り返すように設定しました。GPIO_OUTに設定したピンはRTCCのアラーム割込みが60回発生するとピンを反転させるよう設定しました。
これが思った通り動いているか、時間に大きなずれが無いかを確認します。

僕はスマホのタイマーで適当に時間を測定し、ズレていたら1カウントずつCALレジスタを加算/減算し、再度PICに書き込みました。
結果ブレッドボード上では12時間で5秒ほどのズレまで追い込むことが出来ました。
これは基板に実装した場合また変化する可能性があるので、大体で良いと思います。

次回は基板を設計してElecrowへ投げるところまでを書こうと思います。