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 mbed_nucleo_swo DISCO-F429ZI_LCDTS_demo_richard TEST_SM_SPEED

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SWO.cpp Source File

SWO.cpp

00001 /* mbed SWO Library
00002  *  Copyright (c) 2014, v01: WH. Ported from Segger example (www.segger.com)
00003  *                      v02: WH. Added Class with Stream support
00004  *                2017, v03: WH,PS. Added stream claim for stdout, proposed by Pavel Sorejs
00005  *
00006  * Simple implementation for tracing via Serial Wire Output(SWO) for Cortex-M processors.
00007  * It can be used with Host PC software such as ST-LINK Utility or Segger J-Link SWO viewer.
00008  * This sample implementation ensures that output via SWO is enabled in order to guarantee
00009  * that the application does not hang.
00010  *
00011  * Permission is hereby granted, free of charge, to any person obtaining a copy
00012  * of this software and associated documentation files (the "Software"), to deal
00013  * in the Software without restriction, including without limitation the rights
00014  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00015  * copies of the Software, and to permit persons to whom the Software is
00016  * furnished to do so, subject to the following conditions:
00017  *
00018  * The above copyright notice and this permission notice shall be included in
00019  * all copies or substantial portions of the Software.
00020  *
00021  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00022  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00023  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00024  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00025  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00026  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00027  * THE SOFTWARE.
00028  */
00029 #include "mbed.h"
00030 #include "SWO.h"
00031 
00032 //
00033 // This the Class implementation
00034 //
00035 
00036 /** Create and SWO interface for debugging that supports Stream
00037   * @brief Currently works on nucleo ST-LINK using ST-Link Utility and other devices that support SWD/SWO using Segger SWO viewer
00038   */
00039 SWO_Channel::SWO_Channel (const char *name) : Stream(name) {
00040   //May want to add initialisation stuff here  
00041 }
00042  
00043 
00044 /** Write a single character (Stream implementation)
00045   *
00046   * @param value character to be displayed
00047   * @return value
00048   */
00049 int SWO_Channel::_putc(int value) {
00050   
00051   //Use CMSIS_core_DebugFunctions. See core_cm3.h
00052   ITM_SendChar(value);
00053   
00054   return value;
00055 }
00056 
00057 /** Get a single character (Stream implementation)
00058   * @return -1 Not supported
00059   */
00060 int SWO_Channel::_getc() {
00061     return -1;
00062 }
00063 
00064  /**
00065   * Claim and redirect a stream to this SWO object
00066   * Important: A name parameter must have been added when creating the SWO object.
00067   *
00068   * @param FILE *stream The stream to redirect (default = stdout)
00069   * @return true if succeeded, else false
00070   */  
00071 bool SWO_Channel::claim (FILE *stream) {
00072     if ( FileBase::getName() == NULL) {
00073         error("claim requires a name to be given in the instantiator of the SWO instance!\r\n");
00074     }
00075     
00076     //Add '/' before name:
00077     char *path = new char[strlen(FileBase::getName()) + 2];
00078     sprintf(path, "/%s", FileBase::getName());
00079     
00080     if (freopen(path, "w", stream) == NULL) {
00081         // Failed, should not happen
00082         return false;
00083     }
00084     
00085     delete(path);
00086     
00087     //No buffering
00088     setvbuf(stream, NULL, _IONBF, 32);
00089     return true;
00090 } 
00091  
00092 
00093 
00094 //
00095 //This is the classic implementation
00096 //
00097 
00098 /**
00099  * Defines for Cortex-M debug unit
00100  */
00101 #define ITM_STIM_U32(n) (*(volatile unsigned int*) (0xE0000000+4*n))  // Stimulus Port n Register word access
00102 #define ITM_STIM_U8(n)  (*(volatile unsigned char*)(0xE0000000+4*n))  // Stimulus Port n Register byte access
00103 //#define ITM_STIM_U32_0  (*(volatile unsigned int*)0xE0000000)        // Stimulus Port 0 Register word access
00104 //#define ITM_STIM_U8_0   (*(volatile         char*)0xE0000000)        // Stimulus Port 0 Register byte access
00105 #define ITM_ENA         (*(volatile unsigned int*)0xE0000E00)        // Trace Enable Ports Register
00106 #define ITM_TCR         (*(volatile unsigned int*)0xE0000E80)        // Trace control register
00107 
00108 #define ITM_STIM_FIFOREADY                        0x00000001         // FIFO empty
00109 
00110 //Stuff below is for documentation and needs further testing
00111 // It seems that the Segger SWO Viewer and the ST-Link Utility do most/all of these
00112 // initialisations on the target before starting the session. This is probably not the case 
00113 // when using GDB/OpenOCD.
00114 //
00115 //
00116 #if(0)
00117 #include <libopencm3/stm32/rcc.h>
00118 #include <libopencm3/stm32/gpio.h>
00119 
00120 #include <libopencm3/stm32/dbgmcu.h>
00121 #include <libopencm3/cm3/scs.h>
00122 #include <libopencm3/cm3/tpiu.h>
00123 #include <libopencm3/cm3/itm.h> 
00124 
00125 /**
00126  * SWO_Setup() Example
00127  *
00128  * This file is part of the libopencm3 project.
00129  *
00130  * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de> 
00131  * https://github.com/1divf/libopenstm32/blob/master/examples/stm32/stm32-h103/traceswo/traceswo.c
00132  *
00133  */
00134 void SWO_Setup(void) { 
00135     /* Enable trace subsystem (we'll use ITM and TPIU) */
00136     SCS_DEMCR |= SCS_DEMCR_TRCENA;
00137 
00138     /* Use Manchester code for asynchronous transmission */
00139     TPIU_SPPR = TPIU_SPPR_ASYNC_MANCHESTER;
00140     TPIU_ACPR = 7;
00141 
00142     /* Data width is 1 byte */
00143     TPIU_CSPSR = TPIU_CSPSR_BYTE;
00144 
00145     /* Formatter and flush control */
00146     TPIU_FFCR &= ~TPIU_FFCR_ENFCONT;
00147 
00148     /* Enable TRACESWO pin for async mode */
00149     DBGMCU_CR = DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE_ASYNC;
00150 
00151     /* Unlock access to ITM registers */
00152     /* FIXME: Magic numbers... Is this Cortex-M3 generic? */
00153     *((volatile uint32_t*)0xE0000FB0) = 0xC5ACCE55;
00154 
00155     /* Enable ITM with ID = 1 */
00156     ITM_TCR = (1 << 16) | ITM_TCR_ITMENA;
00157     /* Enable stimulus port 1 */
00158     ITM_TER[0] = 1; 
00159 }
00160 
00161 /**
00162  * SWO_Setup() Example
00163  *
00164  * http://forum.segger.com/index.php?page=Thread&threadID=608
00165  *
00166  */
00167 void SWO_Setup_1(void) { 
00168   U32 SWOPrescaler;
00169   U32 SWOSpeed;
00170 
00171 //<Init PLL, set CPU clock to 72 MHz>  // Optional, so I do not pos it here
00172 
00173   SWOSpeed = 6000000;
00174    *((volatile unsigned *)0xE000EDFC) = 0x01000000;   // "Debug Exception and Monitor Control Register (DEMCR)"
00175    *((volatile unsigned *)0xE0042004) = 0x00000027;
00176    *((volatile unsigned *)0xE00400F0) = 0x00000002;   // "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO)
00177   SWOPrescaler = (72000000 / SWOSpeed) - 1;  // SWOSpeed in Hz
00178    *((volatile unsigned *)0xE0040010) = SWOPrescaler; // "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output
00179    *((volatile unsigned *)0xE0000FB0) = 0xC5ACCE55;   // ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC
00180    *((volatile unsigned *)0xE0000E80) = 0x0001000D;   // ITM Trace Control Register
00181    *((volatile unsigned *)0xE0000E40) = 0x0000000F;   // ITM Trace Privilege Register
00182    *((volatile unsigned *)0xE0000E00) = 0x00000001;   // ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port.
00183    *((volatile unsigned *)0xE0001000) = 0x400003FE;   // DWT_CTRL
00184    *((volatile unsigned *)0xE0040304) = 0x00000100;   // Formatter and Flush Control Register
00185 }
00186 #endif
00187 
00188 /**
00189  * SWO_PrintChar()
00190  *
00191  * @brief 
00192  *   Checks if SWO is set up. If it is not, return,
00193  *    to avoid program hangs if no debugger is connected.
00194  *   If it is set up, print a character to the ITM_STIM register
00195  *    in order to provide data for SWO.
00196  * @param c The Character to be printed.
00197  * @notes   Additional checks for device specific registers can be added.
00198  */
00199 void SWO_PrintChar(char c) {
00200 
00201 #if(1)
00202 //Use CMSIS_core_DebugFunctions. See core_cm3.h
00203   ITM_SendChar (c);
00204 
00205 #else
00206 //Use Segger example. Basically same as CMSIS
00207 
00208   // Check if ITM_TCR.ITMENA is set
00209   if ((ITM_TCR & 1) == 0) {
00210     return;
00211   }
00212 
00213   // Check if stimulus port is enabled
00214   if ((ITM_ENA & 1) == 0) {
00215     return;
00216   }
00217 
00218   // Wait until STIMx FIFO is ready, then send data
00219 //  while ((ITM_STIM_U8(0) & 1) == 0);
00220   while (!(ITM_STIM_U8(0) & ITM_STIM_FIFOREADY));    
00221   ITM_STIM_U8(0) = c;
00222   
00223 //  while ((ITM_STIM_U32(0) & 1) == 0);
00224 //  ITM_STIM_U32(0) = c;
00225 
00226 #endif
00227 }
00228 
00229 /**
00230  * SWO_PrintString()
00231  *
00232  * @brief Print a string via SWO.
00233  * @param *s The string to be printed.
00234  *
00235  */
00236 void SWO_PrintString(const char *s) {
00237 
00238   // Print out characters until \0
00239   while (*s) {
00240     SWO_PrintChar(*s++);
00241   }
00242 }
00243 
00244 
00245