avr-libc  2.0.0
Standard C library for AVR-GCC

AVR Libc Home Page

AVRs

AVR Libc Development Pages

Main Page

User Manual

Library Reference

FAQ

Example Projects

<avr/fuse.h>: ヒューズサポート
概要

ヒューズAPIを使用すると、コンパイル対象のAVRデバイスのヒューズ設定を指定できます。ヒューズ設定は、リンク後のELF出力ファイルの特別なセクションに配置されます。

プログラミングツールは、ELFファイルに埋め込まれたヒューズ情報を利用でき、フラッシュとEEPROMメモリを書き込む前にヒューズを書き込む必要があるか判断します。1つのELFファイルへAVRの書込みに必要なすべての情報を含めることができます。

ヒューズAPIを使用するには、<avr/io.h>をインクルードしてください。個別のI/Oヘッダファイルと<avr/fuse.h>ファイルが自動的に読み込まれます。この2つのファイルは、AVRヒューズ設定に必要なすべての機能を提供します。

ヒューズAPI

各I/Oヘッダファイルでは、AVRデバイスにあるヒューズバイトの数を定義したFUSE_MEMORY_SIZEマクロを定義しなければなりません。

新しい型 __fuse_t は、構造体で定義され、構造体のフィールド数は、FUSE_MEMORY_SIZEマクロのヒューズバイトの数により決まります。

FUSE_MEMORY_SIZE == 1の時は、unsigned char型のbyteの1フィールドのみ。

FUSE_MEMORY_SIZE == 2の時は、unsigned char型のlow と high の2フィールド。

FUSE_MEMORY_SIZE == 3の時は、unsigned char型のlow と high、extendedの3フィールド。

FUSE_MEMORY_SIZE > 3の時は、FUSE_MEMORY_SIZEのサイズのunsigned char型の配列での byte の1フィールド。

便利なマクロ FUSEMEM は、カスタムセクション名 ".fuse"へのGCC属性として定義されています。

便利なマクロ FUSES は、FUSEMEMで定義された属性にある__fuse_t型の__fuse変数の宣言を定義しています。この変数により、エンドユーザーはヒューズデータを簡単に設定できます。

注意
デバイス特有のI/OヘッダファイルでFUSEMEMが定義済みの時は、FUSEMEMは再定義されません。デバイス特有のI/OヘッダファイルでFUSESが定義済みの時は、FUSESは再定義されません。

各AVRデバイスのI/Oヘッダには、デバイスで利用できる実際のヒューズビットを指定する定義済みマクロ一式があります。AVRヒューズは負論理で、論理値1はプログラムされていない(無効)で、論理値0はプログラムされた(有効)なビットになります。ヒューズビットごとに定義されたマクロは、マスクされたビットごとの反転で実装されています。たとえば、ATmega128のFUSE_EESAVEヒューズは、つぎのように定義されています。

#define FUSE_EESAVE ~_BV(3)
注意
_BVマクロは、ビット番号からビットマスクを生成します。そして、ヒューズメモリバイトの論理値を反転させます。

ヒューズビットマクロを組み合わせてヒューズバイト全体を示すには、つぎのようにANDのビット演算子を使います。

(FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN)

各デバイスのI/Oヘッダには、利用できる各ヒューズバイトのデフォルト値を提供するマクロも定義されています。LFUSE_DEFAULTは、Lowヒューズバイトを定義しています。HFUSE_DEFAULTは、Highヒューズバイトを定義しています。EFUSE_DEFAULTは、Extendedヒューズバイトを定義しています。

FUSE_MEMORY_SIZE > 3の時は、FUSE0_DEFAULT FUSE1_DEFAULT FUSE2_DEFAULT FUSE3_DEFAULT FUSE4_DEFAULT ……のように、ヒューズバイトのデフォルト値を提供するマクロが定義されています。

APIの使い方例

すべてをまとめるのは簡単です。C99の指示初期化子を使います。

#include <avr/io.h>
FUSES =
{
.low = LFUSE_DEFAULT,
.high = (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN),
.extended = EFUSE_DEFAULT,
};
int main(void)
{
return 0;
}

または、FUSESマクロの代わりに変数を直接使用します。

#include <avr/io.h>
__fuse_t __fuse __attribute__((section (".fuse"))) =
{
.low = LFUSE_DEFAULT,
.high = (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN),
.extended = EFUSE_DEFAULT,
};
int main(void)
{
return 0;
}

C++コンパイラでは指示初期化子を使えないため、つぎのようにする必要があります。

#include <avr/io.h>
FUSES =
{
LFUSE_DEFAULT, // .low
(FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN), // .high
EFUSE_DEFAULT, // .extended
};
int main(void)
{
return 0;
}

ただし、このAPIを適切に使用するために注意事項があります。

APIのすべての定義を取得するために、必ず<avr/io.h>をインクルードしてください。FUSESマクロは、ヒューズデータを格納するグローバル変数を定義します。この変数は、独自のリンカセクションへ配置されます。変数の初期化により、必要なヒューズの値がすぐに設定されます。

ELFファイル内の .fuse セクションは、変数の初期値のみ取得します。つまり、関数内でこの変数に値を設定できず、新しい値はELFの.fuseセクションへ反映されません。

FUSESマクロで宣言されたグローバル変数には、先頭に2つのアンダースコア(__)がつきます。つまり、ライブラリを意味する「実装用」として予約されており、ユーザーの変数名と競合することはありません。

__fuse_t構造体のすべてのフィールドを初期化する必要があります。ヒューズビットのすべてのバイトは、標準でプログラムされていない(無効)である論理値1に設定されているためです。通常の初期化されていないデータは、すべて論理値0に標準で設定されます。そのため、標準値であっても、すべてのヒューズバイトを初期化することは重要です。設定しないと、ヒューズビットが目的の設定にプログラムされない可能性があります。

コンパイルとリンカのコマンドラインで-mmcu=deviceフラグを使用し、正しいデバイスを選択し、<avr/io.h>をインクルードするときに正しいI/Oヘッダファイルを読み込むようにしてください。

つぎのコマンドラインで、ELFファイルの.fuseセクションの内容を表示できます。

avr-objdump -s -j .fuse <ELF file>

セクションの内容には、左側にアドレスが、つぎに下位アドレスから上位アドレスに向い左から右にデータが表示されます。