AVR Libc Home Page | ![]() |
AVR Libc Development Pages | ||
Main Page | FAQ | Library Reference | Additional Documentation | Example Projects |
<avr/sfr_defs.h>
ファイルはすべての <avr/ioXXXX.h>
ファイルからインクルードされます。これは特殊機能レジスタを単なるCの変数や定数に見えるように定義するマクロを持っています。これは
_SFR_ASM_COMPAT
定義によります。<avr/iom128.h>
にある、どうやってそのようなマクロを定義するかについてのいくつかの例題も紹介します。
#define PORTA _SFR_IO8(0x1b) #define TCNT1 _SFR_IO16(0x2c) #define PORTF _SFR_MEM8(0x61) #define TCNT3 _SFR_MEM16(0x88)
_SFR_ASM_COMPAT
が定義されていないとき、CプログラムはPORTAなどの名前を直接Cの表現式内(代入式の左辺でも)に利用できるようになり、GCCはそれに対応します(可能なら短いI/O命令(in/outなど)を用います)。
__SFR_OFFSET
定義はこの場合は使われません。
_SFR_ASM_COMPAT
を値 1 で定義すると、これらの名前(PORTAなど)を、IOレジスタのアドレスを表す単なる定数として用いるようになります。これはプリプロセッサによるアセンブラ(*.S)ソースファイルを扱う際には必要なことですが、__ASSEMBLER__
が定義される場合には自動的に定義されます。デフォルトでは、すべてのアドレス値はlds/sts命令で使えるメモリアドレスとして定義されます。これらのアドレス値をin/out値で用いるには、0x20を引いてやらなければなりません。
過去の互換性のために、古いアセンブラソースは、以下の記述を先頭に追加してください。
#define __SFR_OFFSET 0
これは自動的にI/O 空間アドレスから0x20を引いてくれます。しかしこれは裏技です。以下のように定義アドレスをマクロで変更するようソースを書き換えることを推奨します。この修正が終わったら
__SFR_OFFSET
定義はもはや不要です。削除してください。
実際の例:このコードは、SPMCR
が異なるアドレスにあるデバイス間で、ブートローダーで共用できるコードとなります。
※out命令が利用可能なら利用し、だめならsts命令を利用する。in/out用アドレスは_SFR_IO_ADDR()で、lds/sts用アドレスは_SFR_MEM_ADDR()で生成する。
<avr/iom163.h>: #define SPMCR _SFR_IO8(0x37) <avr/iom128.h>: #define SPMCR _SFR_MEM8(0x68)
#if _SFR_IO_REG_P(SPMCR) out _SFR_IO_ADDR(SPMCR), r24 #else sts _SFR_MEM_ADDR(SPMCR), r24 #endif
SREGなど、対象IOアドレスがIOスペースに入っているとわかっていれば、
_SFR_IO_REG_P
マクロで判定することなくin/out/cbi/sbi/sbic/sbis
命令が利用可能です。もし誤っていればアセンブラは"I/Oアドレスが0-0x3fの範囲外だ"
と文句を言いますので、誤ったまま使用する危険はなく、安全といえます。
__SFR_OFFSET
を定義しない場合 (その場合はデフォルト値0x20となります)、すべての特殊機能レジスタアドレスはメモリアドレスとなります(たとえばSREGは0x5f)。速度やコードサイズの要求が厳しくなくて、上記のような汚い記述が嫌いなら、このアドレス値を用いて常にlds/sts命令でメモリマップドIO方式のアクセスを行うことができます。しかし、これは
__SFR_OFFSET
!= 0x20の時は使えません。そこで、(__SFR_OFFSET
== 0x20) の場合のみ定義されるマクロを念のため組み込んでください。
sts _SFR_ADDR(SPMCR), r24
Cプログラムでは、_SFR_ASM_COMPAT
と__SFR_OFFSET
の値により起こりえる3つの組み合わせへの対応がサポートされています。_SFR_ADDR(SPMCR)
マクロはSPMCR
レジスタのアドレスを得るのに用いられます(0x57
又は0x68、デバイスによって異なる)。