]> sigrok.org Git - sigrok-dumps.git/commitdiff
arm_trace: Add ARM ETMv3/ITM trace dumps.
authorPetteri Aimonen <redacted>
Mon, 23 Feb 2015 17:10:07 +0000 (19:10 +0200)
committerUwe Hermann <redacted>
Mon, 2 Mar 2015 10:01:43 +0000 (11:01 +0100)
arm_trace/stm32f105/README [new file with mode: 0644]
arm_trace/stm32f105/trace_example.c [new file with mode: 0644]
arm_trace/stm32f105/trace_example.elf [new file with mode: 0644]
arm_trace/stm32f105/trace_example.sr [new file with mode: 0644]

diff --git a/arm_trace/stm32f105/README b/arm_trace/stm32f105/README
new file mode 100644 (file)
index 0000000..54d3aaf
--- /dev/null
@@ -0,0 +1,58 @@
+-------------------------------------------------------------------------------
+ARM ETM/ITM Tracing
+-------------------------------------------------------------------------------
+
+This is an example capture from ARM Cortex-M3 ETM/ITM trace stream.
+
+The trace was captured from STM32F105 microcontroller while running
+this software (revision 5a1553c):
+https://github.com/PetteriAimonen/STM32_Trace_Example
+
+The example software outputs both ITM and ETM trace as follows:
+
+1) The main loop blinks PC8 approx every 10 ms.
+   On every blink it prints "On" and "Off" to ITM port 0.
+
+2) TIM2 interrupt blinks PC9 approx every 6 ms.
+   It is kept on for the duration of a bubble_sort() call.
+   ETM tracing is enabled for the duration of that subroutine.
+   Sort results are printed to ITM port 1.
+
+3) DWT is continuously reporting exception status and periodically
+   reporting PC values (these go to the ITM stream).
+
+Both ITM and ETM are mixed into the same stream by TPIU module
+ITM is configured as stream 1 and ETM as stream 2.
+
+Trace output is configured as 8 MHz UART protocol from TRACESWO pin.
+
+
+Logic analyzer setup
+--------------------
+
+The logic analyzer used was an FX2 based device (at 24MHz):
+
+  Probe       STM32F105
+  ---------------------
+  3           PC9
+  5           SWO
+  7           PC8
+
+
+Data
+----
+
+Capture command:
+
+  sigrok-cli -d fx2lafw -c samplerate=24MHz -C 4=SWO,2=PC9,6=PC8 -o trace_example.sr --time 50
+
+Decoding command for ITM output:
+
+  sigrok-cli -i trace_example.sr -P \
+    uart:rx=SWO:baudrate=8000000,arm_tpiu:stream=1,arm_itm:elffile=trace_example.elf
+
+Decoding command for ETM output:
+
+  sigrok-cli -i trace_example.sr -P \
+    uart:rx=SWO:baudrate=8000000,arm_tpiu:stream=2,arm_etmv3:elffile=trace_example.elf
+
diff --git a/arm_trace/stm32f105/trace_example.c b/arm_trace/stm32f105/trace_example.c
new file mode 100644 (file)
index 0000000..71cfeb7
--- /dev/null
@@ -0,0 +1,211 @@
+/* 2015 Petteri Aimonen <jpa@git.mail.kapsi.fi>
+ * Public domain
+ *
+ * This file is an example on how to configure the TPIU/DWT/ITM/ETM blocks
+ * on a Cortex-M3 microcontroller for tracing the execution. Trace data is
+ * output from the TRACESWO pin.
+ *
+ * Designed to run especially on STM32 Value Line discovery board, but should
+ * be easily adaptible to other boards also. Note that the STM32F100 chip on
+ * value line discovery does not have ETM feature.
+ *
+ * What this does:
+ * 1) Configures the trace pin to output TPIU formatted trace from both ITM and ETM.
+ * 2) Blinks a led, while monitored by ITM tracing.
+ * 3) Causes periodic interrupts, where it runs bubblesort while tracing it with ETM.
+ */
+
+#include "stm32f10x.h"
+#include "core_cm3.h"
+#include "arm_etm.h"
+
+int globalCounter; // For watchpoint example
+
+void hardfault_handler(void) { for(;;); }
+
+void configure_tracing()
+{
+    /* STM32 specific configuration to enable the TRACESWO IO pin */
+    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
+    AFIO->MAPR |= (2 << 24); // Disable JTAG to release TRACESWO
+    DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; // Enable IO trace pins
+    
+    if (!(DBGMCU->CR & DBGMCU_CR_TRACE_IOEN))
+    {
+        // Some (all?) STM32s don't allow writes to DBGMCU register until
+        // C_DEBUGEN in CoreDebug->DHCSR is set. This cannot be set by the
+        // CPU itself, so in practice you need to connect to the CPU with
+        // a debugger once before resetting it.
+        return;
+    }
+    
+    /* Configure Trace Port Interface Unit */
+    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // Enable access to registers
+    TPI->ACPR = 0; // Trace clock = HCLK/(x+1) = 8MHz
+    TPI->SPPR = 2; // Pin protocol = NRZ/USART
+    TPI->FFCR = 0x102; // TPIU packet framing enabled when bit 2 is set.
+                       // You can use 0x100 if you only need DWT/ITM and not ETM.
+    
+    /* Configure PC sampling and exception trace  */
+    DWT->CTRL = (1 << DWT_CTRL_CYCTAP_Pos) // Prescaler for PC sampling
+                                           // 0 = x32, 1 = x512
+              | (0 << DWT_CTRL_POSTPRESET_Pos) // Postscaler for PC sampling
+                                                // Divider = value + 1
+              | (1 << DWT_CTRL_PCSAMPLENA_Pos) // Enable PC sampling
+              | (2 << DWT_CTRL_SYNCTAP_Pos)    // Sync packet interval
+                                               // 0 = Off, 1 = Every 2^23 cycles,
+                                               // 2 = Every 2^25, 3 = Every 2^27
+              | (1 << DWT_CTRL_EXCTRCENA_Pos)  // Enable exception trace
+              | (1 << DWT_CTRL_CYCCNTENA_Pos); // Enable cycle counter
+    
+    /* Configure instrumentation trace macroblock */
+    ITM->LAR = 0xC5ACCE55;
+    ITM->TCR = (1 << ITM_TCR_TraceBusID_Pos) // Trace bus ID for TPIU
+             | (1 << ITM_TCR_DWTENA_Pos) // Enable events from DWT
+             | (1 << ITM_TCR_SYNCENA_Pos) // Enable sync packets
+             | (1 << ITM_TCR_ITMENA_Pos); // Main enable for ITM
+    ITM->TER = 0xFFFFFFFF; // Enable all stimulus ports
+    
+    /* Configure embedded trace macroblock */
+    ETM->LAR = 0xC5ACCE55;
+    ETM_SetupMode();
+    ETM->CR = ETM_CR_ETMEN // Enable ETM output port
+            | ETM_CR_STALL_PROCESSOR // Stall processor when fifo is full
+            | ETM_CR_BRANCH_OUTPUT; // Report all branches
+    ETM->TRACEIDR = 2; // Trace bus ID for TPIU
+    ETM->TECR1 = ETM_TECR1_EXCLUDE; // Trace always enabled
+    ETM->FFRR = ETM_FFRR_EXCLUDE; // Stalling always enabled
+    ETM->FFLR = 24; // Stall when less than N bytes free in FIFO (range 1..24)
+                    // Larger values mean less latency in trace, but more stalls.
+    // Note: we do not enable ETM trace yet, only for specific parts of code.
+}
+
+void configure_watchpoint()
+{
+    /* This is an example of how to configure DWT to monitor a watchpoint.
+       The data value is reported when the watchpoint is hit. */
+    
+    /* Monitor all accesses to GPIOC (range length 32 bytes) */
+    DWT->COMP0 = (uint32_t)GPIOC;
+    DWT->MASK0 = 5;
+    DWT->FUNCTION0 = (2 << DWT_FUNCTION_FUNCTION_Pos) // Report data and addr on watchpoint hit
+                   | (1 << DWT_FUNCTION_EMITRANGE_Pos);
+    
+    /* Monitor all accesses to globalCounter (range length 4 bytes) */
+    DWT->COMP1 = (uint32_t)&globalCounter;
+    DWT->MASK1 = 2;
+    DWT->FUNCTION1 = (3 << DWT_FUNCTION_FUNCTION_Pos); // Report data and PC on watchpoint hit
+}
+
+// Print a given string to ITM.
+// This uses 8 bit writes, as that seems to be the most common way to write text
+// through ITM. Otherwise there is no good way for the PC software to know what
+// is text and what is some other data.
+void ITM_Print(int port, const char *p)
+{
+    if ((ITM->TCR & ITM_TCR_ITMENA_Msk) && (ITM->TER & (1UL << port)))
+    {
+        while (*p)
+        {
+            while (ITM->PORT[port].u32 == 0);
+            ITM->PORT[port].u8 = *p++;
+        }
+    }
+}
+
+// Write a 32-bit value to ITM.
+// This can be used as a fast way to log important values from code.
+void ITM_SendValue (int port, uint32_t value)
+{
+    if ((ITM->TCR & ITM_TCR_ITMENA_Msk) && (ITM->TER & (1UL << port)))
+    {
+        while (ITM->PORT[port].u32 == 0);
+        ITM->PORT[port].u32 = value;
+    }
+}
+
+void delay()
+{
+    for (int i = 0; i < 10000; i++)
+        asm("nop");
+}
+
+void bubble_sort (int *a, int n) {
+    int i, t, s = 1;
+    while (s) {
+        s = 0;
+        for (i = 1; i < n; i++) {
+            if (a[i] < a[i - 1]) {
+                t = a[i];
+                a[i] = a[i - 1];
+                a[i - 1] = t;
+                s = 1;
+            }
+        }
+    }
+}
+
+void TIM2_IRQ()
+{
+    int values[5] = {35,2,235,11,2};
+
+    // We are very interested in how the values get sorted,
+    // so we enable ETM tracing for it.
+    ETM_TraceMode();
+    GPIOC->BSRR = (1 << 9); // Toggle a led so that we can see the latency in ETM trace
+    bubble_sort(values, 5);
+    GPIOC->BRR = (1 << 9);
+    ETM_SetupMode();
+
+    // We can also use ITM to send the result of the sort
+    // Note that we use port 1 here so that output does not get mixed
+    // with port 0 output from main thread.
+    ITM_Print(1, "Sort");
+    for (int i = 0; i < 5; i++)
+        ITM_SendValue(1, values[i]);
+    
+    TIM2->SR = 0; // Clear interrupt flag
+}
+
+int main(void)
+{
+    configure_tracing();
+    configure_watchpoint();
+
+    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
+    GPIOC->CRH = 0x44444433; // GPIOC 8 and 9 as output (STM32F1 discovery leds)
+    
+    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
+    NVIC_EnableIRQ(TIM2_IRQn);
+    TIM2->ARR = 50000;
+    TIM2->DIER = 1;
+    TIM2->CR1 = 1;
+    
+    ITM_Print(0, "Boot");
+    
+    globalCounter = 0;
+    
+    for (;;)
+    {
+        delay();
+        GPIOC->BSRR = (1 << 8);
+        ITM_Print(0, "On");
+
+        delay();
+        GPIOC->BRR = (1 << 8);
+        ITM_Print(0, "Off");
+        
+        globalCounter++; // This will trigger the watchpoint
+    }
+}
+
+
+void* myvectors[] 
+__attribute__ ((section("vectors")))= {
+    (void*)0x20002000, // Stack ptr
+    main,       // Reset addr
+    hardfault_handler,
+    hardfault_handler,
+    [16 + TIM2_IRQn] = TIM2_IRQ
+};
+
diff --git a/arm_trace/stm32f105/trace_example.elf b/arm_trace/stm32f105/trace_example.elf
new file mode 100644 (file)
index 0000000..10cb434
Binary files /dev/null and b/arm_trace/stm32f105/trace_example.elf differ
diff --git a/arm_trace/stm32f105/trace_example.sr b/arm_trace/stm32f105/trace_example.sr
new file mode 100644 (file)
index 0000000..b1e3c59
Binary files /dev/null and b/arm_trace/stm32f105/trace_example.sr differ