Nuvoton社の若干古いマイコンNUC120の評価ボードをIAR社の無償評価版の開発環境で動かしております。別シリーズ投稿にて無償評価版のサイズ制限キツイのでArmのアセンブラの練習用だ、などとブーたれておりますが、それはそれで、やれることはある、と。まずはマイコン動かすときの基本の一つ、クロックとタイマチック割り込みについてみてみます。
※「鳥なき里のマイコン屋」投稿順Indexはこちら
ボードを動かすのに現在使っているのは、10年も前のNuvoton社のボードサポートパッケージ(BSP)というソフトウエア環境なのです。これに好感を持ったのは、「ちゃんとドライバ関数のドキュメントが付属」しておる、という1点です。どことは言えませんが、某中華MCUベンダのパッケージなど、ライブラリのソースはあるものの、ドキュメント無く、常にソースを読まねば何が用意されているのかも分かりませぬ。
今回使用を試みますのは、Arm社がCortex-M0の実装において「オプシショナルな」system timerとしている Systickであります。Arm社の方で規定している部分だけれど、実装の可否はMCUベンダ次第。Nuvoton社のManualを見れば、実装されておる筈。ちょうどArm社とNuvoton社の「境界」に位置しているので、Nuvoton社のドライバパッケージのマニュアルだけでは済まず、かといってArm社のマニュアルだけでも済まずという微妙な存在。
それでは現物に聞いた方が手っ取り早いと、前回動作させたLチカのサンプルプログラムに以下を組み込み、その設定値がどうなっているのか観察してみました。
temp[0] = *((uint32_t*)0xE000ED00); // CPUID temp[1] = *((uint32_t*)0xE000E010); // SYST_CSR temp[2] = *((uint32_t*)0xE000E014); // SYST_RVR temp[3] = *((uint32_t*)0xE000E018); // SYST_CVR
直接メモリアドレスを書くような不作法な操作をしてしまいました。多分、調べたらこの辺にアクセスするためのArm定義の関数があるのだと思いますが、探すよりは書いた方が早いかと。ただ、ArmのドキュメントをサーチしてもSystickについて説明しているところは見つかりやすいのだけれど、肝心の「在りか」についてなかなか書いてありません。奥の方にM0コアが使っているメモリマップがあるのでそこからGET。サーチで時間使った。。。
なお、最初に読み出している0xE00ED00番地からはCortex-M0のCPUIDが読み出せます。コアはM0なので以下の値が読み出せるに決まっているので、「ちゃんと読み出せている」証拠にはなるかと読みました。
0x410CC200
SYST_CSRというレジスタがSystickの制御レジスタで、Armのドキュメントによれば、カウンタがカウント中であればビット16に1が、またカウントが許可されていればビット0に1が立っている筈ですが、Lチカ・サンプル・プログラムの設定のままだとどちらも0で動作していないことが分かります。
一方、Lチカでのクロック設定らしき部分を引用させていただくと、こんな感じ。私は、これみて外部の12MHzクリスタル(ボード上に鎮座してます)で動作しているのだ、と早合点しました。しかし、最近のMCUのクロックの設定は結構複雑。NUC120も多少古いとは言え、それなりに複雑。一応、「現物」確認を誓いました(アイキャッチ画像を見ていただくと分かるとおり、前回からの間にNUC120エバボードにピンヘンダを半田付けしました。たまたま、2列のピンヘッダにちょうどいい長さのものが手元になく、剣山みたいな感じになってしまいましたが。
/* SYSCLK =>12Mhz*/ UNLOCKREG(); SYSCLK->PWRCON.XTL12M_EN = 1;
実際にSysTickタイマを動作させるために追加してみたのは以下です。SystemCoreClockという変数に実際の動作周波数[Hz]が代入され、それを何回カウントして0になったらSystickを発生するか(リロード値)を決めているようだたので、以下の設定であれば、1秒間に100回Systick割り込みが発生すると期待。
SystemCoreClockUpdate(); SysTick_Config(SystemCoreClock / 100);
割り込みの方は、キメウチの名前でハンドラから「呼ばれる」関数を書いておけば、本当のハンドラがそれを呼び出してくれるみたいだったので、以下のようにしてみました。カウント変数のビット0が0だったら、ポートBの 1番をON,1だったらOFF。このビットにしたのは、Lチカで使っているボード上のLEDがポートBの0番に接続していたので、その御隣という理由であります。
void SysTick_Handler(void) { sTicks++; if (sTicks & 1) { DrvGPIO_ClrBit(E_GPB,1); } else { DrvGPIO_SetBit(E_GPB,1); } }
さて、これだけの仕込みをして、IARツールチェーンでビルドし、Nu-linkで書き込んで動作させたときの動作結果はこんな感じ。なにやら大変そうですが、一撃です。わずかばかりの大域大域変数をウオッチするための設定をしたので即座に知りたいことが分かります。
まず、SystemCoreClock値は22118400と読み取れます。大体22MHz。この値はNUC120の内蔵発振器(クリスタルに比べると精度がよくない)に見えます。先ほど外付けの12MHzクリスタルのクロックを使っているのかと思いましたが、それとは違っているようです。まあ、実測するまでは分かりませんが。
次にtemp[0]にはArm Cortex-M0のCPUID値が読めている筈。読めてます、OK。次のtemp[1]がSystick Timerの設定で、0x10007をArm社のマニュアルに従い解釈すると、
-
- ダウンカウント中
- SysTickのクロックソースはプロセッサクロック
- カウンタが0になったら割り込み発生
- Systickの動作許可
です。いい感じです。temp[2]にはカウントが0になった後のリロード値です。
221183
これは、221183から数えて0になったら割り込みということで、先ほどのSystemCoreClock値の丁度100分の1なので、1秒間に100回、0までカウントダウンされるということであります。そしてカウンタの現在値がtemp[3]、1秒に100回呼ばれている筈の割り込みハンドラの回数カウントsTicksの値が217。
辻褄あっている、感じがします。
が、最後、現物でそれを確認すべきでしょう。そのためにポートBの1番(18番ピン)にSystickハンドラが呼ばれる度にトグルする信号を出してあります。例によって Digilent製Analog Discovery2で観察、こんな感じ。
周波数約50Hz。ハンドラ自体は100Hzですが、呼ばれる度にトグルなので周波数はその半分です。波形をみれば、ハンドラがほぼ正確に10ms毎に走っていることが分かります。
SystickタイマOKだな。
でも、各部クロックの設定方法怪しい。ちゃんと調べておかないと。