2019-10-07 02:25 AM
I need to use the ETM on a STM32H753 but without debugging tool. The idea is to record the execution trace all the time, and when the firmware encounter a critiical issue, output the trace to an external tool or program it to flash for later analysis. It is designed to work in operational mode, not through a debugging tool.
The documentation of ARM is very confusing on the topic. Some documents mentions the ETB (Embedded Trace Buffer) other documents mentions the ETF (Embedded Trace FIFO) but I couldn't really understand which is doing what.
I don't really understand what functionality of the STM32 to use to implement what I need, and also how to do it. Strangely enough, I didn't find any code example of discussion about this online. it's surprising because recording execution trace sounds like a very interesting functionality in safety critical environments in particular.
2019-10-07 06:22 AM
Tends to be the domain of debugger writers, ARM should have app notes, but presupposes familiarity with HW/SW at this level.
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0242b/DDI0242.pdf
Others on the forum have built trace HW, so might have some specific insight.
@Bob Boys any thoughts on the internal mechanics ARM can share?
2019-10-07 07:05 AM
Thank you Clive. So I've read again the related section in the ref Manual. What I deduced is that ARM provides several ways to store the execution trace and among them ST chose to implement the ETF.
This ETF can be setup in Circular Mode, which looks like the mode I need:
"3. Circular buffer mode
The trace memory is used as a circular buffer. Trace data is captured into the Trace
memory starting from the location pointed to by the write pointer register. Even when
the trace memory is full, incoming trace data continues to be overwritten into the trace
memory until a stop condition occurs.
In this mode, the ETF stores the trace data on-chip, so the trace log size is limited to
that of the ETF SRAM, 4 Kbytes in this case. Being a circular buffer, if the FIFO
becomes full, incoming trace data overwrites the oldest stored data and the oldest
stored data is lost. Therefore the contents of the trace buffer represent the most recent
activity of the processor, up to the point when the buffer was stopped, rather than all
the activity since the trace was started.
There are three possible methods to read out the buffer contents once the trace stops:
– via the Trace port - with the TPIU enabled, the contents of the buffer are output
over the Trace port. This can be done by setting the DRAINBUF bit in the
ETF_FFCR register.
– via the Debug port - the debugger can read the buffer via the RRD register that is
accessible over the system APB-D.
– by software - the processor can read the buffer via the RRD register, since the
APB-D is accessible from the system bus."
The reference manual also gives the description of the ETF registers. I will try to implement the functionality based on this but I find the documentation ia bit "light" to do so without wasting days. So I would still appreciate tips, code examples or application notes.
2019-10-07 08:58 AM
Like I said, I think ARM has app notes it shares with debugger developers. You might find reference to them via open source debugger projects, things like Open OCD spring to mind. ARM's forums may be a better place to ask, and might have debugger specific sub-forums.
2019-10-07 10:56 AM
These have been suggested, perhaps a bit heavy going
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0494d/DDI0494D_coresight_etm_m7_r0p1_trm.pdf
http://static.docs.arm.com/ihi0064/d/IHI0064D_etm_v4_architecture_spec.pdf
2019-10-07 11:05 AM
The "Debug Infrastructure" has some coverage here
Likely has material that "ARM® Cortex®-M7 Integration and Implementation Manual" would have, but you don't qualify to access (not a licensor of chip IP).
2019-10-08 06:03 AM
So I've based my implementation on two documents, the section on ETF in STMicro STM32 reference manual and ARM's Trace Memory Controller Reference Manual. In the latter in particular there is a sequence to setup the ETF:
Circular Buffer mode
The recommended standard usage model in this mode is as follows:
1. Wait until TMCReady is equal to one.
2. Program the MODE Register for Circular Buffer mode.
3. Program the FFCR Register. ARM recommends that you set the TrigOnTrigIn,
FOnTrigEvt, StopOnFl, EnTI, and EnFt bits. This enables formatting, inserting a trigger
when a trigger is observed on TRIGIN, and following a delay corresponding to the value
of the TRG Register, flushing and then stopping the TMC.
4. Program the TRG Register, to control the amount of buffer to be dedicated to the period
after a trigger is observed.
5. Set the TraceCaptEn bit in the CTL Register. This starts the trace session.
6. Wait until TMCReady is equal to one. This indicates that the trace session is over.
7. Read the contents of the trace buffer by performing successive reads to the RRD Register,
until the value 0xFFFFFFFF is returned.
8. Clear the TraceCaptEn bit in the CTL Register.
The notion of triggers is more or less incomprehensible so I've stupidly written the registers as described without really understanding what's going on.
But actually I can't go very far in my debug: it looks like the ETF registers are not accessible (they're all read to 0 either through the debugger or through my embedded software). There is probably an "enable" bit somewhere to activate or clock the TMC or ETM or ETF or who knows what macrocell.
Here is the piece of quick and dirty code I tried, every register is read to 0 and not modified by this code
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
// enable ETM trace
*ETM_PRGCTRL = 1;
// enable ETF circular mode
*ETF_FFCR = 0x00001123; // ARM recommends to set bits TRIGONTRIGIN FONTRIGEVT STOPONFL ENTI AND ENFT
*ETF_TRG = 16; // number of 32 words to capture
*ETF_CTL = 1; // enable trace
i = 1000;
while(i--)
asm("nop"); // ******** processing just to fill the trace
while ( ((*ETF_STS) & (1<<2)) == 0 );
printf("*ETF_RRD=0x%x\r\n", *ETF_RRD);
printf("*ETF_RRD=0x%x\r\n", *ETF_RRD);
printf("*ETF_RRD=0x%x\r\n", *ETF_RRD);
printf("*ETF_RRD=0x%x\r\n", *ETF_RRD);
*ETF_CTL = 0; // disable trace
2019-10-08 06:29 AM
I'd expect you'd need to unlock each unit via it's LAR (Lock Access Register) on CM7 chips.
2019-10-08 06:50 AM
Indeed ! There is an ETM_LAR and an ETF_LAR, i've just found it. So now I can write in ETM registers but not in ETF :(
To be continued :)
2019-10-09 01:39 AM
I've found this comment on the Segger forum:
"(...) unfortunately ST made the decision with the STM32H7 to "hide" some trace related modules behind the APB instead of AHB as it is usual for Cortex-M7. That way the generic trace init process becomes highly ungeneric."
ST people, could you comment on that ?