Preparing Raspberry PI for JTAG Debugging

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:

  1. Determine the revision of your Raspberry PI board. Connect to it using SSH and run the following command:
    cat /proc/cpuinfo
  2. Use the revision table to look up the board revision. In this tutorial we will use Model B v2.0 (revision 0xe).
  3. 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:
  4. Here are the GPIO numbers for the current revision:
    JTAG pin "ALT4" mode "ALT5" mode
  5. Download Raspberry PI schematics PDF for the board revision you found out in step 2. Each JTAG pin (except TRST) can be routed to one of 2 GPIO pins. Use the schematics to find GPIO pins that are connected to the GPIO connector:
  6. We will now need to wire the selected pins from the P1 connector to a 20-pin JTAG connector. Use the JTAG-20 pinout to map the P1 pins to the JTAG-20 pins:
    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
  7. Now we can make an adapter cable that will connect the pins from the 26-pin P1 connector on Raspberry PI to the 20-pin JTAG connector. This can be done by carefully opening and detaching the 26-pin connector from a 26-pin cable and attaching the wires from the 14-pin cable to it ordered according to the table above:
  8. Each wire can be carefully pushed into the correct position using a pincette:
  9. Double-triple check your wiring. Wrong wiring/cable orientation can permanently damage your Raspberry PI, your JTAG programmer and even your PC connected to it! Test the correctness of each pin. E.g. we can test JTAG pin 3 (nTRST = GPIO22) by connecting a LED between pins 3 and 4 (4 is GND) and running the following commands in your Raspberry PI terminal over SSH:
    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':
  10. Now that we have verified that the GPIO pins are connected to correct JTAG pins we need to switch them from the GPIO mode to JTAG mode. The table above summarized the alternative function numbers that we need to select for each pin. This is done by accessing the GPFSELx registers of the BCM2835 chip. The easiest way to access them from a user-mode Linux program is by using the /dev/mem device (note that the 0x7E20xxxx addresses mentioned in the BCM2835 reference are the physical addresses. the corresponding virtual addresses are 0x2020xxxx). To do this, upload, the JtagEnabler.cpp file to your Raspberry PI, compile and run it:
    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);
  11. Now we are ready to start debugging. In this tutorial we will use a Segger J-Link programmer with the OpenOCD tool, however you can use any other supported programmer instead. Download our OpenOCD package and the USBDriverTool. Connect the J-Link programmer, launch USBDriverTool, select the J-Link device and install the WinUSB drivers for it:
  12. We're almost ready. Before we can start debugging our Raspberry PI we need to create a target configuration file for OpenOCD. The target configuration file should specify the ARM11 core, the JTAG ID of the BCM2835 chip and should set basic JTAG parameters. Create a file called raspberry.cfg in the <OpenOCD directory>\share\openocd\scripts\target directory with the following contents:
    adapter_khz 1000
    adapter_nsrst_delay 400
    reset_config none

    if { [info exists CHIPNAME] } {
    } else {
    set _CHIPNAME rspi

    if { [info exists CPU_TAPID ] } {
    } else {
    set _CPU_TAPID 0x07b7617F

    jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID

    target create $_TARGETNAME arm11 -chain-position $_TARGETNAME
    rspi.arm configure -event gdb-attach { halt }
  13. Now connect your JTAG programmer to Raspberry PI and run OpenOCD:
    cd <OpenOCD directory>\share\openocd\scripts
    ..\..\..\bin\openocd.exe -f interface/jlink.cfg -f target/raspberry.cfg
  14. 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.
  15. 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
    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.