Thomas makes, writes

2007-01-01

Debugging the free_ecb_at91 board using JTAG

source: wikipedia

For a school project early 2007 (a study of embedded Linux on the AT91RM9200 ARM9 processor) I got familiar with the GNU development tools and setup required to run a Linux based operating system.

Using the setup described here I was able to inspect the inner workings of Darrell loader in real time, set hardware breakpoints, step through the program flow and inspect values of program variables while the CPU core was halted.

Hardware

I constructed a JTAG connector cable to connect the 6 pin JTAG header on the ecb_at91 board to a standard 20-pin ARM JTAG header as they are used in many boards and JTAG dongles with ARM cores. As JTAG interface I used a arm-usb-ocd dongle manufactured by Olimex.

The connections are as follows:

1
2     GREEN   VREF
3
4     BLUE    GND
5     BROWN   TDI
6
7     YELLOW  TMS
8
9     ORANGE  TCK
10
11
12
13    RED     TDO
14
...
20

I soldered a 1x6 pinheader connector to the board, and a 3 pin jumper header to manipulate the processor's JTAGSEL signal.

Software

I used a cross compiling toolchain of GCC, built using crosstool. The JTAG interfacing software side was done by OpenOCD, which speaks the GDB debug protocol.

OpenOCD configuration file

#daemon configuration
telnet_port 4444
gdb_port 3333

#interface
interface ft2232
ft2232_device_desc "Olimex OpenOCD JTAG A"
ft2232_layout "olimex-jtag"
ft2232_vid_pid 0x15BA 0x0003
jtag_speed 2

#use combined on interfaces or targets that can't set TRST/SRST separately
#reset_config trst_and_srst
reset_config none
#srst_pulls_trst

#jtag scan chain
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
jtag_device 4 0x1 0xf 0xe

#target configuration
daemon_startup reset
#target <type> <endianess> <reset mode>
target arm920t little run_and_halt 0 arm920t
working_area 0 0x200000 0x4000 backup
run_and_halt_time 0 30

GDB init

When invoking the GNU Debugger (gdb), some routine configuration steps have to be made. I put these in a file named 'gdbinit', which I source right after I invoked arm-softfloat-linux-gnu-gdb, or by starting gdb with the arguments -x gdbinit.

target remote localhost:3333
set remote hardware-watchpoint-limit 2
monitor arm7_9 force_hw_bkpts enable

This configuration has the following effect: Since the ARM9 core has support for but two hardware breakpoints, gdb has to be made aware of this, if not gdb reports an error when resuming the core after it has been halted.

Result

Behold a short summary transcript of some of the things I was able to do:

(gdb) l
280           puts("4: Start u-boot\n");
281           puts("5: Upload Filesystem image\n");
282           puts("6: Memory test\n");
283           dispmenu = 0;
284         }
285         if(tstc()){
286           key = getc();
287           autoboot = 0;
288         }
289         else
(gdb) b 282
Breakpoint 2 at 0x898: file src/board.c, line 282.
(gdb) i b
Num Type           Disp Enb Address    What
2   breakpoint     keep y   0x00000898 in start_armboot at src/board.c:282
(gdb) c
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap.
start_armboot () at src/board.c:282
282           puts("6: Memory test\n");
(gdb)

(gdb) l
139
140       puts ("Writing... ");
141
142       ptr = (int *) base;
143       for (i = 0; i < len / sizeof(int); i++)
144           *(ptr++) = i;
145
146       puts ("Reading... ");
147
148       ptr = (int *) base;
(gdb) b 140
Breakpoint 70 at 0x534: file src/board.c, line 140.
(gdb) c
Continuing.

Breakpoint 70, memory_test (base=536870912, len=16777216) at src/board.c:140
140       puts ("Writing... ");
(gdb) p ptr
$5 = (int *) 0x1000000
(gdb) d b
Delete all breakpoints? (y or n) y
(gdb) l
135     int memory_test(int base, int len)
136     {
137             int *ptr;
138       int i;
139
140       puts ("Writing... ");
141
142       ptr = (int *) base;
143       for (i = 0; i < len / sizeof(int); i++)
144           *(ptr++) = i;
(gdb) b 144
Breakpoint 71 at 0x550: file src/board.c, line 144.
(gdb) c
Continuing.

Breakpoint 71, memory_test (base=536870912, len=4194304) at src/board.c:144
144           *(ptr++) = i;
(gdb) p i
$6 = 0
(gdb) c
Continuing.

Breakpoint 71, memory_test (base=536870912, len=4194304) at src/board.c:144
144           *(ptr++) = i;
(gdb) p i
$7 = 1
(gdb) c
Continuing.

Breakpoint 71, memory_test (base=536870912, len=4194304) at src/board.c:144
144           *(ptr++) = i;
(gdb) p i
$8 = 2
(gdb)