Sahara's WebLog

日記のような、備忘録のような、うらみつらみのような、自慢のような…。

PIC18のdelayで「in-line delay argument too large」って叱られる件

__delay大好きな私にとって、表題の件は重要なので調べてみた。

MicrochipのForumで、リミットがあるんだというような書き込みがあったので、XC8のUsr’s Guideを開いて見てみると、
Chapter 3. How To’s
3.5 GETTING MY APPLICATION TO DO WHAT I WANT
• How Can I Implement a Delay in My Code?
という、そのものずばりの内容が書いてあった。
pic18_delay

If an accurate delay is required, or if there are other tasks that can be performed during the delay, then using a timer to generate an interrupt is the best way to proceed.
If these are not issues in your code, then you can use the compiler’s in-built delay pseudo-functions: _delay, __delay_ms or __delay_us; see Appendix A. Library Functions. These all expand into in-line assembly instructions or a (nested) loop of instructions which will consume the specified number of cycles or time. The delay argument must be a constant and less than approximately 179,200 for PIC18 devices and approximately 50,659,000 for other devices.
Note that these code sequences will only use the NOP instruction and/or instructions which form a loop. The alternate PIC18-only versions of these pseudo-functions, e.g., _delaywdt, can use the CLRWDT instruction as well. See also, Appendix A. Library Functions.

正確なdelayが必要なときや、delay中に他の事をやらせたいときにはタイマー割り込みを使ってね。
_delay, __delay_ms そして __delay_usってのがあって、インライン・アセンブラに展開されて所定のサイクルを消費することで時間を稼ぐよ。
delayの引数は、PIC18では179200、その他では50659000より少ない定数が指定できるよ。
NOPとループで時間稼ぎしているだけなんだって覚えておいてね。
PIC18では_delaywdtという関数も使えるよ。

__delaywdt_ms(x) // request a delay in milliseconds
__delaywdt_us(x) // request a delay in microseconds
On PIC18 devices only, you can use the alternate WDT-form of these functions, which uses the CLRWDT instruction as part of the delay code. See the _delaywdt function.

とは言っても、別に179200のリミットが外れるわけでは無いようで、
For very large delays, call this function multiple times.
と書いてある。
まあ、そうだろうね。

さて、では、エラーにならないようにするには、179200ってどう計算すればいいのかということになる。
__delay_msや__delay_usは、結局内部で__delay();に換算していて、その際の値が179200を越えたらダメっていう意味だと思う。
仮に8MHzで__delay_ms(100);とやって、NOP();だけで消化しようとすると、100/1000秒間に8MHzのPICは何サイクル分仕事するかと考えればいい。
8MHzは1秒間に8000000/4サイクル仕事をするので、これを1/10すると200000となって179200を超えてしまう。
__delay_ms(89);だと、(8000000/4)×(89/1000)=178000となって超えずに、計算上も実際もエラーにならない。
ただ、現実にはNOPでやったりloopでやったりだと思うので、User’s Guideにも「approximately」となっていて、試してみたら__delay_ms(98);はコンパイルできた、計算上は196000なのに。

せっかく高機能なんだから、Timer割り込み使えよ。
割り込みでやるほどのことも無い単純作業だけならもっと低機能のPIC使えよ。
Microchipさん的に言えば、こういうことでしょう。

このエントリーをはてなブックマークに追加

Posted under: PIC18F14K50, PIC18F2550, PIC18F4550


コメントを残す

メールアドレスが公開されることはありません。

Time limit is exhausted. Please reload CAPTCHA.