USB(ホストモード)
USBメモリ 読み書き(MSDクラス)
(→プロジェクトファイル(Harmony Ver.2.04版 ) ダウンロード)
USBメモリの中にファイルを作成してテキストを書き込み、 これを読みだし表示する例を紹介します。 Harmonyのライブラリとしては、USBホストモード制御のMSDクラスを使用しています。 ・ プログラムはマイクロチップのサンプルソフト"C:\microchip\harmony\v2_04\apps\usb\host\msd_basic"を参考にして作成しています。 ・ マイクロチップが提供してくれるMSDクラスのフレームワークには、USBメモリがPICに接続するためのドライバー(部分)も含まれています。 |
|
<仕様> |
|
・PIC32MZのUSBモジュールを使用してUSBメモリの読み書きを行う。 ・読み書きするファイルはテキストファイルとする。 ・USBメモリの挿入を検出した場合は以下の動作を行う。 ①キャラクタ液晶に以下を表示して1.5sec待つこと。 1行目: USB Memory 2行目: has connected ②(ロング)ファイル名LonfFileName.txt のテキストファイルを新規作成して書き込み可能モードでオープンする。 尚、ファイル名LonfFileName.txtの ファイルが 既にUSBメモリの(ルート)中に存在する場合は、この既存ファイルをオープンする。 キャラクタ液晶に以下を表示して1.5sec待つこと。 1行目: FileOpened !! 2行目: ファイル名 ③オープンしたファイルに "How are you? " を書き込む。 既存のファイルを開いた場合は"How are you? " を追記する。 ④ファイルを閉じて、以下を表示して1.5sec待つこと 1行目: Writed 2行目: and Closed ⑤再び、ファイル名LonfFileName.txt のファイルを読み込み専用モードで開き、ファイルの内容を読みだし、以下をキャラクタ液晶に表示する。 1行目: ファイルの先頭から16文字 2行目: ファイルの内容が読みだされた回数XXを "Number=XX" の形式で表示する。 ・起動後、液晶に以下表示後、2sec待つこと。 1行目: USB MSD 2行目: File RW start ! |
<外観>PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
<動作結果> (→ 動画:1080pのHD動画を見ることができます。)
■キャラクタ液晶表示
①起動後 | ②USBメモリ挿入検出後 | ③ファイル新規作成 or 既存ファイルオープン後 |
|
![]() |
![]() |
![]() |
|
④ファイルへの書き込み完了 &ファイルクローズ後 |
⑤ファイル内容を読み出して表示(1行目) & 挿入検出回数表示(2行目) (1回目の挿入検出後) |
⑥ファイル内容を読み出して表示(1行目) & 挿入検出回数表示(2行目) (2回目の挿入検出後) |
|
![]() |
![]() |
![]() |
|
⑦ ファイル内容を読み出して表示(1行目) & 挿入検出回数表示(2行目) (3回目の挿入検出後) |
|||
![]() |
■ USBメモリのファイルの表示
PCのWindowsエクスプローラから USBメモリ内のLongFileName.txtファイルの内容をエディタで表示したものです。 尚、実験では
PIC起動前のUSBメモリはフォーマット済みでファイルは何もない状態にしています。
■ 備考
・ プログラムを書き込んだ後 一度PICの電源をOFFにしなと動作しないPICがありました。
・ USBメモリのアタッチ検出が 若干不安定な時がありました。 ノイズが原因?
<解説>記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います。
(以下は、Harmony v2.04 をもとに作成しています。最新のバージョンとは異なる点があるかもしれませんので注意してください。)
■ MHC設定
■ Options
■Pin Settings
特に設定なし
■キャラクタ液晶表示ライブラリの追加要領
キャラクタ液晶表示のライブラリ 1lcd_lib_XC32.h と 1lcd_lib_XC32.cを main.cと同じフォルダにコピーして、プロジェクトに追加します。
(使い方 → キャラクタ液晶表示方法 参照)
プロジェクトへの追加は以下のようにします。
■app.h を以下の要領で変更します。
①列挙型変数 APP_STATES の定義を以下のように変更します。
typedef enum
{
APP_STATE_BUS_ENABLE = 0,
PP_STATE_WAIT_FOR_BUS_ENABLE_COMPLETE,
APP_STATE_WAIT_FOR_DEVICE_ATTACH,
APP_STATE_DEVICE_CONNECTED,
PP_STATE_MOUNT_DISK,
APP_STATE_UNMOUNT_DISK,
PP_STATE_OPEN_FILE,
PP_STATE_WRITE_TO_FILE,
APP_STATE_CLOSE_FILE,
APP_STATE_IDLE,
PP_STATE_ERROR
} APP_STATES;
②構造体 APP_DATAのメンバーを以下のように変更します。
typedef struct
{
/* The application's current state */
/* SYS_FS File handle for 1st file */
SYS_FS_HANDLE fileHandle;
/* Application's current state */
APP_STATES state;
/* Application data buffer */
uint8_t data[1024];
/* Number of bytes written */
uint32_t nBytesWritten;
/* Number of bytes read */
uint32_t nBytesRead;
bool deviceIsConnected;
} APP_DATA;
以下、app.h
■ app.cに、青字部の修正、追加をします。
①インクルードファイルを追加します。stdio.hがないと、sprintf( )がコンパイラのバージョンによってコンパイルで警告となることが
あります。
#include "stdio.h"
#include "1lcd_lib_XC32.h"
②液晶表示のバッファー、ファイル読み出しに係るファッバー、またファイルに下記込む文字列などを定義します。
char Buf[32]; //液晶表示バッファー
char tempBuf[1];
char tempBuf2[512]; //ファイル読み書きバッファ
char tempBuf3[512]; //ファイル読み書きバッファ
int eof; //ファイルのEOF
int ix = 0;
int Num = 0; //USBメモリ 読み出し回数
char myData[] = "How are you? "; //ファイルへの書き込み文字列
③NOPによる遅延関数delay_us(), delay_ms()を定義します。
void delay_us(volatile unsigned int usec) //1μsec遅延
{
volatile int count;
count = (int)(delay_Clock/20000000)*usec;
……
……
④液晶を初期化して、起動直後の文字列表示を行います。
lcd_init(); // LCD初期化
lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"USB MSD ");//
lcd_str(Buf); //液晶表示
……
……
⑤以下の関数はUSBのホストレーヤのイベントをチェックするコールバック関数です。 関数 USB_HOST_EventHandlerSet()により
このコールバック関数は、APP_Tasks()の中で設定されています。 ホストレーヤに問題が発生した場合に、引数 eventに情報が
送られてきます。 尚、サンプルプログラムではイベントに対する処理は 記述していません。
(例)USB_HOST_EVENT_DEVICE_UNSUPPORTED: 接続不可 or エラー発生
USB_HOST_EVENT_HUB_TIER_LEVEL_EXCEEDED: 接続されているハブの数がオーバー
USB_HOST_EVENT_PORT_OVERCURRENT_DETECTED: USB負荷電流過大
USB_HOST_EVENT_RESPONSE APP_USBHostEventHandler (USB_HOST_EVENT event,
void * eventData, uintptr_t context)
{
switch (event)
{
case USB_HOST_EVENT_DEVICE_UNSUPPORTED:
break;
default:
break;
}
return(USB_HOST_EVENT_RESPONSE_NONE);
}
⑥以下の関数はファイルシステムがマウントされたか否かのイベントをチェックするコールバック関数です。 関数
SYS_FS_EventHandlerSet()によりこのコールバック関数は、APP_Tasks()の中で設定されています。
void APP_SYSFSEventHandler(SYS_FS_EVENT event, void * eventData, uintptr_t
context)
{
switch(event)
{
case SYS_FS_EVENT_MOUNT: //マウント検出の場合
appData.deviceIsConnected = true;
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"USB Memory ");//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf," has connected "); //
lcd_str(Buf); // 開始メッセージ1行目表示
delay_ms(1500);
break;
case SYS_FS_EVENT_UNMOUNT:
appData.deviceIsConnected = false;
break;
default:
break;
}
}
⑦ SYS_FS_EventHandlerSet()でファイルシステムマウントチェック用のコールバック関数APP_SYSFSEventHandler()を設定しています。
また、USB_HOST_EventHandlerSet()でホストレーヤイベントチェック用コールバック関数APP_USBHostEventHandler()を設定しています。
USB_HOST_BusEnable()でUSBホストバスを有効化しています。
case APP_STATE_BUS_ENABLE:
/* Set the event handler and enable the bus */
SYS_FS_EventHandlerSet(APP_SYSFSEventHandler, (uintptr_t)NULL);//FSマウントチェック用コールバック関数を設定
USB_HOST_EventHandlerSet(APP_USBHostEventHandler, 0);//ホストレーヤイベントチェック用コールバック関数を設定
USB_HOST_BusEnable(0); //USBホストバス有効化
appData.state = APP_STATE_WAIT_FOR_BUS_ENABLE_COMPLETE;
break;
⑧USBホストバスが有効になるまで待ちます。
case APP_STATE_WAIT_FOR_BUS_ENABLE_COMPLETE:
if(USB_HOST_BusIsEnabled(0))
{
appData.state = APP_STATE_WAIT_FOR_DEVICE_ATTACH;
}
break;
⑨USBデバイスがアタッチされた場合、次のステートに移行します。
case APP_STATE_WAIT_FOR_DEVICE_ATTACH: //USBメモリのアタッチを待つ
/* Wait for device attach. The state machine will move
* to the next state when the attach event
* is received. */
if(appData.deviceIsConnected) // //USBデバイスがアタッチされた場合
{
appData.state = APP_STATE_DEVICE_CONNECTED;
}
break;
⑩ファイルオープンステートに移行します。
case APP_STATE_DEVICE_CONNECTED:
/* Device was connected. We can try mounting the disk */
appData.state = APP_STATE_OPEN_FILE;
break;
⑪SYS_FS_FileOpen()でファイル名LongFileName.txtのファイルを開きます。ファイルが存在しない場合は新規に作成します。
成功した場合は、液晶の1行目に"File Opened !!"を2行目にLongFileName.txt"を表示します。
case APP_STATE_OPEN_FILE:
/* Try opening the file for append */
appData.fileHandle = SYS_FS_FileOpen("/mnt/myDrive1/LongFileName.txt",
(SYS_FS_FILE_OPEN_APPEND_PLUS));
if(appData.fileHandle == SYS_FS_HANDLE_INVALID)
{
/* Could not open the file. Error out*/
appData.state = APP_STATE_ERROR;
}
else
{
/* File opened successfully. Write to file */
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"FileOpened !! ");//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"LongFileName.txt"); //
lcd_str(Buf); // 開始メッセージ1行目表示
delay_ms(1500);
appData.state = APP_STATE_WRITE_TO_FILE;
}
break;
⑫SYS_FS_FileWrite()で"How are you? "をファイルに書き込みが成功したら次のステートに移行します。
case APP_STATE_WRITE_TO_FILE:
/* Try writing to the file */
if (SYS_FS_FileWrite( appData.fileHandle, myData, sizeof(myData) )
== -1)
{
/* Write was not successful. Close the file
* and error out.*/
SYS_FS_FileClose(appData.fileHandle);
appData.state = APP_STATE_ERROR;
}
else
{
/* We are done writing. Close the file */
appData.state = APP_STATE_CLOSE_FILE;
}
break;
⑬ファイルを閉じて、液晶の1行目に"Writed"を、2行目に"and Closed"を表示します。 その後ファイルを読み取り専用モードで開き
1バイトづつファイルエンドまで読み出します。 この読み出したファイル先頭16バイトを液晶の1行目に表示します。2行目には
何回目(XX回目)の呼び出しであるのか"Number=XX"と云った形式で表示します。その後アイドルステートに移行します。
case APP_STATE_CLOSE_FILE:
/* Close the file */
SYS_FS_FileClose(appData.fileHandle);
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"Writed ");//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf," and Closed "); //
lcd_str(Buf); // 開始メッセージ1行目表示
delay_ms(1500);
SYS_FS_HANDLE fileHandle2 = SYS_FS_FileOpen("/mnt/myDrive1/LongFileName.txt",
(SYS_FS_FILE_OPEN_READ));
do
{
SYS_FS_FileRead(fileHandle2, tempBuf, 1); //1バイトづつ読出し
eof = SYS_FS_FileEOF(fileHandle2); //EOFチェック
if(eof != true)
{
tempBuf2[ix] = tempBuf[0];
ix++;
}
}while(eof != true); //ファイルエンドでない場合は、繰り返し読む
SYS_FS_FileClose(fileHandle2); //ファイルを閉じる
Num++;
lcd_cmd(0x80); //1目の先頭へ
sprintf(tempBuf3,"%s ",tempBuf2);
lcd_str(tempBuf3);
lcd_cmd(0xC0); //2目の先頭へ
sprintf(Buf,"Number=%d ",Num); //液晶に"Write OK !"
を表示
lcd_str(Buf);
/* The test was successful. Lets idle. */
appData.state = APP_STATE_IDLE;
break;
⑭ このアイドルステートでは、USBデバイスが抜かれた場合には再アタッチを待つステートに移行するようにします。
case APP_STATE_IDLE:
/* The application comes here when the demo has completed
* successfully. Provide LED indication. Wait for device detach
* and if detached, wait for attach. */
if(appData.deviceIsConnected == false) //USBメモリを抜くと 挿入検出待ちモードに移行する。
{
appData.state = APP_STATE_WAIT_FOR_DEVICE_ATTACH;
}
break;
以下、app.c