pp.301-302
非公式訳
AVRは8ビットマイコンです。つまりデータは一度に8ビットずつしか処理できません。しかしTimer1のレジスタのうち、TCNT1
、OCR1A
、ICR1
などは16ビットレジスタです。こうした16ビットレジスタは2つの8ビットレジスタに分割されていて、それぞれ個別にアクセスするしくみになっています。ほとんどの場合はこれで問題ありません。たとえば、(訳註: 16ビットレジスタである)SP
レジスタ(スタックポインタ)に値をロードするときは、下に示したように、最初は半分だけ(訳註: SPL
)に値をロードし、次いで残りの半分(訳註: SPH
)に値をロードします。
LDI R16, 0x12 OUT SPL, R16 LDI R16, 0x34 OUT SPH, R16 ; これでSPが0x3412になった。
しかし16ビットタイマーでは、レジスタの値を一度に全部読み書きしないと問題になることがあります。たとえば以下のような状況を考えてみましょう。
TCNT1
レジスタに0x15FF
という値が入っているとします。TCNT1
の下位バイト0xFF
を読み出して、それをR20
にストアするとします。このとき同時にタイマークロックが発生すると、TCNT1
の値は0x1600
になります。そうなってからTCNT1
の上位バイト0x16
を読み出して、その値をR21
にストアするとします。今読んだばかりの値を見ると、R21:R20
= 0x16FF
です。そのため、本当はTCNT1
には0x15FF
という値が入っていたのに、0x16FF
という値が入っていたように見えてしまいます。
この問題は、多くの8ビットマイコンが抱えています。しかしAVRは、バッファーとして使うTEMP
という8ビットレジスタでこの問題を解消しています。図9-22を見てください。16ビットレジスタの上位バイトを読み書きするときは、その値がTEMP
レジスタに書き込まれます。16ビットレジスタの下位バイトに書き込むときには、TEMP
レジスタの内容も16ビットレジスタの上位バイトに書き込まれます。たとえば以下のプログラムを検討してみましょう。
LDI R16, 0x15 STS TCNT1H, R16 ; TEMPに0x15がストアされる。 LDI R16, 0xFF STS TCNT1L, R16 ; TCNT1Lに0xFFがストアされると同時にTCNT1HにTEMPの内容(0x15)がストアされる。
STS TCNT1H, R16
が実行されたあと、R16
の内容である0x15
がTEMP
レジスタにストアされます。STS TCNT1L, R16
が実行されると、R16
の内容である0xFF
がTCNT1L
にロードされ、TEMP
レジスタの内容である0x15
がTCNT1H
にロードされます。そのため、0x15FF
が一度にTCNT1
レジスタにロードされます。
AVRの内部回路を考慮すれば、16ビットレジスタの上位バイトに先に書き込んでから下位バイトに書き込むべきです。そうしないと、プログラムがうまく動きません。例として下のコードを見てください。
LDI R16, 0xFF STS TCNT1L, R16 ; TCNT1Lに0xFFが代入され、TCNT1HにTEMPの内容(不定値)が代入される。 LDI R16, 0x15 STS TCNT1H, R16 ; TEMPに0x15が代入される。
このコードは正常には動作しません。その理由は、TCNT1L
に値がロードされるときにTEMP
の内容がTCNT1H
にロードされるからです。TCNT1L
レジスタに値がロードされるときには、TEMP
にはガーベジ(不適切なデータ)が入っています。これでは、望みどおりの動作にはなりません。
16ビットレジスタの下位バイトを読み出すときは、上位バイトの内容がTEMP
レジスタにコピーされます。したがって、下のプログラムを実行するとTCNT1
の内容が読み出されます。
LDS R20, TCNT1L ; R20にTCNT1Lの内容が代入され、TEMPにTCNT1Hの内容が代入される。 LDS R21, TCNT1H ; R21にTEMPの内容が代入される。
16ビットレジスタの上位バイト、下位バイトを読み出すときは、その順番に気をつけなければなりません。そうしないと結果を誤ります。
OCR1A
、OCR1B
の各レジスタを読み出すときはTEMP
レジスタはからんでこないことに注目してください。(以下略~)
――――――――――――――――――――――――――――――――――
訳註:
まとめると
- 16 ビットレジスタの上位バイトを相手に値を読み書きをしようとしても、実際に読み書きの相手になるのは
TEMP
レジスタである。 - 16 ビットレジスタの下位バイトを相手に値を読み書きをすると、下位バイトは実際に読み書きされるが、同時に上位バイトと
TEMP
レジスタとの間でも読み書きが実行される。
具体的にいうと
- 16 ビットレジスタの上位バイトに書き込もうとしても、実際には
TEMP
レジスタに書き込まれる。 - 16 ビットレジスタの下位バイトに書き込もうとすると、下位バイトに書き込まれるのと同時に、上位バイトに
TEMP
レジスタの内容が書き込まれる。
- 16 ビットレジスタの上位バイトから読み出そうとしても、実際には
TEMP
レジスタから読み出される。 - 16 ビットレジスタの下位バイトから読み出そうとすると、下位バイトから読み出されるのと同時に、上位バイトの値が
TEMP
レジスタに読み出される。
結論だけいうと