Mein Schaltungsentwurf sieht vor mit zwei Slaves an einem SPI Bus vom Atmega328 (16 MHz Takt) aus zu kommunizieren. Um die Latenzen und Abfragedauer möglichst gering zu halten, möchte ich den Bus mit 8 MHz laufen lassen. Auf dem Steckbrett aufgebaut habe ich jedoch Probleme und möchte nun herausfinden woran es liegt. Eine Möglichkeit wäre ja, das der Bustakt für den fliegenden Steckbrettaufbau einfach zu hoch ist. Ohne das ich jetzt einfah den Takt runterdrehe wär meine Frage ob und wie man das sicher ermitteln kann? Gibt es irgendwelche Statusregister zum auslesen, oder könnte man mit dem Oszi was erkennen? (Rigol 1072 vorhanden). Vielleicht hat ja jemand bereit Erfahrung mit solcheb Aufbauten und kann nen Tipp geben. Hilft eine Schirmung der SPI Leitung, oder verdrillen?
1) natürlich ist es hilfreich sich die Signale mit dem Oszi anzuschauen 2) es wäre ebenfalls sinnvoll es zunächst mit einer geringeren Taktfrequenz zu probieren. Um was für Slaves handelt es sich? Ist der Aufbau wirklich fehlerfrei? Gibt es eine stabile Versorgung?
> Probleme Welcher Art? > Ohne das ich jetzt einfah den Takt runterdrehe Warum nicht? Wenn es bei niedrigerem Takt noch immer nicht liefe, wüsste man, dass es nicht am Steckbrettaufbau liegt. Denn mit diesem sollten die 8 MHz eigentlich problemlos möglich sein.
>Hilft eine Schirmung der SPI Leitung, oder verdrillen? Welcher Länge und Art hat deine Verbindung(Kabel, Brücke...)? >Vielleicht hat ja jemand bereit Erfahrung mit solcheb Aufbauten und kann >nen Tipp geben. Ein Display über SPI an einem 20cm langen Flachbandkabel angeschlossen, hatte bei 8MHz machte bereits Probleme. Eine kürzere Verbindung behob das Problem. Gruß J
Olli Z. schrieb: > oder könnte man mit dem Oszi was erkennen? Man könnte mal direkt an den µC Pins messen, wie die Signale aussehen (Masseleitung vom Oszi auch am Massepin des IC abgeschlossen!). Wenn di nicht mal annähernd rechteckig sind, dann liegt schon mal der Schaltungsaufbau im Argen. > Hilft eine Schirmung der SPI Leitung, oder verdrillen? Oder eine Serienterminierung... Lies mal den Beitrag "Serienwiderstand bei Hochfrequenz"
Waehrend die Implementation des MSI Masters in den AVRs halbwegs gelungen ist, ist die SPI Slave Implementation katastrophal. Falls die beiden AVRs synchron laufen, dh ab demselben Clock, gibt es halbwegs eine Chance mit einem tieferen SPI clock. Das Problem ist der Slave hat keinen Buffer. Wenn das Byte drin ist, muss man's sofort holen, sonst ist es weg. Dh bei Clock-Halbe ist nichts mehr mit Interrupt, dh pus/pop, move und so dauert zu lange. Sondern da gibt es nur noch poll-move. In ASM, sonst ist nichts. Andere Controller haben an dieser Stelle einen DMA, der das SPI selbstaendig rumschaufelt. Schneller als Clock-Achtel wird's der Slave kaum machen, eher langsamer.
:
Bearbeitet durch User
Olli Z. schrieb: > Mein Schaltungsentwurf sieht vor mit zwei Slaves an einem SPI Bus vom > Atmega328 (16 MHz Takt) aus zu kommunizieren. Um die Latenzen und > Abfragedauer möglichst gering zu halten, möchte ich den Bus mit 8 MHz > laufen lassen. Mhm, wie willst du die Daten bereit stellen? Ich denke mir bei "nur" der doppelten CPU Taktfrequenz wirst du allgemein grosse Mühe haben mit Daten bereitstellen, abfangen und Auswerten. Sapperlot W. schrieb: > Andere Controller haben an dieser > Stelle einen DMA, der das SPI selbstaendig rumschaufelt. Wenn du unbeding diese uC verwenden willst musst du den SPI-Takt reduzieren. Ansonsten würde ich auf einen STM32 wechseln, welcher der SPI Bus mehrmals abtastet (8-16 fach und entsprechend ein Bit-Wert ermittelt) sowie DMA die dir die CPU entlasten... sonst wird das wohl nichts.
:
Bearbeitet durch User
Sapperlot W. schrieb: > Das Problem ist der Slave hat > keinen Buffer. Wenn das Byte drin ist, muss man's sofort holen, sonst > ist es weg. Noch komplizierter wird es, wenn der Slave gleichzeitig noch senden muss: dann muss nämlich innerhalb einer halben Bitzeit, das Schieberegister "nachbetankt" werden. Halte ich kaum noch für machbar.
Olli Z. schrieb: > Vielleicht hat ja jemand bereit Erfahrung mit solcheb Aufbauten und kann > nen Tipp geben. Hilft eine Schirmung der SPI Leitung, oder verdrillen? Alles nicht nötig. Route sie gescheit: - so kurz wie möglich - Keine Verzweigungen : Über slave1 zu slave2 - Über durchgehender Massefläche routen (unter der Taktleitung keinen Schlitz durchziehen). Das dürfte für 8MHz locker reichen. Beim Breadboard werden es wohl Geschichten wie die Kapaitäten sein, die dir das ruinieren. Wobei mich das wundert: Bei mir am Breadboard laufen die DOGS-Displays und SD-Karten auch immer 20MHz, ohne irgenwelche Probleme. Probiers mit denen statt Drähten, falls du solche verwendet hast: https://www.reichelt.de/Experimentier-Steckboards/STECKBOARD-DBS/3/index.html?ACTION=3&LA=446&ARTICLE=79056&GROUPID=7791&artnr=STECKBOARD+DBS&SEARCH=Steckbr%25FCcken Leitungen kurz halten gilt auch dort.
Es handelt sich um zwei MCP2515. Bislang habe ich MISO/MOSI (eher unkritisch?) und SCK (kritisch) jeweils mit eigenen, ca. 10cm langen, felxiblen Dupont-Steckverbindern an den Arduino-Ports angeschlossen. Jeder Controller verfügt über eine eigene /CS Leitung am Arduino (Digitalausgänge). Weiterhin ist von jedem Controller das /INT Signal an eigene Digitaleingänge an den Arduino geführt. Die Controller sollen CAN-Nachrichten eines 125kbit Busses (11 Bit ID) beidseitig durchrouten, also sowohl senden als auch empfangen. Erstmal ohne Anpassung, wie ein Repeater, später dann mit Datenveränderungen. Wie könnte man vorab rechnerisch ermitteln was für ein SPI-Takt überhaupt notwendig wäre? Also die Daten kommen mit maximal 125kbit rein. Darin enthalten sind auch noch sämtliche Protokollinformationen vom Bus. Sobald die Nachricht im Controllerpuffer (hat nur zwei Stück davon) vollständig angekommen ist, zieht er seine /INT-Leitung auf LOW (so ist er vorab parametriert worden). Diese wird in der Main-Routine abgefragt und liest dann die Daten vom Controller aus. Hierzu sendet die Software über SPI erst das entsprechende Kommando und erhält anschließend die ID und Nutzdaten, also 10 Bytes insgesamt. Dieser Lesevorgang muss so schnell gehen, das eine auf dem anderen Controller evtl. gleichzeitig eintreffende Nachricht nicht durch eine nachfolgende überschrieben werden kann, richtig? Nehm ich hier den ungünstigsten Fall, also ID mit nur einem Datenbyte kommt am Controller an (habe ich auf dem Bus nie gesehen, aber 3 Byte schon...), rechne ich die benötigten Bits zusammen: SOF = 1 ID = 11 RTR = 1 EXT = 1 RES = 1 DLC = 4 DATA = 8 CRC = 15 CRCDEL = 1 ACK = 1 ACKDEL = 1 EOF = 7 ---------- Summe = 52 Bits dann macht das bei ca. 8us pro Bit eine Gesamtzeit von 416us für das gesamte Datagramm. Jetzt müsste ich noch den IFS (Interframespace) hinzurechnen bis theoretisch das nächste Datagramm reinlaufen könnte. Es braucht aber auch noch einige Zeit (ich glaube 20us) bis der INT vom Controller ausgelöst wird. Bis hier hin richtig gerechnet? Jetzt müsste ich es in dieser Zeit schaffen das CAN-Datagramm des anderen Controllers zu lesen, oder dort eines zum senden zu übertragen, damit mit das andere nicht verloren geht. Ich muss also CS des Controllers auf LOW ziehen, das SPI-Kommando zum lesen des Statusregisters senden (um den Empfangspuffer zu ermitteln) = 2 Byte (weil der MCP die Daten zweimal sendet, warum auch immer...). Dann das entsprechende READ-Kommando für den Puffer senden (1 Byte) und dann zuerst die ID empfangen (2 Byte), 2 Dummy-Bytes senden, DLC lesen (1 Byte), Daten lesen (in meinem Beispiel 1 Byte), INT-Flag löschen (1 Byte). Macht zusammen 10 Bytes. Da SPI ja keinen Protokolloverhead hat, könnte man das direkt in Bits ausdrücken, also 80 Bits. Hier kommen vermutlich noch die Zeit für das erkennen des CS und die internen Antwortzeiten auf die Kommandos vom Controller hinzu. Aber ich wär rechnerisch bei knappen 200 khz. Mache ich einen Denkfehler? Unterschätze ich die angegebenen Select- und Verarbeitungszeiten im Atmega? Mein erster Test war mit Arduino-Bordmitteln, also einer Arduino IDE, einer MCP2515-Lib. Ist das vielleicht der Fehler? Sollte ich das lieber ohne das Arduino-Zeugs machen? Direkt in C, mit eigenen Routinen? und vor allem ohne den Arduino-Overhead drumherum?
:
Bearbeitet durch User
Ich würde einen anderen Ansatz wählen: ATMega mit externem Adress/Datenbus mit 2 SJA1000: Da kannst Du auf die Register mit einfachen Speicherzugriffen zugreifen. Wie das mit einem SJA funktioniert, siehst Du hier: http://www.kreatives-chaos.com/artikel/sja1000-testboard Die Erweiterung um einen weiteren SJA1000 ist dann einfach. Das wird auch mit 1MBit/s funktionieren. fchk
Ich hab bei einem Layout mit dem MCP2515 ca. 20 cm lange Leitungen. Der MCP ich ca. 5 cm weg vom xMega , dann kommen 2 cm Leiterbahn , ca. 10 cm Flachbandkabel, dann ca. 3 cm Leiterbahn und dann ein 1,8" Display. Die Taktleitung hab ich mit einer AC-Terminierung abgeschlossen. Die CS Leitungen haben eine Serienterminierung. Mit 8 MHz SPI Takt habe ich kein Problem. Wenn du willst kann ich dir die Werte für die AC-Terminierung senden wenn ich zuhause bin. Gruß JackFrost
Ja, sehr gern. Ich danke auch für den Tipp mit dem Sja1000. Ich wollte jedoch das eine Problem lösen und nicht evtl. durch andere ersetzen. Ist ja manchmal so. Daher bin ich interessiert herauszubekommen was an meinem Design falsch ist. Wenn ich jetzt nach meiner obigen Theorie den SPI Bustakt auf 1 MHz reduziere und dann alles klappt, dürfte das schon ein Beweis sein, klar. Besser wäre wohl, wenn ich mir die Signale im Oszi anschaue, vielleicht trifft mich da schon der Schlag ;-) Leider muss ich das alles ans Auto schleppen, denn in meinen Labortests ist das Problem nicht aufgetaucht. Ich konnte da aber auch nur unidirektional testen und im Auto muss es in beide Richtungen gehen. Wenn ich es richtig verstanden habe liegt der Takt beim SPI nur während des sendens/empfangens an. Ich könnte hier also mit einem Trigger arbeiten. Am besten wird sein, ich protokolliere SCK, MOSI, MISO und CS eines Controllers. Leider hab ich nur ein 4 Kanal-Oszi...
:
Bearbeitet durch User
Doch, sowas hab ich. Ich denk aber das nicht die signalsynchronisastion ein Problem sein kann, sondern die Flanken. Und die kann man mit sowas nicht wirklich messen/sehen. Durch den Schmitt-Trigger sehen die alle gut aus...
Ich hab die AC-Terminierung mit 120 Ohm und 18 pF gemacht. Anbei sind zwei Bilder von CS und Clock am Ende der Leitung. CS sieht gut aus, beim Takt könnte man sicher noch was machen. Aktuell läuft es aber ohne Probleme mit 8 MHz. Gruß JackFrost
So, habe heute mal einen LA an alle Pins geklemmt und die SPI-Clockrate auf 2 MHz (DIV8) runtergetaktet. Folgendes erkenne ich auf screenshot1: * Man sieht sehr schön das INT_NAVCAN vom MCP ausgelöst wird (weil wohl eine Nachricht eingegangen ist). * Das wird kurz drauf vom uC erkannt, der wiederum zum auslesen der CAN Nachricht das CS_NAVCAN auf LOW zieht. * Anschließend ist an MOSI (Arduino zu MCP) eine Bitfolge zu erkennen. Das kürzeste Bit ist genau 1uS lang (kurz rechnen: Kehrwert von 2 MHz = 0,0000005s = 0,5uS. Hhmmm, könnte passen). Die Bitfolge müsse demnach 10010000 sein. Das wäre 90h und entspräche dem Befehl "MCP_READ_RX0". Das ist schon etwas komisch, denn laut Lib-Code müsste erstmal das Statusregister gelesen werden um herauszubekommen in welchem Puffer die CAN-Nachricht liegt. Erst dann kommt der eigentliche Read. Bis dahin sollte INT eigentlich LOW sein. Es ist aber deutlich zu sehen das die Flanke vorher HIGH war. * Der SCK sieht mehr als merkwürdig aus! Vermutlich ist das Signal trotz kurzer Leitung und niedrigerem SPI-Tak so übel, das es der LA nicht sauber darstellt. Denn das müsste doch während der gesamte /CS LOW-Phase sauber anliegen. Ohne die Pulse würde der MCP nichts sinnvolles erhalten. Die anderen Screenshots zeigen wie das im Verlauf aussieht. Ich glaube ich muss doch mal mit dem Oszi drauf.
Bastian W. schrieb: > Ich hab die AC-Terminierung mit 120 Ohm und 18 pF gemacht. Olli Z. schrieb: > Ich glaube ich muss doch mal mit dem Oszi drauf. Ja wie jetzt, ist Olli Z. und Bastian W. der gleiche?
Mitlesa schrieb: > Bastian W. schrieb: >> Ich hab die AC-Terminierung mit 120 Ohm und 18 pF gemacht. > > Olli Z. schrieb: >> Ich glaube ich muss doch mal mit dem Oszi drauf. > > Ja wie jetzt, ist Olli Z. und Bastian W. der gleiche? Nein , sind zwei User. Ich hab derzeit kein Problem mit dem SPI Gruß JackFrost
@Bastian Werner (jackfrost) >Ich hab die AC-Terminierung mit 120 Ohm und 18 pF gemacht. Anbei sind >zwei Bilder von CS und Clock am Ende der Leitung. CS sieht gut aus, beim >Takt könnte man sicher noch was machen. Aktuell läuft es aber ohne >Probleme mit 8 MHz. Naja, da hast du entweder ein Meßproblem (langes Massekabel) oder ein Masseproblem in deiner Verbindung zwischen UC und SPI-Slave. BEsonders der Takt sollte mit einer Masseleitung verdrillt werden und zum SPI-Slave geführt werden. https://www.mikrocontroller.net/articles/Oszilloskop#Tastk.C3.B6pfe_richtig_benutzen
Uh, ich hatte wirklich ein Messproblem. Habe nicht umrissen das ich beim LA nur mit 1MS/s abgetastet hatte. Habe das nun nochmal wiederholt, mit 24MS/s und dann schaut das schon besser aus :-) Damit beantwortet sich auch meine Frage ob der SCK nur während einer Übertragung anliegt. Ja, natürlich. Ich meinte zwar den Takt stark herabgesetzt zu haben, aber der LA misst eine Taktfrequenz von 2 MHz (SPI/8). Hmm... Aber auch hierbei habe ich Aussetzer im CAN-Bus. Ich glaube ich muss die CAN-Signale auch noch in die LA-Ansicht bringen um zu sehen ich ich was verliere. Am besten zwischen TJA1050 und MCP2515 abgreifen mit TTL-Pegel.
Also, soweit ich das bislang ermitteln konnte ist die Kommunikation zwischen uC und MCP ansich schon ok. Alles nachvollziehbar laut Lib und Datenblatt. Mir ist jedoch aufgefallen das in der Lib die ich nutze gerade beim Senden schwächen enthalten sind. Zum einen finde ich im Source div. delayMicroseconds() Aufrufe, die unnötig verzögern. Die Senderoutine sieht so aus, das nach der Übergabe von der Lib selbst der Sendestatus abgefragt wird und diese erst zurückkehrt wenn die Daten erfolgreich gesendet werden konnten, oder ein Timeout (200 ms) auftritt. So lange muss ein anderer MCP warten, bis seine Daten abgerufen werden können. Das dauert öfters bis zu 20ms, was sicher zu lang ist. Entgegen aller Erwartungen ist also nicht das Empfangen das Problem, das geht flott, sondern das senden! Evtl. ist der CAN zu voll oder es gibt dort ein Problem. Ich sollte mir mal die CAN Leitung dazu mit auf den LA legen.
Hier noch ein paar Bilder, diesmal mit dem am TJA1050 abgegriffenen CAN-RX Signal vom Auto (CARCAN). Wer die LA-Software hat (gibts kostenlos zum Download beim Saleae) find im ZIP den gesamten Trace. Ansich sieht das alles super sauber aus, bis halt auf das senden.
:
Bearbeitet durch User
Im Bild "mcp_noloss.png" habe ich mal eine Stelle gewählt wo vier CAN-IDs recht dicht hintereinander kommen. Jedem CAN-TX Paket (unterste Linie) habe ich dem CS-Bereich des Senders zugeordnet und daraus ist ersichtlich das noch bevor die erste Nachricht versendet wurde, drei weitere am MCP eintreffen. Diese werden aber erstmal nicht behandelt, weil der uC noch mit dem senden beschäftigt ist. Die erste CAN-ID (Gelb) ist noch nicht vollständig gelesen während die zweite (Orange) eintrifft. Diese wird also im RX1-Buffer landen. Noch bevor die dritte CAN-ID 8(Grün) beginnt ist die erste vollständig gelesen, was den RX0-Buffer wieder leert. Somit landet die dritte CAN-ID (Grün) im RX0-Buffer. Dadurch das der Arduino gerade damit beschäftigt ist, die erste CAN-ID (Gelb) auf dem anderen CAN-Bus (NAV) zu senden, werden keine CAN-Nachrichten vom MCP (CAR) gelesen. Nun kommt die vierte Nachricht (Blau), welche zunächst im MAP (Message-Assembly-Buffer) des MCP zusammengestellt wird. Wenn diese vollständig ist, kann sie jedoch nicht in einen RX-Buffer übernommen werden, weil diese noch voll sind. Nur durch puren Zufall kommt die nächste (5.) Nachricht erst so viel später, das inzwischen wieder RX-Buffer geleert wurden. Bei einer Folge von fünf CAN-IDs würde die fünfte die vierte im MAP befindliche überschreiben, wodurch diese verloren ging. Ich glaube genau das passiert in "loosing-canrx.png", da geht Nachricht Nummer 6 verloren. Und so wird es mit vielen anderen auch passieren. Verursacht wird das ganze besonders durch dieses ewige warten das die Nachricht auf dem anderen CAN gesendet wurde. Ich frage mich nach wie vor warum das so lange dauert. Im Idealfall (NAV-CAN Bus idle) sollte das nur solange dauert wie das empfangen, d.h. übertragen der CAN-Daten an den MCP und aussenden auf den Bus.
So, möchte auch mal meinen Fortschritt melden. Habe mich inzwischen intensiv mit dem Thema SPI und MCP2515 auseinander gesetzt. Inzwischen ist es mir gelungen die "Zeitfresser" in den Libs zu ermitteln und weitestgehend zu entfernen. Um keine Nachrichten zu verlieren habe ich einen Ringpuffer (Lib "QueueArray") hinzugefügt. Wie im LA-Bild zu erkennen ist es mir selbst bei 500khz SCK gelungen die Durchlaufzeit einer Nachricht auf knappe 2ms zu drücken, was wie ich finde schon ein guter Wert ist. Bidirektional gehen jetzt verlustfrei Nachrichten mit bis zu 15ms Periode durch. Ein Test im Fahrzeug zeigte schon ein deutlich(!) stabileres Bild. Dennoch meldete sich das Radio ab und zu mal ab. Entweder werden hier noch irgendwelche Speziellen Keep-Alives gesendet (rolling counter oder sowas) oder ich habe noch was übersehen. Aktuell habe ich noch keine besonderen Fehlerprüfungen im Code. Einzig wenn der Ringpuffer überläuft gehe ich auf Störung. Das ist bislang aber nie passiert. Ich müsste noch auswerten ob eingehende IDs im MAB überschrieben wurden, dann hätte ich nämlich Paketverluste weil ich zu langsam abrufe. In der Realität sind die CAN-Pakete mitunter direkt hintereinander, weil es verschiedene Sender sind. Das kann ich hier im Labor noch nicht nachstellen, denn unter 15ms Periode kommt mein Aufbau nicht. Liegt entweder am Sender (einfaches USB2CAN Interface) oder doch an der Durchlaufzeit in dem was außerhalb der Arduino loop() passiert. Eine Datenverarbeitung mache ich aktuell nicht. Es soll nur erstmal alles 1:1 in beide Richtungen durch.
Ok, auch wenn sich scheinbar alle anderen bei diesem Thread "abgemeldet" haben, möchte ich noch zurückmelden das meine Schaltung nun läuft, nachdem ich den SPI-Takt von 0,5 MHz auf 8 MHz erhöht habe (nachdem ja nun bewiesen war, das nicht der hohe SPI-Takt das Problem war). Es geht also doch, popeliger Arduino mit zwei effen MCP2515 Wald-und-Wiesen Controllern. Unabhängig davon habe ich mir SJA2000T Controller besorgt und div. ST32M Boards mit single und dual-CAN, ebenso wie einen Arduino Due, ebenfalls mit 2x CAN on Board. Mal sehen was die so können :-) Mein nächstes Ziel wäre es dann, die empfangenen Daten auf eine SD-Card schreiben zu können, zur Laufzeit. Aktuell würde ich behaupten das das zusätzlich sogar noch mit dem Arduino Nano klappt, weil auf dem SPI-Bus noch genug Zeit ist....
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.