Forum: Mikrocontroller und Digitale Elektronik ARM Cortex M3/M4: Software-Breakpoints


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

am Cortex M3/M4 kann ich ja eine begrenzte Anzahl von 
Hardware-Breakpoints setzen. Hochwertigere Programmer à la J-Link oder 
Lauterbach können zusätzlich noch Breakpoints erzeugen, indem sie 
bestimmte Stellen des Binaries garnieren, und die entsprechende Stelle 
per Prozessort-Simulation füllen.

Wie sieht es eigentlich mit reinen Software Breakpoints aus? Dazu würde 
kein "hochwertiger" Debugger benötigt, weil aus dem Binary nichts 
gelöscht wird.

Was nicht funktioniert:
1
#include <signal.h>
2
3
uint32_t foo(uint8_t v, int o)
4
{
5
    if( o >= 0 )
6
    {
7
        return v<<o;
8
    }
9
    else
10
    {
11
       raise(SIGINT);  
12
       return -1;
13
    }
14
}

Wäre ja auch zu einfach.

Aber gibt es einen ähnlichen Mechanismus, der funktioniert, und den ich 
bis jetzt einfach übersehen habe? (Klar - ich könnte meine normalen 
Breakpoints einfach auf die beiden Fault-Handler setzen - aber das ist 
nicht gemeint.)

von Bernd K. (prof7bit)


Lesenswert?

Du suchst vermutlich asm("bkpt")

von Dr. Sommer (Gast)


Lesenswert?

1
__asm__ volatile ("asm");
 damit es Standard konform ist und nicht wegoptimiert wird. In der CMSIS 
gibt es auch eine Funktion __BKPT() dafür.

von Walter T. (nicolas)


Lesenswert?

Danke genau das hatte ich gesucht!

von Walter T. (nicolas)


Lesenswert?

Gibt es eigentlich irgendetwas, was dagegen spricht, die Fault-Handler 
fest mit Breakpoints zu versehen?

Solange der Debugger angesteckt ist, muß man nicht mehr stoppen, um zu 
sehen, daß er angesprungen wurde (was vorteilhaft ist, weil es 
mittlerweile sehr, sehr selten passiert), wenn nicht, passiert nichts.

von Dr. Sommer (Gast)


Lesenswert?

Walter T. schrieb:
> Gibt es eigentlich irgendetwas, was dagegen spricht, die Fault-Handler
> fest mit Breakpoints zu versehen?

Nö, mache ich immer so.

Walter T. schrieb:
> wenn nicht, passiert nichts.

Doch, ohne Debugger dran bewirkt BKPT dass der Prozessor stehen bleibt.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Man könnt sich auch eine schöne Ausgabe über den SWO oder Debuguart 
bauen wenn die Kiste im Faulthandler hängt.
zB ein Registerdump und ein paar der Bits aus dem SCB Abfragen.

Dann weiste auch schon wer den explodierenden Speicherzugriff verursacht 
hat (wenn die MPU aktiviert ist)

Beitrag #5952904 wurde von einem Moderator gelöscht.
von Olaf (Gast)


Lesenswert?

> Man könnt sich auch eine schöne Ausgabe über den SWO oder Debuguart
> bauen wenn die Kiste im Faulthandler hängt.

Ja, kann man machen. Sowas mache ich z.B bei meinen alten H8. 
Gelegentlich sehr praktisch.


[Achtung schlimmer Autor]
> Ja zeig mal du Schwätzer.
> Da kommt doch nur heiße Luft.

Man zeigt nicht immer alles weil es schoener ist wenn die dummen so wie 
du nicht immer klauen koennen.

Olaf

von Walter T. (nicolas)


Lesenswert?

Klauen? Die Ausgabe per SWO ist doch schon in SysCalls implementiert. 
Was kann man an einem printf() noch klauen?

von Markus F. (mfro)


Lesenswert?

Dr. Sommer schrieb:
> _asm_ volatile ("asm");

Sieht irgendwie nach Endlosrekursion aus ...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
1
__asm__ volatile ("asm");
> damit es Standard konform ist und nicht
> wegoptimiert wird.

Ohne Unterstriche funktioniert es in den -std=gnuXXX Einstellungen, mit 
überall.

"Wegoptimiert" kann es nicht werden, aber ohne volatile kann es ggf. 
verschoben werden.

von Dr. Sommer (Gast)


Lesenswert?

Markus F. schrieb:
> Sieht irgendwie nach Endlosrekursion aus ...

Oh! Es muss natürlich "bkpt" sein. ?‍♂️
Das "__asm__" funktioniert in Gegensatz zu "asm" auch wenn man mit 
-std=cXY und nicht mit -std=gnuXY kompiliert.

... schrieb im Beitrag #5952904:
> Ja zeig mal du Schwätzer.
>
> Da kommt doch nur heiße Luft.

Was hast du denn für Probleme. Das ist sehr wohl machbar. Nur mal eben 
schnell aus dem Ärmel schütteln eher nicht.

Walter T. schrieb:
> Klauen? Die Ausgabe per SWO ist doch schon in SysCalls implementiert.

Wenn das RTOS, welches die SysCalls implementiert, nicht abgestürzt 
ist... so ein FaultHandler sollte komplett unabhängig vom Zustand des 
Programms sein. Damit fällt auch das normale printf flach.

von Bernd K. (prof7bit)


Lesenswert?

Jörg W. schrieb:
> Dr. Sommer schrieb:

>> _asm_ volatile ("asm");
>> damit es Standard konform ist und nicht wegoptimiert wird.

> Ohne Unterstriche funktioniert [...]

Ich denke der weiße Elefant im Raum über den gestern den ganzen Tag lang 
kein einziger auch nur ein Sterbenswörtchen verloren hat (was mich schon 
ein bisschen verwunderte hier im Forum) ist dieses hier:

   Error: bad instruction `asm'

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bernd K. schrieb:
> kein einziger auch nur ein Sterbenswörtchen verloren hat

Weil der Tippfehler völlig offensichtlich ist.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Folgendes verwende ich. Ist natürlich nur relevant bei verbundenem 
Debugger. Im Grunde: Wenn Debugger connected, setze die Traps. 
Funktioniert für die Faults.
1
#include: Kette zu "Pack\\ARM\\CMSIS\\5.5.2\\CMSIS\\Core\\Include\\core_cm3.h"
2
3
#ifndef __FINAL_RELEASE
4
  // Early Trap Faults when debugging (Hard Fault, ...)
5
  if(CoreDebug->DHCSR & (1 << CoreDebug_DHCSR_C_DEBUGEN_Pos)) {
6
    CoreDebug->DEMCR |= (1<<CoreDebug_DEMCR_VC_HARDERR_Pos) | 
7
                        (1<<CoreDebug_DEMCR_VC_INTERR_Pos)  | 
8
                        (1<<CoreDebug_DEMCR_VC_BUSERR_Pos)  | 
9
                        (1<<CoreDebug_DEMCR_VC_STATERR_Pos) | 
10
                        (1<<CoreDebug_DEMCR_VC_CHKERR_Pos)  | 
11
                        (1<<CoreDebug_DEMCR_VC_NOCPERR_Pos) | 
12
                        (1<<CoreDebug_DEMCR_VC_MMERR_Pos)   ;
13
  }
14
15
  // Flag RTOS Stack memories  
16
  memset(tcp_stack         , 0xcc, sizeof(tcp_stack         ));
17
  memset(timer_stack       , 0xcc, sizeof(timer_stack       ));
18
  memset(..._stack         , 0xcc, sizeof(..._stack         ));
19
#else
20
  JTAG_Lock();
21
#endif

von Uwe Bonnes (Gast)


Lesenswert?

Wenn man das Programm im RAM laufen lassen kann, dann kann man beliebig 
viele Breakpoints setzen.

von Olaf (Gast)


Lesenswert?

> Wenn das RTOS, welches die SysCalls implementiert, nicht abgestürzt
> ist... so ein FaultHandler sollte komplett unabhängig vom Zustand des
> Programms sein. Damit fällt auch das normale printf flach.

Genau da ist das Problem. Man muss sich einen eigenen Stack aufsetzen,
an Daten sichern was man uebertragen will. Und darf danach natuerlich 
keine Funktionen des restlichen Systems verwenden weil man ja nicht 
weiss in welchem Zustand das System ist. Ausserdem sollte man darauf 
achten moeglichst wenig Resourcen zu brauchen weil sowas ja mit beliebig 
vielen zukuenftigen Anwendungen laufen soll.
Alles keine grosse Sache, man muss es nur machen. .-)

Olaf

von Dr. Sommer (Gast)


Lesenswert?

Olaf schrieb:
> Man muss sich einen eigenen Stack aufsetzen,

Auf dem Stack werden beim Exception-Eintritt allerdings einige Dinge 
gesichert. Die möchte man wahrscheinlich auch ausgeben. Jetzt kann es 
sein, dass der SP irgendwo in den RAM zeigt, da zwar die gesicherten 
Register drüber geschrieben wurden, aber man nichts weiteres PUSHen 
möchte, weil man dann in einen ungültigen Bereich kommen könnte. Daher 
müsste man sich den SP merken (z.B. in R1), den SP auf einen extra dafür 
reservierten Bereich setzen (globales Array), die Daten des alten SP 
auslesen sofern dieser in einen gültigen Bereich zeigt, und ausgeben. 
Etwas fummelig...

Interessant sollten die Inhalte der gesicherten Register sein, dazu LR, 
und das letzte Stück des Stacks. Zusätzlich könnte man heuristisch 
prüfen, ob die Register Pointer enthalten (d.h. sie in einen gültigen 
Speicherbereich zeigen) und dann ggf. einen Teil des dort zu findenden 
Speichers ausgeben. Der Linux Kernel macht das bei internen Fehlern so, 
das kann enorm praktisch sein um Fehler zu finden ohne gleich den 
Debugger anzuwerfen.

Olaf schrieb:
> Und darf danach natuerlich
> keine Funktionen des restlichen Systems verwenden weil man ja nicht
> weiss in welchem Zustand das System ist

Nur wenn die irgendwelche globalen Zustände nutzen. Sauber gekapselter 
Code sollte das sowieso möglichst nicht tun...

Olaf schrieb:
> Alles keine grosse Sache, man muss es nur machen. .-)

Jo!

von Walter T. (nicolas)


Lesenswert?

Dr. Sommer schrieb:
> Damit fällt auch das normale printf flach.

Ich gebe zu, daß da eine gewisse Polemik drin war. Ich wollte auch nur 
darauf hinaus: In der Implementierung von syscalls.c, die als Template 
von vielen Umgebungen mitgebracht wird, kann man sich das Senden über 
SWO gemütlich abschauen, ohne daß man sich großartig mit einer weiteren 
Peripherie auseinandersetzen muß.

von Stefan F. (Gast)


Lesenswert?

Random .. schrieb:
1
#include: Kette zu "Pack\\ARM\\CMSIS\\5.5.2\\CMSIS\\Core\\Include\\core_cm3.h"

Kette zu? Vorsicht beim Anwenden von ÜbersetzungTools auf Quelltexten!

\\ ist falsch, es muss / heissen (auch unter Windows).

Der Pfad von solchen Standardpaketen sollte im Makefile bzw. Projekt 
konfiguriert sein, so dass man hier schreiben würde:
1
#include: <core_cm3.h>

von Olaf (Gast)


Lesenswert?

> Auf dem Stack werden beim Exception-Eintritt allerdings einige Dinge
> gesichert.

Natuerlich. Deshalb braucht man auch einen eigenen Stack damit man sich 
nichts zerstoert.

> Etwas fummelig...

Ja. Entweder ein paar Zeilen Assembler oder man muss sich sehr genau 
anschauen was der Compiler da macht!

Wie gesagt, ich hab das fuer einen H8 gemacht. Natuerlich wird es da bei 
jedem Controller ein paar spezielle Feinheiten geben.

> Nur wenn die irgendwelche globalen Zustände nutzen. Sauber gekapselter
> Code sollte das sowieso möglichst nicht tun...

Aber du musst dich dann auch darauf verlassen das diese Funktion da ist. 
Ich hab dafuer meine eigene kleine printf-Funktion. Und ich benutze auch 
zur Ausgabe einen Port-Pin mit SoftwareUART weil ich ja nie weiss ob die 
dedizierter Hartware in dem Projekt nicht schon anderswo verwendet wird.

Olaf

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Stefanus F. schrieb:
> Random .. schrieb:
>
1
> #include: Kette zu 
2
> "Pack\\ARM\\CMSIS\\5.5.2\\CMSIS\\Core\\Include\\core_cm3.h"
3
>
>
> Kette zu? Vorsicht beim Anwenden von ÜbersetzungTools auf Quelltexten!
>
> \\ ist falsch, es muss / heissen (auch unter Windows).
>
> Der Pfad von solchen Standardpaketen sollte im Makefile bzw. Projekt
> konfiguriert sein, so dass man hier schreiben würde:
>
>
1
> #include: <core_cm3.h>
2
>

Nix Übersetzungstool, hier ist Anwendergrips gefragt. Ich hab den Pfad 
einfach aus dem Dateisystem kopiert :-)
Die "core_cm<x>.h" wird normalerweise vom Device Header eingebunden, wie 
z.B. sam3x.h
Das direkte include geht natürlich auch, idR. ist im Modul mit main() 
aber bereits der Device Header includiert.

von Bernd K. (prof7bit)


Lesenswert?

Walter T. schrieb:
> Senden über
> SWO
1
#define SYS_OPEN        0x01
2
#define SYS_CLOSE       0x02
3
#define SYS_WRITEC      0x03
4
#define SYS_WRITE0      0x04
5
#define SYS_WRITE       0x05
6
#define SYS_READ        0x06
7
#define SYS_READC       0x07
8
#define SYS_ISTTY       0x09
9
#define SYS_SEEK        0x0a
10
#define SYS_FLEN        0x0c
11
#define SYS_TMPNAM      0x0d
12
#define SYS_REMOVE      0x0e
13
#define SYS_RENAME      0x0f
14
#define SYS_CLOCK       0x10
15
#define SYS_TIME        0x11
16
#define SYS_SYSTEM      0x12
17
#define SYS_ERRNO       0x13
18
#define SYS_GET_CMDLINE 0x15
19
#define SYS_HEAPINFO    0x16
20
#define SYS_EXIT        0x18
21
22
static void command(uint32_t command, void* message) {
23
    __asm__ volatile (
24
        "mov r0, %[command]         \n\t"
25
        "mov r1, %[message]         \n\t"
26
        "bkpt #0xab                 \n\t"
27
        :
28
        : [command] "r" (command)
29
        , [message] "r" (message)
30
        : "r0"
31
        , "r1"
32
        , "memory"
33
    );
34
}
35
36
static void send_buffer(char* buffer, uint32_t len) {
37
    uint32_t msg[3] ={
38
        1,
39
        (uint32_t)buffer,
40
        len
41
    };
42
    command(SYS_WRITE, &msg);
43
}

So irgendwie.

Das hab ich eben bei nem alten Projekt ausgegraben und das hat schonmal 
funktioniert.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Dr. Sommer schrieb:
> Wenn das RTOS, welches die SysCalls implementiert, nicht abgestürzt
> ist... so ein FaultHandler sollte komplett unabhängig vom Zustand des
> Programms sein. Damit fällt auch das normale printf flach.

Daher hat meine Faulthandler Implementierung ein eigenes kleines und 
sehr billiges printf.
Es heißt deprintf, weil dprintf gabs schon in der libc. (Debug printf).
Das is so billig, das kann keine Formatierungen, nut char, string, hex, 
(u)int.
Da eben nichts aus dem restlichen programm genutzt werden darf.

Dr. Sommer schrieb:
> Auf dem Stack werden beim Exception-Eintritt allerdings einige Dinge
> gesichert. Die möchte man wahrscheinlich auch ausgeben. Jetzt kann es
> sein, dass der SP irgendwo in den RAM zeigt, da zwar die gesicherten
> Register drüber geschrieben wurden, aber man nichts weiteres PUSHen
> möchte, weil man dann in einen ungültigen Bereich kommen könnte. Daher
> müsste man sich den SP merken (z.B. in R1), den SP auf einen extra dafür
> reservierten Bereich setzen (globales Array), die Daten des alten SP
> auslesen sofern dieser in einen gültigen Bereich zeigt, und ausgeben.
> Etwas fummelig...

Wenn der Faulthandler, sagen wir Usagefault, nicht auf den Stack pushen 
kann, dann wird das zum hardfault und im SCB ist Stackerr gesetzt.
Dem Hardfault ist egal ob er pushen kann oder nicht.
Daher schrieb ich ja oben, dass man die SCB Bits lesbar ausgeben muss, 
dann sieht man auch, dass man dem Regiosterdump nicht trauen kann.
Was ich in der Tat noch mal machen müsste ist den sp neu zu setzen bevor 
ich nach C gehe. Bisher hab ich mir aber den Stack noch nie so übel 
zerballert auf nem Cortex-M.
Den Stack könnt man sich auch einfach auf den Stack aus der IVT setzen, 
das sollte weit genug am Anfang sein um sich nicht das heißbegehrte zu 
überschreiben.

Dr. Sommer schrieb:
> Zusätzlich könnte man heuristisch
> prüfen, ob die Register Pointer enthalten (d.h. sie in einen gültigen
> Speicherbereich zeigen) und dann ggf. einen Teil des dort zu findenden
> Speichers ausgeben. Der Linux Kernel macht das bei internen Fehlern so,
> das kann enorm praktisch sein um Fehler zu finden ohne gleich den
> Debugger anzuwerfen.

Klingt nach einem interessanten Vorschlag, sollte ich bei Gelegenheit 
mal einbauen.
Bisher versucht mein Faulthandler nur die letzten Zeichen aus der UART 
FIFO zu kratzen, da könnt ja noch was interessantes drinnestehen.

@Bernd K:
Das sieht jetzt aber nicht nach SWO aus.
Das packt ne Zahl und ein Pointer in Register, dann wird der Debugger 
angestoßen.
Da macht deine IDE dann irgendwas im Hintergrund.

Ich muss am WE mal mein Minimalbeispiel der Faulthandler fürs Discovery 
zusammenfegen.
Kommt dann ins Code UNterforum und wir kölnne daraus den "perfekten" 
Cortex-M Faulthandler bauen?

von Bernd K. (prof7bit)


Lesenswert?

Mw E. schrieb:
> Das sieht jetzt aber nicht nach SWO aus.

Oh ja, Du hast Recht. Ist schon ziemlich lange her, das was ich gepostet 
habe ist die Semihosting-Schnittstelle. 1 ist das Filehandle für stdout, 
der Debugger spuckt den String dann auf der Konsole aus und lässt sofort 
wieder weiterlaufen. Sorry, verwechselt.

von Jan (Gast)


Lesenswert?

ITM Trace ist auch ne coole Sache, man muss nur im Debugger bei ITM 
Stimulus Port (so heißts bei Keil uVision) Port 0 aktivieren, den trace 
Takt dem CPU Takt anpassen und dann in etwa sowas einbinden (kommt z.B. 
aus der retarget_io.c vom Keil "Compiler Software Pack"):
1
#define ITM_PORT0_U8          (*((volatile uint8_t  *)0xE0000000))
2
#define ITM_PORT0_U32         (*((volatile uint32_t *)0xE0000000))
3
#define ITM_TER               (*((volatile uint32_t *)0xE0000E00))
4
#define ITM_TCR               (*((volatile uint32_t *)0xE0000E80))
5
 
6
#define ITM_TCR_ITMENA_Msk    (1UL << 0)
7
8
/** \brief  ITM Send Character
9
 
10
    The function transmits a character via the ITM channel 0, and
11
    \li Just returns when no debugger is connected that has booked the output.
12
    \li Is blocking when a debugger is connected, but the previous character
13
        sent has not been transmitted.
14
 
15
    \param [in]     ch  Character to transmit.
16
 
17
    \returns            Character to transmit.
18
 */
19
20
int32_t ITM_SendChar (int32_t ch) {
21
  if ((ITM_TCR & ITM_TCR_ITMENA_Msk) && /* ITM enabled */
22
      (ITM_TER & (1UL << 0)        )) { /* ITM Port #0 enabled */
23
    while (ITM_PORT0_U32 == 0);
24
    ITM_PORT0_U8 = (uint8_t)ch;
25
  }
26
  return (ch);
27
}
28
29
static int stdout_putchar (int ch) {
30
  return (ITM_SendChar(ch));
31
}
32
33
34
__attribute__((weak))
35
int fputc (int c, FILE * stream) {
36
 
37
  if (stream == &__stdout) {
38
    return (stdout_putchar(c));
39
  }
40
 
41
  return (-1);
42
}
Damit kann man jetzt z.B. über puts oder printf oder alles, was den 
stdout benutzt direkt und sehr schnell Nachrichten über SWO raus hauen.

von Stefan F. (Gast)


Lesenswert?

> ITM_SendChar
Die Funktion befindet sich bereits in der CMSIS-Core Library.

Nur die anderen beiden müsste man selbst hinzufügen. Ich kenne das aber 
etwas anders in Kombination mit der newlib-nano:
1
// Redirect standard output to the trace SWO output
2
int _write(int file, char *ptr, int len)
3
{
4
    for (int i=0; i<len; i++)
5
    {
6
        ITM_SendChar(*ptr++);
7
    }
8
    return len;
9
}

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Angehängte Dateien:

Lesenswert?

Da fehlt aber dann auchnoch der Init der Tracecell und Konsorten.
Im Anhang mal noch die Datei für SWO Init, SWO Ausgabe und printf 
überschreiben für die newlib nano.

Es sind noch ein paar magic Numbers drinne, die kommen aber noch raus.
Die Doku zu dem Tracegedöhns ist etwas schwer zu lesen.

von Stefan F. (Gast)


Lesenswert?

Mw E. schrieb:
> Da fehlt aber dann auchnoch der Init der Tracecell und Konsorten.

Ging bei mir (STM32F1, STM32F3 und STM32L0) bisher immer ohne diesen 
Aufwand. Die Schnittstelle konfiguriert und öffnet doch der Debugger - 
dachte ich.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Der Debugger selber nicht, aber eventuell ein Debugscript was von der 
IDE vorher geladen wird.
(man muss eben seine IDE kennen)

In diese Falle biste doch schonmal bei einer PLL Einstellung getappt ;)

Also wenn du bei einer IDE ansagst, dass du per SWO was empfangen 
willst, dann wird da vllt so ein Script ausgeführt.
Wenn dus nur per STlink draufkopierst und dann im ST utility den SWO 
Viewer aktivierst, dann brauchst du den Initcode.

von Stefan F. (Gast)


Lesenswert?

Mw E. schrieb:
> In diese Falle biste doch schonmal bei einer PLL Einstellung getappt ;)

Ach ja, da war doch was.

von Stefan F. (Gast)


Lesenswert?

Mw E. schrieb:
> Wenn dus nur per STlink draufkopierst und dann im ST utility den SWO
> Viewer aktivierst, dann brauchst du den Initcode.

Nee, das habe ich ausprobiert. Mit den "Serial Wire Viewer" im ST-Link 
Utility. Vielleicht haben die das innerhalb der letzten Jahre verändert. 
Ich befasse mich ja noch nicht lange damit.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Walter T. schrieb:
> Gibt es eigentlich irgendetwas, was dagegen spricht, die Fault-Handler
> fest mit Breakpoints zu versehen?

Beim Durchgucken des ARMv7-M Architecture Reference Manual, bin ich 
Gestern über das vector catch feature gestolpert. Ich bin mir noch nicht 
100% sicher, ob es so funktioniert, wie ich es verstehe, aber wenn dem 
so wäre, dann könnte man durch setzen von flags im Register DEMCR eine 
"halting debug trap" für bestimmte Ereignisse setzen.

Das hätte dann den Vorteil, dass keine break points dafür verwendet 
werden müssten.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Torsten R. schrieb:
> Walter T. schrieb:
>> Gibt es eigentlich irgendetwas, was dagegen spricht, die Fault-Handler
>> fest mit Breakpoints zu versehen?
>
> Beim Durchgucken des ARMv7-M Architecture Reference Manual, bin ich
> Gestern über das vector catch feature gestolpert. Ich bin mir noch nicht
> 100% sicher, ob es so funktioniert, wie ich es verstehe, aber wenn dem
> so wäre, dann könnte man durch setzen von flags im Register DEMCR eine
> "halting debug trap" für bestimmte Ereignisse setzen.
>
> Das hätte dann den Vorteil, dass keine break points dafür verwendet
> werden müssten.

Hättest du mal meinen Beitrag gelesen, der macht nämlich genau das 
(fragt vorher noch, ob ein Debugger connected ist) :-)

"
Folgendes verwende ich. Ist natürlich nur relevant bei verbundenem
Debugger. Im Grunde: Wenn Debugger connected, setze die Traps.
Funktioniert für die Faults.
1
#include: (idr. durch device header include chain) "Pack\\ARM\\CMSIS\\5.5.2\\CMSIS\\Core\\Include\\core_cm3.h"
2
3
#ifndef __FINAL_RELEASE
4
  // Early Trap Faults when debugging (Hard Fault, ...)
5
  if(CoreDebug->DHCSR & (1 << CoreDebug_DHCSR_C_DEBUGEN_Pos)) {
6
    CoreDebug->DEMCR |= (1<<CoreDebug_DEMCR_VC_HARDERR_Pos) | 
7
                        (1<<CoreDebug_DEMCR_VC_INTERR_Pos)  | 
8
                        (1<<CoreDebug_DEMCR_VC_BUSERR_Pos)  | 
9
                        (1<<CoreDebug_DEMCR_VC_STATERR_Pos) | 
10
                        (1<<CoreDebug_DEMCR_VC_CHKERR_Pos)  | 
11
                        (1<<CoreDebug_DEMCR_VC_NOCPERR_Pos) | 
12
                        (1<<CoreDebug_DEMCR_VC_MMERR_Pos)   ;
13
  }
14
15
  // Flag RTOS Stack memories  
16
  memset(tcp_stack         , 0xcc, sizeof(tcp_stack         ));
17
  memset(timer_stack       , 0xcc, sizeof(timer_stack       ));
18
  memset(..._stack         , 0xcc, sizeof(..._stack         ));
19
#else
20
  JTAG_Lock();
21
#endif

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Random .. schrieb:
> Folgendes verwende ich. Ist natürlich nur relevant bei verbundenem
> Debugger. Im Grunde: Wenn Debugger connected, setze die Traps.
> Funktioniert für die Faults.

Die Abfrage müsstest Du Dir sparen können: "If DHCSR.C_DEBUGEN is set to 
0, the processor ignores the value of this bit."

Ich würde das Register evtl. auch einfach in der Konfiguration des 
Debuggers setzen.

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.