Part 4: Enabling JTAG in Firmware and Using It with OpenOCD
Author: Shafeeque Olassery Kunnikkal | Category: Hardware Hacking, IoT, JTAG, STM32, STM32F411, STM32F411CE, STM32F411CEU6, Tigard | Leave a Comment
Overview
Once you’ve discovered your JTAG pins using JTAGenum, you might want to enable them in your own firmware, or use them with a tool like OpenOCD for real debugging. This part shows how to:
- Enable JTAG pins explicitly in your firmware (via STM32CubeMX or code)
- Maintain those pin functions across reboots
- Set up OpenOCD to use your confirmed pinout
Why Enable JTAG in Firmware?
On many STM32 boards, including the Black Pill:
- The default firmware does not enable JTAG.
- Even if pins are physically accessible, they may be set as GPIO by code.
- If JTAG is disabled or overridden, tools like JTAGenum or OpenOCD will not connect.
When is this needed?
- If you’re writing your own application firmware and want to debug it via JTAG.
- If you want your board to always be JTAG-accessible for recovery or testing.
- If you’re building educational tools or lab setups.
Enabling JTAG Using STM32CubeMX
The easiest way to enable JTAG at firmware level is to configure it in STM32CubeMX:
Steps:
- Open STM32CubeMX
- Load or create a project for STM32F411CE (or your chip)
- In the Pinout view:
- Right-click on pins PA15, PB3, and PB4
- Set them to SYS_JTDI, SYS_JTDO-SWO, and SYS_JTRST respectively
- Go to System Core → SYS in the Configuration panel
- Set Debug to
Full SWJ (JTAG-DP + SW-DP)
- Generate code (HAL-based or LL) and open in STM32CubeIDE or your IDE
Optional: In the generated main.c
, do not change the mode of the configured pins — let the HAL handle it.
Enabling JTAG Manually in Firmware (Bare Metal)
If you prefer direct register-level setup:
// Enable AFIO and remap JTAG
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->MAPR &= ~(AFIO_MAPR_SWJ_CFG); // Clear bits
AFIO->MAPR |= 0x00000000; // Full JTAG enabled
// Set pin modes (e.g., for PA15, PB3, PB4)
GPIOA->CRH |= (0b1011 << 28); // PA15: AF Push-pull, 50MHz
GPIOB->CRL |= (0b1011 << 12); // PB3: AF Push-pull, 50MHz
GPIOB->CRL |= (0b1011 << 16); // PB4: AF Push-pull, 50MHz
This ensures that JTAG pins are not accidentally reconfigured by your own firmware.
Using OpenOCD with Discovered JTAG Pins
Now that JTAG is confirmed and enabled, you can use OpenOCD to connect.
Example: Custom OpenOCD Interface Config (with FTDI or Tigard)
Create a config file blackpill-jtag.cfg
:
interface ftdi
ftdi_vid_pid 0x0403 0x6010
transport select jtag
ftdi_layout_signal nTRST -data 0x01 -noe 0x02
ftdi_layout_signal TCK -data 0x04 -noe 0x08
ftdi_layout_signal TMS -data 0x10 -noe 0x20
ftdi_layout_signal TDI -data 0x40 -noe 0x80
ftdi_layout_signal TDO -input 1
adapter_khz 1000
Then run:
openocd -f blackpill-jtag.cfg -f target/stm32f4x.cfg
If the pin mappings are correct and JTAG is enabled, you should see:
Info : JTAG tap: stm32f4.cpu tapped
Info : stm32f4.cpu: hardware has 6 breakpoints, 4 watchpoints
Final Thoughts
- Discovering pins is just the first step.
- For persistent and reliable use of JTAG, enable it in firmware and know how to configure your debugger.
- This empowers you to build resilient workflows for debugging, testing, and even hardware forensics.
That wraps up Part 4.