/* mbed SWO Library * Copyright (c) 2014, v01: WH. Ported from Segger example (www.segger.com) * v02: WH. Added Class with Stream support * 2017, v03: WH,PS. Added stream claim for stdout, proposed by Pavel Sorejs * * Simple implementation for tracing via Serial Wire Output(SWO) for Cortex-M processors. * It can be used with Host PC software such as ST-LINK Utility or Segger J-Link SWO viewer. * This sample implementation ensures that output via SWO is enabled in order to guarantee * that the application does not hang. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "mbed.h" #include "SWO.h" // // This the Class implementation // /** Create and SWO interface for debugging that supports Stream * @brief Currently works on nucleo ST-LINK using ST-Link Utility and other devices that support SWD/SWO using Segger SWO viewer */ SWO_Channel::SWO_Channel (const char *name) : Stream(name) { //May want to add initialisation stuff here } /** Write a single character (Stream implementation) * * @param value character to be displayed * @return value */ int SWO_Channel::_putc(int value) { //Use CMSIS_core_DebugFunctions. See core_cm3.h ITM_SendChar(value); return value; } /** Get a single character (Stream implementation) * @return -1 Not supported */ int SWO_Channel::_getc() { return -1; } /** * Claim and redirect a stream to this SWO object * Important: A name parameter must have been added when creating the SWO object. * * @param FILE *stream The stream to redirect (default = stdout) * @return true if succeeded, else false */ bool SWO_Channel::claim (FILE *stream) { if ( FileBase::getName() == NULL) { error("claim requires a name to be given in the instantiator of the SWO instance!\r\n"); } //Add '/' before name: char *path = new char[strlen(FileBase::getName()) + 2]; sprintf(path, "/%s", FileBase::getName()); if (freopen(path, "w", stream) == NULL) { // Failed, should not happen return false; } delete(path); //No buffering setvbuf(stream, NULL, _IONBF, 32); return true; } // //This is the classic implementation // /** * Defines for Cortex-M debug unit */ #define ITM_STIM_U32(n) (*(volatile unsigned int*) (0xE0000000+4*n)) // Stimulus Port n Register word access #define ITM_STIM_U8(n) (*(volatile unsigned char*)(0xE0000000+4*n)) // Stimulus Port n Register byte access //#define ITM_STIM_U32_0 (*(volatile unsigned int*)0xE0000000) // Stimulus Port 0 Register word access //#define ITM_STIM_U8_0 (*(volatile char*)0xE0000000) // Stimulus Port 0 Register byte access #define ITM_ENA (*(volatile unsigned int*)0xE0000E00) // Trace Enable Ports Register #define ITM_TCR (*(volatile unsigned int*)0xE0000E80) // Trace control register #define ITM_STIM_FIFOREADY 0x00000001 // FIFO empty //Stuff below is for documentation and needs further testing // It seems that the Segger SWO Viewer and the ST-Link Utility do most/all of these // initialisations on the target before starting the session. This is probably not the case // when using GDB/OpenOCD. // // #if(0) #include #include #include #include #include #include /** * SWO_Setup() Example * * This file is part of the libopencm3 project. * * Copyright (C) 2009 Uwe Hermann * https://github.com/1divf/libopenstm32/blob/master/examples/stm32/stm32-h103/traceswo/traceswo.c * */ void SWO_Setup(void) { /* Enable trace subsystem (we'll use ITM and TPIU) */ SCS_DEMCR |= SCS_DEMCR_TRCENA; /* Use Manchester code for asynchronous transmission */ TPIU_SPPR = TPIU_SPPR_ASYNC_MANCHESTER; TPIU_ACPR = 7; /* Data width is 1 byte */ TPIU_CSPSR = TPIU_CSPSR_BYTE; /* Formatter and flush control */ TPIU_FFCR &= ~TPIU_FFCR_ENFCONT; /* Enable TRACESWO pin for async mode */ DBGMCU_CR = DBGMCU_CR_TRACE_IOEN | DBGMCU_CR_TRACE_MODE_ASYNC; /* Unlock access to ITM registers */ /* FIXME: Magic numbers... Is this Cortex-M3 generic? */ *((volatile uint32_t*)0xE0000FB0) = 0xC5ACCE55; /* Enable ITM with ID = 1 */ ITM_TCR = (1 << 16) | ITM_TCR_ITMENA; /* Enable stimulus port 1 */ ITM_TER[0] = 1; } /** * SWO_Setup() Example * * http://forum.segger.com/index.php?page=Thread&threadID=608 * */ void SWO_Setup_1(void) { U32 SWOPrescaler; U32 SWOSpeed; // // Optional, so I do not pos it here SWOSpeed = 6000000; *((volatile unsigned *)0xE000EDFC) = 0x01000000; // "Debug Exception and Monitor Control Register (DEMCR)" *((volatile unsigned *)0xE0042004) = 0x00000027; *((volatile unsigned *)0xE00400F0) = 0x00000002; // "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO) SWOPrescaler = (72000000 / SWOSpeed) - 1; // SWOSpeed in Hz *((volatile unsigned *)0xE0040010) = SWOPrescaler; // "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output *((volatile unsigned *)0xE0000FB0) = 0xC5ACCE55; // ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC *((volatile unsigned *)0xE0000E80) = 0x0001000D; // ITM Trace Control Register *((volatile unsigned *)0xE0000E40) = 0x0000000F; // ITM Trace Privilege Register *((volatile unsigned *)0xE0000E00) = 0x00000001; // ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port. *((volatile unsigned *)0xE0001000) = 0x400003FE; // DWT_CTRL *((volatile unsigned *)0xE0040304) = 0x00000100; // Formatter and Flush Control Register } #endif /** * SWO_PrintChar() * * @brief * Checks if SWO is set up. If it is not, return, * to avoid program hangs if no debugger is connected. * If it is set up, print a character to the ITM_STIM register * in order to provide data for SWO. * @param c The Character to be printed. * @notes Additional checks for device specific registers can be added. */ void SWO_PrintChar(char c) { #if(1) //Use CMSIS_core_DebugFunctions. See core_cm3.h ITM_SendChar (c); #else //Use Segger example. Basically same as CMSIS // Check if ITM_TCR.ITMENA is set if ((ITM_TCR & 1) == 0) { return; } // Check if stimulus port is enabled if ((ITM_ENA & 1) == 0) { return; } // Wait until STIMx FIFO is ready, then send data // while ((ITM_STIM_U8(0) & 1) == 0); while (!(ITM_STIM_U8(0) & ITM_STIM_FIFOREADY)); ITM_STIM_U8(0) = c; // while ((ITM_STIM_U32(0) & 1) == 0); // ITM_STIM_U32(0) = c; #endif } /** * SWO_PrintString() * * @brief Print a string via SWO. * @param *s The string to be printed. * */ void SWO_PrintString(const char *s) { // Print out characters until \0 while (*s) { SWO_PrintChar(*s++); } }