Guten Abend, ich habe schon länger ein Problem mit meiner Software auf dem Atmega. Hardware fehler schließ ich aus. Info zur Hardware/Software. Es handelt sich um einen Atmega 644 der mit 16 Mhz läuft. Der Atmega ist mit einem MCP2515 und MCP2551 an der Can Bus Seite verbunden. Zum PC wird mit einem FTDI treiber über UART gesendet. Das Programm funktioniert ohne Probleme, wenn nur CanBus Nachrichten empfangen werden und diese zum PC gesendet werden. Werden gleichzeitig von PC auf den CANBus nachrichten gesendet, stürzt das Programm ab und startet neu und stürzt wieder ab und startet wieder neu solange ich nicht den ext. Reset drücke. Nicht Sofort sondern meistens nach ein paar 100 Nachrichten. Kann aber auch vorkommen das ein paar 1000 Nachrichten hin und herschickt und erst dann abstürzt. Manchmal bleibt das Programm aber einfach hängen und der Watchdog schaltet sich ein. Der Programmcode ist auf ein minimum reduziert, der Fehler aber noch immer vorhanden. Ich habe im Programm so eine Art Zeilenmarke eingebaut, diese wird dann vom Watchdog angezeigt. gebracht hat mir das aber nichts. Anscheinend bleibt das Programm hängen, wenn es den UART Interrupt beendet. Aber wo er dannach genau hinspringt kann ich trotzdem nicht sagen. Meistens stürzt der Atmega aber sofort ab ohne das der Watchdog eingeschaltet wird. Ich finde den Fehler einfach nicht, es sind schon soviele Tage vergangen und das Programm stürzt noch immer ab.
Hallo Kevin, Ohne Quellcode bzw. Listing ist das schwer zu sagen. Klingt nach interrupt gesteuerten Prozessen, die sich globale Variablen teilen und das nicht ordentlich synchronisiert ist. Grüße aus Bayern Bernhard
Auch Stack-Probleme haben solche Effekte. Also Stack zu klein bzw zuviele Stackvariablen. Oder der Stack wird überschrieben.
Hallo Ben, Habe das Projekt im ersten Beitrag angehängt. Ist ein komplettes AVR Studio 4 Projekt gepackt als rar. Soll ich es anders Abspeichern? Hab soviel schon überlegt an was es liegen kann und komm aber nicht drauf bzw. fehlen mir wahrscheinlich kenntnisse dafür. Aber das mit einer Variable was nicht stimmt, klingt für mich auch plausibel. Ich habe ein Interrupt BADISR, diese wird nicht ausgeführt und auch hab ich geprüft ob einer der beiden FIFO voll wird, aber auch dass konnte ich nicht feststellen.
Conny G. schrieb: > Auch Stack-Probleme haben solche Effekte. Also Stack zu klein bzw > zuviele Stackvariablen. Oder der Stack wird überschrieben. Würde ich auch drauf tippen.
Hallo Kevin, Sorry, hab ich nicht gesehen, dass Du das Programm angehängt hast. Schau ich mir mal an.
Narbend, was auf den ersten Blick unglücklich gelöst ist: Du rufst aus deinem Uart-Receive-Interrupt heraus "write_string_dogm" auf. Unglücklich in zweierlei Hinsicht: - Durch die Aufrufkette hinter "write_string_dogm" packst du dir nochmal einen ganzen haufen Worte auf den ohnehin schon vollen Stack - write_string_dogm ruft indirekt wieder write_dogm auf, wo sich ein Haufen Delay's tummeln. D.h. blockst du damit weitere Interrupts, die du dann verpennst. Besser isses, die ISR kurz und knackig zu machen und keine weiteren Funktionen aufzurufen, sondern dort lediglich ein Flag zu setzen, welches du dann in einer Endlosschleife in "main" auswertest. Ich denke nach wie vor Absturzursache ist Stacküberlauf. Gruss, Heinz
Hallo Heinz, du hast recht. Der Aufruf zur Anzeige im Display ist im Interrupt falsch. Hab es allerdings mit einer if abfrage eingebaut um festzustellen, ob der FIFO Voll ist oder ziemlich stark befüllt ist. if(freeIndex == PUFFER_UART) write_string_dogm("Fehler UART_FIFO_OVERFLOW");//Puffer Overflow if(freeIndex == 10) write_string_dogm("[10in]");//Puffer Overflow Das Display bleibt allerdings leer und der Atmega bleibt trotzdem hängen oder stürzt ab. Die Funktionen sind nur zum testen in der ISR, werden wieder entfernt sobald es irgendwann mal funktionieren sollte. EDIT: Muss mich nochmal korrigieren. Ich habe gerade nochmal getestet und dabei festgestellt, dass ich nach einer gewissen zeit ( eben immer unterschiedlich ) keine Nachrichten mehr zum PC gesendet bekomme. Daraus schließe ich, dass das Programm hängen geblieben ist. Aber nach kurzer Zeit darauf wird mir im Display Fehler UART FIFO OVerflow angezeigt. Nachrichten erhalte ich trotzdem keine mehr. Nach Reset funktionierts wieder
:
Bearbeitet durch User
Wirf mal einen Blick ins map-file. Du belegst allein schon ca 3 kb mit statischen Objekten im RAM. Der Killer sind die 15 UART_FIFO-dinger mit jeweils 155 Bytes.. D.h. allein damit belegst du schon grob gerechnet 2,5k. Dann kommt noch Kleinkram dazu. Und in main holst du dir dann nochmal 500 Bytes vom Stack. D.h. da bleibt nicht nicht mehr viel übrig für weitere lokale Vars., Rücksprungadressen und gepushte Registerinhalte. -> Quick Fix:weniger UART_FIFO-Dinger oder die struct UART_FIFOs kleiner machen. -> Besser: Programmdesign überdenken Ich poste dir gleich noch mal ein Stück programmcode, mit dem du zur Laufzeit gucken kannst, wieviel Stack/Heap du noch frei hast. Gruss, Heinz
get_mem_unused() liefert die anzahl Bytes zwischen Heap und Stack, die noch nie genutzt wurden. D.h. nicht den aktuellen Stand, sondern den Minimalwert. Das Ganze funktioniert so, daß zu Beginn der gesamte RAM mit einem Muster beschrieben wird. get_mem_unused() guckt dann, wieviel davon noch vorhanden ist. Hope that helps, Heinz
Jetzt is schon recht spät.. ich habe das probiert und mir im laufendem Betrieb deine funktion ausgegeben. Daraufhin hab ich die Variabel größen in meinem Programm verkleinert. Deine Funktion zeigt mir jetzt ca 3000 byte an. Es ist einmal vorgekommen beim testen: Programm hängt, deine funktion zeigt mir 0 Byten. Ansonsten hängt mein Programm obwohl platz vorhanden ist. Es läuft aber besser wie vorher.
dynamischen Speicher ... sollte man strikt vermeiden. sonst ist es gar nicht moeglich soviel platz zu verbrauchen. bei ausschlisslich statischen variablen weiss man fast ganz genau wieviel platz man braucht
Ich vermute immer noch, dass du dir da irgendwo verschachtelte Interrupts zusammenbaust. Anders kann ich mir nicht erklären, daß der Stack überläuft. Eine offensichtliche endlose Rekursion sehe ich auf den ersten Blick nicht. Für mich ist nach wie vor die Implementierung von "write_dogm" das rote Tuch. Du verballerst darin für jedes einzelne Zeichen 4ms mit aktivem Warten. Zudem rufst du das mal aus dem Hauptprogrammpfad auf, mal aus dem Interrupt. D.h. ein gerade aktives "write_dogm_string", das aus dem Hauptprogrammpfad aufgerufen wurde, kann erneut durch ein "write_dogm_string", das aus einem Interrupt heraus aufgerufen wurde, unterbrochen werden. Das gibt im mindesten merkwürdige Effekte auf dem Display. Zum anderen dauert jede Ausgabe von Zeichenketten aus Prozessorsicht Ewigkeiten. Gerade wenn du diese Ausgabe aus einem Interrupt heraus machst, sind weitere Interrupts für Ewigkeiten gesperrt und du verpasst möglichweise weitere Interrupts. Ich würde wie oben schon gesagt vorgehen: a)Interrupts kurz und knackig und keinen zeitintensiven Dinge aus Interrupts heraus. D.h. Im Interrupt selbst nur Flags oder Zählervariablen setzen und die dann in "main" abarbeien b) write_dogm nicht mit aktivem Warten implementieren, sondern dafür einen Ausgabepuffer und Timerinterrupt verwenden. c) statt cli() ... sei() immer ATOMIC_BLOCK(RESTORESTATE) verwenden. Macht in deinem Code jetzt keinen Unterschied, aber das ist ein extrem guter Kandidat zum Selbstabschießen. Gruss, Heinz
Warum nimmt man nicht einfach einen 1284 mit seinen 16 kiB, um die Speicherproblematik auszuschließen bzw. zu bestätigen? Danach kann man weitersuchen.
Warum immer selbst das RAD neu erfinden? http://www.mhs-elektronik.de/index.php?module=content&action=show&page=tinycan_hardware Und weitere dutzende !!!
Zuuz schrieb: > Warum immer selbst das RAD neu erfinden? > > http://www.mhs-elektronik.de/index.php?module=content&action=show&page=tinycan_hardware > > Und weitere dutzende !!! Weil es beim Elektronikbasteln um den Spass an der Aufgabe geht. Sonst würde auch jeder einfach nur mit Arduino und Shields hantieren statt selber eine Schaltung machen.
Die letzten Tage hab ich damit verbracht das Design sprich den Programmcode zu ändern. Danke schonmal an die Denkanstösse bzw. Hilfe. Die UART-FIFO Dinger hab ich entfernt und dafür einen Rinpuffer mit char[100] und 2 Zeigern verwendet. Die Struktur für CAN Nachrichten wurde jetzt ebenfalls als Ringpuffer mit Zeigern realisiert. Die Interrupts sind so kurz und schnell wie möglich, alle daten werden in der main() verarbeitet. Data: 320 Bytes ( 7.8% Full ) zeigt mir der Compiler. Also hat der AVR jetzt reichlich Reserven. Das Programm funktioniert soweit, bis jetzt kein Absturz mehr. Leider werden jetzt einige Interrupts und somit CAN Nachrichten "verschluckt". Gekennzeichnet hab ich es im Programm mit if(MCPMessageReceived[1] == MCP_BUFFER_1) PIEP1(500); Wenn diese Anweisung Wahr ergibt, heißt es, das Flag für den MCP2515 Buffer 1 VOLL ist noch immer gesetzt. Da der MCP2515 nur 2 Buffer für Nachrichten enthält, überschreibt er eine vorhanden oder kann diese nicht mehr speichern. Kann sich bitte einer mein Programmcode anschauen und mir vll zu dem Problem eine Antwort geben? Gibt es eine Funktion die sehr viel Geschwindigkeit kostet? Die einzige Funktion die mir ins Auge sticht ist: char bufferString[60]; sprintf(bufferString,"%c%#3x>%#2.2x>%#2.2x>%#2.2x %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x%c",2,LesezeigerCAN->id,LesezeigerCAN->rtr,LesezeigerCAN->length, LesezeigerCAN->data[0], LesezeigerCAN->data[1], LesezeigerCAN->data[2], LesezeigerCAN->data[3], LesezeigerCAN->data[4], LesezeigerCAN->data[5], LesezeigerCAN->data[6], LesezeigerCAN->data[7],3); uart_puts(bufferString); Braucht der Prozessor viel zeit um diese Funktion abzuarbeiten? würde es die geschwindigkeit verbessern diese Funktion selber mir bit Shifting zu erstellen? Ich werde vll versuchen als nächstes einige Programmabschnitte mit einem Timer zu analysieren. Ich weis nicht ob es der richtige weg ist oder ob es vll Physikalisch nicht möglich ist mit dieser Hardware die Nachrichten von einem 500kbit bus mit voller Geschwindigkeit echtzeit auf den PC zu übertragen.
> Gibt es eine Funktion die sehr viel Geschwindigkeit kostet? ja "uart_puts" bzw. "uart_putc" - hier vertrödelst du immer noch Zeit mit aktivem Warten. Dh. solange bis das letzte Byte im Sendepuffer steht, beschäftigt sich uart_puts mit nichts anderem als warten. Neben dem Empfang, den du ja schon auf Interrupt-Betrieb gebaut hast, solltest du auch das Senden auf Interrupt-Betrieb umstellen. -> guck dir mal P. Fleury's UART-Lib an. > Ich weis nicht ob es der richtige weg ist oder ob > es vll Physikalisch nicht möglich ist mit dieser Hardware die > Nachrichten von einem 500kbit bus mit voller Geschwindigkeit echtzeit > auf den PC zu übertragen. Hängt primär von der max. Busauslastung ab: Rechne mal überschlagsmäßig: 500kbit -> ca. 50kByte pro Sekunde -> alle 20 µS ein Byte bei 100% Buslast -> Bei F_CPU=16MHz (stimmt das?) und platt gerechnet 2 Clock cycles / Instruction hast du dann gerade mal durchschnittlich 160 Maschinenbefehle, um ein Byte zu empfangen, umzupacken, rauszusenden, und das nur in eine Richtung. D.h. bidirektional dann nur noch 80 Maschinenbefehle - Nun wirst du keine 100% Buslast haben, aber sagen wir mal 50%. D.h. ganz grob gepeilt: 160 Maschinenbefehle pro Byte. Hängt aber primär von der tatsächlichen Busauslastung ab. Wenn du nur kurze Zeiten mit hoher Buslast hast, dann kannst du das über fettere Puffer abpuffern (Platz genug hast du jetzt ja ;-) ), wenns im Mittel 50% Busauslastung sind, dann meine Baucheinschätzung: Funktioniert nicht aus der Tüte programmiert, sondern erfordert hardcore-Optimierung. Mit der Reaktivierung von "dogm_write_string" und dem damit verbundenen "warte 4 ms pro Zeichen" schon gar nicht. >sprintf(bufferString, ... Kannst du ja mal in einem anderen Projekt testen, ungefähr so: - 16bit-Timer (Timer1) im NormalMode mit 1MHz hochzählen lassen - Interrupts deaktivieren - TCNT1 auslesen - sprintf aufrufen - TCNT1 auslesen -> Differenz der beiden TCNT1-Werte = Ausführungszeit(sprintf) in µS. Gruss, Heinz
Wollte mich nochmal kurz melden. Es funktioniert jetzt alles wunderbar. Der letzte Fehler lag daran, dass ein Fehler im UART Ringpuffer vorhanden war und dieser deswegen immer in der Schleife blockierte. Vielen Dank vor allem an katastrophenheinz der mir wirklich sehr gut weitergeholfen hat. Programm stürzt jetzt nicht mehr ab, auch mit kompletten Programmunfang, und ist zudem super schnell gegenüber meiner vorgänger Version.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.