AVR Libc Home Page AVRs AVR Libc Development Pages
Main Page FAQ Library Reference Additional Documentation Example Projects

A simple project
[Demo projects]

この時点であなたは既にGNUツールのインストールを終えていることでしょう。この章では、我々はあなたにAVRプロジェクトのGNUツールを使って小さな製作例をお見せします。この章を読み終わる頃にはあなたはこれらのツールがどのように使われ、Makefileをどのように作成するか感じが掴めるようになるでしょう。

The Project

このプロジェクトでは、パルス幅変調(PWM)を使ってLEDを2秒ごとに点滅させます。AT90S2313プロセッサを使います。この試作回路を schematic diagramに示します。 もしあなたが開発キットをお持ちなら、自作するよりはそれを使った方がよいでしょう。

Note:
AT90S2313は旧デバイスとなりました。2313後継のピンコンパチなATtiny2313や、ATmega8およびその後継のATmega48/88/168がより適切です。これらはオリジナルのデモプロジェクトができた頃から一般的になってきました??。
これらの新しいデバイスについては、外部発振子をつけてクロックを供給する必要もありません。これらのデバイスは内蔵1MHz発振子で動くように設定された状態で出荷されています。そのためC1、C2、Q1は省略可能になります。通常、この実験用と二はリセットへの外部回路も省略可能です。バイパスキャパシタ(パスコン)C4、LED、R2は必要ですのでそのままにしておいてください。 ATmega8/48/88/168については、LED接続にはPB1(DIP28パッケージではPIN15)を利用してください(OC1機能ピンがその位置にあります)。このデモはその他の多くの種類のAVRに移植できます。各々のデバイスについてのOC1機能ピンの位置は各々のAVRハードウェアに依存します。(データシートをお読みください)
demo.png

Schematic of circuit for demo project

ソースコードは demo.c です。 この例のために、 demo.c というファイルが作られます。コードの勘所としては:

Note [1]:
AVRマイクロコントローラシリーズは、年々改良を続け、いくつもの新機能が追加されています。タイマ/カウンタ1の基本的なコンセプトはこのシンプルデモが最初に書かれた2001年初頭と比べても変わっていません。しかしレジスタ名やビット名称は新しい機能のためいくらか変更があります。さらに、比較一致出力1Aに対応する出力ピンの配置については、AVRデバイスによって異なります。ファイル iocompat.hは、#ifdef節を使っていくつかのデバイスに対しこれらの違いを吸収しようと試みたものです。実際のプログラムは、シンボル名共通セット定義の上で動きます。このファイルで定義されているマクロは以下のものがあります。
Note [2]:
ISR() は割り込み関数を構成するマクロです。このケースでは、割り込み関数はタイマ1がオーバーフローしたときに呼び出されます。割り込みプログラムの書き方については <avr/interrupt.h>: Interrupts.に詳しく書かれています。
Note [3]:
PWMには10-bit modeが使われているので、現在の値を記憶するには16-bit の変数が必要です。
Note [4]:
ここで新しいPWM値を決定します。
Note [5]:
ここでは新しい計算値がPWMレジスタに書き込まれます。ここは割り込みルーチン内なので、レジスタを16bitとして読み書きすることは安全です(非分断命令)。割り込みの外部で、割り込みルーチンがこのレジスタやTEMPバッファを共用する他のレジスタを操作する可能性がある場合には、この処理は割り込み禁止にして行わなければなりません。 FAQ entry-16-bit タイマ関連レジスタが時々壊れるんですけど? もご覧ください。
Note [6]:
このルーチンはリセット後呼び出されます。PWMを初期化し、割り込みを有効にしています。
Note [7]:
このプログラムのメインループは何もしていません。すべての動作は割り込みルーチンだけで行われています!
電力削減のため、sleep_mode()で次の割り込みまでプロセッサをスリープにしています。もちろん、この電力削減はLED点灯による電力消費の前には微々たるものではあります。ここではあくまで基礎的な原則のデモンストレーションのために行ってみました。
Note [8]:
初期のAVRデバイスは、lowカレント(シンクカレント、ピンをLowにしてVccとの間で負荷をドライブする)よりも、ソースカレント(ピンをHighにしてGNDとの間で負荷をドライブする)の方が出力が飽和しやすい性質がありました。そのため、(ソースカレントで)LEDを直接接続しても電流はたかだか15mAでした(少なくともATmega128においては)。しかしながら、AtmelはIOソースドライブ能力を劇的に改選してきたため、Vcc=5Vの環境では電流制限抵抗 R2 が必要になりました。その値は150Ω程度が適切です。Vcc=3Vの場合は、現在でも制限抵抗を省略できます。

The Source Code

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <joerg@FreeBSD.ORG> がこのファイルを書きました。あなたがこのことを覚えている限り、
 * この作品を好きなように使って構いません。いつの日かお会いする機会があり、この作品が
 * あなたにとって価値があったと思ったなら、お返しにビールを一杯奢ってください!
 *                                                                Joerg Wunsch
 * ----------------------------------------------------------------------------
 *
 * 簡単なAVRのデモプログラムです。OC1/OC1AとGND間に直結したLEDをコントロールします。
 * LEDの明るさはPWMによってコントロールされます。PWM1周期毎に、PWM値は増加又は
 * 減少します。以上。
 *
 * $Id: demo.c,v 1.6.2.3 2006/01/05 21:33:08 joerg_wunsch Exp $
 */

#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] */
{
    /* TMR1を10-bit PWMで動かす(一部のATtinyデバイスでは8-bit PWM) */
    TCCR1A = TIMER1_PWM_INIT;
    /*
     *  timer 1 をスタートする。
     *
     * NB: TCCR1A と TCCR1B は同じレジスタを指すことがあり得ます。could actually be the same register, so
     * 衝突が起こらないよう注意してください。
     */
    TCCR1B |= TIMER1_CLOCKSOURCE;
    /*
     * もしあれば、デバイス依存タイマ1セットアップフックプログラムを呼び出す。
     */
#if defined(TIMER1_SETUP_HOOK)
    TIMER1_SETUP_HOOK();
#endif

    /* PWM値を0に */
    OCR = 0;

    /* OC1を出力設定に */
    DDROC = _BV (OC1);

    /* タイマ1オーバーフロー割り込み有効 */
    TIMSK = _BV (TOIE1);
    sei ();
}

int
main (void)
{

    ioinit ();

    /* 無限ループ。割り込みが残りを実行します。 */

    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プロセッサと見なしてリンクを行いますが、これはあなたが望むことじゃないでしょう。

オブジェクトファイルをチェックする

さて、バイナリファイルができました。他にやることがあるでしょうか(AVRマイコンチップに書き込みを行うこと以外)?
GNU Binutilsセットには、生成されたオブジェクトファイルを取り扱うのに有用なたくさんのツールがあります。その1つが avr-objdumpです。これはオブジェクトファイルから各種情報を取り出し、いろいろ有用な方法で情報を提示します。コマンド名だけをタイプすると、オプションのリストが表示されます。
簡単に紹介すると、できあがったアプリケーションのサイズを知りたいときは、-h optionが使えます。このオプションの出力は各 section がどれ位のメモリスペースを使っているかを表しています。(. .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         000000ec  00000000  00000000  00000094  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00800060  000000ec  00000180  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000003  00800060  00800060  00000180  2**0
                  ALLOC
  3 .noinit       00000000  00800063  00800063  00000180  2**0
                  CONTENTS
  4 .eeprom       00000000  00810000  00810000  00000180  2**0
                  CONTENTS
  5 .stab         0000078c  00000000  00000000  00000180  2**2
                  CONTENTS, READONLY, DEBUGGING
  6 .stabstr      000007ca  00000000  00000000  0000090c  2**0
                  CONTENTS, READONLY, DEBUGGING
Disassembly of section .text:

00000000 <__vectors>:
   0:	12 c0       	rjmp	.+36     	; 0x26 <__ctors_end>
   2:	73 c0       	rjmp	.+230    	; 0xea <__bad_interrupt>
   4:	72 c0       	rjmp	.+228    	; 0xea <__bad_interrupt>
   6:	71 c0       	rjmp	.+226    	; 0xea <__bad_interrupt>
   8:	70 c0       	rjmp	.+224    	; 0xea <__bad_interrupt>
   a:	6f c0       	rjmp	.+222    	; 0xea <__bad_interrupt>
   c:	6e c0       	rjmp	.+220    	; 0xea <__bad_interrupt>
   e:	6d c0       	rjmp	.+218    	; 0xea <__bad_interrupt>
  10:	11 c0       	rjmp	.+34     	; 0x34 <__vector_8>
  12:	6b c0       	rjmp	.+214    	; 0xea <__bad_interrupt>
  14:	6a c0       	rjmp	.+212    	; 0xea <__bad_interrupt>
  16:	69 c0       	rjmp	.+210    	; 0xea <__bad_interrupt>
  18:	68 c0       	rjmp	.+208    	; 0xea <__bad_interrupt>
  1a:	67 c0       	rjmp	.+206    	; 0xea <__bad_interrupt>
  1c:	66 c0       	rjmp	.+204    	; 0xea <__bad_interrupt>
  1e:	65 c0       	rjmp	.+202    	; 0xea <__bad_interrupt>
  20:	64 c0       	rjmp	.+200    	; 0xea <__bad_interrupt>
  22:	63 c0       	rjmp	.+198    	; 0xea <__bad_interrupt>
  24:	62 c0       	rjmp	.+196    	; 0xea <__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
  32:	4e c0       	rjmp	.+156    	; 0xd0 <main>

00000034 <__vector_8>:

enum { UP, DOWN };

ISR (TIMER1_OVF_vect)		/* Note [2] */
{
  34:	1f 92       	push	r1
  36:	0f 92       	push	r0
  38:	0f b6       	in	r0, 0x3f	; 63
  3a:	0f 92       	push	r0
  3c:	11 24       	eor	r1, r1
  3e:	2f 93       	push	r18
  40:	3f 93       	push	r19
  42:	8f 93       	push	r24
  44:	9f 93       	push	r25
    static uint16_t pwm;	/* Note [3] */
    static uint8_t direction;

    switch (direction)		/* Note [4] */
  46:	80 91 62 00 	lds	r24, 0x0062
  4a:	99 27       	eor	r25, r25
  4c:	00 97       	sbiw	r24, 0x00	; 0
  4e:	39 f0       	breq	.+14     	; 0x5e <__SREG__+0x1f>
  50:	01 97       	sbiw	r24, 0x01	; 1
  52:	b9 f0       	breq	.+46     	; 0x82 <__SREG__+0x43>
  54:	20 91 60 00 	lds	r18, 0x0060
  58:	30 91 61 00 	lds	r19, 0x0061
  5c:	21 c0       	rjmp	.+66     	; 0xa0 <__SREG__+0x61>
    {
        case UP:
            if (++pwm == TIMER1_TOP)
  5e:	20 91 60 00 	lds	r18, 0x0060
  62:	30 91 61 00 	lds	r19, 0x0061
  66:	2f 5f       	subi	r18, 0xFF	; 255
  68:	3f 4f       	sbci	r19, 0xFF	; 255
  6a:	30 93 61 00 	sts	0x0061, r19
  6e:	20 93 60 00 	sts	0x0060, r18
  72:	83 e0       	ldi	r24, 0x03	; 3
  74:	2f 3f       	cpi	r18, 0xFF	; 255
  76:	38 07       	cpc	r19, r24
  78:	99 f4       	brne	.+38     	; 0xa0 <__SREG__+0x61>
                direction = DOWN;
  7a:	81 e0       	ldi	r24, 0x01	; 1
  7c:	80 93 62 00 	sts	0x0062, r24
  80:	0f c0       	rjmp	.+30     	; 0xa0 <__SREG__+0x61>
            break;

        case DOWN:
            if (--pwm == 0)
  82:	20 91 60 00 	lds	r18, 0x0060
  86:	30 91 61 00 	lds	r19, 0x0061
  8a:	21 50       	subi	r18, 0x01	; 1
  8c:	30 40       	sbci	r19, 0x00	; 0
  8e:	30 93 61 00 	sts	0x0061, r19
  92:	20 93 60 00 	sts	0x0060, r18
  96:	21 15       	cp	r18, r1
  98:	31 05       	cpc	r19, r1
  9a:	11 f4       	brne	.+4      	; 0xa0 <__SREG__+0x61>
                direction = UP;
  9c:	10 92 62 00 	sts	0x0062, r1
            break;
    }

    OCR = pwm;			/* Note [5] */
  a0:	3b bd       	out	0x2b, r19	; 43
  a2:	2a bd       	out	0x2a, r18	; 42
  a4:	9f 91       	pop	r25
  a6:	8f 91       	pop	r24
  a8:	3f 91       	pop	r19
  aa:	2f 91       	pop	r18
  ac:	0f 90       	pop	r0
  ae:	0f be       	out	0x3f, r0	; 63
  b0:	0f 90       	pop	r0
  b2:	1f 90       	pop	r1
  b4:	18 95       	reti

000000b6 <ioinit>:
}

void
ioinit (void)			/* Note [6] */
{
    /* Timer 1 is 10-bit PWM (8-bit PWM on some ATtinys). */
    TCCR1A = TIMER1_PWM_INIT;
  b6:	83 e8       	ldi	r24, 0x83	; 131
  b8:	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;
  ba:	8e b5       	in	r24, 0x2e	; 46
  bc:	81 60       	ori	r24, 0x01	; 1
  be:	8e bd       	out	0x2e, r24	; 46
    /*
     * 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;
  c0:	1b bc       	out	0x2b, r1	; 43
  c2:	1a bc       	out	0x2a, r1	; 42

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

    /* Enable timer 1 overflow interrupt. */
    TIMSK = _BV (TOIE1);
  c8:	84 e0       	ldi	r24, 0x04	; 4
  ca:	89 bf       	out	0x39, r24	; 57
    sei ();
  cc:	78 94       	sei
  ce:	08 95       	ret

000000d0 <main>:
}

int
main (void)
{
  d0:	cf e5       	ldi	r28, 0x5F	; 95
  d2:	d4 e0       	ldi	r29, 0x04	; 4
  d4:	de bf       	out	0x3e, r29	; 62
  d6:	cd bf       	out	0x3d, r28	; 61

    ioinit ();
  d8:	ee df       	rcall	.-36     	; 0xb6 <ioinit>

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

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

000000ea <__bad_interrupt>:
  ea:	8a cf       	rjmp	.-236    	; 0x0 <__heap_end>

リンカマップファイル

avr-objdump はとても有用ですが、時にリンカによって生成されるリンクに関する情報が必要になることがあります。"Map file"はこれらの情報を含んでいます。マップファイルはあなたが作ったコードやデータのサイズをモニタするのに有用です。また、各モジュールがどこにロードされたか、ライブラリのどのモジュールがロードされたかを教えてくれます。これはあなたのアプリケーションに対し別の視点を与えてくれます。マップファイルを得るために、私は通常-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       0xec
 *(.vectors)
 .vectors       0x00000000       0x26 /junk/AVR/avr-libc-1.4/avr/lib/avr4/atmega8/crtm8.o
                0x00000000                __vectors
                0x00000000                __vector_default
                0x00000026                __ctors_start = .

.text ステートメント (プログラム命令が保存されるところ) は0番地から始まっています。

 *(.fini2)
 *(.fini1)
 *(.fini0)
                0x000000ec                _etext = .

.data           0x00800060        0x0 load address 0x000000ec
                0x00800060                PROVIDE (__data_start, .)
 *(.data)
 *(.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
 *(COMMON)
                0x00800063                PROVIDE (__bss_end, .)
                0x000000ec                __data_load_start = LOADADDR (.data)
                0x000000ec                __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 で示されています)。命令は フラッシュを276バイト使っています。

.data セグメント(static指定された初期化されている変数が保存されている)は0x60番地から始まっている。これはATmega8 プロセッサのI/Oレジスタがある場所の直後にあたります。

.data セグメントの次の利用可能アドレス(※ここでは次の.bss) もまた0x60である。このアプリケーションは初期化済みデータを持たないようです。

.bss セグメント (初期化されないデータが保存されている場所) は0x60番地から始まっています。

.bss セグメントの次の利用可能なアドレスは0x63です。アプリケーションは3バイトの初期化されていないデータを持つことがわかります。

.eeprom セグメント(EEPROM上変数が保存されるところ)は0x00番地から始まっています。

.eeprom セグメントの次の利用可能なアドレスもまた0x00番地です。このアプリケーションはEEPROM上変数を使っていないようです。

Intel Hex ファイル( .hex ファイル)

さて、バイナリ形式のアプリケーションができました。しかしこれをどうやってプロセッサに書き込めばいいのでしょうか?多くの(すべてではない)プログラマ(書き込み器)はGNUの実行形式ファイルを受け付けてくれません。そこで、もう少し加工してやる必要があります。次のステップは実行されるバイナリ部分を取り出し、 .hex 形式ファイルに納めることです。GNU ユーティリティは avr-objcopy というツールでそれを行います。
以下のコマンドにより、ROMに納めるべき内容が私たちのプロジェクトのバイナリ出力から取り出され、demo,hexファイルに書き込まれます。
    $ avr-objcopy -j .text -j .data -O ihex demo.elf demo.hex

demo.hex ファイルの中身です。(※テキストファイルです)

:1000000012C073C072C071C070C06FC06EC06DC0CE
:1000100011C06BC06AC069C068C067C066C065C0F7
:1000200064C063C062C011241FBECFE5D4E0DEBF50
:10003000CDBF4EC01F920F920FB60F9211242F9377
:100040003F938F939F93809162009927009739F097
:100050000197B9F0209160003091610021C020919A
:100060006000309161002F5F3F4F3093610020931B
:10007000600083E02F3F380799F481E080936200AD
:100080000FC02091600030916100215030403093CA
:100090006100209360002115310511F41092620077
:1000A0003BBD2ABD9F918F913F912F910F900FBE25
:1000B0000F901F90189583E88FBD8EB581608EBD1F
:1000C0001BBC1ABC82E087BB84E089BF789408958A
:1000D000CFE5D4E0DEBFCDBFEEDF85B7806885BF5A
:0C00E000889585B78F7785BFF8CF8ACF51
:00000001FF

-j .text -j .data オプションは .text と .data セグメントから抽出した情報を出力するよう指示します。もしEEPROMセグメント指定すれば、EEPROMに書き込むための .hex ファイルが得られます。

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

これによって得られたdemo_eeprom.hex の中身です。

:00000001FF

これは中身が空っぽの .hex ファイルです。(我々はEEPROM変数を指定しなかったのですから、これは予想されることです)

プロジェクトをMake Buildする

これらのコマンドを繰り返し打ち込むより、makefileに置き換えてしまった方がいいです。デモプロジェクトをmakeを使って組み立てるには、まず以下のような内容をMakefileとして保存します。
※ makefileは現在のavrgcc(少なくとも20040720版以降)では、Mfileという便利なツールで自動生成することができるようになりました。 WinAVRの標準インストールではデスクトップにショートカットができています。
Note:
この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     = atmega16
#MCU_TARGET     = atmega163
#MCU_TARGET     = atmega164
#MCU_TARGET     = atmega165
#MCU_TARGET     = atmega168
#MCU_TARGET     = atmega169
#MCU_TARGET     = atmega32
#MCU_TARGET     = atmega324
#MCU_TARGET     = atmega325
#MCU_TARGET     = atmega3250
#MCU_TARGET     = atmega329
#MCU_TARGET     = atmega3290
#MCU_TARGET     = atmega48
#MCU_TARGET     = atmega64
#MCU_TARGET     = atmega644
#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 $< $@

%_eeprom.srec: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@

%_eeprom.bin: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@

# 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.4.1 on 23 Jan 2006.