This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Record trace on-chip with ETM on STM32H7 (Cortex M7)

Every now and then, as a side project, I try to setup the ETM on my STM32H7 to record the execution trace on-chip in circular buffer mode. The goal is really to record the trace ON CHIP and in some particular cases output this trace to the external world, but there is no specific tools like Lauterbach or ULink Pro involved. I don't need to filter the instructions, I want to record every instruction.

I've read plenty of ARM documentation (ETMv4 architecture spec, Coresight ref manual, amrV7 arch manual and of course STM32 ref manual) but still couldn't understand exactly how it works. In particular what is not clear is the relationship between the different components : ETM, ETF, DWT, Trace Funnel.

Here is the code I've got right now.

#define ETM_PRGCTRL  ( (volatile uint32_t *)(0xE0041000 + 4))
#define ETM_LAR  ( (volatile uint32_t *)(0xE0041000 + 0xFB0))
#define ETM_STAT  ( (volatile uint32_t *)(0xE0041000 + 0xC))
#define ETM_CONFIG  ( (volatile uint32_t *)(0xE0041000 + 0x10))
#define ETM_EVENTCTRL0  ( (volatile uint32_t *)(0xE0041000 + 0x20))
#define ETM_EVENTCTRL1  ( (volatile uint32_t *)(0xE0041000 + 0x24))
#define ETM_STALLCTRL  ( (volatile uint32_t *)(0xE0041000 + 0x2C))
#define ETM_SYNCPR  ( (volatile uint32_t *)(0xE0041000 + 0x34))
#define ETM_TRACEIDR  ( (volatile uint32_t *)(0xE0041000 + 0x40))
#define ETM_TSCTRL  ( (volatile uint32_t *)(0xE0041000 + 0x30))
#define ETM_VICTRL  ( (volatile uint32_t *)(0xE0041000 + 0x80))
#define ETM_VIIECTRL  ( (volatile uint32_t *)(0xE0041000 + 0x84))
#define ETM_VISSCTRL  ( (volatile uint32_t *)(0xE0041000 + 0x88))

#define CSTF_BASE_ADDR  0x5C013000
#define CSTF_LAR   ( (volatile uint32_t *)(CSTF_BASE_ADDR + 0xFB0))
#define CSTF_CTRL   ( (volatile uint32_t *)(CSTF_BASE_ADDR + 0))

#define ETF_BASE_ADDR	0x5C014000
#define ETF_RRD   ( (volatile uint32_t *)(ETF_BASE_ADDR + 0x10))
#define ETF_CTL   ( (volatile uint32_t *)(ETF_BASE_ADDR + 0x20))
#define ETF_FFCR  ( (volatile uint32_t *)(ETF_BASE_ADDR + 0x304))
#define ETF_TRG   ( (volatile uint32_t *)(ETF_BASE_ADDR + 0x1C))
#define ETF_STS   ( (volatile uint32_t *)(ETF_BASE_ADDR + 0x0C))
#define ETF_LAR   ( (volatile uint32_t *)(ETF_BASE_ADDR + 0xFB0))

#define DWT_BASE_ADDR	0xE0001000
#define DWT_CTRL  ( (volatile uint32_t *)(DWT_BASE_ADDR + 0x0))
#define DWT_COMP0  ( (volatile uint32_t *)(DWT_BASE_ADDR + 0x20))
#define DWT_MASK0  ( (volatile uint32_t *)(DWT_BASE_ADDR + 0x24))
#define DWT_FUNCT0  ( (volatile uint32_t *)(DWT_BASE_ADDR + 0x28))
#define DWT_LAR   ( (volatile uint32_t *)(DWT_BASE_ADDR + 0xFB0))

#define DEMCR  ( (volatile uint32_t *)(0xE000EDFC))
 

{
    // enable DWT
    *DEMCR |= 1<<24; 

    // don't know if DWT is mandatory to feed ETM ? I don't need any filtering
    *DWT_LAR = 0xC5ACCE55;
    *DWT_CTRL = 0;
    *DWT_COMP0 = 0x08000000;
    *DWT_MASK0 = 24;
    *DWT_FUNCT0 = 0x00000008;
    *DWT_CTRL = 1;

   
    // CSTF: enable cortex M7 ETM slave port 
    *CSTF_LAR = 0xC5ACCE55;
    *CSTF_CTRL |= 1;

    // setup ETM: exactly the values from ETM arch manual 4.5.1
    *ETM_LAR  = 0xC5ACCE55;
    *ETM_PRGCTRL &= ~1;
    *ETM_CONFIG = 0x000018C1;
    *ETM_EVENTCTRL0 = 0;
    *ETM_EVENTCTRL1 = 0;
    *ETM_STALLCTRL = 0;
    *ETM_SYNCPR = 0x0000000C;
    *ETM_TRACEIDR = 0xAB;
    *ETM_TSCTRL = 0;
    *ETM_VICTRL = 0x201;
    *ETM_VIIECTRL = 0;
    *ETM_VISSCTRL = 0;
    *ETM_PRGCTRL |= 1;

    // I want the ETM to feed the ETF SRAM memory
    *ETF_LAR  = 0xC5ACCE55;
    *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

    
    // piece of bullshit code to record
    U4_INDEX = 1000;
    while(U4_INDEX--)
        __NOP();

    // wait for ETF status to be set ??
    while ( ((*ETF_STS) & (1<<2)) == 0 );

    // read ETF through its FIFO
    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
 }

The status bit of ETF never raises (ETF FIFO apparently remains empty all the time).

Any idea ?