This tutorial shows how to prepare your Raspberry PI board for debugging with JTAG (we have tested this with Raspberry Pi 1, 2, 3 and 4). 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:
- Determine the revision of your Raspberry PI board. Connect to it using SSH and run the following command:
- Use the revision table to look up the board revision. In this tutorial we will use Model B v2.0 (revision 0xe), however the same schematics also works for Raspberry Pi 3 and Raspberry Pi 4.
- 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. You can find the GPIO pins corresponding to these in the datasheet for BCM2835 (Raspberry Pi 1-3) or BCM2711 (Raspberry Pi 4). Search for “_TCK” to find the GPIO number table:
- Here are the GPIO numbers for the current revision:
JTAG pin “ALT4” mode “ALT5” mode
(Raspberry Pi 1-3 only)
TDI GPIO26 GPIO4 TDO GPIO24 GPIO5 TMS GPIO27 GPIO12 TCK GPIO25 GPIO13 RTCK GPIO23 GPIO6 TRST GPIO22 N/A
- 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:
- 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 (Rpi 1-3)
GPIO26 (Rpi Pi 4)
ALT5 (Rpi Pi 1-3)
ALT4 (Rpi Pi 4)
7 (Rpi 1-3)
37 (Rpi 4)
7 TMS GPIO27 ALT4 13 9 TCK GPIO25 ALT4 22 11 RTCK GPIO23 ALT4 16 13 TDO GPIO24 ALT4 18
- 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:
- Each wire can be carefully pushed into the correct position using a pincette:
- 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’:
- The easiest way to test out the JTAG connection is to create a kernel module project with VisualKernel that can configure and verify the JTAG setup automatically:Alternatively you can follow the steps below to check your JTAG connection manually.
Checking the JTAG connection manually
- 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. On Raspberry Pi 1-3, 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 1-3 (not 4!), 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);
Note that if you are using Raspberry Pi 3, you would need to change the peripheral base address from 0x20000000 to 0x3f000000.
On Raspberry Pi 4 (BCM2711 chip), setting the GPFSELx registers is not sufficient to enable JTAG debugging. Instead, you need to add the following line to the /boot/config.txt file:
This will both configure the pins, and enable the JTAG module on the BCM2711 chip. Make sure it is added before the model-specific sections (e.g. [pi4]) or inside the [all] section. You can also add model-specific sections to use GPIO4 for TDI on Raspberry Pi 1-3 and GPIO26 on Raspberry Pi 4:
[all] enable_jtag_gpio=1 gpio=22-27=a4 [pi1] gpio=4=a5 [pi2] gpio=4=a5 [pi3] gpio=4=a5
- 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 theUSBDriverTool. Connect the J-Link programmer, launch USBDriverTool, select the J-Link device and install the WinUSB drivers for it:
- 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 correct ARM core, set the the JTAG ID and configure multi-core debugging so that GDB doesn’t break the target. You download configuration files for Raspberry Pi 1-4 boards tested with Linux kernel debugging here:
- 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
- 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.