I am trying to switch from JTAG to SWD without any external devices. Why? Because I would like to use the SWO pin to send a stream of logging information to another device.
To accomplish this without using an external debugger, I have connected the nTRST pin (PB4) to SWDIO (PA13) and TDI pin (PA15) to SWCLK (PA14). The idea is then to put out the pattern and clock on nTRST and TDI pin to send them to SWDIO and SWCLK.
Inside the reference manual (RM0008) on chapter 31.3.1, it shows the sequence to switch from SWJ-DP to SW-DP which is as follows:
- Go to line reset by sending at least 50 clock cycles with TMS (SWDIO) = 1
- Send the bit pattern 0111100111100111 (MSB transmitted first), so in my case 0b1110011110011110 when shifting out LSB first.
- Send at least 50 clock cycles with TMS (SWDIO) = 1
Now to the interesting part, I have managed to get this to work on an STM32F303 microcontroller, however, when I do the same on an STM32F103 microcontroller it does not work. BUT... if I instead connect the STM32F103 to a JTAG-lock-pick-Tiny-v2 and use OPENOCD it works. More on this later down.
Some interesting facts/things I have found, but that I am not sure of whether or not they are relevant.
- Inside the RM0008 on chapter 31.4, it says: "The STM32F10xxx MCUs are available in various packages with different numbers of available pins. As a result, some functionality (ETM) related to pin availability may differ between packages.
- Inside the CoreSight DAP-Lite Technical Reference Manual on chapter 2.2.5, there is a fourth step when switching from JTAG to SWD. The fourth step is to perform a READID to validate that SWJ-DP has switched to SWD.
- To be able to output data on the GPIO pins I have to use the function:
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); /* JTAG-DP Disabled and SerialWire-DebugPort (SW-DP) Enabled */
I have tried to compare the output of my GPIO "bitbanging" to the output when using OPENOCD. The first difference is the clock speed, which with OPENOCD and the JTAG-lock-pick-Tiny-v2 is 1MHz, and with bitbanging it is around 22kHz. I have tried with speeds above 125kHz as in "nRF51 Series Reference Manual" on chapter 11.1.2 it says that the minimum clock speed is 125kHz on SWDCLK. No difference. The bit sequence is the same for OPENOCD and my bitbanging, however after the second "line reset" OPENOCD does do the READID as mentioned in the fourth step and some other reads and writes, see image below:
To perform a READID you are supposed to send the pattern 0b10100101, which I added to after my second line reset with no difference. I have used a SALEAE logic analyzer to compare the traffic, see below:
Update/Edit: I edited the config file for OpenOCD to use 22kHz frequency, this also works i.e. no problem using lower frequencies. I downloaded the source code for OpenOCD and edited it to halt after sending the "magic" sequence. It does not work. I then set OpenOCD to halt after reading the IDCODE. Still does not work, so there must be something important in the writes and read.
Update/Edit 2:
After digging some more in the source code for OpenOCD, I believe I have found the problem. In the file arm_adi_v5.c, I have added a while(1){}
before and after this code:
LOG_DEBUG("DAP: wait CDBGPWRUPACK");
retval = dap_dp_poll_register(dap, DP_CTRL_STAT,
CDBGPWRUPACK, CDBGPWRUPACK,
DAP_POWER_DOMAIN_TIMEOUT);
if (retval != ERROR_OK)
return retval;
If the while(1){}
is used before it does not work and if we set it after it does work. And extracting the signals from Saleae and diff them in meld I get:
The different part is:
SWD,Request DebugPort Write CTRL/STAT,,,,,,,,,,,,,,
,SWD,Turnaround,,,,,,,,,,,,,,
,SWD,ACK OK,,,,,,,,,,,,,,
,SWD,Turnaround,,,,,,,,,,,,,,
,SWD,WData '1342177312' reg CTRL/STAT bits CSYSPWRUPACK=0, CSYSPWRUPREQ=1, CDBGPWRUPACK=0, CDBGPWRUPREQ=1, CDBGRSTACK=0, CDBGRSTREQ=0, TRNCNT='0', MASKLANE='0', WDATAERR=0, READOK=0, STICKYERR=1, STICKYCMP=0, TRNMODE=Normal, STICKYORUN=0, ORUNDETECT=0
,SWD,Data parityok,,,,,,,,,,,,,,
,SWD,Request DebugPort Read CTRL/STAT,,,,,,,,,,,,,,
,SWD,Turnaround,,,,,,,,,,,,,,
,SWD,ACK OK,,,,,,,,,,,,,,
,SWD,WData '4026531840' reg CTRL/STAT bits CSYSPWRUPACK=1, CSYSPWRUPREQ=1, CDBGPWRUPACK=1, CDBGPWRUPREQ=1, CDBGRSTACK=0, CDBGRSTREQ=0, TRNCNT='0', MASKLANE='0', WDATAERR=0, READOK=0, STICKYERR=0, STICKYCMP=0, TRNMODE=Normal, STICKYORUN=0, ORUNDETECT=0
,SWD,Data parityok,,,,,,,,,,,,,,
,SWD,Request DebugPort Write CTRL/STAT,,,,,,,,,,,,,,
,SWD,Turnaround,,,,,,,,,,,,,,
,SWD,ACK OK,,,,,,,,,,,,,,
,SWD,Turnaround,,,,,,,,,,,,,,
,SWD,WData '1342177280' reg CTRL/STAT bits CSYSPWRUPACK=0, CSYSPWRUPREQ=1, CDBGPWRUPACK=0, CDBGPWRUPREQ=1, CDBGRSTACK=0, CDBGRSTREQ=0, TRNCNT='0', MASKLANE='0', WDATAERR=0, READOK=0, STICKYERR=0, STICKYCMP=0, TRNMODE=Normal, STICKYORUN=0, ORUNDETECT=0
,SWD,Data parityok,,,,,,,,,,,,,,
,SWD,Request DebugPort Read CTRL/STAT,,,,,,,,,,,,,,
,SWD,Turnaround,,,,,,,,,,,,,,
,SWD,ACK OK,,,,,,,,,,,,,,
,SWD,WData '4026531840' reg CTRL/STAT bits CSYSPWRUPACK=1, CSYSPWRUPREQ=1, CDBGPWRUPACK=1, CDBGPWRUPREQ=1, CDBGRSTACK=0, CDBGRSTREQ=0, TRNCNT='0', MASKLANE='0', WDATAERR=0, READOK=0, STICKYERR=0, STICKYCMP=0, TRNMODE=Normal, STICKYORUN=0, ORUNDETECT=0
,SWD,Data parityok,,,,,,,,,,,,,,
I will update again once I have made more progress.