Debugging

Zeitmessung

Bestimmen der Zeit bis zu einem Haltepunkt:

Timer2 ist ein 32 Bit Timer, er kann verwendet werden, um die Mikrosekunden zu zähle (2^32=4*10^9 = 4000s = 71.6 Minuten).

Dazu muss allerdings der Timer angehalten werden, wenn ein Haltepunkt angesprungen wird.

 

Um also z.B. die Zeit für einen Interrupt von Timer1 zu bestimmen werden beide Timer beim Anspringen des Interrupts angehalten und mit TIM2->CNT der Zählerstand von Timer2, dessen Prescaler auf 1us gestellt wird  (bei 84MHz z.B. auf 83) , ausgelesen.

 

Timer anhalten, wenn ein Haltepunkt erreicht wird.

 

DBGMCU->APB1FZ |= (DBGMCU_APB1_FZ_DBG_TIM2_STOP);

DBGMCU->APB2FZ |= (DBGMCU_APB2_FZ_DBG_TIM1_STOP);

// DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_WWDG_STOP; Watchdogs anhalten

// DBGMCU->APB1FZ |= DBGMCU_APB1_FZ_DBG_IWDG_STOP;

 

 

ITM

Image1

Debugger properties

Die Instrumentation Macro Cell ist eine Hardwarekomponente, die Daten über eine Debug-Schnittstelle senden und empfangen kann; diese über Memory-Mapping, sodass die Übertragung viel schneller als über z.B: die Serielle Schnittstelle erfolgen kann. Bei ST Nucleo Boards ist diese ARM Komponente ist über SWO (Serial Wire Out) zugänglich.

Sie verfügt über ein 10 Byte FIFO, sodass bei zu hoher Schreibgeschwindigkeit auf diese Schnittstelle Daten verloren gehen können.

Image2

 

1)

Channel 0 … Text

Channel31 … RTOS

2) Databreakpoint: eine globale Variable kann beobachtet werden.

Image3

Ausgabe eines Characters

 

ITM_SendChar('A');

 

 

Ausgabe mit printf()

1. #include <stdio.h>

2. __io_putchar ersetzen:

/* USER CODE BEGIN 4 */

int __io_putchar(int ch)

{

uint8_t c[1];

c[0] = ch & 0x00FF;

//HAL_UART_Transmit(&huart2, &*c, 1, 10);

ITM_SendChar(c[0]);

return ch;d

}

 

 

/* USER CODE END 4 */

 

3. printf("Hallo\n"); !!!

funktioniert ohne \n nicht!!!! weil der Schreib-Puffer nicht ausgelesen wird; Abhilfe:

 

setvbuf(stdout, (char*)NULL, _IONBF, 0);  schaltet den Puffer aus

 

ITM_Print und ITM_SendValue

https://github.com/PetteriAimonen/STM32_Trace_Example/blob/master/trace_example.c

 

 

// Print a given string to ITM.

// This uses 8 bit writes, as that seems to be the most common way to write text

// through ITM. Otherwise there is no good way for the PC software to know what

// is text and what is some other data.

void ITM_Print(int port, const char *p)

{

    if ((ITM->TCR & ITM_TCR_ITMENA_Msk) && (ITM->TER & (1UL << port)))

    {

        while (*p)

        {

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

            ITM->PORT[port].u8 = *p++;

        }

    }

}

 

// Write a 32-bit value to ITM.

// This can be used as a fast way to log important values from code.

void ITM_SendValue (int port, uint32_t value)

{

    if ((ITM->TCR & ITM_TCR_ITMENA_Msk) && (ITM->TER & (1UL << port)))

    {

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

        ITM->PORT[port].u32 = value;

    }

}