Setup OpenOCD with JTAG + UART on raspberry pi 4 using FT232H

Setup OpenOCD with JTAG + UART on raspberry pi 4 using FT232H

Hello everyone. On today's blog, I'll tell you about how to setup JTAG + Serial connection on the Raspberry pi 4B and configure OpenOCD to debug the RPi4b. Be sure to follow every line or you might end in problem ;)

Pre-requisite Material

Hardwares

  1. Raspberry Pi 4B [of course we need it ;) ]
  2. FT232H based FTDI module
  3. CH340G module or any other serial capable module
  4. Jumper wires
  5. USB extension if you don't have many USB port [ Like me :( ]
    1. Softwares

      1. Minicom, picocom, tio, screen or any other terminal emulator which can access serial devices
      2. OpenOCD for accessing target and interfaces
      3. GDB, prefrebably the aarch64-none-elf-gdb gdb
      4. telnet [ We are back to stone-age boizz ]
      5. Setting up Serial connection using CH340G USB to TTL module

        CH340G is a cheap USB to TTL module which support baud rate from 50 to 2000000 bps. You can get it for around ~$2 on Aliexpress or your local electronic shop. Although keep in mind, that this module doesn't have a DTR pin but a little hack, you can add one. Read more about it here.

        Raspberry Pi has two in-built UART which are as follows:

        • PL011
        • mini UART

        We'll be using PL011 instead of the primary mini-UART because of the following reason: Mini UART uses the frequency which is linked to the core frequency of GPU, so whenever the GPU frequency changes, UART baud rate changes too. This makes the mini UART unstable which may lead to data loss or corruption. The PL011 UART on the other hand, has a fixed fixed frequency which doesnt change. Although frequency of mini-UART can fixed by adding gpu_freq = 250 or 500, in the config.txt. PL011 is 16650 compatible UART, This controller also includes other features not present in the mini UART controller such as framing error detection, break detection, receive timeout interrupts and parity bit support.

        Enable serial connection on raspberry pi 4B

        open config.txt file in the boot partition of the SD card and append the following at the bottom.

        dtoverlay = disable-bt

        enable_uart=1

        open cmdline.txt file in the boot partition of the SD card and append the following at the starting of line. Keep in mind about the spaces.

        console=serial0,115200 console=tty1

        Connection

        Serial connection goes from:

        CH340G TX <->GPIO 15 (RX)

        CH340G RX <-> GPIO 14 (RX)

        GND <-> GND

        UART friting.png Note: This is a generic img I could find similar to CH340G

        Attaching to terminal

        You can check out if the USB is connected or not by using lsusb. It should show something like :

        ...
        Bus 001 Device 007: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
        ...
        

        In order to check which port your serial device is connected to, we can use dmesg. It should show something like this

        ...
        [ 2027.884884] ch341 1-3:1.0: ch341-uart converter detected
        [ 2027.885573] usb 1-3: ch341-uart converter now attached to ttyUSB0
        

        in my case it is /dev/ttyUSB0, so now I'll attach my terminal with serial using screen, picocom, tio or any of your choice.

        sudo screen /dev/ttyUSB0 115200 
                       or
        sudo picocom -b 115200 /dev/ttyUSB0
                       or
        sudo tio -b 115200 /dev/ttyUSB0
        

        Setting up JTAG connection using FT232H module.

        This chip from FTDI is similar to their USB to serial converter chips but adds a 'multi-protocol synchronous serial engine (MPSSE)' which allows it to speak many common protocols like SPI, I2C, serial UART, JTAG, and many more. There's even some additional digital GPIO pins that you can read and write to do things like flash LEDs, read switches or buttons, and more. For here, we are only only focusing on JTAG (MPSSE) mode. I'll be using a generic CJMCU FT232H module which I got for ~$15 from local electronic shop.

        You might wonder what these led near the power led would do, even though they are not blinking. These leds needs to be setup first in order to see them blink. These are used for async communication like the serial protocol. You can get more info about this board on shukran github page.

        Enable JTAG on Raspberry pi 4B

        The Raspberry Pi 4 doesn't have dedicated JTAG pins. Instead, you must configure the GPIO pins (GPIO22-GPIO27) to activate the JTAG functionality. The RPi 4 documentation refers to this as Alt4 functions of those pins. Alt5 does exist too, which goes from GPIO4, 5, 6, 12 and 13. you can check this out from pinout.xyz or eLinux. In the end you should see a screen like this.

        One more thing to note on JTAG with Raspberry pi 4B is that, by default, All the GPIO pins are pulled down, according to the BCM2711 documentation (see this). So in order to let the data flow freely, we will have to disable them. In the config.txt in the boot partition of SD card, append the following at the bottom.

        # Disable pull downs
        gpio=22-27=np
        
        # Enable jtag pins (i.e. GPIO22-GPIO27)
        enable_jtag_gpio=1
        

        Connection

        TCK (GPIO 25) <-> D0

        TDI (GPIO 26) <-> D1

        TDO (GPIO 24) <-> D2

        TMS (GPIO 27) <-> D3

        TRST (GPIO 22) <-> D4

        SRST (NC) <-> NC

        RTCK (GPIO 23) <-> D7

        JTAG.png

        Note: D0-D7 refers to ADBUS0-ADBUS7 on the documentation of FT232H

        Note: I could not find CJMCU FT232H module but the adafruit FT232H is similar to that

        You can check out if the USB is connected or not by lsusb It should show something like :

        ...
        Bus 001 Device 009: ID 0403:6014 Future Technology Devices International, Ltd FT232H Single HS USB-UART/FIFO IC
        ...
        

        Attaching with OpenOCD

        Installing OpenOCD

        For building OpenOCD, I would recommed to follow the steps given on this guide.

        OpenOCD configuration

        For FT232H, I would recommend the following configuration. This can be stored under the interface folder or anywhere you want.

        # config file for generic FT232H based USB-serial adaptor
        # TCK:  D0
        # TDI:  D1
        # TDO:  D2
        # TMS:  D3
        # TRST: D4
        # SRST: D5
        # RTCK: D7
        
        adapter speed 3000
        
        # Setup driver type
        adapter driver ftdi
        
        # Common PID for FT232H
        ftdi vid_pid 0x0403 0x6014
        
        ftdi layout_init 0x0078 0x017b
        
        # Set sampling to allow higher clock speed
        ftdi_tdo_sample_edge falling
        
        ftdi layout_signal nTRST -ndata 0x0010 -noe 0x0040
        ftdi layout_signal nSRST -ndata 0x0020 -noe 0x0040
        
        # change this to 'transport select swd' if required
        transport select jtag
        
        # references
        # http://sourceforge.net/p/openocd/mailman/message/31617382/
        # http://www.baremetaldesign.com/index.php?section=hardware&hw=jtag
        

        For the raspberry pi 4B configuration, I would recommend the default which comes with OpenOCD. This is stored under the target folder.

        # SPDX-License-Identifier: GPL-2.0-or-later
        
        # The Broadcom BCM2711 used in Raspberry Pi 4
        # No documentation was found on Broadcom website
        
        # Partial information is available in raspberry pi website:
        # https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/
        
        if { [info exists CHIPNAME] } {
            set  _CHIPNAME $CHIPNAME
        } else {
            set  _CHIPNAME bcm2711
        }
        
        if { [info exists CHIPCORES] } {
            set _cores $CHIPCORES
        } else {
            set _cores 4
        }
        
        if { [info exists USE_SMP] } {
            set _USE_SMP $USE_SMP
        } else {
            set _USE_SMP 0
        }
        
        if { [info exists DAP_TAPID] } {
            set _DAP_TAPID $DAP_TAPID
        } else {
            set _DAP_TAPID 0x4ba00477
        }
        
        jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4
        adapter speed 3000
        
        dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
        
        # MEM-AP for direct access
        target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0
        
        # these addresses are obtained from the ROM table via 'dap info 0' command
        set _DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000}
        set _CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000}
        
        set _smp_command "target smp"
        
        for { set _core 0 } { $_core < $_cores } { incr _core } {
            set _CTINAME $_CHIPNAME.cti$_core
            set _TARGETNAME $_CHIPNAME.cpu$_core
        
            cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core]
            target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME
        
            set _smp_command "$_smp_command $_TARGETNAME"
        }
        
        if {$_USE_SMP} {
            eval $_smp_command
        }
        
        # default target is cpu0
        targets $_CHIPNAME.cpu0
        

        Connect the JTAG cable to the desktop computer. On Linux, either you should use openocd with sudo, or adjust the udev rules to access the device without sudo. I am using it with sudo. OpenOCD requires 2 -f arguments, one for the target device, and one for the interface device. Invoke OpenOCD by

        sudo openocd -f interface/ftdi/cjmcu-ft232h.cfg -f target/bcm2711.cfg

        On a successful connection, you'll see a screen like below:

        Open On-Chip Debugger 0.11.0+dev-00698-gcc8b49185 (2022-06-01-19:06)
        Licensed under GNU GPL v2
        For bug reports, read
            http://openocd.org/doc/doxygen/bugs.html
        jtag
        Info : Listening on port 6666 for tcl connections
        Info : Listening on port 4444 for telnet connections
        Info : clock speed 3000 kHz
        Info : JTAG tap: bcm2711.cpu tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x4)
        Info : bcm2711.cpu0: hardware has 6 breakpoints, 4 watchpoints
        Info : bcm2711.cpu1: hardware has 6 breakpoints, 4 watchpoints
        Info : bcm2711.cpu2: hardware has 6 breakpoints, 4 watchpoints
        Info : bcm2711.cpu3: hardware has 6 breakpoints, 4 watchpoints
        Info : gdb port disabled
        Info : starting gdb server for bcm2711.cpu0 on 3333
        Info : Listening on port 3333 for gdb connections
        Info : starting gdb server for bcm2711.cpu1 on 3334
        Info : Listening on port 3334 for gdb connections
        Info : starting gdb server for bcm2711.cpu2 on 3335
        Info : Listening on port 3335 for gdb connections
        Info : starting gdb server for bcm2711.cpu3 on 3336
        Info : Listening on port 3336 for gdb connections
        

        Connecting OpenOCD with telnet

        Once we know we have OpenOCD up and running successfully, we can telnet into its CLI interface to run various JTAG commands or pre-defined routines.

        telnet 127.0.0.1 4444
        

        Running scan_chain is a quick and simple way to check if you are getting any communication over your JTAG TAP. On a successful connection, you will see something like below:

        Trying 127.0.0.1...
        Connected to 127.0.0.1.
        Escape character is '^]'.
        Open On-Chip Debugger
        > scan_chain
            TapName             Enabled  IdCode     Expected   IrLen IrCap IrMask
        -- ------------------- -------- ---------- ---------- ----- ----- ------
         0 auto0.tap              Y     0x4ba00477 0x4ba00477     4 0x01  0x03
        

        GDB with OpenOCD

        You can start a gdb session with openOCD by aarch64-rtems6-gdb and then in GDB session, add target ext :3333. By using this you'll see a configuration like this.

        GNU gdb (GDB) 11.2
        Copyright (C) 2022 Free Software Foundation, Inc.
        License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
        This is free software: you are free to change and redistribute it.
        There is NO WARRANTY, to the extent permitted by law.
        Type "show copying" and "show warranty" for details.
        This GDB was configured as "--host=x86_64-linux-gnu --target=aarch64-rtems6".
        Type "show configuration" for configuration details.
        For bug reporting instructions, please see:
        <https://www.gnu.org/software/gdb/bugs/>.
        Find the GDB manual and other documentation resources online at:
            <http://www.gnu.org/software/gdb/documentation/>.
        
        For help, type "help".
        --Type <RET> for more, q to quit, c to continue without paging--
        Type "apropos word" to search for commands related to "word".
        (gdb) target ext :3333
        Remote debugging using :3333
        warning: No executable has been specified and target does not support
        determining executable automatically.  Try using the "file" command.
        0xffffffc010ad283c in ?? ()
        (gdb)
        

        Troubleshooting

        If you find the serial interface is missing lots of characters and feels slow. This could be due to interference being captured by the unshielded jumper wires between the CH340G and the RPi4. It can also occur due to a long jumper wire (>50cm) or unshielded USB extension cable. Ways to resolve the interference issue is to move the setup far from things that are oscillating (e.g. fans, compressors, motors, CRTs, microwaves, radio enabled devices). If possible, its also advised to keep the exposed RPi4 on a static resistant matte and/or grounded to prevent interference or damage from static discharge.

        If you're getting something like below, in the OpenOCD.

        Open On-Chip Debugger 0.11.0+dev-00698-gcc8b49185 (2022-06-01-19:06)
        Licensed under GNU GPL v2
        For bug reports, read
            http://openocd.org/doc/doxygen/bugs.html
        jtag
        Info : Listening on port 6666 for tcl connections
        Info : Listening on port 4444 for telnet connections
        Info : clock speed 10000 kHz
        Error: JTAG scan chain interrogation failed: all ones
        Error: Check JTAG interface, timings, target power, etc.
        Error: Trying to use configured scan chain anyway...
        Error: bcm2711.cpu: IR capture error; saw 0x0f not 0x01
        Warn : Bypassing JTAG setup events due to errors
        Error: Invalid ACK (7) in DAP response
        Error: JTAG-DP STICKY ERROR
        

        This is usually caused by interference, not connecting device properly or Pi not being booted properly. Check out serial to check if the pi is booting or not. Double check your connection and use as short wire as possible (I used wire of 10cm only). If not sure about the pinouts, check out pinout.xyz .

        Conclusion

        In this blog, we have learnt about how to connect raspberry pi 4B with serial module, setup JTAG connection, OpenOCD configuration for FT232H module and how to connect OpenOCD with GDB. Gathering All this info took me some time, there's a lot of guide about how to setup raspberry pi with FT2322H but not with this. In the end you'll see a screen like this. Hopefully someone in the future will find this to be helpful ;) Like, comment, subscribe and share it with your friends (。•̀ᴗ-)✧

        2022-06-08_12-36.png If you encounter any issues or have any thoughts on this article, please leave a comment below. I'll get back to you as soon as I can.

Did you find this article valuable?

Support Mohd Noor Aman by becoming a sponsor. Any amount is appreciated!