AVR Libc Home Page AVRs AVR Libc Development Pages
Main Page User Manual Library Reference FAQ Alphabetical Index Example Projects

簡単なプロジェクト
[デモプロジェクト]

ここまでに、GNUツールをあなたのシステムにインストール、構築して設定しておかなければなりません。この章では、AVRプロジェクトでのGNUツールの簡単な使用方法の例を紹介しています。この章を読んだあとに、ツールがどのように使われるか、Makefileがどのように設定されるかをより良い感触がつかめるでしょう。

プロジェクト

このプロジェクトは、2秒ごとにLEDをパルス幅変調(PWM)で徐々に点滅させます。AT90S2313プロセッサをコントローラとして使用します。このデモンストレーション用回路は、回路図に示します。もし開発キットを持っていれば、このプロジェクトのために回路を作るよりも、開発キットを使うことができるでしょう。

注釈:
ただ、AT90S2313はすでに廃版になりました。その後継で、このプロジェクトとピン互換であるATtiny2313や、あるいはとても人気があるATmega8かその後継(ATmega48/88/168)を使用することで、オリジナルのデモプロジェクトから作ることが出来ます。これら全ての最新のデバイスでは、1MHzの内部クロックを使用可能にして出荷されているため、もはや外部水晶は必要ありません。そして、C1、C2とQ1を省略できます。通常、この実験では、/RESETの外部回路(R1、C3)を同様に省略することが出来ます。そして、AVRとLED、バイパスコンデンサ C3とたぶんR2だけになります。ATmega8/48/88/168では、LEDの接続にPB1 (DIP-28では15ピン)を使用してください。その上で、このデモは多くの異なる他のAVRに移植されています。OCピンの一は異なるAVRで変化し、それはAVRのハードウェアに依存します。

demo.png

Schematic of circuit for demo project

ソースコードはdemo.cにあります。この例のために、このソースコードを含むdemo.cを作成してください。コードのより重要ないくつかの部分は次の通りです。

Note [1]:
AVRマイクロコントローラシリーズは、過去数年の間に開発されているように、新機能が時間をかけて追加されています。たとえtimer/counter1の基本概念は、この簡単なデモが最初に書かれていたときの2001年初頭時代と同じでも、レジスタとビットの名前は、新機能を反映するために若干変更されています。また、LEDの制御に使用している比較出力の1A(古いデバイスでは1)ピンのポートやピン配置は、異なるAVR間で変ります。iocompat.hファイルは、プリプロセッサの#ifdef命令文を用いてこれら全ての違いを抽象化しようとしています。そして、実際のプログラムでは、共通のシンボル名のセットを用いて操作するこができます。このファイルで定義されているマクロは次の通りです。
Note [2]:
ISR()は、割込み処理の関数を示すマクロです。この場合、タイマー1のオーバーフロー時に関数が呼び出されます。割込みの設定は、<avr/interrupt.h>: 割込みの中でより詳細に説明されています。
Note [3]:
PWMが10ビットモードで使われているため、現在の値を記憶するために16ビットの変数が必要になります。
Note [4]:
このセクションでPWMの新しい値を決定します。
Note [5]:
ここれは、新しく計算した値をPWMレジスタにロードします。割込み処理の中にいるため、レジスタに16ビットの代入を使うことは安全です。割込みの外であって、割込み処理がこのレジスタ(または、TEMPを使用する別のレジスタ)にアクセスすることが出来たという可能性があるならば、代入は割込みを使用不可能にして実行されなければなりません。FAQ entryの適切な項を見てください。
Note [6]:
この処理は、リセットの後に呼び出されます。そして、PWMの初期化と割込みを許可します。
Note [7]:
プログラムのメインループは、何もしません。全ての作業は割込み処理で行われます。sleep_mode()は、次の割込みまでプロセッサを休止状態にし、電力を削減します。もちろん、LEDを動かしているので、それは顕著ではないでしょう。ただ、基本原則のデモをここでは述べているだけです。
Note [8]:
初期のAVRデバイスは、電流を供給する時はむしろ低い電流で飽和するため、LEDを直接接続して、LEDに流れる電流はおよそ15mAです。しかし、最新の部品(少なくともATmega128)では、AtmelがIOのソース能力を大幅に増やしたので、Vccを5Vで動作させる場合にはR2が必要になります。その値は150Ω程度です。3Vで回路を動作させるときは、まだ省略することが出来ます。

ソースコード

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 * ----------------------------------------------------------------------------
 *
 * Simple AVR demonstration.  Controls a LED that can be directly
 * connected from OC1/OC1A to GND.  The brightness of the LED is
 * controlled with the PWM.  After each period of the PWM, the PWM
 * value is either incremented or decremented, that's all.
 *
 * $Id: demo.c 1637 2008-03-17 21:49:41Z joerg_wunsch $
 */

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#include "iocompat.h"           /* Note [1] */

enum { UP, DOWN };

ISR (TIMER1_OVF_vect)           /* Note [2] */
{
    static uint16_t pwm;        /* Note [3] */
    static uint8_t direction;

    switch (direction)          /* Note [4] */
    {
        case UP:
            if (++pwm == TIMER1_TOP)
                direction = DOWN;
            break;

        case DOWN:
            if (--pwm == 0)
                direction = UP;
            break;
    }

    OCR = pwm;                  /* Note [5] */
}

void
ioinit (void)                   /* Note [6] */
{
    /* Timer 1 is 10-bit PWM (8-bit PWM on some ATtinys). */
    TCCR1A = TIMER1_PWM_INIT;
    /*
     * Start timer 1.
     *
     * NB: TCCR1A and TCCR1B could actually be the same register, so
     * take care to not clobber it.
     */
    TCCR1B |= TIMER1_CLOCKSOURCE;
    /*
     * Run any device-dependent timer 1 setup hook if present.
     */
#if defined(TIMER1_SETUP_HOOK)
    TIMER1_SETUP_HOOK();
#endif

    /* Set PWM value to 0. */
    OCR = 0;

    /* Enable OC1 as output. */
    DDROC = _BV (OC1);

    /* Enable timer 1 overflow interrupt. */
    TIMSK = _BV (TOIE1);
    sei ();
}

int
main (void)
{

    ioinit ();

    /* loop forever, the interrupts are doing the rest */

    for (;;)                    /* Note [7] */
        sleep_mode();

    return (0);
}

コンパイルとリンク

最初にしなければならないことは、ソースをコンパイルすることです。コンパイルの時に、コンパイラは-mmcuオプションを指定することでプロセッサのタイプを知っている必要があります。-Osオプションは、コンパイラに効果的なスペース使用(コードの実行速度は我慢できる範囲で遅くなる)のためにコードを最適化するようにコンパイラに指示します。-gは、デバック情報の埋め込みに使います。デバッグ情報は逆アセンブルに有用で、.hexファイル上には結局無いので、私は通常使っています。最後に、-cは、コンパイルして終る、リンクしないことをコンパイラに指示します。このデモは、コンパイルして1つにリンクすることは、十分小さいステップです。しかし、現実のプロジェクトでは、モジュールがいくつもあり、一般的にいくつもコンパイルして分割されてプロジェクトに組み入れていて、、1つにリンクされる必要があります。

    $ avr-gcc -g -Os -mmcu=atmega8 -c demo.c

コンパイルはdemo.oファイルを作ります。次に、demo.elfと呼ばれるバイナリファイルにリンクします。

    $ avr-gcc -g -mmcu=atmega8 -o demo.elf demo.o

リンクの時にMCUタイプを指定することが重要です。コンパイラは、スタートアップファイルと一緒にリンクされるランタイムライブラリを選択するため、-mmcuオプションを使用します。このオプションを指定しないと、確実にあなたが望んでいない、コンパイラが8515プロセッサ環境に初期設定されます。

オブジェクトファイルの考察

現在、バイナリファイルがあります。生成されたオブジェクトファイルを操作するための多くの役立つツールから成り立つGNU Binutils スイートで、さまざまな役立つことができます。(または、これをプロセッサーに入れます?)1つのツールにavr-objdumpがあります。これは、オブジェクトファイルから情報を取り出し、役立つ情報を表示します。このコマンド自体を入力すると、オプションを一覧表示します。

たとえば、アプリケーションのサイズの雰囲気をつかむために、 option can be used. オプションを使うことができます。このオプションの出力は、各セクションでどれだけのスペースを使用しているかを表示します。(.stabや .stabstrセクションは、デバッグ情報を持っていて、ROMファイルには含まれません。)

さらに役に立つオプションは-Sです。このオプションはバイナリ・ファイルを逆アセンブリして、出力でソースコードを点在させてくれます!この方法は、ライブラリやベクターテーブルの内容からの処理を含んでいるため、コンパイラで-Sを付けるより私の考えでは良い方法です。また、全ての"フィックスアップ"が満たされています。言い換えると、このオプションによって生成されるリストは、プロセッサが実際に動作するコードを反映しています。

    $ avr-objdump -h -S demo.elf > demo.lst

次にdemo.lst ファイルに保存された内容を示します。

demo.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000000fa  00000000  00000000  00000074  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .bss          00000003  00800060  00800060  0000016e  2**0
                  ALLOC
  2 .stab         00000b88  00000000  00000000  00000170  2**2
                  CONTENTS, READONLY, DEBUGGING
  3 .stabstr      0000077e  00000000  00000000  00000cf8  2**0
                  CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
   0:	12 c0       	rjmp	.+36     	; 0x26 <__ctors_end>
   2:	76 c0       	rjmp	.+236    	; 0xf0 <__bad_interrupt>
   4:	75 c0       	rjmp	.+234    	; 0xf0 <__bad_interrupt>
   6:	74 c0       	rjmp	.+232    	; 0xf0 <__bad_interrupt>
   8:	73 c0       	rjmp	.+230    	; 0xf0 <__bad_interrupt>
   a:	72 c0       	rjmp	.+228    	; 0xf0 <__bad_interrupt>
   c:	71 c0       	rjmp	.+226    	; 0xf0 <__bad_interrupt>
   e:	70 c0       	rjmp	.+224    	; 0xf0 <__bad_interrupt>
  10:	1a c0       	rjmp	.+52     	; 0x46 <__vector_8>
  12:	6e c0       	rjmp	.+220    	; 0xf0 <__bad_interrupt>
  14:	6d c0       	rjmp	.+218    	; 0xf0 <__bad_interrupt>
  16:	6c c0       	rjmp	.+216    	; 0xf0 <__bad_interrupt>
  18:	6b c0       	rjmp	.+214    	; 0xf0 <__bad_interrupt>
  1a:	6a c0       	rjmp	.+212    	; 0xf0 <__bad_interrupt>
  1c:	69 c0       	rjmp	.+210    	; 0xf0 <__bad_interrupt>
  1e:	68 c0       	rjmp	.+208    	; 0xf0 <__bad_interrupt>
  20:	67 c0       	rjmp	.+206    	; 0xf0 <__bad_interrupt>
  22:	66 c0       	rjmp	.+204    	; 0xf0 <__bad_interrupt>
  24:	65 c0       	rjmp	.+202    	; 0xf0 <__bad_interrupt>

00000026 <__ctors_end>:
  26:	11 24       	eor	r1, r1
  28:	1f be       	out	0x3f, r1	; 63
  2a:	cf e5       	ldi	r28, 0x5F	; 95
  2c:	d4 e0       	ldi	r29, 0x04	; 4
  2e:	de bf       	out	0x3e, r29	; 62
  30:	cd bf       	out	0x3d, r28	; 61

00000032 <__do_clear_bss>:
  32:	10 e0       	ldi	r17, 0x00	; 0
  34:	a0 e6       	ldi	r26, 0x60	; 96
  36:	b0 e0       	ldi	r27, 0x00	; 0
  38:	01 c0       	rjmp	.+2      	; 0x3c <.do_clear_bss_start>

0000003a <.do_clear_bss_loop>:
  3a:	1d 92       	st	X+, r1

0000003c <.do_clear_bss_start>:
  3c:	a3 36       	cpi	r26, 0x63	; 99
  3e:	b1 07       	cpc	r27, r17
  40:	e1 f7       	brne	.-8      	; 0x3a <.do_clear_bss_loop>
  42:	4d d0       	rcall	.+154    	; 0xde <main>
  44:	56 c0       	rjmp	.+172    	; 0xf2 <exit>

00000046 <__vector_8>:
#include "iocompat.h"		/* Note [1] */

enum { UP, DOWN };

ISR (TIMER1_OVF_vect)		/* Note [2] */
{
  46:	1f 92       	push	r1
  48:	0f 92       	push	r0
  4a:	0f b6       	in	r0, 0x3f	; 63
  4c:	0f 92       	push	r0
  4e:	11 24       	eor	r1, r1
  50:	2f 93       	push	r18
  52:	3f 93       	push	r19
  54:	8f 93       	push	r24
    static uint16_t pwm;	/* Note [3] */
    static uint8_t direction;

    switch (direction)		/* Note [4] */
  56:	80 91 60 00 	lds	r24, 0x0060
  5a:	88 23       	and	r24, r24
  5c:	c1 f4       	brne	.+48     	; 0x8e <__vector_8+0x48>
    {
        case UP:
            if (++pwm == TIMER1_TOP)
  5e:	20 91 61 00 	lds	r18, 0x0061
  62:	30 91 62 00 	lds	r19, 0x0062
  66:	2f 5f       	subi	r18, 0xFF	; 255
  68:	3f 4f       	sbci	r19, 0xFF	; 255
  6a:	30 93 62 00 	sts	0x0062, r19
  6e:	20 93 61 00 	sts	0x0061, r18
  72:	83 e0       	ldi	r24, 0x03	; 3
  74:	2f 3f       	cpi	r18, 0xFF	; 255
  76:	38 07       	cpc	r19, r24
  78:	09 f1       	breq	.+66     	; 0xbc <__vector_8+0x76>
            if (--pwm == 0)
                direction = UP;
            break;
    }

    OCR = pwm;			/* Note [5] */
  7a:	3b bd       	out	0x2b, r19	; 43
  7c:	2a bd       	out	0x2a, r18	; 42
}
  7e:	8f 91       	pop	r24
  80:	3f 91       	pop	r19
  82:	2f 91       	pop	r18
  84:	0f 90       	pop	r0
  86:	0f be       	out	0x3f, r0	; 63
  88:	0f 90       	pop	r0
  8a:	1f 90       	pop	r1
  8c:	18 95       	reti
ISR (TIMER1_OVF_vect)		/* Note [2] */
{
    static uint16_t pwm;	/* Note [3] */
    static uint8_t direction;

    switch (direction)		/* Note [4] */
  8e:	81 30       	cpi	r24, 0x01	; 1
  90:	29 f0       	breq	.+10     	; 0x9c <__vector_8+0x56>
  92:	20 91 61 00 	lds	r18, 0x0061
  96:	30 91 62 00 	lds	r19, 0x0062
  9a:	ef cf       	rjmp	.-34     	; 0x7a <__vector_8+0x34>
            if (++pwm == TIMER1_TOP)
                direction = DOWN;
            break;

        case DOWN:
            if (--pwm == 0)
  9c:	20 91 61 00 	lds	r18, 0x0061
  a0:	30 91 62 00 	lds	r19, 0x0062
  a4:	21 50       	subi	r18, 0x01	; 1
  a6:	30 40       	sbci	r19, 0x00	; 0
  a8:	30 93 62 00 	sts	0x0062, r19
  ac:	20 93 61 00 	sts	0x0061, r18
  b0:	21 15       	cp	r18, r1
  b2:	31 05       	cpc	r19, r1
  b4:	11 f7       	brne	.-60     	; 0x7a <__vector_8+0x34>
                direction = UP;
  b6:	10 92 60 00 	sts	0x0060, r1
  ba:	df cf       	rjmp	.-66     	; 0x7a <__vector_8+0x34>

    switch (direction)		/* Note [4] */
    {
        case UP:
            if (++pwm == TIMER1_TOP)
                direction = DOWN;
  bc:	81 e0       	ldi	r24, 0x01	; 1
  be:	80 93 60 00 	sts	0x0060, r24
  c2:	db cf       	rjmp	.-74     	; 0x7a <__vector_8+0x34>

000000c4 <ioinit>:

void
ioinit (void)			/* Note [6] */
{
    /* Timer 1 is 10-bit PWM (8-bit PWM on some ATtinys). */
    TCCR1A = TIMER1_PWM_INIT;
  c4:	83 e8       	ldi	r24, 0x83	; 131
  c6:	8f bd       	out	0x2f, r24	; 47
     * Start timer 1.
     *
     * NB: TCCR1A and TCCR1B could actually be the same register, so
     * take care to not clobber it.
     */
    TCCR1B |= TIMER1_CLOCKSOURCE;
  c8:	8e b5       	in	r24, 0x2e	; 46
  ca:	81 60       	ori	r24, 0x01	; 1
  cc:	8e bd       	out	0x2e, r24	; 46
#if defined(TIMER1_SETUP_HOOK)
    TIMER1_SETUP_HOOK();
#endif

    /* Set PWM value to 0. */
    OCR = 0;
  ce:	1b bc       	out	0x2b, r1	; 43
  d0:	1a bc       	out	0x2a, r1	; 42

    /* Enable OC1 as output. */
    DDROC = _BV (OC1);
  d2:	82 e0       	ldi	r24, 0x02	; 2
  d4:	87 bb       	out	0x17, r24	; 23

    /* Enable timer 1 overflow interrupt. */
    TIMSK = _BV (TOIE1);
  d6:	84 e0       	ldi	r24, 0x04	; 4
  d8:	89 bf       	out	0x39, r24	; 57
    sei ();
  da:	78 94       	sei
}
  dc:	08 95       	ret

000000de <main>:

int
main (void)
{

    ioinit ();
  de:	f2 df       	rcall	.-28     	; 0xc4 <ioinit>

    /* loop forever, the interrupts are doing the rest */

    for (;;)			/* Note [7] */
        sleep_mode();
  e0:	85 b7       	in	r24, 0x35	; 53
  e2:	80 68       	ori	r24, 0x80	; 128
  e4:	85 bf       	out	0x35, r24	; 53
  e6:	88 95       	sleep
  e8:	85 b7       	in	r24, 0x35	; 53
  ea:	8f 77       	andi	r24, 0x7F	; 127
  ec:	85 bf       	out	0x35, r24	; 53
  ee:	f8 cf       	rjmp	.-16     	; 0xe0 <main+0x2>

000000f0 <__bad_interrupt>:
  f0:	87 cf       	rjmp	.-242    	; 0x0 <__vectors>

000000f2 <exit>:
	ASSEMBLY_CLIB_SECTION
	.global _U(exit)
	.type	_U(exit), "function"

_U(exit):
	cli
  f2:	f8 94       	cli
	XJMP	_U(_exit)
  f4:	00 c0       	rjmp	.+0      	; 0xf6 <_exit>

000000f6 <_exit>:
  f6:	f8 94       	cli

000000f8 <__stop_program>:
  f8:	ff cf       	rjmp	.-2      	; 0xf8 <__stop_program>

リンカーマップファイル

avr-objdumpはとても役に立ちますが、時にリンカによって生成されるリンクについての情報を見なければならないことがあります。マップファイルはこの体の情報を含みます。マップファイルは、あなたのコードとデータのサイズをモニタするのに役立ちます。それも、モジュールがどこにロードされるか、ライブラリからのモジュールがどれか示しています。それは、あなたのアプリケーションも別の見方となります。マップライフを得るために、通常はリンクコマンドに-Wl,-Map,demo.mapを加えます。demo.mapを生成する次のコマンドを使って再リンクします。(一部を下で示す。)

    $ avr-gcc -g -mmcu=atmega8 -Wl,-Map,demo.map -o demo.elf demo.o

demo.mapファイルには、いくつかの興味深いポイントがあります。

.rela.plt
 *(.rela.plt)

.text           0x00000000       0xfa
 *(.vectors)
 .vectors       0x00000000       0x26 /home/joerg/src/avr-libc/avr/lib/avr4/atmega8/crtm8.o
                0x00000000                __vectors
                0x00000000                __vector_default
 *(.vectors)
 *(.progmem.gcc*)
 *(.progmem*)
                0x00000026                . = ALIGN (0x2)
                0x00000026                __trampolines_start = .
 *(.trampolines)
 .trampolines   0x00000026        0x0 linker stubs
 *(.trampolines*)
                0x00000026                __trampolines_end = .
 *(.jumptables)
 *(.jumptables*)
 *(.lowtext)
 *(.lowtext*)
                0x00000026                __ctors_start = .

.text セグメント(プログラム命令を格納)は、0x0の場所から始まります。

 *(.fini2)
 *(.fini2)
 *(.fini1)
 *(.fini1)
 *(.fini0)
 .fini0         0x000000f6        0x4 /usr/local/lib/gcc/avr/4.3.4/avr4/libgcc.a(_exit.o)
 *(.fini0)
                0x000000fa                _etext = .

.data           0x00800060        0x0 load address 0x000000fa
                0x00800060                PROVIDE (__data_start, .)
 *(.data)
 .data          0x00800060        0x0 demo.o
 .data          0x00800060        0x0 /home/joerg/src/avr-libc/avr/lib/avr4/atmega8/crtm8.o
 .data          0x00800060        0x0 /home/joerg/src/avr-libc/avr/lib/avr4/exit.o
 .data          0x00800060        0x0 /usr/local/lib/gcc/avr/4.3.4/avr4/libgcc.a(_exit.o)
 .data          0x00800060        0x0 /usr/local/lib/gcc/avr/4.3.4/avr4/libgcc.a(_clear_bss.o)
 *(.data*)
 *(.rodata)
 *(.rodata*)
 *(.gnu.linkonce.d*)
                0x00800060                . = ALIGN (0x2)
                0x00800060                _edata = .
                0x00800060                PROVIDE (__data_end, .)

.bss            0x00800060        0x3
                0x00800060                PROVIDE (__bss_start, .)
 *(.bss)
 .bss           0x00800060        0x3 demo.o
 .bss           0x00800063        0x0 /home/joerg/src/avr-libc/avr/lib/avr4/atmega8/crtm8.o
 .bss           0x00800063        0x0 /home/joerg/src/avr-libc/avr/lib/avr4/exit.o
 .bss           0x00800063        0x0 /usr/local/lib/gcc/avr/4.3.4/avr4/libgcc.a(_exit.o)
 .bss           0x00800063        0x0 /usr/local/lib/gcc/avr/4.3.4/avr4/libgcc.a(_clear_bss.o)
 *(.bss*)
 *(COMMON)
                0x00800063                PROVIDE (__bss_end, .)
                0x000000fa                __data_load_start = LOADADDR (.data)
                0x000000fa                __data_load_end = (__data_load_start + SIZEOF (.data))

.noinit         0x00800063        0x0
                0x00800063                PROVIDE (__noinit_start, .)
 *(.noinit*)
                0x00800063                PROVIDE (__noinit_end, .)
                0x00800063                _end = .
                0x00800063                PROVIDE (__heap_start, .)

.eeprom         0x00810000        0x0
 *(.eeprom*)
                0x00810000                __eeprom_end = .

.textセグメントの最後のアドレスは、0x114_etextのことを示す)で、命令はFLASHを276バイト使用します。

.dataセグメント(静的変数の初期値を格納)は、0x60から開始していますう。これは、ATmega8プロセッサのレジスタバンクの後の最初のアドレスです。

.dataセグメントの次に使用できるアドレスは0x60ですから、このアプリケーションには初期化されたデータがありません。

.bssセグメント(初期化されていないデータを格納)は、0x60の場所から開始しています。

.bssセグメントの次に使用できるアドレスは、0x63ですから、このアプリケーションは、初期化されないデータで3バイト使用します。

.eepromセグメント(EEPROMの変数を格納)は、0x0から開始します。

.eepromセグメントの次に使用できるアドレスは0x0ですから、EEPROMの変数はありません。

Intel Hexファイルの生成

アプリケーションのバイナリファイルがありますが、どうやってプロセッサに入れますか?(全て出ないにしても)多くのプログラマーは実行可能なGNU実行ファイルを入力ファイルとして認めないため、もう少し処理する必要があります。次のステップは、バイナリの一部を抽出して、.hexファイルに情報を保存することです。これをするGNUユーティリティは、avr-objcopyと呼ばれます。

ROMコンテンツは、プロジェクトのバイナリから取り出すことができ、次の個万を使って、demo.hexファイルに入れることができます。

    $ avr-objcopy -j .text -j .data -O ihex demo.elf demo.hex

結果のdemo.hexファイルのには次の内容が含まれます。

:1000000012C076C075C074C073C072C071C070C0B9
:100010001AC06EC06DC06CC06BC06AC069C068C0D9
:1000200067C066C065C011241FBECFE5D4E0DEBF47
:10003000CDBF10E0A0E6B0E001C01D92A336B1072D
:10004000E1F74DD056C01F920F920FB60F921124B8
:100050002F933F938F93809160008823C1F4209168
:100060006100309162002F5F3F4F30936200209318
:10007000610083E02F3F380709F13BBD2ABD8F9116
:100080003F912F910F900FBE0F901F9018958130C8
:1000900029F02091610030916200EFCF2091610042
:1000A0003091620021503040309362002093610013
:1000B0002115310511F710926000DFCF81E08093A8
:1000C0006000DBCF83E88FBD8EB581608EBD1BBC29
:1000D0001ABC82E087BB84E089BF78940895F2DF80
:1000E00085B7806885BF889585B78F7785BFF8CF3E
:0A00F00087CFF89400C0F894FFCF0A
:00000001FF

-jオプションは、.textと.dataセグメントから情報を得ることを指示します。もしEEPROMセグメントを指定するなら、EEPROMをプログラムするのに使用する.hexファイルを生成することができます。

    $ avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex demo.elf demo_eeprom.hex

ここでは、demo_eeprom.hexファイルは何も書かれるものはなく、空のファイルになります。

GNU binutilsのバージョン2.17からは、空のEEPROMファイルを生成するのに使用されるavr-objcopyが、.eepromセクションが空の入力であるため直ちに中止されます。それを捕らえるMakefileにエラーを知らせて、空のファイルが生成されていないことについてメッセージを表示させます。

プロジェクトをMake構築すること

何度もこれらのコマンドを入力するよりはむしろ、作るためのファイルに全てを設定することができます。デモプロジェクトの構築にmakeを使用しており、Makefileと呼ばれる以下のファイルに保存しています。

注釈:
このMakefileは、GNUバージョンのmakeの入力でのみ使用できます。
PRG            = demo
OBJ            = demo.o
#MCU_TARGET     = at90s2313
#MCU_TARGET     = at90s2333
#MCU_TARGET     = at90s4414
#MCU_TARGET     = at90s4433
#MCU_TARGET     = at90s4434
#MCU_TARGET     = at90s8515
#MCU_TARGET     = at90s8535
#MCU_TARGET     = atmega128
#MCU_TARGET     = atmega1280
#MCU_TARGET     = atmega1281
#MCU_TARGET     = atmega1284p
#MCU_TARGET     = atmega16
#MCU_TARGET     = atmega163
#MCU_TARGET     = atmega164p
#MCU_TARGET     = atmega165
#MCU_TARGET     = atmega165p
#MCU_TARGET     = atmega168
#MCU_TARGET     = atmega169
#MCU_TARGET     = atmega169p
#MCU_TARGET     = atmega2560
#MCU_TARGET     = atmega2561
#MCU_TARGET     = atmega32
#MCU_TARGET     = atmega324p
#MCU_TARGET     = atmega325
#MCU_TARGET     = atmega3250
#MCU_TARGET     = atmega329
#MCU_TARGET     = atmega3290
#MCU_TARGET     = atmega48
#MCU_TARGET     = atmega64
#MCU_TARGET     = atmega640
#MCU_TARGET     = atmega644
#MCU_TARGET     = atmega644p
#MCU_TARGET     = atmega645
#MCU_TARGET     = atmega6450
#MCU_TARGET     = atmega649
#MCU_TARGET     = atmega6490
MCU_TARGET     = atmega8
#MCU_TARGET     = atmega8515
#MCU_TARGET     = atmega8535
#MCU_TARGET     = atmega88
#MCU_TARGET     = attiny2313
#MCU_TARGET     = attiny24
#MCU_TARGET     = attiny25
#MCU_TARGET     = attiny26
#MCU_TARGET     = attiny261
#MCU_TARGET     = attiny44
#MCU_TARGET     = attiny45
#MCU_TARGET     = attiny461
#MCU_TARGET     = attiny84
#MCU_TARGET     = attiny85
#MCU_TARGET     = attiny861
OPTIMIZE       = -O2

DEFS           =
LIBS           =

# You should not have to change anything below here.

CC             = avr-gcc

# Override is only needed by avr-lib build system.

override CFLAGS        = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS       = -Wl,-Map,$(PRG).map

OBJCOPY        = avr-objcopy
OBJDUMP        = avr-objdump

all: $(PRG).elf lst text eeprom

$(PRG).elf: $(OBJ)
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)

# dependency:
demo.o: demo.c iocompat.h

clean:
        rm -rf *.o $(PRG).elf *.eps *.png *.pdf *.bak 
        rm -rf *.lst *.map $(EXTRA_CLEAN_FILES)

lst:  $(PRG).lst

%.lst: %.elf
        $(OBJDUMP) -h -S $< > $@

# Rules for building the .text rom images

text: hex bin srec

hex:  $(PRG).hex
bin:  $(PRG).bin
srec: $(PRG).srec

%.hex: %.elf
        $(OBJCOPY) -j .text -j .data -O ihex $< $@

%.srec: %.elf
        $(OBJCOPY) -j .text -j .data -O srec $< $@

%.bin: %.elf
        $(OBJCOPY) -j .text -j .data -O binary $< $@

# Rules for building the .eeprom rom images

eeprom: ehex ebin esrec

ehex:  $(PRG)_eeprom.hex
ebin:  $(PRG)_eeprom.bin
esrec: $(PRG)_eeprom.srec

%_eeprom.hex: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ \
        || { echo empty $@ not generated; exit 0; }

%_eeprom.srec: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@ \
        || { echo empty $@ not generated; exit 0; }

%_eeprom.bin: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@ \
        || { echo empty $@ not generated; exit 0; }

# Every thing below here is used by avr-libc's build system and can be ignored
# by the casual user.

FIG2DEV                 = fig2dev
EXTRA_CLEAN_FILES       = *.hex *.bin *.srec

dox: eps png pdf

eps: $(PRG).eps
png: $(PRG).png
pdf: $(PRG).pdf

%.eps: %.fig
        $(FIG2DEV) -L eps $< $@

%.pdf: %.fig
        $(FIG2DEV) -L pdf $< $@

%.png: %.fig
        $(FIG2DEV) -L png $< $@

ソースコードの参照


Automatically generated by Doxygen 1.7.2 on Wed Feb 16 2011.

翻訳更新:2011年10月12日 by cega