2026-01-22 10:49 AM
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
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 = 0b111111u;
// 5. Write 0x1 to the ITM Trace Privilege Register to unmask stimulus ports 7:0
ITM->TPR = 1u;
// (not documented)
// ITM->LAR = 0u;
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?
2026-01-22 10:57 AM
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.