Skip to main content
Associate III
January 22, 2026
Question

Cannot set ITMENA

  • January 22, 2026
  • 1 reply
  • 169 views

I'm attempting to follow https://community.st.com/t5/stm32-mcus/using-the-itm-console-for-printf-redirects-and-lwip-debug/tac-p/850072/highlight/true#M1661 but this always fails. This is on an STM32F303K8T. My reference manual says

avidroneg_0-1769105638276.png

and offers an example:

    "To output a simple value to the TPIU:
• Configure the TPIU and assign TRACE I/Os by configuring the DBGMCU_CR (refer to
Section 33.17.2: TRACE pin assignment and Section 33.16.3: Debug MCU
configuration register)
• Write 0xC5ACCE55 to the ITM Lock Access Register to unlock the write access to the
ITM registers
• Write 0x00010005 to the ITM Trace Control Register to enable the ITM with Sync
enabled and an ATB ID different from 0x00
• Write 0x1 to the ITM Trace Enable Register to enable the Stimulus Port 0
• Write 0x1 to the ITM Trace Privilege Register to unmask stimulus ports 7:0
• Write the value to output in the Stimulus Port Register 0: this can be done by software
(using a printf function)"

Based on this, and based on the IDE-provided definition of ITM_SendChar:

/**
 \brief ITM Send Character
 \details Transmits a character via the ITM channel 0, and
 \li Just returns when no debugger is connected that has booked the output.
 \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted.
 \param [in] ch Character to transmit.
 \returns Character to transmit.
 */
__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch)
{
 if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */
 ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */
 {
 while (ITM->PORT[0U].u32 == 0UL)
 {
 __NOP();
 }
 ITM->PORT[0U].u8 = (uint8_t)ch;
 }
 return (ch);
}

I have written:

// Number of ITM ports (defined by the ARM standard)
static const size_t N_PORTS = 32u;


bool logi_enable_itm(void) {
 // Follow along with 33.14.2 'Example of configuration'

 // 1. Configure the TPIU and assign TRACE I/Os by configuring the DBGMCU_CR
 // Done by the debugger host (i.e. Cube).

 // 2. Write 0xC5ACCE55 to the ITM Lock Access Register to unlock the write access to the
 // ITM registers
 ITM->LAR = 0xC5ACCE55u;

 // 3. Write to the ITM Trace Control Register to enable the ITM
 ITM->TCR = ITM_TCR_ITMENA_Msk;

 // 4. Write to the ITM Trace Enable Register to enable the Stimulus Ports
 ITM->TER = 0xFFu;

 // 5. Write 0x1 to the ITM Trace Privilege Register to unmask stimulus ports 7:0
 ITM->TPR = 1u;

 return true;
}

static bool ITM_SendCharTo(uint8_t ch, uint8_t port) {
 if (port >= N_PORTS)
 	return false;
 const uint32_t
 tcr = ITM->TCR & ITM_TCR_ITMENA_Msk, // ITM enabled
 ter = ITM->TER & (1u << port); // port enabled
 if (!(tcr && ter))
 return false;

 while (ITM->PORT[port].u32 == 0u)
 __NOP();

 ITM->PORT[port].u8 = ch;
 return true;
}

 

but this always hangs on the NOP loop. I've also tried changing the ITM_TCR_TraceBusID and enabling SYNC, to no avail.

What could be happening here?

1 reply

avidronegAuthor
Associate III
January 22, 2026

Right after posting this, I found that STCube's SWV ITM Data Console needed to have Start Trace enabled for the loop to unblock, which I guess is what is implied by the SYNC feature. That's fine for debugging I guess, but this seems like a non-starter for production when the debugger is not connected.