SSブログ
English Version

PIC24FJ64GAのRTCCモジュール実験 [PIC]

 PIC24FJ64GAにはRTCC(リアルタイムクロックカレンダ)モジュールが内蔵されていて 32.768kHzのクリスタルを外付けすることで時刻や年月日(うるう年対応)をハードウェアで管理できます。また、一定時間間隔(1分、10分、1時間、1日等)や指定の時刻に割り込みを発生させることができます。
 アラームに関しては繰り返し数設定やxx秒の時(1分間隔)等、通常の使用で必要になると思われる殆どのパターンに対応できそうです。
 ロギング装置等で消費電力を下げるために通常はsleep状態にしておき、それなりに正確な一定時間間隔で測定処理を行い、データとともに時刻も保存したいような場合に便利です。

 今回は既存のRTCC用のライブラリは使わず、picle言語とアセンブラでRTCCを実験的に動かしてみました。
 回路はごく一般的なもので回路図を以下に示します。
 インターネット上では水晶発振が不安定だった事例等があるようですが、今回はブレッドボード上での実験でしたが安定して発信しました。プローブをつないで波形を見ても問題ない状態でした。
 また、回路図描画に使用したCADについてですが、DesignSpark PCB はUIは非常に使い易いのですが回路図の見た目がイマイチなので、今回は KiCAD で回路図を描いてみました。
★2017/03/18 追記
 回路図には書いていませんがシリアル接続は RP8:RX(受信)17番ピン、 RP9:TX(送信)18番ピン になります。
 シリアルモード : 19200bps、8bit、パリティ無し、Stopビット:1

RTCCモジュール実験回路(KiCAD)


 RTCC 用のクロックを有効にするためには RTCC 関連のレジスタの設定だけでは駄目で、OSCCON レジスタ内の SOSCEN(Secondary Oscillator Enable)のビットを1にする必要があります。
 かつ、RCFGCAL レジスタの RTCEN(RTCC Enable bit)を1にする必要がありますが、RCFGCAL レジスタを変更するためには このレジスタ内の RTCWREN を1にする必要があります。
 これらの変更を行うためにはそれぞれのレジスタに対してアンロックシーケンスを行う必要があり、この部分と sleep 命令実行の部分はアセンブラで記述し、picle言語からコールすることにしました。
 アセンブラのソースが下記で「PIC24FJ64GAでのアセンブラ環境覚書」の記事で書いた方法で ソース部分のみのhexファイルを作成し、OneBitLoader で書き込みました。
 ヘキサファイルは ここ からダウンロードできます。

assembler source to enable RTCC
/*************************************
  RealTimeClock setting
    made by skyriver at 2017/03/11
**************************************/
    .title  "Real Time Clock"
    .include "p24fj64ga002.inc"

    .section    .text_Ap,code,address( 0x7c00 )

    bra     EnableRtc
    bra     RtLockFree

;
; set device into sleep mode
;
Sleep:
    pwrsav  #SLEEP_MODE
    return

;
; unlock RealTimeRegister(RCFGCAL)
;
RtLockFree:
    mov     #NVMKEY,w1  ; unlock to write RCFGCAL
    mov.b   #0x55,w0
    disi    #3
    mov.b   w0,[w1]
    mov.b   #0xaa,w0
    mov.b   w0,[w1]
    bset    RCFGCAL,#13 ; set RTCWREB bit
    return

;
; enable real time clock(activate secondary OSC)
;
EnableRtc:
    mov     #OSCCONL,w0 ; open lock OSCCONL
    mov.b   #0x46,w1
    mov.b   #0x57,w2
    disi    #2
    mov.b   w1,[w0]
    mov.b   w2,[w0]
    bset.b  OSCCONL,#1  ; set SOSCEN bit
    return

    .end


 注意点としては RCFGCAL レジスタの RTCWREN ビットを1にした後、RCFGCAL レジスタの書き換え時に RTCWREN を1にしたままにしておけば、その後もアンロックシーケンスを行わなくても RCFGCAL レジスタを変更できます。
 RTCWREN ビットを0の状態で書き換えた後は、ロック状態となりアンロックシーケンスを行わないと書き換えができない状態になります。
 また、時刻情報とアラーム時刻の設定と読込みは設定データ種別毎にレジスタアドレスがあるのではなく、それぞれ RCFGCAL と ALCFGRPT レジスタ内にインデックスを設定し、RTCVAL、ALRMVALレジスタを使ってアクセスします(レジスタ用のメモリ空間の肥大防止のためと思います)

 RTCCモジュールの試験プログラムは下記のとおりで、アセンブラ側の処理を外部宣言してコールしています。
 RTCC から10秒毎(秒の1桁目が5)に割り込み要求が掛かることで、sleep 状態から抜け、時刻を表示後、sleep するようにしています。
 RTCC の割り込みプライオリティを1に設定し、割り込みレベルも1にしているので実際は割り込み処理は実行されず、sleep から抜けるだけになっています。
 時刻表示処置(DspTime)の最後で Timer_ を設定しウエイトしていますが、時刻表示出力のシリアルデータが送信完了するまで待つためです。
 sleep 状態では CPUが停止しますが、シリアルモジュールへのクロックも止めているのでウエイトを入れないと表示が尻切れになってしまいます。
 また、sleep 中はエスケープキーでの中断もできない状態になります。実際の装置に使う場合はスイッチ入力でも sleep から抜けるようにできます。

PIC24FJ RTCC module test(picle言語)
# PIC24FJ64GA002 RTCC test
# written with picle language by skyriver
#   2017/03/10 ver 0.01

var _REG,RCFGCAL,PADCFG1,RTCVAL,ALCFGRPT,ALRMVAL;
var RDBUF;

proc EnableRtc() = $7c00;
proc RtLockFree() = $7c02;
proc SleepMode() = $7c04;


proc DspTime() {
    var i,sec;
    do {
        sec = RTCVAL[0];    # get second data
        RCFGCAL[0] = $a300; # set index
        for ( i = 0; i < 4; i=i+1 ) {
            RDBUF[i] = RTCVAL[0];
        }
    } while ( sec <> RDBUF[3] );
    PrnStr_("\n20");
    PrnHexB_( RDBUF[0] );
    for ( i = 1; i < 4; i=i+1 ) {
        PrnStr_(" ");
        PrnHex_( RDBUF[i] );
    }
    Timer_ = 1;
    while ( Timer_ ) {}
}

proc init() {
    RDBUF = Array_(0);
    RCFGCAL = $0626;
    PADCFG1 = $02fc;
    RTCVAL = $0624;
    ALRMVAL = $0620;
    ALCFGRPT = $0622;
    _REG[$9b] = $40;    # enable RTC int(set IEC3)
    _REG[$42] = $20;    # set interrupt level to 1(set SR)
    _REG[$c3] = 1;      # set RTC priority to 1(set IPC15)
    EnableRtc();
}

proc main() {
    init();
    RtLockFree();

    RCFGCAL[0] = $a300;

    RTCVAL[0] = $17;    # set year
    RTCVAL[0] = $0311;  # set day
    RTCVAL[0] = $0623;  # set week & hour
    RTCVAL[0] = $1000;  # set min & sec

    ALCFGRPT[0] = $c800;	# set 10sec alarm
    ALRMVAL[0] = $0005;

    while (1) {
        SleepMode();
        _REG[$8b] = 0;  # clear RTCIF
        DspTime();
    }
}



[ 前へ ] 連載記事 [ 次へ ]

nice!(0)  コメント(0)  トラックバック(1) 
共通テーマ:趣味・カルチャー

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 1