Serial Wire Output (SWO) viewer for tracing purposes. Tested on F401 and ST-LINK Utility as well as for F103 and Segger J-Link SWO viewer.

Dependents:   WiFi_Scanner DISCO-F429ZI_LCDTS_demo_richard mbed_nucleo_swo

Committer:
wim
Date:
Thu Aug 24 18:15:02 2017 +0000
Revision:
4:53de8ef789f3
Parent:
3:e5af2e131b95
Added stream claim for stdout, proposed by Pavel Sorejs.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
wim1:bae4cff278f6 1/* mbed SWO Library
wim2:ef928f61a770 2 * Copyright (c) 2014, v01: WH. Ported from Segger example (www.segger.com)
wim3:e5af2e131b95 3 * v02: WH. Added Class with Stream support
wim4:53de8ef789f3 4 * 2017, v03: WH,PS. Added stream claim for stdout, proposed by Pavel Sorejs
wim1:bae4cff278f6 5 *
wim2:ef928f61a770 6 * Simple implementation for tracing via Serial Wire Output(SWO) for Cortex-M processors.
wim1:bae4cff278f6 7 * It can be used with Host PC software such as ST-LINK Utility or Segger J-Link SWO viewer.
wim1:bae4cff278f6 8 * This sample implementation ensures that output via SWO is enabled in order to guarantee
wim1:bae4cff278f6 9 * that the application does not hang.
wim1:bae4cff278f6 10 *
wim1:bae4cff278f6 11 * Permission is hereby granted, free of charge, to any person obtaining a copy
wim1:bae4cff278f6 12 * of this software and associated documentation files (the "Software"), to deal
wim1:bae4cff278f6 13 * in the Software without restriction, including without limitation the rights
wim1:bae4cff278f6 14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
wim1:bae4cff278f6 15 * copies of the Software, and to permit persons to whom the Software is
wim1:bae4cff278f6 16 * furnished to do so, subject to the following conditions:
wim1:bae4cff278f6 17 *
wim1:bae4cff278f6 18 * The above copyright notice and this permission notice shall be included in
wim1:bae4cff278f6 19 * all copies or substantial portions of the Software.
wim1:bae4cff278f6 20 *
wim1:bae4cff278f6 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
wim1:bae4cff278f6 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
wim1:bae4cff278f6 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
wim1:bae4cff278f6 24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
wim1:bae4cff278f6 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
wim1:bae4cff278f6 26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
wim1:bae4cff278f6 27 * THE SOFTWARE.
wim1:bae4cff278f6 28 */
wim2:ef928f61a770 29#include "mbed.h"
wim0:0fd55660fc26 30#include "SWO.h"
wim0:0fd55660fc26 31
wim3:e5af2e131b95 32//
wim3:e5af2e131b95 33// This the Class implementation
wim3:e5af2e131b95 34//
wim3:e5af2e131b95 35
wim3:e5af2e131b95 36/** Create and SWO interface for debugging that supports Stream
wim3:e5af2e131b95 37 * @brief Currently works on nucleo ST-LINK using ST-Link Utility and other devices that support SWD/SWO using Segger SWO viewer
wim3:e5af2e131b95 38 */
wim4:53de8ef789f3 39SWO_Channel::SWO_Channel (const char *name) : Stream(name) {
wim3:e5af2e131b95 40 //May want to add initialisation stuff here
wim3:e5af2e131b95 41}
wim4:53de8ef789f3 42
wim3:e5af2e131b95 43
wim3:e5af2e131b95 44/** Write a single character (Stream implementation)
wim3:e5af2e131b95 45 *
wim3:e5af2e131b95 46 * @param value character to be displayed
wim3:e5af2e131b95 47 * @return value
wim3:e5af2e131b95 48 */
wim3:e5af2e131b95 49int SWO_Channel::_putc(int value) {
wim3:e5af2e131b95 50
wim3:e5af2e131b95 51 //Use CMSIS_core_DebugFunctions. See core_cm3.h
wim3:e5af2e131b95 52 ITM_SendChar(value);
wim3:e5af2e131b95 53
wim3:e5af2e131b95 54 return value;
wim3:e5af2e131b95 55}
wim3:e5af2e131b95 56
wim3:e5af2e131b95 57/** Get a single character (Stream implementation)
wim3:e5af2e131b95 58 * @return -1 Not supported
wim3:e5af2e131b95 59 */
wim3:e5af2e131b95 60int SWO_Channel::_getc() {
wim3:e5af2e131b95 61 return -1;
wim3:e5af2e131b95 62}
wim3:e5af2e131b95 63
wim4:53de8ef789f3 64 /**
wim4:53de8ef789f3 65 * Claim and redirect a stream to this SWO object
wim4:53de8ef789f3 66 * Important: A name parameter must have been added when creating the SWO object.
wim4:53de8ef789f3 67 *
wim4:53de8ef789f3 68 * @param FILE *stream The stream to redirect (default = stdout)
wim4:53de8ef789f3 69 * @return true if succeeded, else false
wim4:53de8ef789f3 70 */
wim4:53de8ef789f3 71bool SWO_Channel::claim (FILE *stream) {
wim4:53de8ef789f3 72 if ( FileBase::getName() == NULL) {
wim4:53de8ef789f3 73 error("claim requires a name to be given in the instantiator of the SWO instance!\r\n");
wim4:53de8ef789f3 74 }
wim4:53de8ef789f3 75
wim4:53de8ef789f3 76 //Add '/' before name:
wim4:53de8ef789f3 77 char *path = new char[strlen(FileBase::getName()) + 2];
wim4:53de8ef789f3 78 sprintf(path, "/%s", FileBase::getName());
wim4:53de8ef789f3 79
wim4:53de8ef789f3 80 if (freopen(path, "w", stream) == NULL) {
wim4:53de8ef789f3 81 // Failed, should not happen
wim4:53de8ef789f3 82 return false;
wim4:53de8ef789f3 83 }
wim4:53de8ef789f3 84
wim4:53de8ef789f3 85 delete(path);
wim4:53de8ef789f3 86
wim4:53de8ef789f3 87 //No buffering
wim4:53de8ef789f3 88 setvbuf(stream, NULL, _IONBF, 32);
wim4:53de8ef789f3 89 return true;
wim4:53de8ef789f3 90}
wim4:53de8ef789f3 91
wim4:53de8ef789f3 92
wim3:e5af2e131b95 93
wim3:e5af2e131b95 94//
wim3:e5af2e131b95 95//This is the classic implementation
wim3:e5af2e131b95 96//
wim3:e5af2e131b95 97
wim1:bae4cff278f6 98/**
wim1:bae4cff278f6 99 * Defines for Cortex-M debug unit
wim1:bae4cff278f6 100 */
wim3:e5af2e131b95 101#define ITM_STIM_U32(n) (*(volatile unsigned int*) (0xE0000000+4*n)) // Stimulus Port n Register word access
wim3:e5af2e131b95 102#define ITM_STIM_U8(n) (*(volatile unsigned char*)(0xE0000000+4*n)) // Stimulus Port n Register byte access
wim0:0fd55660fc26 103//#define ITM_STIM_U32_0 (*(volatile unsigned int*)0xE0000000) // Stimulus Port 0 Register word access
wim0:0fd55660fc26 104//#define ITM_STIM_U8_0 (*(volatile char*)0xE0000000) // Stimulus Port 0 Register byte access
wim0:0fd55660fc26 105#define ITM_ENA (*(volatile unsigned int*)0xE0000E00) // Trace Enable Ports Register
wim0:0fd55660fc26 106#define ITM_TCR (*(volatile unsigned int*)0xE0000E80) // Trace control register
wim0:0fd55660fc26 107
wim2:ef928f61a770 108#define ITM_STIM_FIFOREADY 0x00000001 // FIFO empty
wim2:ef928f61a770 109
wim2:ef928f61a770 110//Stuff below is for documentation and needs further testing
wim2:ef928f61a770 111// It seems that the Segger SWO Viewer and the ST-Link Utility do most/all of these
wim2:ef928f61a770 112// initialisations on the target before starting the session. This is probably not the case
wim2:ef928f61a770 113// when using GDB/OpenOCD.
wim2:ef928f61a770 114//
wim2:ef928f61a770 115//
wim2:ef928f61a770 116#if(0)
wim2:ef928f61a770 117#include <libopencm3/stm32/rcc.h>
wim2:ef928f61a770 118#include <libopencm3/stm32/gpio.h>
wim2:ef928f61a770 119
wim2:ef928f61a770 120#include <libopencm3/stm32/dbgmcu.h>
wim2:ef928f61a770 121#include <libopencm3/cm3/scs.h>
wim2:ef928f61a770 122#include <libopencm3/cm3/tpiu.h>
wim2:ef928f61a770 123#include <libopencm3/cm3/itm.h>
wim2:ef928f61a770 124
wim1:bae4cff278f6 125/**
wim2:ef928f61a770 126 * SWO_Setup() Example
wim1:bae4cff278f6 127 *
wim2:ef928f61a770 128 * This file is part of the libopencm3 project.
wim2:ef928f61a770 129 *
wim2:ef928f61a770 130 * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
wim2:ef928f61a770 131 * https://github.com/1divf/libopenstm32/blob/master/examples/stm32/stm32-h103/traceswo/traceswo.c
wim2:ef928f61a770 132 *
wim2:ef928f61a770 133 */
wim2:ef928f61a770 134void SWO_Setup(void) {
wim2:ef928f61a770 135 /* Enable trace subsystem (we'll use ITM and TPIU) */
wim2:ef928f61a770 136 SCS_DEMCR |= SCS_DEMCR_TRCENA;
wim2:ef928f61a770 137
wim2:ef928f61a770 138 /* Use Manchester code for asynchronous transmission */
wim2:ef928f61a770 139 TPIU_SPPR = TPIU_SPPR_ASYNC_MANCHESTER;
wim2:ef928f61a770 140 TPIU_ACPR = 7;
wim2:ef928f61a770 141
wim2:ef928f61a770 142 /* Data width is 1 byte */
wim2:ef928f61a770 143 TPIU_CSPSR = TPIU_CSPSR_BYTE;
wim2:ef928f61a770 144
wim2:ef928f61a770 145 /* Formatter and flush control */
wim2:ef928f61a770 146 TPIU_FFCR &= ~TPIU_FFCR_ENFCONT;
wim2:ef928f61a770 147
wim2:ef928f61a770 148 /* Enable TRACESWO pin for async mode */
wim2:ef928f61a770 149 DBGMCU_CR = DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE_ASYNC;
wim2:ef928f61a770 150
wim2:ef928f61a770 151 /* Unlock access to ITM registers */
wim2:ef928f61a770 152 /* FIXME: Magic numbers... Is this Cortex-M3 generic? */
wim2:ef928f61a770 153 *((volatile uint32_t*)0xE0000FB0) = 0xC5ACCE55;
wim2:ef928f61a770 154
wim2:ef928f61a770 155 /* Enable ITM with ID = 1 */
wim2:ef928f61a770 156 ITM_TCR = (1 << 16) | ITM_TCR_ITMENA;
wim2:ef928f61a770 157 /* Enable stimulus port 1 */
wim2:ef928f61a770 158 ITM_TER[0] = 1;
wim2:ef928f61a770 159}
wim2:ef928f61a770 160
wim2:ef928f61a770 161/**
wim2:ef928f61a770 162 * SWO_Setup() Example
wim2:ef928f61a770 163 *
wim2:ef928f61a770 164 * http://forum.segger.com/index.php?page=Thread&threadID=608
wim2:ef928f61a770 165 *
wim2:ef928f61a770 166 */
wim2:ef928f61a770 167void SWO_Setup_1(void) {
wim2:ef928f61a770 168 U32 SWOPrescaler;
wim2:ef928f61a770 169 U32 SWOSpeed;
wim2:ef928f61a770 170
wim2:ef928f61a770 171//<Init PLL, set CPU clock to 72 MHz> // Optional, so I do not pos it here
wim2:ef928f61a770 172
wim2:ef928f61a770 173 SWOSpeed = 6000000;
wim2:ef928f61a770 174 *((volatile unsigned *)0xE000EDFC) = 0x01000000; // "Debug Exception and Monitor Control Register (DEMCR)"
wim2:ef928f61a770 175 *((volatile unsigned *)0xE0042004) = 0x00000027;
wim2:ef928f61a770 176 *((volatile unsigned *)0xE00400F0) = 0x00000002; // "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO)
wim2:ef928f61a770 177 SWOPrescaler = (72000000 / SWOSpeed) - 1; // SWOSpeed in Hz
wim2:ef928f61a770 178 *((volatile unsigned *)0xE0040010) = SWOPrescaler; // "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output
wim2:ef928f61a770 179 *((volatile unsigned *)0xE0000FB0) = 0xC5ACCE55; // ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC
wim2:ef928f61a770 180 *((volatile unsigned *)0xE0000E80) = 0x0001000D; // ITM Trace Control Register
wim2:ef928f61a770 181 *((volatile unsigned *)0xE0000E40) = 0x0000000F; // ITM Trace Privilege Register
wim2:ef928f61a770 182 *((volatile unsigned *)0xE0000E00) = 0x00000001; // ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port.
wim2:ef928f61a770 183 *((volatile unsigned *)0xE0001000) = 0x400003FE; // DWT_CTRL
wim2:ef928f61a770 184 *((volatile unsigned *)0xE0040304) = 0x00000100; // Formatter and Flush Control Register
wim2:ef928f61a770 185}
wim2:ef928f61a770 186#endif
wim2:ef928f61a770 187
wim2:ef928f61a770 188/**
wim1:bae4cff278f6 189 * SWO_PrintChar()
wim1:bae4cff278f6 190 *
wim1:bae4cff278f6 191 * @brief
wim1:bae4cff278f6 192 * Checks if SWO is set up. If it is not, return,
wim1:bae4cff278f6 193 * to avoid program hangs if no debugger is connected.
wim1:bae4cff278f6 194 * If it is set up, print a character to the ITM_STIM register
wim1:bae4cff278f6 195 * in order to provide data for SWO.
wim1:bae4cff278f6 196 * @param c The Character to be printed.
wim1:bae4cff278f6 197 * @notes Additional checks for device specific registers can be added.
wim1:bae4cff278f6 198 */
wim1:bae4cff278f6 199void SWO_PrintChar(char c) {
wim0:0fd55660fc26 200
wim2:ef928f61a770 201#if(1)
wim2:ef928f61a770 202//Use CMSIS_core_DebugFunctions. See core_cm3.h
wim2:ef928f61a770 203 ITM_SendChar (c);
wim2:ef928f61a770 204
wim2:ef928f61a770 205#else
wim2:ef928f61a770 206//Use Segger example. Basically same as CMSIS
wim2:ef928f61a770 207
wim0:0fd55660fc26 208 // Check if ITM_TCR.ITMENA is set
wim0:0fd55660fc26 209 if ((ITM_TCR & 1) == 0) {
wim0:0fd55660fc26 210 return;
wim0:0fd55660fc26 211 }
wim1:bae4cff278f6 212
wim0:0fd55660fc26 213 // Check if stimulus port is enabled
wim0:0fd55660fc26 214 if ((ITM_ENA & 1) == 0) {
wim0:0fd55660fc26 215 return;
wim0:0fd55660fc26 216 }
wim0:0fd55660fc26 217
wim1:bae4cff278f6 218 // Wait until STIMx FIFO is ready, then send data
wim2:ef928f61a770 219// while ((ITM_STIM_U8(0) & 1) == 0);
wim2:ef928f61a770 220 while (!(ITM_STIM_U8(0) & ITM_STIM_FIFOREADY));
wim1:bae4cff278f6 221 ITM_STIM_U8(0) = c;
wim2:ef928f61a770 222
wim1:bae4cff278f6 223// while ((ITM_STIM_U32(0) & 1) == 0);
wim1:bae4cff278f6 224// ITM_STIM_U32(0) = c;
wim2:ef928f61a770 225
wim2:ef928f61a770 226#endif
wim0:0fd55660fc26 227}
wim0:0fd55660fc26 228
wim1:bae4cff278f6 229/**
wim1:bae4cff278f6 230 * SWO_PrintString()
wim1:bae4cff278f6 231 *
wim1:bae4cff278f6 232 * @brief Print a string via SWO.
wim1:bae4cff278f6 233 * @param *s The string to be printed.
wim1:bae4cff278f6 234 *
wim1:bae4cff278f6 235 */
wim0:0fd55660fc26 236void SWO_PrintString(const char *s) {
wim1:bae4cff278f6 237
wim1:bae4cff278f6 238 // Print out characters until \0
wim0:0fd55660fc26 239 while (*s) {
wim0:0fd55660fc26 240 SWO_PrintChar(*s++);
wim0:0fd55660fc26 241 }
wim3:e5af2e131b95 242}
wim3:e5af2e131b95 243
wim3:e5af2e131b95 244
wim3:e5af2e131b95 245