SNSへはこちら

MPLAB Snapを買った&使ってみた(4) – PIC24

続いて本命の PIC です。その前に手持ちの PIC18 について。
PIC18 で LVP(Low-level Programming) を使えば MPLAB Snap 使えるんじゃね?とか言っていましたが、IDE 側からデバッグアダプタの選択が不可というこのなので、物によっては旧来の PIC には使用できないことがはっきりと分かりました。
一方で使用できるものが存在して、その場合にはプロジェクト作成時に Snap が選択可能になっています。ということで PIC18 については後ほど記事にしたいと思います。

まぁ、考えてみれば確かに 8bit 時代の AVR よりも圧倒的にコード効率の悪い PIC を進んで選択する理由というのはないわけです。しかも高電圧プログラミングという全時代的な書き込み方法をデフォルトにしているデバイスは、時代遅れなのは自明ですね(dis っているわけではない)。あらゆるチップをディスコンさせない Microchip 社も、そういうことを思って旧来の PIC を切り捨てたのでしょう。

16bitのPIC

ということで、PIC にしては割と新し目の PIC24 をターゲットにします。もうここまで来ると、HVP とか LVP とかの区別は無くなっていて、全て電源電圧印加で書き込みを実行できます。用意したのは秋月で買ったものです↓

電子部品,通販,販売,半導体,IC,LED,マイコン,電子工作PICマイコン PIC24FJ64GB002-I/SP秋月電子通商 電子部品通信販売

コンパイラは XC16 が必要となります。

やりかた

何の引っ掛かりもなくデバッグやら書き込みやらが出来てしまいます。あ、あとこれは 3.3V のデバイスなので要注意です。

これで記事が終わるのも寂しいので、クロック設定を 32MHz にして、Lチカするところまで持っていきましょう。割り込みフラグは使いますが、割り込み自体は不使用です。

クロック設定

まずはクロックのダイアグラムを見ましょう。データシートより。

こんな経路で行けばいいですね。PLL で元の 8MHz を逓倍しています。続いて PLL を見てみましょう。

ここから、以下を設定すればいいと考えられます。

  • CLKDIV をいい感じに調整して 4MHz とする
  • PLL の Prescaler を 1 とする
  • CPDIV を /1 にする

この内、最初の項目ですが、実は何もしなくても、元の FRC = 8MHz が2分周されています。残りの下2つは Configuration Bits で設定が可能です。IDE の Window -> Target Memory Views -> Configuration Bits を選択して開きましょう。
とりあえず ウォッチドッグタイマ系はウザいので全て切ります(必須ではない)。次のように。

  • DSBOREN を OFF に
  • DSWDTEN を OFF に

続いて本命のクロック設定です。

  • FNOSC を FRCPLL に
  • PLL96MHZ を ON に
  • PLLDIV を NODIV に

これでFRC から分周されたクロックが PLL に入力されます。あとは Generate Source Code to Output を押して、ヘッダにコピペし、include すれば設定完了です。コードを一切書かなくていいのは便利ですねぇ。

面倒くさい人向けに、このコンフィグのコードを晒しましょうか。


// PIC24FJ64GB002 Configuration Bit Settings // 'C' source line config statements // CONFIG4 #pragma config DSWDTPS = DSWDTPSF // DSWDT Postscale Select (1:2,147,483,648 (25.7 days)) #pragma config DSWDTOSC = LPRC // Deep Sleep Watchdog Timer Oscillator Select (DSWDT uses Low Power RC Oscillator (LPRC)) #pragma config RTCOSC = SOSC // RTCC Reference Oscillator Select (RTCC uses Secondary Oscillator (SOSC)) #pragma config DSBOREN = OFF // Deep Sleep BOR Enable bit (BOR disabled in Deep Sleep) #pragma config DSWDTEN = OFF // Deep Sleep Watchdog Timer (DSWDT disabled) // CONFIG3 #pragma config WPFP = WPFP63 // Write Protection Flash Page Segment Boundary (Highest Page (same as page 42)) #pragma config SOSCSEL = SOSC // Secondary Oscillator Pin Mode Select (SOSC pins in Default (high drive-strength) Oscillator Mode) #pragma config WUTSEL = LEG // Voltage Regulator Wake-up Time Select (Default regulator start-up time used) #pragma config WPDIS = WPDIS // Segment Write Protection Disable (Segmented code protection disabled) #pragma config WPCFG = WPCFGDIS // Write Protect Configuration Page Select (Last page and Flash Configuration words are unprotected) #pragma config WPEND = WPENDMEM // Segment Write Protection End Page Select (Write Protect from WPFP to the last page of memory) // CONFIG2 #pragma config POSCMOD = NONE // Primary Oscillator Select (Primary Oscillator disabled) #pragma config I2C1SEL = PRI // I2C1 Pin Select bit (Use default SCL1/SDA1 pins for I2C1 ) #pragma config IOL1WAY = ON // IOLOCK One-Way Set Enable (Once set, the IOLOCK bit cannot be cleared) #pragma config OSCIOFNC = OFF // OSCO Pin Configuration (OSCO pin functions as clock output (CLKO)) #pragma config FCKSM = CSDCMD // Clock Switching and Fail-Safe Clock Monitor (Sw Disabled, Mon Disabled) #pragma config FNOSC = FRCPLL // Initial Oscillator Select (Fast RC Oscillator with Postscaler and PLL module (FRCPLL)) #pragma config PLL96MHZ = ON // 96MHz PLL Startup Select (96 MHz PLL Startup is enabled automatically on start-up) #pragma config PLLDIV = NODIV // USB 96 MHz PLL Prescaler Select (Oscillator input used directly (4 MHz input)) #pragma config IESO = ON // Internal External Switchover (IESO mode (Two-Speed Start-up) enabled) // CONFIG1 #pragma config WDTPS = PS32768 // Watchdog Timer Postscaler (1:32,768) #pragma config FWPSA = PR128 // WDT Prescaler (Prescaler ratio of 1:128) #pragma config WINDIS = OFF // Windowed WDT (Standard Watchdog Timer enabled,(Windowed-mode is disabled)) #pragma config FWDTEN = OFF // Watchdog Timer (Watchdog Timer is disabled) #pragma config ICS = PGx1 // Emulator Pin Placement Select bits (Emulator functions are shared with PGEC1/PGED1) #pragma config GWRP = OFF // General Segment Write Protect (Writes to program memory are allowed) #pragma config GCP = OFF // General Segment Code Protect (Code protection is disabled) #pragma config JTAGEN = ON // JTAG Port Enable (JTAG port is enabled) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #include <xc.h>

ということで適当にLチカ

ここではだいたい 1msec タイマーを作ります。まずはてきとーに何も考えずに書いた Timer1 の初期化コードです。

// For 32MHz system clock
void timer1_init(void) {
    T1CONbits.TCKPS = 0b10; // divided by 64
    TMR1 = 0;
    PR1 = 250 - 1;
}

あ、嘘です。少し考えました。データシートの説明に依ると、Timer1 に入力されるクロックは2分周されているとのことでした。なのでそれを考慮に入れて計算した次第です。

これで TMR1 == PR1 となったときには 1msec が経過しているということです。次の実装もてきとーに。

void ms_wait(uint16_t ms) {
    T1CONbits.TON = 1;
    for(volatile uint16_t i=0; i<ms; i++) {
        IFS0bits.T1IF = 0;
        while( !IFS0bits.T1IF );
    }
    T1CONbits.TON = 0;
}

これで一応完成です。Lチカしてみましょう。

int main(void) {
    timer1_init();
    TRISAbits.TRISA0 = 0;
    while(1) {
        ms_wait(500);
        LATAbits.LATA0 ^= 1;
    }
    return 0;
}

出来ましたかね。出力ピンは2番ピンになります。以上です。