【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を止めたくなかったからインクリメントにしてみた。

ちなみに、インクリメントしているunUsedValuevolatile修飾をしている。これが何かっていうと、コンパイラによる最適化を防ぐためのやつ。もしこれをやらないと、無駄なループとみなされて除去されてしまう(はず)

おすすめ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です