【LPCマイコン】Delay関数を組み込む
今回の内容はタイトルまんまですね。LPCマイコンを普通に使おうとしたらDelay関数が見当たらなかった(実はあるかもしれないが)ので自作してみたお話
Delay関数はSystickTimerというタイマーを使って構成してみようと思う
SystickTimerとは
データシートを読んでみると
The system tick timer (SysTick timer) is part of the ARM Cortex-M3 core and is identical
for all LPC15xx parts.
って書いてある。つまるところこれはLPCではなくCoretex-M3….CPUに備え付けられている機能らしい。
SystickTimerの使い方
動作周波数の設定
通常はレジスタ叩いて設定するものだと思うんだけどLPCマイコンはさまざまなAPIが用意されててこのタイマも例外じゃない。SystickTimerはその中でも特に簡単で、以下の関数だけで設定することができる__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks);
ticksの設定の仕方だけど、クロック周波数がSystemCoreClock
でDelayの周波数をfreq
とすると、
$$ticks = \frac{SystemCoreClock}{freq}$$
になる。SystemCoreClock
で動くタイマーをfreq
で分周して動かしてるって感じになるかな
割り込みのエントリーポイント
動作周波数を設定したら、割り込み時にハンドルされる関数を定義してあげる。Systickのハンドラは以下の関数として定義するように決められてる。extern "C" void SysTick_Handler(){}
この関数の中ではDelay用のカウンタをインクリメントするだけでいいと思う。
Delay関数の全体像
てことで実際のDelay関数はこんな感じになる。
volatile static uint64_t tick; static constexpr uint64_t freq = 100000; // T = 10[us]. volatile static uint32_t unUsedValue; void Init(){ SysTick_Config(SystemCoreClock / freq); tick = 0; } static inline void ClearTick(){ tick = 0; } static inline uint64_t CurrentTick(){ return tick; } static inline uint64_t CurrentTickUs(){ return CurrentTick(); } static inline uint64_t CurrentTickMs(){ return CurrentTick() / 100; } void DelayUs(const uint64_t _us){ ClearTick(); while(CurrentTickUs() <= (_us / 10)){ // __NOP()だとCPUが止まるから unUsedValue++; } } void DelayMs(const uint64_t _ms){ ClearTick(); while(CurrentTickMs() < _ms) { unUsedValue++; } } void Delay(const uint64_t _sec){ auto time = _sec; while(time > 0){ DelayMs(1000); time--; } } extern "C" void SysTick_Handler(){ tick++; }
今回はDelayの分解能を10[us]に設定してある。この状態でDelayUs(250);
とかすれば任意の待機時間を生成できる。待機には__NOP()
をしてもよかったんだけどCPUを止めたくなかったからインクリメントにしてみた。
ちなみに、インクリメントしているunUsedValue
は volatile
修飾をしている。これが何かっていうと、コンパイラによる最適化を防ぐためのやつ。もしこれをやらないと、無駄なループとみなされて除去されてしまう(はず)
最近のコメント