JTAG Implementation Evolution From 2.25Mbps to 9Mbps - grumat/glossy-msp430 GitHub Wiki

JTAG Implementation Evolution: From 2.25 Mbps (ST-Link V2) to 9 Mbps (dtrig/BluePill)

Executive Summary

The glossy-msp430 project supports two distinct JTAG implementations, each optimized for different hardware constraints:

Implementation Hardware Target Speed Clock Source Release Use Case
GeneratorSTLinkPWM ST-Link V2 Clone 2.25 Mbps Timer PWM v1.0 Low-cost accessibility; educational use
DtrigJtag BluePill/F103 9 Mbps SPI + Timer Toggle v2.0+ Performance debugging; production use

This document traces the architectural evolution, explains why each design made different trade-offs, and when to use each variant.


Part 1: The Twin Implementations

1.1 Quick Comparison Table

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     JTAG IMPLEMENTATION COMPARISON                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Aspect              โ”‚ GeneratorSTLinkPWM   โ”‚ DtrigJtag                  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Hardware Target     โ”‚ ST-Link V2 Clone     โ”‚ BluePill / STM32F103       โ”‚
โ”‚ Speed               โ”‚ 2.25 Mbps            โ”‚ 9 Mbps (9ร— faster!)        โ”‚
โ”‚ Cost (Hardware)     โ”‚ $3-5                 โ”‚ $15-20                     โ”‚
โ”‚ Clock Source        โ”‚ TIM1 PWM (50% duty) โ”‚ SPI + TIM1 Toggle Mode     โ”‚
โ”‚ Data Transfer       โ”‚ DMA to GPIO BSRR    โ”‚ SPI DMA (byte-per-cycle)   โ”‚
โ”‚ JTDI/JTDO Control   โ”‚ GPIO BSRR writes    โ”‚ SPI peripheral (native)    โ”‚
โ”‚ TMS Control         โ”‚ GPIO BSRR writes    โ”‚ TIM1_CH2N toggle (0-DMA)   โ”‚
โ”‚ DMA Channels Used   โ”‚ 3 (read/write/tms)  โ”‚ 2 (SPI RX/TX only)         โ”‚
โ”‚ Port Layout         โ”‚ Split (PA/PB)       โ”‚ Single (PA only)           โ”‚
โ”‚ Synchronization     โ”‚ Timer repetition ctr โ”‚ Critical section + CNT     โ”‚
โ”‚ Speed-Grades        โ”‚ 1 (fixed)           โ”‚ 5 (0.5-9 Mbps)             โ”‚
โ”‚ TCLK Support        โ”‚ Via SPI bit-stream  โ”‚ Via SPI burst + PWM muting โ”‚
โ”‚ Overhead            โ”‚ High DMA arbitration โ”‚ Low (SPI native protocol)  โ”‚
โ”‚ Temperature Stable  โ”‚ ยฑ0.5% (PLL)         โ”‚ ยฑ0.1% (SPI baud ratio)     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Part 2: Why Two Implementations?

2.1 Hardware Constraints Led to Different Solutions

ST-Link V2 Clone Constraints:

  • GPIO pins split across Port A (PA6/PA7) and Port B (PB13/PB14)
  • No SPI peripheral easily available without internal surgery
  • Maximum 2.25 MHz due to 3-channel DMA arbitration overhead
  • Physical layout forces multi-port coordination

BluePill Advantages:

  • All JTAG signals on Port A (PA5/PA6/PA7)
  • SPI1 peripheral native to pins PA5/PA6/PA7
  • Flexible timer channels for TMS modulation
  • Single-port DMA enables 9 MHz operation

2.2 Design Philosophy

GeneratorSTLinkPWM (ST-Link V2):

"Given rigid hardware constraints, maximize speed with autonomous hardware waveforms rather than CPU bit-banging."

  • Accepted lower speed (2.25 Mbps) for cost reduction and accessibility
  • Prioritized robustness (deterministic waveforms) over throughput

DtrigJtag (BluePill):

"Leverage SPI efficiency and timer versatility to achieve native protocol speeds."

  • Exploits flexible GPIO routing and native peripherals
  • Prioritizes performance (9 Mbps) for production debugging

Part 3: Architectural Comparison

3.1 GeneratorSTLinkPWM Architecture (2.25 Mbps)

The Problem: Split GPIO ports + no SPI + need precision clock

The Solution: Automated waveform generation via PWM + multi-DMA

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚         STM32F103 (ST-Link V2 Clone)                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚ TIM1 (Master Timer, 8-count cycle)                 โ”‚ โ”‚
โ”‚  โ”‚  โ€ข PWM on CH1N (PB13) โ†’ JTCK (50% duty)           โ”‚ โ”‚
โ”‚  โ”‚  โ€ข CCR2 (count 5) โ†’ triggers DMA for JTMS writes  โ”‚ โ”‚
โ”‚  โ”‚  โ€ข CCR3 (count 1) โ†’ triggers DMA for JTDI writes  โ”‚ โ”‚
โ”‚  โ”‚  โ€ข CCR4 (count 0) โ†’ triggers DMA for JTDO reads   โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚             โ”‚                                          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚ DMA Arbitration (3 channels, different addresses)   โ”‚
โ”‚  โ”‚                                                    โ”‚
โ”‚  โ”‚  DMA1_Ch2: Port A IDR โ†’ Memory (JTDO read)       โ”‚
โ”‚  โ”‚  DMA1_Ch3: Memory โ†’ Port A BSRR (JTDI write)     โ”‚
โ”‚  โ”‚  DMA1_Ch4: Memory โ†’ Port B BSRR (JTMS write)     โ”‚
โ”‚  โ”‚                                                    โ”‚
โ”‚  โ”‚ โš  Problem: Each channel = ~115 ns overhead       โ”‚
โ”‚  โ”‚            3 channels ร— 8-count = 444 ns cycle   โ”‚
โ”‚  โ”‚            Margin: ~99 ns (safe but tight)       โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚             โ”‚                                          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚ GPIO Ports (Split across A and B)               โ”‚   โ”‚
โ”‚  โ”‚  PA6/PA7 (JTDO/JTDI)  โ”€โ†’ Target JTAG            โ”‚   โ”‚
โ”‚  โ”‚  PB13/PB14 (JTCK/JTMS) โ”€โ†’                        โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚             โ”‚                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
              โ”‚
         โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”
         โ”‚ MSP430    โ”‚
         โ”‚ Target    โ”‚
         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key Bottleneck: DMA arbitration across 3 separate peripheral addresses

  • Each DMA request: ~115 ns (setup + arbitrate + transfer)
  • 3 channels per cycle ร— 115 ns = 345 ns minimum
  • At 2.25 MHz, cycle = 444 ns โ†’ only 99 ns margin โœ“ but limited

3.2 DtrigJtag Architecture (9 Mbps)

The Insight: SPI handles data transfer natively; timer toggle mode handles TMS for free

The Solution: SPI + Timer Toggle Mode + Critical-Section Synchronization

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚         STM32F103 (BluePill, Flexible GPIO)             โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚ SPI1 (Data Transfer, byte-per-8-cycles)            โ”‚ โ”‚
โ”‚  โ”‚  โ€ข SCK = PA5 (JTCK) โ€” SPI clock (8 cycles/byte)   โ”‚ โ”‚
โ”‚  โ”‚  โ€ข MOSI = PA7 (JTDI) โ€” TX via DMA1_Ch3            โ”‚ โ”‚
โ”‚  โ”‚  โ€ข MISO = PA6 (JTDO) โ€” RX via DMA1_Ch2            โ”‚ โ”‚
โ”‚  โ”‚                                                    โ”‚ โ”‚
โ”‚  โ”‚  DMA Cost: Only 2 channels (RX/TX)                โ”‚ โ”‚
โ”‚  โ”‚  Each byte: 8 cycles @ APB2 / N baud             โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚         โ”‚                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ TIM1 (TMS Generator, Toggle Mode, zero-DMA)       โ”‚  โ”‚
โ”‚  โ”‚  โ€ข CH2N = PB14 (JTMS) โ€” toggle output            โ”‚  โ”‚
โ”‚  โ”‚  โ€ข CH3 DMA-trigger = CCR2 reload (one DMA shot)  โ”‚  โ”‚
โ”‚  โ”‚  โ€ข CH4 DMA-trigger = CCR2 reload (one DMA shot)  โ”‚  โ”‚
โ”‚  โ”‚                                                   โ”‚  โ”‚
โ”‚  โ”‚  Toggle Pattern (Toggle mode):                    โ”‚  โ”‚
โ”‚  โ”‚   Entry:      CCR2 = count N โ†’ toggle โ†’ TMS LOW  โ”‚  โ”‚
โ”‚  โ”‚   Exit:       CCR2 = count M โ†’ toggle โ†’ TMS HIGH โ”‚  โ”‚
โ”‚  โ”‚   Return:     CCR2 = count Z โ†’ toggle โ†’ TMS LOW  โ”‚  โ”‚
โ”‚  โ”‚                                                   โ”‚  โ”‚
โ”‚  โ”‚  DMA Cost: Only 2 CCR2 reloads (not per-bit!)   โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚         โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Critical Section: Atomic SPI + TIM1 Launch       โ”‚  โ”‚
โ”‚  โ”‚                                                   โ”‚  โ”‚
โ”‚  โ”‚  void Start(..., uint16_t cnt_offset) {          โ”‚  โ”‚
โ”‚  โ”‚    {                                              โ”‚  โ”‚
โ”‚  โ”‚      CriticalSection lock;  โ† Disable interrupts โ”‚  โ”‚
โ”‚  โ”‚      SpiTxDma::Enable();    โ† Start SPI DMA     โ”‚  โ”‚
โ”‚  โ”‚      CycleTimer::CounterResume(); โ† Resume TIM1 โ”‚  โ”‚
โ”‚  โ”‚    }  โ† Re-enable interrupts                      โ”‚  โ”‚
โ”‚  โ”‚  }                                                โ”‚  โ”‚
โ”‚  โ”‚                                                   โ”‚  โ”‚
โ”‚  โ”‚  Result: SPI and TIM1 phase-locked from bit 0   โ”‚  โ”‚
โ”‚  โ”‚  cnt_offset pre-loads TIM1 CNT for TMS timing   โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚         โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ GPIO Port A (All JTAG signals on same port!)     โ”‚  โ”‚
โ”‚  โ”‚  PA5 (SPI SCK) โ”€โ†’ JTCK                           โ”‚  โ”‚
โ”‚  โ”‚  PA6 (SPI MISO) โ”€โ†’ JTDO                          โ”‚  โ”‚
โ”‚  โ”‚  PA7 (SPI MOSI) โ”€โ†’ JTDI                          โ”‚  โ”‚
โ”‚  โ”‚                                                  โ”‚  โ”‚
โ”‚  โ”‚ GPIO Port B                                     โ”‚  โ”‚
โ”‚  โ”‚  PB14 (TIM1_CH2N) โ”€โ†’ JTMS                       โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚         โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
          โ”‚
     โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”
     โ”‚ MSP430    โ”‚
     โ”‚ Target    โ”‚
     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key Innovation:

  • SPI handles data transfer (byte per 8 cycles, protocol-native)
  • TIM1 toggle mode provides TMS pulses for FREE (no per-bit DMA cost)
  • Only 2 DMA channels needed (SPI RX/TX) โ†’ 4ร— less arbitration
  • Critical section ensures first bit alignment โ†’ cnt_offset tuning per grade

Result: Can sustain 9 Mbps safely โœ“


Part 4: Why Speed Differs (The Physics)

4.1 DMA Arbitration Analysis

At 2.25 MHz (GeneratorSTLinkPWM):

Cycle time: 444 ns (8-count ร— 55.5 ns/count)

Timeline:
  Count 0: DmaRead (Port A IDR)     โ”€ 115 ns
  Count 1: DmaWrite (Port A BSRR)   โ”€ 115 ns  (gap: 55 ns)
  Count 2: DmaTms (Port B BSRR)     โ”€ 115 ns  (gap: 55 ns)
  Count 3-7: PWM high/low, wait for next cycle

Total margin: ~99 ns โ†’ Safe โœ“ (but no room to increase speed)

At 9 Mbps (DtrigJtag, per byte):

Cycle time: 111 ns (8-count ร— 13.9 ns/count @ 72 MHz with N=8 prescaler)

Timeline (Single-port SPI):
  SPI TX DMA: Start transfer (DMA native, single address)
  TIM1 Toggle: Hardware generates TMS transitions
  
  No per-bit DMA arbitration!
  
Total margin: Excellent โœ“ (can add speed grades safely)

Key Insight:

  • GeneratorSTLinkPWM: Each DMA request = separate peripheral address = full setup/arbitrate/transfer cycle
  • DtrigJtag: SPI peripheral handles clock/data natively; toggle mode needs zero DMA

4.2 Synchronization Strategy Differences

GeneratorSTLinkPWM (Timer repetition counter):

// Set exact cycle count via RCR (repetition counter)
BeatTimer::SetupRepetition(kTimerPeriod_, 1); // repeat once
// Timer runs autonomously for exact bit count

DtrigJtag (Critical section + CNT preload):

// Lock interrupts, launch SPI and TIM1 atomically
{
  CriticalSection lock;
  SpiTxDma::Enable();              // Start SPI first byte
  CycleTimer::CounterResume();     // Resume TIM1 with preset CNT
}
// cnt_offset = LA-calibrated phase shift per speed grade

Part 5: Historical Evolution

Timeline: How Did We Get Here?

Phase 1: Discovery (Early Design)

  • Problem identified: ST-Link V2 clone lacks SPI but has GPIO and timer
  • Initial attempt: Naive bit-banging (unreliable, jittery)
  • Solution: GeneratorSTLinkPWM template (Timer PWM + 3-channel DMA)
  • Result: 2.25 Mbps, stable, deterministic
  • Release: v1.0

Phase 2: SPI Opportunity (BluePill)

  • Observation: BluePill has flexible GPIO + native SPI on PA5/PA6/PA7
  • Strategy: Use SPI for data (byte per 8 cycles) + timer for TMS
  • Challenge: TMS timing must align with SPI bit edges
  • Solution: Critical section synchronization + cnt_offset tuning
  • Result: 9 Mbps, 4ร— faster than ST-Link V2
  • Release: v1.5+

Phase 3: Optimization (Current)

  • Insight: TIM1 toggle mode generates TMS pulses with zero DMA cost
  • Improvement: Removed 3rd DMA channel (TMS control)
  • Validation: Speed grades (0.5, 1.125, 2.25, 4.5, 9 Mbps) with per-grade tuning
  • Addition: TCLK high-frequency support (~450 kHz) via SPI burst
  • Release: v2.0+

Part 6: Detailed Technical Comparison

6.1 Clock Generation

Aspect GeneratorSTLinkPWM DtrigJtag
Clock Source TIM1 PWM (GPIO output) SPI SCK (peripheral)
Frequency Control Timer prescaler SPI baud rate (BR field)
Duty Cycle Fixed 50% (4 high, 4 low) Fixed 50% (SPI native)
Accuracy ยฑ0.5% (PLL drift) ยฑ0.1% (baud ratio)
Jitter ยฑ1 timer count (~55 ns @ 2.25 MHz) <1 ns (SPI native)
Adjustability Single fixed speed 5 speed grades at runtime

6.2 Data Transfer

Aspect GeneratorSTLinkPWM DtrigJtag
JTDI/JTDO Method DMA to GPIO BSRR SPI MOSI/MISO via DMA
Unit of Transfer Per-DMA (variable) Per-byte (8 cycles/byte)
DMA Channels 2 (RX, TX) 2 (RX, TX)
Arbitration Overhead None (not used for JTDI) Minimal (SPI protocol)
Throughput Limited by timer cycle Limited by SPI baud
Byte Alignment 8-count cycle per bit Native (8 counts/byte)

6.3 TMS (Mode Select) Generation

Aspect GeneratorSTLinkPWM DtrigJtag
TMS Method DMA writes to GPIO BSRR TIM1_CH2N toggle mode
DMA Channels for TMS 1 dedicated 0 (toggle is hardware)
Pulses per Frame Multiple (every state change) 3 (entry, exit, RTI)
Control Method Per-bit DMA updates Two CCR2 reload DMA shots
Timing Precision Timer-based (counts) Toggle mode (exact)
CPU Overhead Render TMS sequence each frame Render TMS bit pattern once

Key Difference: DtrigJtag's toggle mode requires only 2 DMA writes for entire TMS sequence, vs GeneratorSTLinkPWM's multi-write approach.

6.4 Hardware Port Usage

GeneratorSTLinkPWM:

Port A: PA6 (JTDO), PA7 (JTDI)
Port B: PB13 (JTCK), PB14 (JTMS)
        โ†‘ Separate DMA writes needed

DtrigJtag:

Port A: PA5 (SPI SCK=JTCK), PA6 (SPI MISO=JTDO), PA7 (SPI MOSI=JTDI)
        โ†‘ Single peripheral, atomic SPI protocol
Port B: PB14 (TIM1_CH2N=JTMS) โ€” no DMA

Part 7: Implementation Details

7.1 File Structure

GeneratorSTLinkPWM (ST-Link V2):

Firmware.shared/
  drivers/
    JtagDev.tim.cpp           โ† Main implementation
  util/
    WaveJtag.h               โ† GeneratorSTLinkPWM template
target.stlinv2/
  platform.h                  โ† Pin definitions

DtrigJtag (BluePill):

Firmware.shared/
  drivers/
    JtagDev.dtrig.cpp        โ† Main implementation
  util/
    DtrigJtag.h              โ† DtrigJtag template
target.bluepill/
  platform.h                  โ† Pin definitions

7.2 Speed Grade Configuration (DtrigJtag Only)

DtrigJtag supports 5 speed grades tuned via cnt_offset parameter:

// From JtagDev.dtrig.cpp
static constexpr uint16_t kDtrigCntOffset_1 = 2;  // 0.5625 MHz (slowest, safest)
static constexpr uint16_t kDtrigCntOffset_2 = 2;  // 1.125 MHz
static constexpr uint16_t kDtrigCntOffset_3 = 2;  // 2.25 MHz
static constexpr uint16_t kDtrigCntOffset_4 = 4;  // 4.5 MHz
static constexpr uint16_t kDtrigCntOffset_5 = 4;  // 9 MHz (fastest)

// Each grade calibrated with logic analyzer to align TMS toggles
// with SPI bit edges within the 8-count cycle

GeneratorSTLinkPWM: Fixed 2.25 MHz (no speed grades)

7.3 TCLK (Flash Clock) Support

Implementation Method Frequency
GeneratorSTLinkPWM Via SPI bit-stream (kJtmsWave pattern) ~450 kHz
DtrigJtag SPI burst at reduced baud + GPIO muting ~450 kHz

Both achieve ~450 kHz for MSP430 flash operations (requires <500 kHz per spec).


Part 8: Performance Comparison

8.1 Real-World Speed Impact

Scenario: Reading 256 bytes from target flash

Operation: 16-bit reads ร— 128 = 2048 JTAG clock cycles total

GeneratorSTLinkPWM @ 2.25 MHz:
  Time = 2048 cycles / 2.25 MHz = 911 ยตs
  Frame overhead: ~50 ยตs (20 frames ร— ~2.5 ยตs setup)
  Total: ~961 ยตs

DtrigJtag @ 9 Mbps:
  Time = 2048 cycles / 9 MHz = 228 ยตs
  Frame overhead: ~20 ยตs (20 frames ร— ~1 ยตs setup)
  Total: ~248 ยตs

Speedup: 961 / 248 โ‰ˆ 3.87ร— (vs theoretical 4ร—)
         Reason: Frame overhead amortized over multiple transfers

Real Impact:

  • Small reads (1-4 bytes): ~10-50 ยตs difference (imperceptible)
  • Large transfers (>256 bytes): dtrig clearly faster
  • Typical debug session: Mix of operations, overall 2-3ร— faster

8.2 Throughput Limits

GeneratorSTLinkPWM:

  • Theoretical max: 2.25 Mbps (2,250,000 bits/sec)
  • Practical max: ~1.8 Mbps (accounting for frame gaps, bus arbitration)

DtrigJtag:

  • Theoretical max: 9 Mbps (9,000,000 bits/sec @ 72 MHz / 8 prescaler)
  • Practical max: ~8.5 Mbps (accounting for frame gaps, DMA setup)

Part 9: When to Use Each Implementation

Selection Matrix

Use GeneratorSTLinkPWM (2.25 Mbps, ST-Link V2) if:

  • โœ“ Hardware: ST-Link V2 clone (constrained GPIO, no SPI)
  • โœ“ Budget: $3-5 required
  • โœ“ Use case: Educational, accessibility, proof-of-concept
  • โœ“ Speed acceptable: โ‰ค2.25 Mbps is enough
  • โœ“ Availability: Local hobbyist shop has stock

Use DtrigJtag (9 Mbps, BluePill) if:

  • โœ“ Hardware: STM32F103 BluePill or equivalent
  • โœ“ Performance: Need โ‰ฅ4 Mbps
  • โœ“ Use case: Production debugging, development
  • โœ“ Features: Speed-grade tuning, TCLK support required
  • โœ“ Flexibility: Can use 5 different speed grades

Hardware Compatibility Table

Hardware Implementation Speed Notes
ST-Link V2 Clone GeneratorSTLinkPWM 2.25 Mbps Fixed; only option
BluePill (STM32F103) DtrigJtag 9 Mbps 5 speed grades
Nucleo-L432KC DtrigJtag 9 Mbps Limited testing
Nucleo-G431KB DtrigJtag 9 Mbps Limited testing
Custom F1/F3 board DtrigJtag (if PA5/PA6/PA7 available) 9 Mbps Board-dependent

Part 10: Key Takeaways

10.1 Design Lessons

Lesson Implication
Hardware constraints drive design ST-Link V2's split GPIO โ†’ timer/DMA; BluePill's SPI โ†’ dtrig
DMA arbitration is expensive Each peripheral address = ~115 ns overhead; limits speed
SPI is underrated for JTAG Native protocol efficiency beats bit-banging by 4ร—
Timer toggle mode is free TIM1_CH2N toggle costs zero DMA budget
Synchronization matters Critical section + cnt_offset = phase-locked precision
Speed grades = robustness Tuning per frequency proves margins exist

10.2 Code Quality Insights

  • GeneratorSTLinkPWM: Template-heavy, demonstrates C++17 constexpr tricks
  • DtrigJtag: More complex (critical sections, timing tuning), but clearer intent
  • Both use bmt abstractions exclusively (no raw register access)

10.3 Future Directions

Potential optimizations:

  • Extend DtrigJtag to G4/L4 families (higher clock = higher Mbps possible)
  • Explore H7 dual-DMA for ST-Link V2 โ†’ eliminate arbitration, reach 3-4 Mbps
  • Add variable speed-grade support to GeneratorSTLinkPWM (minor work)

Conclusion

The evolution from 2.25 Mbps (GeneratorSTLinkPWM) to 9 Mbps (DtrigJtag) illustrates how hardware constraints and design choices shape performance:

  1. ST-Link V2: Rigid GPIO + no SPI โ†’ timer/DMA workaround โ†’ 2.25 Mbps
  2. BluePill: Flexible GPIO + native SPI โ†’ SPI + timer toggle โ†’ 9 Mbps

Each implementation is optimal for its target hardware and use case. The project supports both because different users have different priorities: cost vs. performance, accessibility vs. production-grade debugging.


References & Related Documents

  • Repurposing-ST-Link-V2-Clones-for-MSP430-JTAG-Debugging.md โ€” Detailed GeneratorSTLinkPWM design
  • Firmware.shared/util/DtrigJtag.h โ€” DtrigJtag template documentation
  • Firmware.shared/drivers/JtagDev.dtrig.cpp โ€” DtrigJtag implementation & speed grades
  • Firmware.shared/util/TimDmaWave.h โ€” Timer/DMA utilities (supports both approaches)
  • CODE_GUIDELINES.md โ€” C++17 template and bmt abstraction standards