#freeze
[[FrontPage]]

2009/05/20 からのアクセス回数 &counter;

#contents

** サンプルプログラム [#qbca2fe2]
組み込みソフトで最初のプログラムは、いつもLEDの点滅です。
Interface 2009/5月号では、LEDの点滅プログラムに割り込みを使っていましたが、
これは大きなルール違反です。

最初のプログラムは、できるだけシンプルにし、最低限の設定にしないとうまく動かなかった
時に、原因の切り分けが難しくなります。

今回のプログラムは、
[[nandさんのテストプログラム>http://homepage.mac.com/nand/hacks/olimex-sam7p64.html]]
を参考に、Olimex のサイトにあった LED を点滅させるプログラムから、crt0.S, リンクコマンドファイル
を修正し、必要最低限にカットしました。

** Eclipseプロジェクトの作成 [#we68027a]
最初に、Eclipseに組み込み用Cのプロジェクトを作成します。
File->New->C Project...を選択するか、図の用に右クリックでC Project...を選択します。

&ref(eclipse-1.jpg);

次にProjectnmae:にプロジェクト名を入力します。ここでは、sam7s-t0としました。
Project type:として、Makefile projectのEmpty Projectを選択し、-- Other Toolchain --を選択して
Finishボタンを押します。

&ref(eclipse-2.jpg);

プロジェクトができたら、&ref(src.zip);を解凍し、srcフォルダ以下のファイルをプロジェクトにドラッグします。

** ファイルの説明 [#fee86a45]
srcディレクトリには、以下のファイルが含まれています。

- AT91SAM7S64.h: sam7sのヘッダファイルです(Olimexのサンプルから引用)
- crt0.S: Cルート0呼びます。Cのmain関数を呼ぶための前処理をします(Olimexのサンプルを修正)
- main.c: Cのメインプログラムです(nandさんのプログラムから修正)
- Makefile: makeコマンド用の設定ファイルです(nandさんのプログラムから修正)
- sam7s_ram.cmd: リンク用のコマンドファイルで、RAM用のプログラムを作成します(Olimexのサンプルを修正)

*** main.c [#d86c5351]
main.cは、非常にシンプルです。
PIO_PER, PIO_OERを設定し、2個のLEDを交互に点滅するために、PIO_CODR, PIO_SODRを設定し、
delayで時間間隔をとります。

#pre{{
#include "AT91SAM7S64.h"

#define	DELAY_COUNT	5769	// for 18.432MHz (original 6000000 for 48MHz)
void delay(int n);

int main() {
	AT91C_BASE_PIOA->PIO_PER = (1 << 17) | (1 << 18);
	AT91C_BASE_PIOA->PIO_OER = (1 << 17) | (1 << 18);

	for (;;) {
		AT91C_BASE_PIOA->PIO_CODR = (1 << 18);
		AT91C_BASE_PIOA->PIO_SODR = (1 << 17);
		delay(DELAY_COUNT);
		AT91C_BASE_PIOA->PIO_SODR = (1 << 18);
		AT91C_BASE_PIOA->PIO_CODR = (1 << 17);
		delay(DELAY_COUNT);
	}
}

void delay(int n) {
	while (--n)
		;
}
}}

*** Makefile [#e55540e2]
Makefileは、デフォルトのルールを使って、オブジェクトファイルまでコンパイルを行い、最後の
allで、ELFファイル(main.out)、バイナリファイル(main.bin)を作成します。


- 最初に、使用するコマンドを定義しています。
- ファイルを追加する場合には、OBJECTSに追加したファイルのオブジェクトファイル名を追加します。

#pre{{
CC = /opt/local/bin/arm-elf-gcc
AS = /opt/local/bin/arm-elf-as
LD = /opt/local/bin/arm-elf-ld -v
CP = /opt/local/bin/arm-elf-objcopy
OD = /opt/local/bin/arm-elf-objdump

CFLAGS	= -march=armv4t -mthumb -g
ASFLAGS = -Wa,-mthumb
LFLAGS	= -Map main.map -Tsam7s_ram.cmd

OBJECTS	= crt0.o main.o

all: crt0.o main.o
	$(LD)  $(LFLAGS) -o main.out -Map main.map $(OBJECTS)
	$(CP) -j .text -j .data -O binary main.out main.bin
	$(OD) -x --syms main.out > main.dmp

main.o: main.c

crt0.o: crt0.S

clean:
	rm -f $(OBJECTS) main.out main.bin main.map main.dmp
}}

*** crt0.S, sam7s_ram.cmd [#da412e52]
crt0.S, sam7s_ram.cmdは、長いのと私のフォロー範囲を超えているので、
修正したポイントだけを説明します。

crt0.Sでは、
- 割り込みベクトルの設定
- グローバル変数のRAM領域へのコピー

をします。

割り込みベクトルの設定は以下のように定義しています。
#pre{{
/* identify all GLOBAL symbols  */
.global _vec_reset
.global _vec_undef
.global _vec_swi
.global _vec_pabt
.global _vec_dabt
.global _vec_rsv
.global _vec_irq
.global _vec_fiq
.global AT91F_Irq_Handler
.global	AT91F_Default_FIQ_handler
.global	AT91F_Default_IRQ_handler
}}

グローバル変数のRAM領域へのコピーは、_init_reset:の
#pre{{
		/* copy initialized variables .data section  (Copy from ROM to RAM) */
                ldr     R1, =_etext
                ldr     R2, =_data
                ldr     R3, =_edata
1:        		cmp     R2, R3
                ldrlo   R0, [R1], #4
                strlo   R0, [R2], #4
                blo     1b
}}
のように定義しています。

sam7s_ram.cmdは、リンク用のコマンドで、MEMORY定義と_stack_endの
部分を修正しました。

#pre{{
/* specify the AT91SAM7S64  memory areas  */
MEMORY 
{
	flash	: ORIGIN = 0,          LENGTH = 256K	/* FLASH EPROM		*/	
	ram		: ORIGIN = 0x00200000, LENGTH = 64K  	/* static RAM area	*/
}

/* define a global symbol _stack_end  (see analysis in annotation above) */
_stack_end = 0x0000FFFC;
}}

** makeとデバッグ [#zd15abac]
通常は、EclipseのMakeを使うのですが、その都度設定するのは面倒なので、ターミナルから
makeとopenocdの起動を行います。

*** make [#lef24789]
ターミナルを起動し、プロジェクトのディレクトリに移動します。

#pre{{
$ cd ~/local/workspace/sam7s-t0
$ make
}}

エラーがなければ、これでmakeは完了です。

** デバッグ設定 [#k535c68f]
次にEclipseでデバッガの設定をします。

RunメニューからDebug Configurations...を選択すると図のような設定画面が表示されます。

- Zyling Embedded debug (Native)を選択し、右クリックでNewを選択する
- Name: デバッグ設定名称をつけます、ここではsam7s-t0-ramとします。
- Project: sam7s-t0を選択します。
- C/C++ Application: main.outを指定します。

&ref(debug-1.jpg);

次にDebuggerタグを選択します。
- GDB debugger: gdbの場所を指定します、ここでは/opt/local/arm-elf/bin/arm-elf-gdbを指定しました。
- Use full file path to set breakpointsを選択します。

&ref(debug-2.jpg);

最後にCommandsタグを選択します。
- initialize commands
 target remote localhost:3333
をセットします。
- Run commandsに
#pre{{
monitor soft_reset_halt 
monitor armv4_5 core_state arm 
monitor mww 0xffffff60 0x00320100 
monitor mww 0xfffffd44 0xa0008000 
monitor mww 0xfffffc20 0xa0000601 
monitor wait 100 
monitor mww 0xfffffc2c 0x00480a0e 
monitor wait 200 
monitor mww 0xfffffc30 0x7 
monitor wait 100 
monitor mww 0xfffffd08 0xa5000401 
set remote memory-write-packet-size 1024 
set remote memory-write-packet-size fixed 
set remote memory-read-packet-size 1024 
set remote memory-read-packet-size fixed 
monitor mww 0xfffffd00 0xa5000004 
monitor mww 0xffffff00 0x01 
monitor reg pc 0x00000000 
monitor arm7_9 sw_bkpts enable
#load
continue
}}
をセットします。

通常は、最後に
 load
をしていするのですが、USB Blasterのドライバーがわるいのか、途中でエラーになってしまいますので、
#でコメントアウトしています。

これで、Closeを選択して設定を保存します。

** Openocdの起動とデバッグ [#r919e7d1]
openocd.cfgとして今回は、以下のようの内容を設定します。
#pre{{
#define our ports
telnet_port 4444
gdb_port 3333

#commands specific to the USB Blaster
interface usb_blaster
usb_blaster_vid_pid 0x09fb 0x6001

#reset_config <signals> [combination] [trst_type] [srst_type]
reset_config srst_only srst_pulls_trst

#jtag_device <IR length> <IR capture> <IR mask> <IDCODE instruction>
jtag_device 4 0x1 0xf 0xe

#daemon_startup <'attach'|'reset'>
daemon_startup reset

#target <type> <endianess> <reset_mode> <jtag#> [variant]
target arm7tdmi little run_and_init 0 arm7tdmi_r4

#working_area <target#> <address> <size> <'backup'|'nobackup'> 
working_area 0 0x00200000 0x4000 nobackup

#run_and_halt_time <target#> <time_in_ms>
run_and_halt_time 0 30
}}

ターミナルからopenocdを起動します、以下のようにデバイスを認識すればOKです。
#pre{{
$ openocd -f openocd.cfg
Open On-Chip Debugger 1.0 (2009-04-13-07:33) svn:753M
$URL: svn://svn.berlios.de/openocd/trunk/src/openocd.c $
Info:    options.c:50 configuration_output_handler(): Open On-Chip Debugger 1.0 (2009-04-13-07:33) svn:753M
Info:    jtag.c:1403 jtag_examine_chain(): JTAG device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
}}

loadがデバッグ設定でできなかったので、手動でプログラムをロードします。
別のターミナルで
- telnet localhost 4444と入力
- load_image main.outでロードコマンドを入力する

と、少し時間がかかりますが、以下のように出力されます。

#pre{{
term-2 $  telnet localhost 4444
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying fe80::1...
telnet: connect to address fe80::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> load_image main.out
388 byte written at address 0x00200000
downloaded 388 byte in 22.681808s
> 
}}

最後にEclipseのDebugを実行します。

指定したブレークポイントで止まればOKです。USB Blasterのドライバーとても遅く、1分ほどかかります。

ステップ実行もとても遅いですが、プログラムが期待通りに動かなかった最後の砦として、
デバッガは有効です。

&ref(debug-4.jpg);

** ROMへの書き込み [#l22c9448]
このままでは、電源を切るとプログラムが消えてしまいますので、ROMへの書き込みを行います。
では、なぜRAMに書き込んでいたのでしょう。

RAMのメリットは、
- ブレークポイントが自由に設定できる、ROMの場合同時に2個までしか設定できない。
- RAMの方が動作が速い(と言われています)

RAMの欠点は
- プログラム領域までRAMに書き込むため、大きなプログラムを書き込めない

*** makeの変更 [#k1ada3c5]
話を先にすすめて、makeの設定を変更します。

Makefileをコピーして、以下の設定を変更します
 LFLAGS	= -Map main.map -Tsam7s_ram.cmd
を
 LFLAGS	= -Map main.map -Tsam7s_rom.cmd

にします。

さらに、以下のファイルを追加します。
- &ref(openocd-rom.cfg); : ROMへの書き込み用Openocdスクリプト
- &ref(sam7s_rom.cmd); : ROM用のリンクコマンド
- &ref(script.ocd); : 書き込みようスクリプト

ここで、script.ocdのFlushへの書き込みコマンドは、openocdのバージョンに
よって異なります。ご使用のバージョンに合わせて変更してください。
今回は、flash write_bank を使用しました。
#pre{{
# flash write 0 main.bin 0x0
# flash write is deprecated and my not be available in your OpenOCD-version, update to: 
# flash write_binary 0 main.bin 0x0
# flash write_binary is deprecated and my not be available in your OpenOCD-version, update to:
flash write_bank 0 main.bin 0x0
}}

*** makeと書き込み [#c4addedb]
準備ができたので、ターミナルから以下のコマンドを実行します。

#pre{{
$ make clean
$ make -f Makefile.rom
$ openocd -f openocd-rom.cfg 
}}

書き込みが終わったら、JTAGライターをケーブルを外して、ボードの電源を入れ直してください。
LEDが点滅すれば成功です。

*** ROM版のデバッグ [#i5cb95d4]
デバッグ設定は、RAMとROMで若干ことなります。

- デバッグ設定を複製して、sam7s-t0-romとします。
- CommandsタグをのRun commandsを以下のように変更します。
#pre{{
monitor soft_reset_halt 
monitor armv4_5 core_state arm 
monitor mww 0xffffff60 0x00320100 
monitor mww 0xfffffd44 0xa0008000 
monitor mww 0xfffffc20 0xa0000601 
monitor wait 100 
monitor mww 0xfffffc2c 0x00480a0e 
monitor wait 200 
monitor mww 0xfffffc30 0x7 
monitor wait 100 
monitor mww 0xfffffd08 0xa5000401 
set remote memory-write-packet-size 1024 
set remote memory-write-packet-size fixed 
set remote memory-read-packet-size 1024 
set remote memory-read-packet-size fixed 
monitor arm7_9 force_hw_bkpts enable 
symbol-file main.out 
continue  
}}

では、ターミナルでopenocdを起動して、
#pre{{
$ openocd -f openocd.cfg 
}}

デバッグ対象として、sam7s-t0-romを選択します。

- 動作が、ちょっと不安定?なのか、点滅の動作がスムーズではありません。

しかし、RAMと同様におそいながらも、デバッグできます。

&ref(board.jpg);

** コメント [#za87c24f]
この記事は、

#vote(おもしろかった[6],そうでもない[0],わかりずらい[0])
#vote(おもしろかった[7],そうでもない[0],わかりずらい[0])

皆様のご意見、ご希望をお待ちしております。

#comment_kcaptcha

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
SmartDoc