PIC HID Bootloader

last updata : 2018/04/10

HID Bootloaderを使ったアプリケーションの作り方(PIC16)

桜

2018年の桜

熊本の八重桜

アプリケーションの作成の前に

最初に、通常のアプリケーションのプロジェクトを作成します。 その後下記の設定を加えることで、HID ブートローダに対応したアプリケーションを作成できます。

1. リンカにて、Codeoffsetを変更する。

MPLAB C IDEの[Project Properties]を開いて、[XC8 linker]-[Addition options] を変更します。

Codeoffset

Codeoffsetは、プログラムの開始位置を変更します。 通常はアドレスの"0x000"から始まります。 Codeoffsetを「0x504」にするとアドレスの"0x504"から始まるようになります。

Microchip純正のHIDブートローダを使用する場合は、Codeoffsetを「0x904」とします。

2. リンカにて、ROM rangesを変更する。
ROM Ranges

次に、[XC8 linker]-[Memory model] を変更します。

ROM rangesは、使う領域を(メモリ)を指定します。 ROM rangesを「default,-0-503」に指定します。

  • default : 全領域
  • -0-503 : 0x000~0x0503 を除く(ブートローダー領域/他)

という意味になります。

Microchip純正のHIDブートローダを使用する場合は、ROM rangesを「default,-0-903」とします。

3. HID ブートローダをロードする (オプション)

アプリケーションに、HID ブートローダーを組み込む作業です。 Pickit3等のライタで、ブートローダ付きアプリケーションを書き込みたいときに使います。 HID ブートローダーのみで書き換える場合は不要です。

注. この機能を使うとコンフィグワードの問題が起きます。 対応としてコンフィグワードを書かない(使わない)方向で行きます。

[Projects]タブ-[Loadables] を右クリックすると[Add Loadable Project...]または[Add Loadable File...]があります。

[Add Loadable File...]は、HID ブートローダのHexファイルを指定します。

通常は、こちらを使います。

Add Loadable Project

[Add Loadable Project...]は、左のダイアログがてて、プロジェクト(BOOTLOADERr.X)とアプリケーションに対応する コンフィグレーションを選択します。

HID ブートローダの変更(configuration bitの変更等)があるときは、こちらを使ったほうが便利です。 ただし、アセンプルの時間が増えます。

サンプル アプリケーション

USB HID カスタム通信のサンプル アプリケーションです。

HID sample (HID Bootloader (pic16f145x_family対応) Restart Address:0x0504)

hid_sample_100pic16.zip

Project タブ
ヘッダファイル
usbconfig.h
アプリケーション固有のUSB設定を行います。
usbdesc_Custom.h
USBのディスクリプタ(HIDのカスタム)を設定を行います。
usbhiddev.h
usbhiddev.cのヘッダファイルです。

この3種ヘッダファイルは、usbconfig.h -> usbdesc_Custom.h -> usbhiddev.h の流れで1つにまとまっています。

usbconfig.h と usbdesc_Custom.h は、アプリケーションによって変更しなければなりません。 usbhiddev.hは、USB通信の本体のヘッダなので変更はしません。

ソースファイル
main_pic16f1455.c
メインプログラムです。
usbhiddev.c
USB HID通信のプログラム本体です。
ブートローダーHexファイル
pic16f145x_bootloadr.hex
アプリケーションにブートローダー組み込む為のファイルです。

このファイルは、基本的に使いません。 また、configuration bitを内蔵発振仕様のxc8形式に変更してあります。

メインプログラムの解説を少し。

このサンプルは、HIDで通信処理を行います。64byte/msで通信できます。 512kbps相当かな?

これができれば、PCとやり取りができます。 PC側のプログラムも必要ですけど、HIDなのでドライバが標準のものが使えます。 (ドライバを自前で用意する必要がない。)

通信は、SIO同様に必要な時にデータを送ります。 有効なデータ量が可変なので、この方法を取っています

ちなみにHID キーボードやマウスは、データの変更があった時に加え一定間隔にデータを出しています。 データ抜けを防ぐには有効です。

コードの一部の解説を

1. configuration bit の設定について
// Configuration ///////////////////////////////////////////////////////////////
#define USE_INTERNAL_OSC            // 内部発振SBを使う時
//#define USE_HID_BOOTLOADER            // Loadables にプートローダーを設定する時
// PIC16のコンフィグ生成で同じ設定をしても mpasmとxc8で違う値なります。
// mpasmは、0x3FFFが基準で xc8は、0xFFFFが基準。その為コードが不一致とみなされます。
// 書き込めば同じなのですが…
#ifndef USE_HID_BOOTLOADER
#if defined(USE_INTERNAL_OSC)
// CONFIG1
#pragma config FOSC = INTOSC        // Oscillator Selection Bits (INTOSC oscillator: I/O function on...
#pragma config WDTE = SWDTEN        // Watchdog Timer Enable (WDT controlled by the SWDTEN bit in the...
#pragma config PWRTE = ON           // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = OFF          // MCLR Pin Function Select (MCLR/VPP pin function is digital in...
               :
               :
#pragma config PLLEN = ENABLED      // PLL Enable Bit (3x or 4x PLL Enabled)
#pragma config STVREN = ON          // Stack Overflow/Underflow Reset Enable (Stack Overflow or Under...
#pragma config BORV = LO            // Brown-out Reset Voltage Selection (Brown-out Reset Voltage 
#pragma config LPBOR = OFF          // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF            // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must...

PICには、ブートローダーが書き込まれており"configuration bit"は、変更できないためです。 ブートローダーと同じ"configuration bit"を記入してください。(ErrorとかWarring等になります。)

MPASMとxc8では異なるconfiguration bit値を生成します。 その為プートローダーをロードしてアプリケーションに組み込むとエラーになります。 その場合は、USE_HID_BOOTLOADER を有効にしてconfiguration bit値を生成しないようにします。

外部発振を使う時は USE_INTERNAL_OSC を無効にします。

2. USB割り込み処理
////////////////////////////////////////////////////////////////////////////////
// USB割り込み処理部処理部
// 引  数	: 無し
// 戻り値	: 無し
// USBのプラグ&プレイ関連の処理を行っています。必須です。 
////////////////////////////////////////////////////////////////////////////////
void interrupt Isr()
{
    // USB割り込み処理
    USBInterruptTasks();
}

USBの通信処理(主にプラグ&プレイ関連)を割り込みで行います。 通常の通信も割り込みますがフラグ処理するのみです。

時間的制約が少ないので、低レベル割り込みにします。 基本的に1mS毎の割り込みがあります。

USBの通常データ通信は、ProcessIO関数内で送受信します。

2. アプリケーションからHID ブートローダへの行き方
////////////////////////////////////////////////////////////////////////////////
// ブートローダー処理部
// 引  数	: 受信データバッファポインタ
// 戻り値	: 無し
// sw2または受信コマンドによりHIDブートローダーへ移行します。
// PIC 新型2KB版 HID Bootloaderに対応しています。
////////////////////////////////////////////////////////////////////////////////
void bootloader(uint8_t* pbuf)
{
    if (!sw2 || (pbuf != 0 && *(pbuf+0) == 'B'
        && *(pbuf+1) == 'o' && *(pbuf+2) == 'o' && *(pbuf+3) == 't')) {
        INTCONbits.GIE  = 0;                // 割り込み禁止
        INTCONbits.PEIE = 0	;               // 周辺割り込み許可
        LATA  = 0;                          // ポートAクリア
        LATC  = 0;                          // ポートCクリア
        TRISA = 0;                          // ポートA初期化
        TRISC = 0;                          // ポートC初期化
        uint16_t cnt = 0xFFF;
        while (cnt--) { 
            CLRWDT();
            UCON = 0;                       // ウェイト付きUSB停止
        }
        asm("movlp 0x00");
        asm("goto  0x001C");                // bootloader Entryへ
    }
}

サンプルでは、sw2または、通信文の[Boot]にてHID ブートローダに移行します。

ROMアドレスの0x1CにHID ブートローダのエントリ(入口)が設定してありますので必ずインラインアセンブラでジャンプします。 ジャンプ先で、スタックポインタやバンク等の処理をしますので、気にせず飛びます。

このエントリはMicrochip純正のHIDブートローダにもありますので、同じように使えます。

気にして欲しいのは、各機能を停止することです。A/DやSIOを使ってるなら必ず初期状態にすることです。 割り込みも禁止して下さい。内部は停止していても外部割込みとかあると困ります。 ポートも初期化していますが、これはアプリケーション次第で安全に停止できる状態ならOKです。

「// ウェイト付きUSB停止」がありますが…PC本体の切断/接続待ちの状態を確保するためです。 長い分には問題ないです。

3. USBステータス処理 (サスペンド処理等)
////////////////////////////////////////////////////////////////////////////////
// USBステータスによる各処理部
// 引  数	: 無し
// 戻り値	: 無し
//* サスペンド処理
// サスペンド時にスリープします。
////////////////////////////////////////////////////////////////////////////////
void MainUsbStatus()
{
    // USB ステータス表示処理 ///////////////////////////////////////////////////
                :
                :
    // サスペンド処理 ///////////////////////////////////////////////////////////
    if (USBGetDeviceState() == CONFIGURED_STATE && USBIsSuspended() ) {
        // メインのサスペンド移行処理部
                :
                :
        // サスペンド中何もせずスリープする
        while (!USBIsActive() && !STATUSbits.nTO) {
            Sleep();
        }
        // メインのウェイクアップ処理部
                :
                :
    }
}

USBのステータスを見て処理する部分です。 基本敵にサスペンド時のメイン処理を行います。

スリープ状態を解除するのは、ウォッチドックタイマです。 スリープ状態をUSB割り込みで解除するには、電力管理ををIDLE モードにする必要があります。 このサンプルでは、USB割り込みでの解除は、使っていません。

PC側 プログラム

pic18Non-Jと同じPC側 プログラムを使用します。 詳しくは、こちら(PC側 プログラム)を参照してください。

Hex ファイルのconfiguration bit

mpasmとxc8Dで同じコンフィグの設定をしてもHex値が違う現象に遭遇。 一寸調べてみました。

     :
:020000040001F9
:02000E008C0F55
:02001000CF1F00
:00000001FF

mpasmの生成したconfiguration bit(Hex データ)

     :
:020000040001F9
:04000E008CCFCFDFE5
:00000001FF

xc8の生成したconfiguration bit(Hex データ)

最初の「:020000040001F9」拡張アドレスの設定で コンフィグのアベースドレスで す。

最後の「:00000001FF」Hexファイルの終了を示してます。

データ部分の mpasmは 0x0F8C,0x1FCF で xc8は 0xCF8C,0xDFCF と違っています。 PIC16FのFlashROMは、14bitだから両方とも0x0F8C,0x1FCFが書き込まれます。

免 責

情報は出来るだけ正確に書くつもりです。ただこの記事を見て作ると思ったときは、 個人の責任において作業を行なってください。 データの喪失や機器の損傷が有っても、一切の責任は取れません。