1 /* 2015 Petteri Aimonen <jpa@git.mail.kapsi.fi>
4 * This file is an example on how to configure the TPIU/DWT/ITM/ETM blocks
5 * on a Cortex-M3 microcontroller for tracing the execution. Trace data is
6 * output from the TRACESWO pin.
8 * Designed to run especially on STM32 Value Line discovery board, but should
9 * be easily adaptible to other boards also. Note that the STM32F100 chip on
10 * value line discovery does not have ETM feature.
13 * 1) Configures the trace pin to output TPIU formatted trace from both ITM and ETM.
14 * 2) Blinks a led, while monitored by ITM tracing.
15 * 3) Causes periodic interrupts, where it runs bubblesort while tracing it with ETM.
18 #include "stm32f10x.h"
22 int globalCounter; // For watchpoint example
24 void hardfault_handler(void) { for(;;); }
26 void configure_tracing()
28 /* STM32 specific configuration to enable the TRACESWO IO pin */
29 RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
30 AFIO->MAPR |= (2 << 24); // Disable JTAG to release TRACESWO
31 DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; // Enable IO trace pins
33 if (!(DBGMCU->CR & DBGMCU_CR_TRACE_IOEN))
35 // Some (all?) STM32s don't allow writes to DBGMCU register until
36 // C_DEBUGEN in CoreDebug->DHCSR is set. This cannot be set by the
37 // CPU itself, so in practice you need to connect to the CPU with
38 // a debugger once before resetting it.
42 /* Configure Trace Port Interface Unit */
43 CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // Enable access to registers
44 TPI->ACPR = 0; // Trace clock = HCLK/(x+1) = 8MHz
45 TPI->SPPR = 2; // Pin protocol = NRZ/USART
46 TPI->FFCR = 0x102; // TPIU packet framing enabled when bit 2 is set.
47 // You can use 0x100 if you only need DWT/ITM and not ETM.
49 /* Configure PC sampling and exception trace */
50 DWT->CTRL = (1 << DWT_CTRL_CYCTAP_Pos) // Prescaler for PC sampling
52 | (0 << DWT_CTRL_POSTPRESET_Pos) // Postscaler for PC sampling
53 // Divider = value + 1
54 | (1 << DWT_CTRL_PCSAMPLENA_Pos) // Enable PC sampling
55 | (2 << DWT_CTRL_SYNCTAP_Pos) // Sync packet interval
56 // 0 = Off, 1 = Every 2^23 cycles,
57 // 2 = Every 2^25, 3 = Every 2^27
58 | (1 << DWT_CTRL_EXCTRCENA_Pos) // Enable exception trace
59 | (1 << DWT_CTRL_CYCCNTENA_Pos); // Enable cycle counter
61 /* Configure instrumentation trace macroblock */
62 ITM->LAR = 0xC5ACCE55;
63 ITM->TCR = (1 << ITM_TCR_TraceBusID_Pos) // Trace bus ID for TPIU
64 | (1 << ITM_TCR_DWTENA_Pos) // Enable events from DWT
65 | (1 << ITM_TCR_SYNCENA_Pos) // Enable sync packets
66 | (1 << ITM_TCR_ITMENA_Pos); // Main enable for ITM
67 ITM->TER = 0xFFFFFFFF; // Enable all stimulus ports
69 /* Configure embedded trace macroblock */
70 ETM->LAR = 0xC5ACCE55;
72 ETM->CR = ETM_CR_ETMEN // Enable ETM output port
73 | ETM_CR_STALL_PROCESSOR // Stall processor when fifo is full
74 | ETM_CR_BRANCH_OUTPUT; // Report all branches
75 ETM->TRACEIDR = 2; // Trace bus ID for TPIU
76 ETM->TECR1 = ETM_TECR1_EXCLUDE; // Trace always enabled
77 ETM->FFRR = ETM_FFRR_EXCLUDE; // Stalling always enabled
78 ETM->FFLR = 24; // Stall when less than N bytes free in FIFO (range 1..24)
79 // Larger values mean less latency in trace, but more stalls.
80 // Note: we do not enable ETM trace yet, only for specific parts of code.
83 void configure_watchpoint()
85 /* This is an example of how to configure DWT to monitor a watchpoint.
86 The data value is reported when the watchpoint is hit. */
88 /* Monitor all accesses to GPIOC (range length 32 bytes) */
89 DWT->COMP0 = (uint32_t)GPIOC;
91 DWT->FUNCTION0 = (2 << DWT_FUNCTION_FUNCTION_Pos) // Report data and addr on watchpoint hit
92 | (1 << DWT_FUNCTION_EMITRANGE_Pos);
94 /* Monitor all accesses to globalCounter (range length 4 bytes) */
95 DWT->COMP1 = (uint32_t)&globalCounter;
97 DWT->FUNCTION1 = (3 << DWT_FUNCTION_FUNCTION_Pos); // Report data and PC on watchpoint hit
100 // Print a given string to ITM.
101 // This uses 8 bit writes, as that seems to be the most common way to write text
102 // through ITM. Otherwise there is no good way for the PC software to know what
103 // is text and what is some other data.
104 void ITM_Print(int port, const char *p)
106 if ((ITM->TCR & ITM_TCR_ITMENA_Msk) && (ITM->TER & (1UL << port)))
110 while (ITM->PORT[port].u32 == 0);
111 ITM->PORT[port].u8 = *p++;
116 // Write a 32-bit value to ITM.
117 // This can be used as a fast way to log important values from code.
118 void ITM_SendValue (int port, uint32_t value)
120 if ((ITM->TCR & ITM_TCR_ITMENA_Msk) && (ITM->TER & (1UL << port)))
122 while (ITM->PORT[port].u32 == 0);
123 ITM->PORT[port].u32 = value;
129 for (int i = 0; i < 10000; i++)
133 void bubble_sort (int *a, int n) {
137 for (i = 1; i < n; i++) {
138 if (a[i] < a[i - 1]) {
150 int values[5] = {35,2,235,11,2};
152 // We are very interested in how the values get sorted,
153 // so we enable ETM tracing for it.
155 GPIOC->BSRR = (1 << 9); // Toggle a led so that we can see the latency in ETM trace
156 bubble_sort(values, 5);
157 GPIOC->BRR = (1 << 9);
160 // We can also use ITM to send the result of the sort
161 // Note that we use port 1 here so that output does not get mixed
162 // with port 0 output from main thread.
163 ITM_Print(1, "Sort");
164 for (int i = 0; i < 5; i++)
165 ITM_SendValue(1, values[i]);
167 TIM2->SR = 0; // Clear interrupt flag
173 configure_watchpoint();
175 RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
176 GPIOC->CRH = 0x44444433; // GPIOC 8 and 9 as output (STM32F1 discovery leds)
178 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
179 NVIC_EnableIRQ(TIM2_IRQn);
184 ITM_Print(0, "Boot");
191 GPIOC->BSRR = (1 << 8);
195 GPIOC->BRR = (1 << 8);
198 globalCounter++; // This will trigger the watchpoint
204 __attribute__ ((section("vectors")))= {
205 (void*)0x20002000, // Stack ptr
209 [16 + TIM2_IRQn] = TIM2_IRQ