This tutorial shows how to prepare your Raspberry PI board for debugging with JTAG. Using JTAG will allow debugging the Linux kernel using hardware like Segger J-Link. As Raspberry PI board does not have a connector with a normal JTAG layout, preparing the board for JTAG debugging involves finding the correct pins and wiring them in the correct order. Follow the steps below for a complete walkthrough:
cat /proc/cpuinfo
Use the revision table to look up the board revision. In this tutorial we will use Model B v2.0 (revision 0xe).
In order to find which pins on the board are JTAG pins we need to first find the GPIO numbers that correspond to them. JTAG requires 4 pins: TDI, TDO, TMS and TCK plus TRST and RTCK pins. Get the peripheral datasheet for BCM2835, the microcontroller used by the Raspberry PI board. Search for "_TCK" to find the GPIO number table:
JTAG pin | "ALT4" mode | "ALT5" mode |
TDI | GPIO26 | GPIO4 |
TDO | GPIO24 | GPIO5 |
TMS | GPIO27 | GPIO12 |
TCK | GPIO25 | GPIO13 |
RTCK | GPIO23 | GPIO6 |
TRST | GPIO22 | N/A |
JTAG-20 pin | JTAG signal | GPIO pin | ALT mode | P1 pin |
1 | VREF | N/A | N/A | 1 |
3 | nTRST | GPIO22 | ALT4 | 15 |
4 | GND | N/A | N/A | 9 |
5 | TDI | GPIO4 | ALT5 | 7 |
7 | TMS | GPIO27 | ALT4 | 13 |
9 | TCK | GPIO25 | ALT4 | 22 |
11 | RTCK | GPIO23 | ALT4 | 16 |
13 | TDO | GPIO24 | ALT4 | 18 |
cd /sys/class/gpio
echo 22 > export
cd gpio22
echo out > direction
echo 1 > value
This will turn on the LED until we run 'echo 0 > value':
g++ -o JtagEnabler JtagEnabler.cpp
sudo ./JtagEnabler
Below is the code responsible for setting the alternative functions for all affected pins:
GpioFunctionSelector selector;
selector.SetGPIOFunction(22, GPIO_ALT_FUNCTION_4);
selector.SetGPIOFunction(4, GPIO_ALT_FUNCTION_5);
selector.SetGPIOFunction(27, GPIO_ALT_FUNCTION_4);
selector.SetGPIOFunction(25, GPIO_ALT_FUNCTION_4);
selector.SetGPIOFunction(23, GPIO_ALT_FUNCTION_4);
selector.SetGPIOFunction(24, GPIO_ALT_FUNCTION_4);
adapter_khz 1000
adapter_nsrst_delay 400
reset_config none
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME rspi
}
if { [info exists CPU_TAPID ] } {
set _CPU_TAPID $CPU_TAPID
} else {
set _CPU_TAPID 0x07b7617F
}
jtag newtap $_CHIPNAME arm -irlen 5 -expected-id
$_CPU_TAPID
set _TARGETNAME $_CHIPNAME.arm
target create $_TARGETNAME arm11 -chain-position
$_TARGETNAME
rspi.arm configure -event gdb-attach { halt }
cd <OpenOCD directory>\share\openocd\scripts
..\..\..\bin\openocd.exe -f interface/jlink.cfg -f target/raspberry.cfg
There is a bug in OpenOCD that will prevent Raspberry PI from continuing correctly after a stop unless the initialization is done twice. Close OpenOCD with Ctrl-C and re-run it again. Now the debugging will be usable.
By default OpenOCD opens port 3333 for GDB connections. Start GDB, connect to OpenOCD and test the connection by displaying disassembly and stepping over one instruction:
target remote :3333
x/10i $pc
stepi
x/2i $pc
If stepping over an instruction actually puts you on the next instruction, the JTAG debugging is working. In order to have a meaningful debugging session you will need to rebuild the Raspberry PI kernel and use the symbols obtained during build to debug. Follow the kernel build tutorial to learn about it.
Remember, after you reboot your Raspberry PI you'll need to start OpenOCD, exit it with Ctrl-C and then start it again, otherwise the target won't be resumed correctly after a stop.