2009/05/20 からのアクセス回数 11577
組み込みソフトで最初のプログラムは、いつもLEDの点滅です。 Interface 2009/5月号では、LEDの点滅プログラムに割り込みを使っていましたが、 これは大きなルール違反です。
最初のプログラムは、できるだけシンプルにし、最低限の設定にしないとうまく動かなかった 時に、原因の切り分けが難しくなります。
今回のプログラムは、 nandさんのテストプログラム を参考に、Olimex のサイトにあった LED を点滅させるプログラムから、crt0.S, リンクコマンドファイル を修正し、必要最低限にカットしました。
最初に、Eclipseに組み込み用Cのプロジェクトを作成します。 File->New->C Project...を選択するか、図の用に右クリックでC Project...を選択します。
次にProjectnmae:にプロジェクト名を入力します。ここでは、sam7s-t0としました。 Project type:として、Makefile projectのEmpty Projectを選択し、-- Other Toolchain --を選択して Finishボタンを押します。
プロジェクトができたら、src.zipを解凍し、srcフォルダ以下のファイルをプロジェクトにドラッグします。
srcディレクトリには、以下のファイルが含まれています。
main.cは、非常にシンプルです。 PIO_PER, PIO_OERを設定し、2個のLEDを交互に点滅するために、PIO_CODR, PIO_SODRを設定し、 delayで時間間隔をとります。
#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は、デフォルトのルールを使って、オブジェクトファイルまでコンパイルを行い、最後の allで、ELFファイル(main.out)、バイナリファイル(main.bin)を作成します。
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は、長いのと私のフォロー範囲を超えているので、 修正したポイントだけを説明します。
crt0.Sでは、
をします。
割り込みベクトルの設定は以下のように定義しています。
/* 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:の
/* 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の 部分を修正しました。
/* 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;
通常は、EclipseのMakeを使うのですが、その都度設定するのは面倒なので、ターミナルから makeとopenocdの起動を行います。
ターミナルを起動し、プロジェクトのディレクトリに移動します。
$ cd ~/local/workspace/sam7s-t0 $ make
エラーがなければ、これでmakeは完了です。
次にEclipseでデバッガの設定をします。
RunメニューからDebug Configurations...を選択すると図のような設定画面が表示されます。
次にDebuggerタグを選択します。
最後にCommandsタグを選択します。
target remote localhost:3333をセットします。
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.cfgとして今回は、以下のようの内容を設定します。
#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です。
$ 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がデバッグ設定でできなかったので、手動でプログラムをロードします。 別のターミナルで
と、少し時間がかかりますが、以下のように出力されます。
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分ほどかかります。
ステップ実行もとても遅いですが、プログラムが期待通りに動かなかった最後の砦として、 デバッガは有効です。
このままでは、電源を切るとプログラムが消えてしまいますので、ROMへの書き込みを行います。 では、なぜRAMに書き込んでいたのでしょう。
RAMのメリットは、
RAMの欠点は
話を先にすすめて、makeの設定を変更します。
Makefileをコピーして、以下の設定を変更します
LFLAGS = -Map main.map -Tsam7s_ram.cmd
を
LFLAGS = -Map main.map -Tsam7s_rom.cmd
にします。
さらに、以下のファイルを追加します。
ここで、script.ocdのFlushへの書き込みコマンドは、openocdのバージョンに よって異なります。ご使用のバージョンに合わせて変更してください。 今回は、flash write_bank を使用しました。
# 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 clean $ make -f Makefile.rom $ openocd -f openocd-rom.cfg
書き込みが終わったら、JTAGライターをケーブルを外して、ボードの電源を入れ直してください。 LEDが点滅すれば成功です。
デバッグ設定は、RAMとROMで若干ことなります。
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を起動して、
$ openocd -f openocd.cfg
デバッグ対象として、sam7s-t0-romを選択します。
しかし、RAMと同様におそいながらも、デバッグできます。
この記事は、
皆様のご意見、ご希望をお待ちしております。