AnsweredAssumed Answered

Enabling SWO on a K22

Question asked by Chris Keeser on Aug 8, 2017

Summary: What do I need to do to enable SWO output on the TDO pin for a K22 device?

 

My goal is to enable SWO output on the appropriate pin from bootup without using a debugger.  Put another way, I want to power up my K22 device, connect a logic analyzer to the SWO pin and see data.  I want to be able to see the data without connecting a J-link or any other debug probe to the K22.

 

I have followed the instructions provided by Erick Styger at Tutorial: Using Single Wire Output SWO with ARM Cortex-M and Eclipse | MCU on Eclipse and have successfully enabled SWO, but only when a debug probe is connected. The debugger sends some commands which enables the SWO output when connected, and the SWO data is not present unless those commands are sent.

 

However, the steps described in the blog post do not enable SWO output without a debugger attached.  When the K22 begins execution, the SWO line is logic low, and stays low.  What steps / register writes do I need to perform to enable SWO output all the time?

 

Here is my code:

 

void SWO_Init(uint32_t portBits, uint32_t cpuCoreFreq)
{
    enum class EncodeType : uint32_t
    {
        SYNCHRONOUS = 0,
        MANCHESTER  = 1,
        NRZ         = 2,
    };
    uint32_t SWOSpeed     = 1000000; // 1 Mbs
    uint32_t SWOPrescaler = (cpuCoreFreq / SWOSpeed) - 1;

    /* Turn on the trace block ? */
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;

    /* Specify the way that data will be transmitted via the SWO pin */
    /* "Selected PIN Protocol Register": Select which protocol to use for trace
     * output (2: SWO NRZ, 1: SWO Manchester encoding) */

    *((volatile unsigned *) (ITM_BASE + 0x400F0)) =
        static_cast<uint32_t>(EncodeType::NRZ);

    /* "Async Clock Prescaler Register". Scale the baud rate of the asynchronous
     * output */

    *((volatile unsigned *) (ITM_BASE + 0x40010)) = SWOPrescaler;

    /* ITM Lock Access Register, C5ACCE55 enables more write access to
     * Control Register 0xE00 :: 0xFFC.  WHAT DOES THIS DO?  WHY IS
     * IT REQUIRED? */

    *((volatile unsigned *) (ITM_BASE + 0x00FB0)) = 0xC5ACCE55;

    /* ITM Trace Control Register.  WHY ARE THESE ALL ENABLED? */
    ITM->TCR = ITM_TCR_TraceBusID_Msk | ITM_TCR_SWOENA_Msk |
               ITM_TCR_SYNCENA_Msk | ITM_TCR_ITMENA_Msk;

    /* WHY IS THIS REQUIRED */
    ITM->TPR = ITM_TPR_PRIVMASK_Msk; /* ITM Trace Privilege Register */

    /* ITM Trace Enable Register. Enabled tracing on
     * stimulus ports. One bit per stimulus port. */

    ITM->TER = portBits;

    /* WHAT ARE THESE WRITES FOR? */
    *((volatile unsigned *) (ITM_BASE + 0x01000)) = 0x400003FE; /* DWT_CTRL */
    *((volatile unsigned *) (ITM_BASE + 0x40304)) =
        0x00000100; /* Formatter and Flush Control Register */
}

void SWO_PrintChar(char c, uint8_t portNo)
{
    volatile int timeout;

    /* Check if Trace Control Register (ITM->TCR at 0xE0000E80) is set */
    if((ITM->TCR & ITM_TCR_ITMENA_Msk) == 0)
    {           /* check Trace Control Register if ITM trace is enabled*/
        return; /* not enabled? */
    }
    /* Check if the requested channel stimulus port (ITM->TER at 0xE0000E00) is
     * enabled */

    if((ITM->TER & (1ul << portNo)) == 0)
    {           /* check Trace Enable Register if requested port is enabled */
        return; /* requested port not enabled? */
    }
    timeout = 5000; /* arbitrary timeout value */
    while(ITM->PORT[portNo].u32 == 0)
    {
        /* Wait until STIMx is ready, then send data */
        timeout--;
        if(timeout == 0)
        {
            return; /* not able to send */
        }
    }
    ITM->PORT[portNo].u8 = c;
}

void SWO_PrintString(const char * s, uint8_t portNumber)
{
    while(*s != '\0')
    {
        SWO_PrintChar(*s++, portNumber);
    }
}

int main(void)
{
    /* Init board hardware. */
        CLOCK_EnableClock(
        kCLOCK_PortA); /* Port A Clock Gate Control: Clock enabled */
    PORT_SetPinMux(PORTA, PIN2_IDX,
        kPORT_MuxAlt7); /* PORTA2 (pin 24) is configured as TRACE_SWO */

    BOARD_BootClockHSRUN();

    /* enable NRZ SWO encoding on port 0 with 96 Mhz system clock (1 Mbs) */
    SWO_Init(0x7, 96000000);

    for(;;)
    {
        for(uint32_t i = 0u; i < 100000; i++)
        {
            __asm volatile("NOP");
        }
        SWO_PrintString("Scooby Doo!\r\n", 0);
    }
}

Outcomes