久々の LPC ネタです。
LPC11U35 という USB マイコンがありますね。秋月で小型マイコンボードが売ってますし、このブログでも何回か取り上げました。
この LPC11U35、U が型番にある通り、USB 機能がついています。それで、まあ USB ペリフェラルと言ったら、ムズい、面倒い、臭い、危ない、モテないといった非常に苦しいものですが、なんととある条件下ではこの LPC11U35 はラクラクに USB を実装できるのです。
ROM API
では何故ラクにできるかと言うと、ROM API なるものを積んでいるからです。これは目的はそのまま、ソフトウェアをラクに書けるように NXP 社が LPC マイコン内に仕込んだもので、データのハンドリングや各種割り込み処理などをある程度 ROM に書かれたソフトウェアがやってくれるものです。
ROM は ROM なので、ある程度動作は固定されています。以下の機能を実装しているとユーザーマニュアルにはありました。
- CDC(仮想 COM ポートと言ったらこれ)
- DFU
- HID
- MSC(Mass Storage Class, いわゆる「USB メモリ」はこれ)
つまり、以上の機能を利用する場合に限って USB をラクに実装できるというわけです。
やっていこう
と思ったんですけど、自力でやろうとしても無理です。
なぜかと言うと、ユーザーマニュアルの記述がほぼ皆無なんですよね。この USB 用 ROM API のイントロがあって、次に謎の構造体が来て、そしてただの謎の構造体の羅列が続くのみ。どのような関数を呼べば良いのかとか、相当エスパーな方でなければ無理です。これ絶対 doxygen とかからの出力をそのまま流用しただろ。僕は1分考えて、そっ閉じしました。
なんとなく触れてみる
幸いにも、NXP のサイトでサンプルが配布されているようです。助かった。トップダウン式では無いですが、とにかく動くコードから学べますね。こちらの記事からこの情報を得ました。
サンプルコードのダウンロード
上の記事にあるリンクから...出来ません。
出ましたね〜、この会社の悪いところ。すぐリンクアドレス変えるから、いろいろなものが急に迷子になってしまうんですよ。そして急に公開停止したり。ちょうどダウンロードしたかった奴が案の定被害を受けてます。まあだいたいそうなるだろうなと検討はついていたよ。
その後 WaybackMachine とかで探しましたがダメ。しかし、この GitHub リポジトリにコピーを取っていた方がいたみたいで、ありがたくも頂戴しました。LPC11Uxx LPCXpresso Examples.zip をダウンロードしてください。
MCUXpressoにインポートしてゴチャゴチャする
落としたら展開して、MCUXpresso にインポートしちゃいましょう。USB_ROM_CDC と LPC11Uxx_Driver_Lib をインポートします。
設定等の改変
さて、LPC11U35 に合わせた操作をしていきましょう。此処から先は全て USB_ROM_CDC の話です。
プロジェクトのプロパティを開いて C/C++ Build → MCU Settings に行きます。そこで、LPC11U35/501 を選択。
同じく Settings から、右ペイン Tool Settings → MCU C Compiler → Includes に行き、そのタブ内で "${workspace_loc:/LPC11Uxx_Driver_Lib/inc}"
を上から2番めになるように設定。
これで一度ビルドしてみて通れば OKです。
コードを追加
はい、これでマイコンに書き込むと USB CDC デバイスが完成するのです。
そりゃ出来合いのものだからすぐ出来て当然ですが、それにしてもプロジェクト内のソースファイル数が少ないのが分かりますか?実際の処理を記述しているソースファイルに限れば、main.c
の1つだけですね。すごい。
これで出来たバイナリを書き込んでも、シリアルモニタに対して無視を決め込むことしか出来ないので、main 関数の下部、while
無限ループがある辺りを書き換えましょうか。
strcpy((char *)g_vCOM.txBuf, "Hello");
ms_wait(2000); // wait for the establishment between USB host & device
while (1)
{
g_vCOM.txlen = 4;
VCOM_usb_send(&g_vCOM);
ms_wait(500);
}
これで、0.5sec に1回「Hell」と言ってくれます。あ、そうそう。ms_wait
なんてものはデフォで存在しないので、以下の秘伝のタレを使いました。
void ms_wait(uint32_t msec) {
SysTick->LOAD = 24000 - 1;
SysTick->VAL = 0;
SysTick->CTRL |= (1 << 0);
for(uint32_t i = 0; i < msec; i++) {
while( !(SysTick->CTRL & (1 << 16)) );
}
SysTick->CTRL &= ~(1 << 1);
}
〆
ということで、ひとまず動くプロジェクトを設えました。コード全体を見通してもらっても分かるんですけど、かなりスッキリとしていますよね。これひょっとしたら、USB の規格をあまり知らない人でもデバイスが書けちゃうんじゃないかと思いますよ。
次回以降でその解析、改造、学習をしていく感じで行きます。最後は自分の手で書き上げたいなあ。