Forum: Mikrocontroller und Digitale Elektronik ITM Meldungen ausgeben (Cortex-M3 und höher)


von Hans W. (hanswieland)


Lesenswert?

Ich habe mir überlegt, wie ich bequem Debug Meldungen über ITM ausgeben 
kann. Das Konstrukt mit den variablen Argumenten (args) ist mir 
allerdings neu. Habe ich das so richtig umgesetzt?
1
#include "stm32g4xx.h"
2
#include <stdio.h>
3
#include <stdarg.h>
4
5
// Output an ITM message
6
void debug_print(const char *ptr) {
7
    while (*ptr) {
8
        ITM_SendChar((uint32_t)*ptr++);
9
    }
10
}
11
12
// Like printf() but using ITM. Max. 80 characters.
13
void debug_printf(const char* format, ...) {
14
15
    // Skip if ITM is not enabled
16
    if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) &&((ITM->TER & 1UL) != 0UL)) {
17
18
        char buffer[81]; // change the size if needed
19
        va_list args;
20
        va_start(args, format);
21
        vsnprintf(buffer, sizeof(buffer), format, args);
22
        va_end(args);
23
        debug_print(buffer);
24
    }
25
}
26
27
int main() {
28
    ...
29
    debug_print("Hello World! \n");
30
    int i=42;
31
    debug_printf("value of i is %d \n",i);
32
}

Es funktioniert, aber ist es so auch fachlich sauber?
von Hans W. (hanswieland)


Lesenswert?

Noch eine Frage:
Diese Zeile habe ich aus der CMSIS Bibliothek kopiert:
1
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && ((ITM->TER & 1UL) != 0UL))

Könnte man doch eigentlich auch so schreiben, oder nicht?
1
if ((ITM->TCR & ITM_TCR_ITMENA_Msk) && (ITM->TER & 1UL))
von Harald K. (kirnbichler)


Lesenswert?

Der Code in den Zeilen 19 bis 22 ist soweit formal korrekt, so verwendet 
man va_list.

Unabhängig davon: Die Funktion belegt halt u.a. die Puffergröße auf dem 
Stack, das kann für eine Debugausgabe problematisch werden.

Günstiger könnte es sein, die Variante vfprintf zu verwenden, und die 
dort letztlich rausfallenden Zeichen direkt an ITM_SendChar zu 
übergeben.
Dazu musst Du allerdings rausfinden, wie in Deiner Entwicklungsumgebung 
mit printf und Dateihandles wie stdio etc. umgegangen wird.
Oft muss man nur eine lowlevel-Funktion wie _write ersetzen.


Und rein stilitisch: Was sollen die Leerzeichen vor den Zeilenumbrüchen 
in main()?

> Könnte man doch eigentlich auch so schreiben, oder nicht?

Ja, das kann man.
: Bearbeitet durch User
von Hans W. (hanswieland)


Lesenswert?

Harald K. schrieb:
> Günstiger könnte es sein, die Variante vfprintf zu verwenden, und die
> dort letztlich rausfallenden Zeichen direkt an ITM_SendChar zu
> übergeben.

Ja das klappt.

> Dazu musst Du allerdings rausfinden, wie in Deiner Entwicklungsumgebung
> mit printf und Dateihandles wie stdio etc. umgegangen wird.
> Oft muss man nur eine lowlevel-Funktion wie _write ersetzen.

Jawoll, den Punkt kenne ich. Im Fall von Arduino schien es mir 
naheliegender, einen kleinen Puffer zu verwenden. STM32duino saut eh 
schon herum, was den Speicherbedarf angeht. Da fallen die 81 Bytes nicht 
weiter auf :-)

> Was sollen die Leerzeichen vor den Zeilenumbrüchen in main()?

Soll die Lesbarkeit des Beispiels erhöhen. In echt programmiere ich 
nicht so.
: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Hans W. schrieb:
> Soll die Lesbarkeit des Beispiels erhöhen.

Mir ist es als unerwartet aufgestoßen. Ich hatte mal einen Kollegen, 
der statt "\n" oder der unter Windows üblichen Sequenz "\r\n" hartnäckig 
”\n\r" verwendete, und das auch noch am Zeilenanfang statt -Ende.

Hmm.
von Hans W. (hanswieland)


Lesenswert?

Harald K. schrieb:
> Mir ist es als unerwartet aufgestoßen.

Habe ich gemerkt, ich sehe ein, dass dies eine blöde Idee war.
von Hans-Georg L. (h-g-l)


Lesenswert?

Harald K. schrieb:
> Günstiger könnte es sein, die Variante vfprintf zu verwenden, und die
> dort letztlich rausfallenden Zeichen direkt an ITM_SendChar zu
> übergeben.
> Dazu musst Du allerdings rausfinden, wie in Deiner Entwicklungsumgebung
> mit printf und Dateihandles wie stdio etc. umgegangen wird.
> Oft muss man nur eine lowlevel-Funktion wie _write ersetzen.
1
int __io_putchar(int ch) {
2
    ITM_SendChar(ch);
3
    return ch;
4
}
von Bauform B. (bauformb)


Lesenswert?

Hans W. schrieb:
> Harald K. schrieb:
>> Günstiger könnte es sein, die Variante vfprintf zu verwenden,
>> und die dort letztlich rausfallenden Zeichen direkt an
>> ITM_SendChar zu übergeben.
>
> Im Fall von Arduino schien es mir naheliegender, einen kleinen
> Puffer zu verwenden. STM32duino saut eh schon herum, was den
> Speicherbedarf angeht. Da fallen die 81 Bytes nicht
> weiter auf :-)

Ein Kompromiss: der Puffer könnte static sein. So ein debug_print() 
möchte man irgendwann auch in einem fault handler benutzen, da fällt das 
auf dem Stack eher auf. Dafür lohnt sich evt. sogar Formatierung im 
Eigenbau. Wenn man auf Luxus wie %f, %*.*s verzichtet, braucht die nur 
ca. 12 Byte Puffer für beliebig lange Ausgaben. Und keine lib.

P.S. ich fände debug_printf mit 'f' schöner, gerade, wenn die die lib 
benutzt und alles kann.
Beitrag #8053046 wurde vom Autor gelöscht.
von Harald K. (kirnbichler)


Lesenswert?

Bauform B. schrieb:
> Dafür lohnt sich evt. sogar Formatierung im
> Eigenbau. Wenn man auf Luxus wie %f, %*.*s verzichtet, braucht die nur
> ca. 12 Byte Puffer für beliebig lange Ausgaben. Und keine lib.

Ich frage mich, wieviel Lebenszeit schon sinnlos verschwendet wurde, um 
krampfhaft printf() & Co. zu vermeiden, nur weil es etwas Code einspart.

Damals, als die µCs wirklich noch keinen Programmspeicher hatten, da war 
das wirklich ein Argument, aber hier geht es um irgendeinen Cortex - und 
der hat nun wirklich keine Probleme damit, die wenigen kByte einer 
printf-Implementierung unterzubringen. Und auf float-Unterstützung kann 
man immer noch verzichten; die Runtime-Libraries üblicher Compiler 
bieten genau deswegen verschieden zurechtgekürzte printf-Libraries an.
von Bauform B. (bauformb)


Lesenswert?

Harald K. schrieb:
> Ich frage mich, wieviel Lebenszeit schon sinnlos verschwendet wurde, um
> krampfhaft printf() & Co. zu vermeiden, nur weil es etwas Code einspart.

Mir ging es drum, Abhängigkeiten zu vermeiden, Flash hat man, 
ausreichend. Mit einem printf(), das keinen Stack braucht, kann ich im 
fault handler immer noch "drucken", egal, wie groß das Chaos ist. OK, 
Hintergrund ist auch, ich lasse die Programme erstmal im RAM laufen und 
flashe selten.

Ich finde es auch angenehm, wenig bis keine fremden libs zu brauchen.
von Harald K. (kirnbichler)


Lesenswert?

Bauform B. schrieb:
> Mit einem printf(), das keinen Stack braucht, kann ich im
> fault handler immer noch "drucken", egal, wie groß das Chaos ist.

OK, das Argument ist schlüssig.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.