Hallo Leute vom µC.net
vorweg: ich verwende Atmel Studio 6 und einen AVRICE2 mit JTAG zum
Debuggen/Flashen.
Die Software, welche ich benutze ist ein Professioneller Treiber von HMS
Industrial Networks und laut deren Entwicklungsabteilung mehrmals
getestet.
Dieser generische Treiber besteht aus ca. 80 Header- und Sourcefiles in
C und wird mit ein paar wenigen Callback-funktionen und #defines auf
eine Plattform zugeschnitten. Veröffentlichen darf ich davon nichts...
So ich hoffe das sind ausreichend Infos. So jetzt zur Sache ich habe
einen "Fehler" der mich langsam zur Verzweiflung treibt:
Ich hatte zufällige Abstürze mit meinem AT90CAN128, also habe ich ein
wenig Nachforschung betrieben und bin zu der Erkenntnis gekommen, dass
ein "rogue Pointer" mir das Leben schwer macht.
Also habe ich den RAM mit 0xFF (mit memset, ausgeführt aus .init3)
geflutet und einen Databreakpoint auf die geflutete Sektion angesetzt.
So, nachdem der Breakpoint getriggert wurde, schau ich in den Speicher
und sehe folgendes:
wie man sieht "schiesst" mir hier irgendwas 16bit Nullfolgen in meinen
RAM und zwar an zufälligen stellen. (ich habe das experiment wiederholt
und es waren jedes mal andere Speicherpositionen)
Nun versuche ich herauszufinden, welche pointervariable dafür
verantwortlich ist und komme nicht weiter... kann mir von euch jemand
helfen?
Gibt es auch workarounds, falls ich den Pointer nicht finde oder nicht
ändern kann?
viele Grüße
Alex
P.S. Alle Ideen zur Lösung des Problems sind willkommen (meine Deadline
läuft Ende diesen Monats ab :/ )
Korrelieren die Abstürze mit bestimmten Aktivitäten (CAN-Traffic usw.)?
Da hilft wohl nur, den Code abzuspecken, bis der Fehler nicht mehr
auftritt.
Also Code halbieren, vierteln usw. d.h. binäre Suche.
@ich (Gast)
Ich fragte nur nach einer Weiteren Vorgehensweise, nicht danach wo der
Fehler steckt.
ich schrieb:> Zeile 2A ist der Fehler.> Des weiteren damit die Anderen es auch sehen, Source etc. wäre schon> cool.> Bild des Aufbaues etc.> MfG> ich
Würde euch die 160 files an code ja hochladen, um jedem jegliche
Langeweile der nächsten Wochen zu nehmen, aber leider:
1
** This code is the property of HMS Industrial Networks AB. **
2
** The source code may not be reproduced, distributed, or used without **
3
** permission. When used together with a product from HMS, permission is **
4
** granted to modify, reproduce and distribute the code in binary form **
5
** without any restrictions. **
Peter D. schrieb:> Korrelieren die Abstürze mit bestimmten Aktivitäten (CAN-Traffic usw.)?>> Da hilft wohl nur, den Code abzuspecken, bis der Fehler nicht mehr> auftritt.> Also Code halbieren, vierteln usw. d.h. binäre Suche.
Ich sollte erwähnen, dass ich nur den SPI und GPIO pins nutze. Das sind
die einzigen features die implementiert werden.
CAN benutze ich (noch) garnicht.
Code halbieren bzw. vierteln geht leider nicht, weil der Treiber
Drittanbietersoftware ist und nur als Verbund funktioniert.
Alex schrieb:> Die Software, welche ich benutze ist ein Professioneller Treiber von HMS> Industrial Networks und laut deren Entwicklungsabteilung mehrmals> getestet.
Getestet und Fehlerfreiheit sind verschiedenen Dinge.
Wurde auf dem AVR getestet (welcher) und benutzt Du den gleichen
Compiler mit den gleichen Einstellungen (Optimierungslevel usw.)?
Entweder Du nimmst den Verkäufer der SW in die Pflicht oder debuggst
selber.
Es scheint ja, daß Du die Sourcen hast und nicht nur die Lib.
Einfach ist Code teilen nicht. Man muß für die fehlenden Teile
Simulatoren schreiben.
SPI ist auf den AVRs recht heikel, insbesondere der Slave-Mode ist fast
unbenutzbar.
@buyman
Der Breakpoint greift schon bei .init3 allerdings werden zwischen zwei
Trigger events größere Blöcke von Daten geschrieben (mit größer meine
ich 261 Bytes). Also "verpasst" der debugger viele schreibvorgänge.
@Hans
Alles Klar, wird gemacht! :)
Peter D. schrieb:> SPI ist auf den AVRs recht heikel, insbesondere der Slave-Mode ist fast> unbenutzbar.
Das wäre nicht gut, was gibts da denn für Probleme?
Alex schrieb:> Das wäre nicht gut, was gibts da denn für Probleme?
Das AVR-SPI hat keinen Sendepuffer. Der Master muß also nach jedem Byte
lange Gedenkpausen einlegen, damit der Slave garantiert mögliche andere
Interrupts beenden kann, dann in den SPI-Interrupt springen und dann das
zu sendende Byte aus dem RAM holen und endlich in das Schieberegister
schreiben kann.
Würde der Master mit maximalem Takt laufen, hätte der AVR-Slave gerade
mal einen halben SPI-Takt Zeit dafür.
Da hätte bei Atmel die AVR-Division mal ruhig von der 8051-Division
abkupfern sollen.
Z.B. der AT89C51CC03 hat gepuffertes SPI und obendrein 4
Prioritätslevel, um andere Interrupts sofort unterbrechen zu können:
"When a transmission is in progress a new data can be queued and sent as
soon as transmission has been completed. So it is possible to transmit
bytes without latency, useful in some applications."
Natürlich darf deshalb noch lange nicht eine Lib im SRAM unkontrolliert
rumtrampeln, sondern sollte einfach nur einen Datenfehler signalisieren.
PortA sind 8LEDs, die ich zum Debuggerlosen Fehlersuchen verwende.
Es gibt auch viele Debug features die troz des Auskommentierten
debugStart noch aktiv sind.
Alles was mit "abcc", "ad" oder "appl" anfängt gehört zur Lib.
Die Reset funktion symbolisiert einen Resetwunsch des Geräts (deshalb
wird kein wiklicher Reset ausgelöst), die Funktion wurde bisher aber nie
aufgerufen.
Die Interrupt, welche ich unten abfange sind alle welche es gibt. Dies
dient der Stabilität.
1
//#define debugStart
2
#define F_CPU 8000000
3
4
#include<avr/io.h>
5
#include<util/delay.h>
6
#include<stdlib.h>
7
#include<avr/interrupt.h>
8
9
#include"abcc_td.h"
10
#include"abcc.h"
11
#include"abcc_sys_adapt.h"
12
#include"ad_obj.h"
13
#include"appl_abcc_handler.h"
14
15
#include"abcc_spi_drv.h" // NUR DEBUG, diese zeile samt der datei wieder entfernen! Dient einzig und allein dem Zugriff auf ABCC_DrvSpiGetAnybusState()
@crazyhorse:
Ich habe alle Hardware doppelt und vor kurzem mal ausgetauscht, leider
hat sich dadurch absolut nichts geändert.
@Peda:
Guter Tip! Leider benutze ich keine Interrupts im Master. Und der Slave
ist für mich ne black box...
Hau erstmal den ganzen unnützen Kram raus, d.h. alle überflüssigen #if
und #ifdef.
Und auch diese unnütze BadIsr Geraffel, oder triggert das etwa?
Du mußt schon etwas freundlich zu den Helfern sein und allen Füllstoff
selber entfernen.
Alex schrieb:> Die Initialisierung der Ports und ähnliches steckt in einer Callback> funkton des Treibers und sieht folgendermaßen aus:
So auf keinen Fall, da muß schon ne Funktion darum stehen, sonst gibts
vom Compiler was auf den Deckel.
Peter D. schrieb:> Hau erstmal den ganzen unnützen Kram raus, d.h. alle überflüssigen #if> und #ifdef.> Und auch diese unnütze BadIsr Geraffel, oder triggert das etwa?
BadISR triggert. Obwohl Interrupts vom Treiber nicht gesetzt werden
können (da der treiber die Register nicht kennt) und ich Interrupts
explizit abschalte.
Peter D. schrieb:> So auf keinen Fall, da muß schon ne Funktion darum stehen, sonst gibts> vom Compiler was auf den Deckel.
Natürlich steht das in einer funktion, diese wird auch sauber
aufgerufen. Und die ini läuft durch.
Der ganze Start funktioniert einwandfrei.
Alles klar, dann poste ich den code nochmals moment...
Alex schrieb:> BadISR triggert.
Und warum sagst Du es dann nicht?
Welcher Vector, wo wird der enabled?
Du mußt schon alles ganz genau sagen, was beim Debuggen passiert. Wir
können doch nicht hellsehen.
Oder D. schrieb:> - nie dynamische Variablen verwenden> - nie Delays verwenden. Schon gar nicht in Interrupts.
1. Ok
2. Das triggern eines Interrupts in meiner anwendung stellt einen
schweren fehler dar, das Programm soll an der Stelle festgehalten werden
und die LEDs müssen den Fehler eindeutig anzeigen.
#include"abcc_spi_drv.h" // NUR DEBUG, diese zeile samt der datei wieder entfernen! Dient einzig und allein dem Zugriff auf ABCC_DrvSpiGetAnybusState()
Alles zusammen:
Also BADISR wird getriggert vom externen Interrupt 6 und 7.
Diese setze ich aber im Verlauf der ini 0 (EIMSK)
Der Program counter des µC geht zu scheinbar zufälligen Zeitpunkten auf
den Reset Vector. Allerdings wird kein Flag in MCUSR gesetzt. Den Stack
kann ich sehen aber nicht deuten (Google weiß nicht wie man eine
Rücksprungadresse von Bytefoo unterscheidet und wie man sie einer
Funktion zuordnet oder ich hab keine ahnung nach was ich suchen soll)
Die SPI Kommunikation welche ich hier realisiere gibt NIE eine valide
Prüfsumme zurück, obwohl ich die Frames überprüft habe und sie eindeutig
stimmen. Auch die Bitreihenfolge und die Bytereihenfolge sind richtig,
ebenfalls ist der Inhalt der Frames gültig.
Die Ausführungszeit des Programms verlangsamt sich manchmal extrem
(~Faktor 10000).
Ebenfalls meldet mir der Treiber manchmal (nur manchmal), dass meine
Peripherie defekt sei. Was definitiv nicht der Fall ist (ich habe die
Hardware mehrfach ausgetauscht).
So, ich denke, dass dies alles folgen eines "Amoklaufenden" etwas im RAM
ist.
Aus diesem Grund habe ich die eben genannten Punkte nicht im
Originalpost aufgeführt.
Ich hoffe ich habe nichts vergessen
Hi,
>Also BADISR wird getriggert vom externen Interrupt 6 und 7.
hast du an was gemerkt?
hast du mal das I-Flag bei Eintritt in die "ISR(BADISR_vect)"getestet?
nicht das "Interrupt 6 und 7" einfach "nur" ein Sprungziel war.
Das braucht auf jeden Fall etwas Geduld und eine gute Strategie.
Übrigens wenn ich mal sowas suchen muss haben meine Programmmodule
Durchlaufzahlen in einem Register und ich kann nachher schauen wo das
Prog. kurz vorher war.
Viel Erfolg, Uwe
Ich habe ein Problem ähnlichen Auftretens gehabt, als Ursache stellten
sich spikes auf der Versorgung heraus. Beim simulieren habe ich die
Spannung langsam (!) heruntergeregelt und dann pulsartig wieder hoch.
Die bits im MCUSR waren alle low. Der Prozessor resette sich, dies
konnte gezielt durch das sprungartige hochsetzen der Spannung von
lowlevel aus erreicht werden, auch reproduzierbar.
Das ist allerdings lange her.
Grüsse.
Robert
Ich habe rausgefunden, dass der Treibercode vom Hersteller auf einem 32
Bit MCU getestet wurde. Ich verwende allerdings einen 8Bitter.
Nach was muss ich ausschau halten wenn ich den Code Portieren möchte?
Oder was für Probleme soll ich erwarten?
Alex schrieb:> Nach was muss ich ausschau halten wenn ich den Code Portieren möchte?
Alle int durch long int ersetzen oder besser durch int32_t bzw.
uint32_t.
Alex schrieb:> Ich habe rausgefunden, dass der Treibercode vom Hersteller auf einem 32> Bit MCU getestet wurde. Ich verwende allerdings einen 8Bitter.> Nach was muss ich ausschau halten wenn ich den Code Portieren möchte?> Oder was für Probleme soll ich erwarten?
Auf alles, das sich auf die absolute oder minimale Breite eines
Datentyps verlässt. Prüfen würde ich sicher alle "nackten" Typen, also
short, int, long und long long. Ausserdem, ob die (u)int_fastXX_t Typen
in den Berechnungen wirklich nur XX Bits benötigen. Berechnungen werden
grundsätzlich in int oder grösser ausgeführt, da könnte ein Cast nach 32
Bit fehlen, wo einer nötig ist.
Peter D. schrieb:> Alex schrieb:>> Nach was muss ich ausschau halten wenn ich den Code Portieren möchte?>> Alle int durch long int ersetzen oder besser durch int32_t bzw.> uint32_t.
Das war der entscheidende Hinweis! Vielen vielen Dank! Alle Probleme mit
dem At90 haben sich nun bustäblich in Luft aufgelöst. Habe die
Datentypen durch die jeweiligen (u)intXX_t ersetzt (außer float) und es
geht!
So nebenbei, was ist der unterschied zwischen unsigned char und uint8_t?
Bzw. short, long usw. worin unterscheiden die sich zu den (u)intXX_t
datentypen?
Alex schrieb:>> So nebenbei, was ist der unterschied zwischen unsigned char und uint8_t?> Bzw. short, long usw. worin unterscheiden die sich zu den (u)intXX_t> datentypen?
Merkwürdig dass du das noch nicht verstanden hast, da genau hier ja dein
Problem lag und jetzt beseitigt wurde. Da müsste dir ein Licht aufgehen.
Schau dir einfach mal die Definition der uintXX_t Datentypen an.
uintXX_t geben eine feste Bitlänge an und werden dann je nach Zielsystem
auf die nativen Datentypen (char, int, Long usw.) gemappt). Es ist also
nur eine hardwareübergreifende Möglichkeit Datentypen mit spezifischer
Bitbreite angeben zu können.