MPLAB HarmonyフレームワークでPIC32のLチカ

PIC32 LED flushing with MPLAB Harmony
 
PICマイコンの開発環境であるMPLABには開発をサポートするライブラリーが別途提供されていましたが、従来の方式だとマイコンの型番が変わるとソースコードも変更しなければならないという組み込み開発特有の問題がありました。そこでマイクロチップ社はソースコードを動的に生成することで、開発者が記述するコードをできる限り少なくするためのフレームワーク「MPLAB Harmony」をこれまでのライブラリーの代替として公開しています。これを使うことで、GUIでの数値変更でハードウェア設定やタイマー処理などのPIC32にまつわる様々な構築を行うことができるようになっています。

ネットでの情報が乏しいことや、プログラムリソースを多く消費するのが欠点といえますが、GUIに慣れてしまえばものの5分でUSBキーボードも作れてしまうので、高度な処理が必要であれば利用する価値はあります(そもそもGPIOのオン・オフくらいの処理しかしないのならArduinoのほうが効率的ですし)。

ではMPLAB X IDEMPLAB Harmonyをインストールしたら、IDEを開いて「32-bit MPLAB Harmony Project」を任意のフォルダーに作成しましょう。ここでは自作の開発基盤を用いているので「Target Board」には「Custom」を指定しています。
プロジェクトが作成された直後や、ウィンドウメニューの「Tools→Embedded→MPLAB Harmony Configuler」を選ぶと、マイコンの環境設定画面が表示されます。まずは、マイコンのクロックを指定しましょう。「Clock Diagram」の「System PLL」にある「Auto-Calculate」ボタンを押すと、動作に最適な分周比などを自動で割り当ててくれます。あとは必要に応じて「POSCMOD」「FPBDIV」「UPLLIDIV/UPLLEN/UFRCEN」の値を赤文字の警告が出ない範囲で変更します。
設定が終わったら「Generate Code」を押してプログラムコードを作成させます。この作成作業は、環境設定を変えるごとに実行しなければプログラムに反映されないことや、設定ファイルを保存しないと環境設定をはじめからやり直す羽目になるので注意しましょう。
コードはこのように作成されます。
基本的にはArduinoのように「APP_Initialize()」で初期化のコードを書き、「APP_Task()」で繰り返し実行させたいプログラムを書きます。例えば、「app.c」のコードをこのように差し替えると、以前に紹介したLチカプログラムのHarmony版が完成します。
app-ltika.c
#include "app.h"

void APP_Initialize()
{
    TRISBbits.TRISB0 = 0;
    ANSELBbits.ANSB1 = 0;
    TRISBbits.TRISB1 = 1;    
}

void APP_Tasks()
{
    PORTBbits.RB0 = ~PORTBbits.RB1;
}
ではこのプログラムをHarmonyっぽく改良してみましょう。「MPLAB Harmony Configuler」を開いたら、まずは「Pin Settings」のタブを開き、「4/RB0」と「5/RB1」を画像のように、それぞれ「Led,GPIO_OUT,Digital」「Switch,GPIO_IN,Digital,Change Notifcation」に切り替えてピンの属性値を変更します。名前を指定すると、その名前を使用したポート制御命令が作成されるので、別のマイコンへの移植が容易になります。ちなみにこれは後述のオプション設定でも変更できます。
「Option」タブを選んでオプション設定を開いたら、「Port」の「変化検出を有効(Use Interrupt for Change Notification)?」にチェックを入れて、「INT_DISABLE_INTRRUPT」以外の優先度を選択します。
この状態で「Generate Code」ボタンを押すと、プロジェクトフォルダーの「Source Files/app/system_config/[name]/system_interrupt.c」に割り込み処理関数が生成されるので、ここに割り込み時の処理を記入します(コード生成時に「Automatically Overwrite User Changes」を選ぶと、ここに書いたコードは消えてしまうので注意!)。また、これにより「app.c」の処理は不要になるので、関数の中身は空にしておきましょう。
sysint.c
#include "system/common/sys_common.h"
#include "app.h"
#include "system_definitions.h"

void __ISR(_CHANGE_NOTICE_VECTOR, ipl4AUTO) _IntHandlerChangeNotification(void)
{
    // スイッチの状態を取得(Pin Settingsで指定した名前+StateGetが関数名になっている)
    bool pushed = !SwitchStateGet();
    // LEDの状態を変更
    LedStateSet(pushed);

    /*
    // ピンの番号を直接制御する場合
    // ポートモジュールO(標準)、Bチャンネル、1番ピンの状態を取得
    bool pushed = !PLIB_PORTS_PinGet(PORTS_ID_0, PORT_CHANNEL_B, PORTS_BIT_POS_1);
    // ポートモジュールO(標準)、Bチャンネル、0番ピンの状態を設置
    PLIB_PORTS_PinWrite(PORTS_ID_0, PORT_CHANNEL_B, PORTS_BIT_POS_0, pushed);

    // (その他、主なピン制御にまつわる関数)
    // PLIB_PORTS_PinClear  - 指定のピンをオフにする
    // PLIB_PORTS_PinSet    - 指定のピンをオンにする
    // PLIB_PORTS_PinToggle - 指定のピンのオン・オフを切り替える
    */

    PLIB_INT_SourceFlagClear(INT_ID_0, INT_SOURCE_CHANGE_NOTICE_B);
}
app-empty.c
#include "app.h"

void APP_Initialize()
{
}

void APP_Tasks()
{
}
2018/10/06