Forum: Mikrocontroller und Digitale Elektronik Merkwürdiges Verhalten mit Jlink


von M. Н. (Gast)


Lesenswert?

Hallo,

ich habe einen JLink EDU, mit dem ich einen STM32F407VE programmiere.
Ich habe nun teilweise sehr merkwürdiges Verhalten:

Ich starte den GDB server von Segger und programmiere mit GDB:
1
target extended-remote :2331
2
monitor speed 1000
3
monitor reset
4
load

Da funktioniert auch alles usw. Allerdings habe ich in meinem Code an 
einer Stelle eine C Zeile:
1
ret_ptr = &ring_buffer[get_index]

Da sollte in ret_ptr eigentlich die Adresse des Ringpuffers + Offset 
(get_index) stehen.

Wenn ich mit Ozone allerdings alle Variablen, die beteiligt sind 
anschaue:
ring_buffer ist 0x20001A10,
get_index ist 6,
dann steht aber nach der Code-Zeile in ret_ptr 0x20001A10. Also genau 
das selbe wie in ring_buffer. Wie als ob die Zeile nicht tut. Das merke 
ich auch am externen Verhalten des UARTs, für den dieser Puffer ist. Es 
kommt immer das selbe Zeichen, weil die Offsetaddierung auf den Puffer 
fehlschlägt.

Das Witzige daran ist: Der Code tat einige Wochen bereits. Kann dank 
Versionierungssystem auch ausschließen, dass es daran Anderungen gab.

Ich bin fast bekloppt geworden bei der Fehlersuche. Habe das ELF File 
disassembliert und alles sah gut aus.

Jetzt kommt aber der Hammer: Wenn ich das File einfach mit Ozone nochmal 
neu geladen habe (ohne neues Kompilieren), ging alles wie erwartet. 
Programmiert mit GDB -> Kaputt

Habe dann den JLink abgesteckt und wieder angesteckt -> Programmieren 
mit GDB klappt auch jetzt.

Momentan kann ich den Fehler nicht mehr reproduzieren. Hatte solche 
Probleme bereits häufiger mit verschiedener Target-Hardware. Habe dies 
jedoch teils auf nicht neu kompilierte Projekte etc. geschoben. Das 
heute hat mich 3 Stunden auf Trab gehalten und jetzt isses einfach weg.

Laut Ausgabe macht der Jlink ein Flash-Verify nach dem programmieren. Da 
sollte dann ein kaputter Programmcode doch ausgeschlossen sein.

Kennt jemand solche "merkwürdigen" Phänomene?

Leider kann ich das Ganze nicht weiter debuggen, weil es jetzt weg ist.

von Gnorm (Gast)


Lesenswert?

Und wie ist ring_buffer definiert?

von Gnorm (Gast)


Lesenswert?

Und get_index natuerlich.

von M. Н. (Gast)


Lesenswert?

Gnorm schrieb:
> Und wie ist ring_buffer definiert?

Gnorm schrieb:
> Und get_index natuerlich

Das obige Beispiel war etwas heruntergebrochen. Hier ist die volle 
Funktion
1
/**
2
 * @brief DMA ring buffer for data transfer from peripheral to memory
3
 */
4
struct dma_ring_buffer_to_mem {
5
  void *data_ptr;      /**< @brief Ring buffer */
6
  size_t buffer_count;    /**< @brief Size of buffer in multiples of elements */
7
  DMA_Stream_TypeDef *dma;  /**< @brief DMA Stream used to transfer data */
8
  size_t get_idx;      /**< @brief Get index for SW. Indicates the next element to be read */
9
  uint8_t base_dma_id;    /**< @brief Id of the DMA controller, the stream belongs to. Either 1 or 2. */
10
  size_t element_size;    /**< @brief Size of a buffer element (1, 2, or 4 bytes) */
11
};
1
int dma_ring_buffer_periph_to_mem_get_data(struct dma_ring_buffer_to_mem *buff, const void **data_buff, size_t *len)
2
{
3
  int ret_code = 0;
4
  uint32_t ndtr;
5
  size_t put_idx;
6
7
  if (!buff || !data_buff || !len)
8
    return -1;
9
10
  ndtr = buff->dma->NDTR;
11
  put_idx = buff->buffer_count - ndtr;
12
13
  /* Check if wrap around */
14
  if (put_idx < buff->get_idx) {
15
    /* Available data wraps around end of buffer: Return first part up to the end of the ring buffer */
16
    *data_buff = &(((char *)buff->data_ptr)[buff->get_idx * buff->element_size]);
17
    *len = buff->buffer_count - buff->get_idx;
18
    buff->get_idx = 0;
19
    ret_code = 2;
20
  } else if (put_idx > buff->get_idx) {
21
    /* Data does not wrap around ring buffer. Return full data */
22
    *data_buff = &(((char *)buff->data_ptr)[buff->get_idx * buff->element_size]);
23
    *len = put_idx - buff->get_idx;
24
    buff->get_idx += *len;
25
    ret_code = 1;
26
  } else {
27
    /* No new data */
28
    *len = 0;
29
  }
30
31
  return ret_code;
32
}

Die Zeile
1
  *data_buff = &(((char *)buff->data_ptr)[buff->get_idx * buff->element_size]);
ist das Problem. Mit dem Debugger reingeschaut:
buff->data_ptr: 0x20001A10
buff->element_size: 1
buff->get_index: 6

data_buff war nach der Zeile: 0x20001A10

Wie gesagt. Nach einem erneuten neu-programmieren geht es nun. Dass das 
richtige ELF-File geladen wird, kann ich garantieren, da ich im Kompilat 
den git commit und das Kompilierungsdatum ablege und diese korrekt 
waren.

von Programmierer (Gast)


Lesenswert?

Kann es sein dass der GDB den Code gar nicht geflasht hat, und du 
praktisch das alte Programm debuggt hast? Vielleicht sind im ELF-File 
die Flags nicht richtig gesetzt? Verifiziere doch mal den Flash-Inhalt 
mit Ozone oder JLink.exe nachdem du mit GDB geflasht hast. Ich glaube 
nicht dass es am konkreten Programm liegt; du kannst das ja mal mit 
einem Minimal-Blinky testen (1Hz-Blinker per Ozone drauf flashen, 
5Hz-Blinker per GDB drüber flashen). Ggf. tritt das auch erst bei einer 
bestimmten Programmgröße auf.

Ein ähnliches Problem hatte ich auch mal, da war letztlich eine 
Inkonsistenz im Linkerscript die bewirkt hat, dass der Code nicht im 
Flashbaren ".text"-Segment stand. Der GDB merkt das nicht, da er Code 
(beim Disassemblieren) einfach aus dem ELF-File lädt und man nicht 
merkt, dass im Flash was ganz anderes steht; Ozone merkt es aber schon, 
vor allem wenn man das ELF-File gar nicht lädt sondern einfach nur das 
Programm im Flash debuggt so wie es ist. Da sieht man dann, dass der 
Disassembly-Code nicht so aussieht wie er sein soll.

Das hier
1
ret_ptr = &ring_buffer[get_index];
geht so IMO etwas schöner:
1
ret_ptr = ring_buffer+get_index;

von M. Н. (Gast)


Angehängte Dateien:

Lesenswert?

EDIT: Sorry, das erste Bild war irgendwie Pixelbrei.

Programmierer schrieb:
> Kann es sein dass der GDB den Code gar nicht geflasht hat, und du
> praktisch das alte Programm debuggt hast?

Wie geschrieben: Das compiledatum was im Code steht stimmte.

Programmierer schrieb:
> Ein ähnliches Problem hatte ich auch mal, da war letztlich eine
> Inkonsistenz im Linkerscript die bewirkt hat, dass der Code nicht im
> Flashbaren ".text"-Segment stand. Der GDB merkt das nicht, da er Code
> (beim Disassemblieren) einfach aus dem ELF-File lädt und man nicht
> merkt, dass im Flash was ganz anderes steht; Ozone merkt es aber schon,
> vor allem wenn man das ELF-File gar nicht lädt sondern einfach nur das
> Programm im Flash debuggt so wie es ist. Da sieht man dann, dass der
> Disassembly-Code nicht so aussieht wie er sein soll.

Sowas kann ich mir auch eventuell vorstellen.
Aber momentan geht alles. Ich kann munter programmieren.

Nur eins ist gestern ab und zu passiert. Siehe Screenshot.
Wenn ich über die JLinkExe den Chip lösche, schlägt das manchmal fehl 
mit einem Fehler wie oben.

Beim Programmieren (auch mit Ozone) ist soetwas noch nie vorgekommen. 
Verbindung zwischen JLink und STM geht über so einen Tag-Connect 
Federkontaktstecker. Der sollte aber i.O. sein. Habe ihn auch schon 
mehrfach neu kontaktiert.

Habe erst gestern über längere Zeit (4 Stunden )mit Ozone Daten 
gesamplet. Dabei ist auch kein Kommunikationsproblem auf dem SWD 
aufgetreten. MErkwürdig, dass es nur beim löschen passiert.

Und zum Verständnis nochmal das vorgehen: Ich habe wie oben beschrieben 
das ELF File mit GDB programmiert. Danach hat meine Applikation nicht 
getan. Dann habe ich mich mit Ozone (ohne neu zu programmieren) auf das 
Gerät gehängt und das obige Verhalten beobachtet. Aus Ozone neu 
programmiert -> Tut. Mit GDB wieder drübergebügelt -> Tut nicht. Selbes 
ELF-File.

Aber auch heute tut wieder alles wie es soll. Außer der Flash-Erase. Der 
schlägt manchmal mit diesem RAM-Check Fehler fehl.

von M. Н. (Gast)


Angehängte Dateien:

Lesenswert?

Programmierer schrieb:
> Vielleicht sind im ELF-File
> die Flags nicht richtig gesetzt?

Angehängt ist der Aufbau des ELFs mit arm-none-eabi-readelf erstellt 
(elf.txt).
Dazu habe ich mein (mittlerweile stark verbasteltes) Linkerscript 
angehängt.

IMHO passt das.

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.