Hi, nach Tagen erfolgloser Bastelei und Sucherei muss ich mal mein komplettes Problem hier reinstellen - vielleicht hat ja jemand eine Idee. Ich habe ein SPI Signal: - /SS geht auf LOW - 24 Bits werden übertragen, die Daten sind jeweils bei der fallenden Flanke von SCK gültig - /SS geht auf HIGH Dementsprechend habe ich konfiguriert: - CTRLA.CPOL = 0 und CTRLA.CPHA = 1 für die fallende SCK-Flanke - CTRLA.MODE = 2 für den SPI-Slave - CTRLB.SSDE = 1 für /SS auf LOW, wenn Daten übertragen werden - CTRLB.RXEN = 1 um Daten empfangen zu können - CTRLC.DATA32B = 1 um mehr als 8 Bit in den Eingangspuffer zu bekommen - LENGTH.LEN = 3 und LENGTH.LENEN = 1 um eben meine 24 Bit zu empfangen Ob Daten angekommen sind, frage ich über INTFLAG.RXC ab. Mein Problem: Die Daten, die eintrudeln, sind nur so ähnlich wie das, was ich erwarte. CTRLA.DORD auf 0 oder 1 setzen ändert daran auch nichts, wirklich 100% passen die Daten nie. Weiterhin findet sich im DATA-Register immer mal 0, obwohl das vom Master nie abgesendet wurde. Was ich nicht verstehe: wozu sind diese Werte in LENGTH.LEN und LENGTH.LENEN nötig, wenn doch /SS die Framelänge bestimmt? Setze ich diese beiden Werte nicht, werden mir alle 32 Bit in DATA beschrieben als ob /SS keine Bedeutung hätte (und die Daten sind noch kaputter). Auch völlig unklar: was machen die Clocks beim SPI wenn im Slave-Mode der Master eigentlich einen Clock sendet? Mangels besserer Ideen habe ich "Core" und "Slow" infach mal auf 96 MHz gesetzt. Irgend welche Ideen, warum mein SPI-Master so gar nicht funktionieren mag? Oder gibt es eventuell irgendwo einen funktionierenden Beispielcode für den ATSAMD51? Danke!
- LENGTH.LEN = 3 Müsste da nicht 24 stehen für den SPI? Beim I2C ist das die Anzahl der Bytes, aber beim SPI müsste das die Anzahl der Bits sein.
Rudolph R. schrieb: > Müsste da nicht 24 stehen für den SPI? Das Manual ist da nicht wirklich eindeutig: "In 32-bit Extension mode, this bit field configures the data length after which the flags INTFLAG.RCX or INTFLAG.DRE are raised." Wenn ich da 24 reinschreibe, ist mein DATA-Register wieder komplett voll, sprich alle 32 Bit sind mit irgendwas belegt, nicht nur die unteren 24. Also gehe ich davon aus, dass hier Byte gemeint sind, zumal man Werte bis maximal 256 dort reinschreiben kann (was ja auch mehr wäre als die 32 Bit vom DATA-Register). Der Sinn erschließt sich mir allerdings nicht wirklich.
War jetzt nicht so ganz lustig das auszuprobieren, ich nutze den SPI sonst nur im Master-Modus und musste erstmal zwei Platinen zusammen bringen. Ich benutze ATSAME51 mit externem 16MHz Quarz. Auf beiden Platinen habe ich SERCOM5 auf einem Stecker liegen, für den Slave musste ich die Belegung etwas anpassen, SS kann nur auf Pad2 liegen. Beim Master habe ich das hier laufen:
1 | spi_delay++; |
2 | if(spi_delay > 19) |
3 | { |
4 | spi_delay = 0; |
5 | |
6 | cs_set(); |
7 | small_delay(4); |
8 | spi_transmit(0x55); |
9 | small_delay(5); |
10 | spi_transmit(0xaa); |
11 | small_delay(5); |
12 | spi_transmit(counter++); |
13 | small_delay(4); |
14 | cs_clear(); |
15 | } |
Also nichts wildes, das ganze in einem 5ms Task verpackt. Der Frame hat von CS-Low bis CS-High fast 53µs. Ach ja, den SPI habe ich auf 1MHz eingestellt, CPOL und CPHA auf beiden Seiten Null. Auf der Slave Seite frage ich nur in einer while(1) das RXC Flag ab. Wenn ich den Endwert von spi_delay anpasse, dann ändert sich auch die Blinkfrequenz von der Debug-LED an meinem Slave. Die Slave-Seite hängt an. Ohne das hier:
1 | SERCOM5->SPI.LENGTH.reg = SERCOM_SPI_LENGTH_LENEN | SERCOM_SPI_LENGTH_LEN(3); |
Landen in der Variable spi_data immer 4 Bytes. Aktiviere ich die Zeile sind es immer 3 Bytes. Gehe ich mit dem Debugger auf den Controller sehe ich in der Variable zum Beispiel: 0x004caa55 Continue / Break -> 0x00d0aa55 Continue / Break -> 0x0015aa55 Also das LENGTH Register ist wirklich die Länge in Bytes und das RXC Flag im STATUS Register wird 1 wenn die eingestellte Anzahl empfangen wurde. Wofür auch immer das gut ist, dass man im LENGTH Register bis 0xff einstellen kann. Interessant wäre jetzt nur mal, ob man auch schräge Längen empfangen kann. Laut Datenblatt gibt es noch das hier: Bit 1 – TXC Transmit Complete In Slave mode, this flag is set when the _SS pin is pulled high. Writing '0' to this bit has no effect. Writing '1' to this bit will clear the flag. Das funktioniert nur irgendwie nicht, TXC wird nie gesetzt. Im Debugger sehe ich nur RXC und DRE. Löschen von RXC durch Schreiben von DATA hilft da auch nicht. In den Errata finde ich dazu auch nichts. Als Master sind mir die Dinger lieber. :-)
Rudolph R. schrieb: > Ohne das hier:SERCOM5->SPI.LENGTH.reg = SERCOM_SPI_LENGTH_LENEN | > SERCOM_SPI_LENGTH_LEN(3); > > Landen in der Variable spi_data immer 4 Bytes. > Aktiviere ich die Zeile sind es immer 3 Bytes. Diese Beobachtung habe ich auch schon gemacht. Die Spezifikation beschreibt eigentlich, dass solche Framelengen über /SS ermittelt werden - nur scheint das eben nicht zu funktionieren, ohne den Teil wird DATA immer komplett gefüllt. > Also das LENGTH Register ist wirklich die Länge in Bytes > Wofür auch immer das gut ist, dass man im LENGTH Register bis 0xff > einstellen kann. > Interessant wäre jetzt nur mal, ob man auch schräge Längen empfangen > kann. ...und wofür das auch immer gut ist, dass man das in Bytes konfiguriert, statt in Bits, dann wären auch schräge Längen möglich - nur dazu habe ich nix gefunden (das müsste eigentlich wieder automatisch über /SS gehen können, aber Pustekuchen). > Laut Datenblatt gibt es noch das hier: > Bit 1 – TXC Transmit Complete > In Slave mode, this flag is set when the _SS pin is pulled high. > Das funktioniert nur irgendwie nicht, TXC wird nie gesetzt. Nö, das tut bei mir nicht, man muss wirklich RXC abfragen. > Die Slave-Seite hängt an. Perfekt, Danke!!!
OK, das funktionert trotzdem nicht. Was ich geändert habe: - 120 MHz Clock für den SPI (wie im Beispielcode oben) - Initialisierung auch wie im Beispiel oben - sämtliche Kombinationen von CPOL/CPHA durchprobiert - Eingangssignale überprüft (sieht gut aus, keine Störungen) Was jetzt noch anders ist bei mir: ich verwende andere Eingänge für meine SERCOMs: - SCK an PA22 (-> PINMUX_PA22D_SERCOM5_PAD1) - /SS an PA20 (-> PINMUX_PA20C_SERCOM5_PAD2) - Daten1 an PA21 (-> PINMUX_PA21C_SERCOM5_PAD3) - SCK an PA05 (-> PINMUX_PA05D_SERCOM0_PAD1) - /SS an PA06 (-> PINMUX_PA06D_SERCOM0_PAD2) - Daten2 an PA07 (-> PINMUX_PA07D_SERCOM0_PAD3) Pinmuxing und MISO/MOSI-Mapping sollten passen (die entstammen auch dem ATMEL Start Code, ich habe sie auch noch mal gegengecheckt und konnte kein Problem entdecken): CTRLA.DOPO ist jeweils 0, CTRLA.DIPO jeweils 3. Könnte da trotzdem noch irgend was durcheinander kommen? Allerdings hätte ich ja vermutet, dass bei falschem Pinmuxing oder falscher MISO/MOSI Signalzuweisung einfach gar nichts empfangen wird (also RXC niemals auf 1 geht), weil kein gültiges SPI-Frame erkannt wird, oder? Auf der anderen Seite ist es auch so, dass RXC korrekterweise nie gesetzt wird, wenn ich mein Eingangssignal wegnehme, es wird also auch nicht der Radiosender von nebenan empfangen.
Sortland schrieb: > ATMEL Start Code Damit mag ich nicht mal mehr planen für den Schaltplan,da sind mir einfach zu viele Fehler drin. Du hast doch schon ein einfaches Beispiel von mir, pass das doch direkt mal an - und zwar genau so wie das ist, nur für die anderen Pins. Okay, das init_clock() passt vielleicht nicht, aber wenn man das weg lässt läuft der GCLOCK0 mit 48MHz Default auch nicht ganz langsam.
Rudolph R. schrieb: > Du hast doch schon ein einfaches Beispiel von mir, pass das doch direkt > mal an - und zwar genau so wie das ist, nur für die anderen Pins. > Okay, das init_clock() passt vielleicht nicht, aber wenn man das weg > lässt läuft der GCLOCK0 mit 48MHz Default auch nicht ganz langsam. Das habe ich gemacht und exakt deinen Code verwendet (nur halt mit dem zu meiner Hardware passenden Pinmuxing). Ergebnis: genau der gleiche Datenmüll wie mit dem ATMEL Start Code. Wobei ich "Datenmüll" jetzt etwas genauer spezifizieren kann. Ich sende Frames mit folgendem Format: - 2 Steuerbits (sind immer 01) - 20 Bits Nutzdaten - 2 Paritätsbits (werden derzeit noch nicht verwendet). Nutzdaten auf den Datenkanälen 1 und 2 sind z.B. 0xF0D2B und 0x8F051 es kommen aber an: 0xF2B0D und 0x1F058 Da ließe sich jetzt sogar ein Muster erkennen und die Bits entsprechend tauschen. Aber: das passt nicht immer, beim nächsten Neustart können die Daten anders gemischt sein. insgesamt scheint es aber nur 2 oder 3 verschiedene Varianten von Datenvermischung zu geben.
Da meine Zahlenbeispiele oben wegen der 2-Bit-Verschiebung nicht ganz eindeutig waren, habe ich es noch mal mit den Rohdaten (also inklusive der oberen und unteren beiden Bits probiert. Es scheitn wirklich so zu sein, dass die Bytes wild gemischt werden:
1 | Daten1 Daten2 |
2 | Gesendet: 0x00448dfc 0x007e97c0 |
3 | Empfangen: 0x0044fc8d 0x00c0977e |
Wenn das nicht irgend ein blöder Seiteneffekt von irgend was ganz was anderem ist, ist das schon eher dubios...
>Die Spezifikation >beschreibt eigentlich, dass solche Framelengen über /SS ermittelt werden >- nur scheint das eben nicht zu funktionieren, ohne den Teil wird DATA >immer komplett gefüllt. Das ist ein Irrtum, den Du dringend aufklären solltest. Framelänge hat NIX mit /SS zu tun. Ausser Slave selektieren und evtl/wahrscheinlich SPI State Machine zurücksetzen macht das GAR nix. Man könnte SS sogar ständig aktiv lassen, ohne dass das an der SPI Funktion viel ändern würde,
Hab's nicht genau durchgelesen, was Du gemacht hast, aber i.d.R muss man 24 bits als 3 mal 8 bits übertragen. /SS zwischen den Bytes NICHT deaktivieren, also assert /SS byte 1 byte 2 byte 3 deassert /SS
Und
>- 120 MHz Clock für den SPI (wie im Beispielcode oben)
scheint mir reichlich hoch.
Übliche Tatktfreq für SPI sind < 50MHz.
Oft besteht auch ein Zusammenhang zwischen dem Core Clock
und dem SPI, z.B SPI clock < 1/4 COre Clock.
Filler schrieb: > scheint mir reichlich hoch. > Übliche Tatktfreq für SPI sind < 50MHz. > Oft besteht auch ein Zusammenhang zwischen dem Core Clock > und dem SPI, z.B SPI clock < 1/4 COre Clock. Es geht hier um den SPI-Slave, die SCK-Frequenz des Masters ist deutlich unter den 120 MHz. Dabei handelt es sich nur um den Clock für das SPI-Gerät in der MCU, das hat nichts mit den nach außen geführten Signalen zu tun. Der externe SCK liegt bei etwa 3 MHz.
Filler schrieb: > Das ist ein Irrtum, den Du dringend aufklären solltest. "Bit 1 – TXC Transmit Complete In Slave mode, this flag is set when the _SS pin is pulled high." Du kennst Dich also mit dem Controller aus, dann erkläre uns doch mal diesen Passus im Datenblatt, zu was das gut ist und wie man das benutzt.
So, ich habe mal ein paar Messungen gemacht, um Probeme bei den Eingangssignalen auszuschließen. Das erste Bild ist direkt auf der Leitung (differetielles Signal, auf einer Ader gemessen). Dort sind SCK, /SS und Daten gut zu sehen, das Timing sollte meiner Meinung nach passen (leider nicht mehr im Bild: /SS geht nach den 24 Clocks/Bits nach oben, die Datenleitung geht gleichzeitig auch nach oben). Das Signal ist dort nicht ganz sauber, deswegen das zweite Bild: dieses ist nach dem Receiverbaustein aufgenommen, jetzt mit den Logikpegeln, wie sie direkt in den ATSAMD eingespeist werden (da fehlt eins der Signale, weil ich einfach keine dritte Hand zum Festhalten der Probe auf den entsprechenden Pin hatte, das Singal ist aber da). Hier ist zu sehen, dass die Singale wesentlich sauberer sind, meiner Einschätzung nach sollten die keine Probleme machen. Damit sollte sich das als mögliche Ursache ja ausschließen lassen!?
:
Bearbeitet durch User
Was mir an den Bildern aufgefallen ist, mein Timing vom Master ist dagegen ja extrem entspannt. Also habe ich das gerade mal hochgeschraubt. Das erste was mir wieder aufgefallen ist, die SERCOMs sind mit 100 MHz maximalem core Takt angegeben. Okay, das ist bei 85°C und bei 125°C sind es 90 MHz. Bei 20°C und sonst nichts an wird die eine SERCOM Einheit die 120 MHz schon packen. Aber da es dazu keine Angabe gibt, habe ich den Takt für Master und Slave auf 100MHz abgesenkt. Und da ich keinen Bock hatte die zweite PLL anzuwerfen und einen weiteren GCLOCK zu belegen, läut der CPU-Core jetzt auch auf 100 MHz. Statt dem zahmen SPI-Transfer von oben habe ich jetzt das hier im Master laufen:
1 | PORT->Group[1].OUTCLR.reg = PORT_PB01; |
2 | SERCOM5->SPI.DATA.reg = 0x55; |
3 | while((SERCOM5->SPI.INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC) == 0); |
4 | SERCOM5->SPI.DATA.reg = 0xaa; |
5 | while((SERCOM5->SPI.INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC) == 0); |
6 | SERCOM5->SPI.DATA.reg = counter; |
7 | while((SERCOM5->SPI.INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC) == 0); |
8 | PORT->Group[1].OUTSET.reg = PORT_PB01; |
9 | counter++; |
Um das DATA Register nach dem Transfer nicht lesen zu müssen habe ich den Empfänger abgeschaltet. Die Lücken zwischen den Bytes und zum CS bekomme ich so nicht mehr kleiner. Das wird jetzt auch nicht mehr alle 150ms ausgeführt, sondern alle 2ms. Zusätzlich habe ich den SPI-Clock am Master von 1MHz auf 25MHz erhöht. SERCOM5->SPI.BAUD.reg = 1; Und erstaunlicherweise läuft das immer noch. Beim Slave habe ich nicht nur den Takt auf 100MHz reduziert, ich compiliere das auch gerade ohne Optimierung und mit spi_data und counter als globale volatile Variablen. Der Grund ist das ich die Variablen mit dem SEGGER J-Scope V6.11 über die SWD Schnittstelle nebenbei lese. Und da kommen die 2ms ins Spiel, mein SEGGER J-Link edu mini schafft "nur" 1000 Messungen pro Sekunde. Ich will gar nicht wissen, wie das mit dem Oszi aussieht, aber im J-Scope schnurrt das einfach so ohne Aussetzer durch.
Ursprünglich hatte ich die beiden SPI-Slaves auch mal auf 96 MHz laufen, das hat für das Ergebnis keinen Unterschied gemacht. Auf die 120 MHz bin ich nur hochgegangen, um mit deinem Beispielcode von oben identisch zu sein (die beiden SPI-Master, die ebenfalls vorhanden sind, habe ich auch mal mit 120 MHz probiert - klappt problemlos und das Ausgabetempo ist echt enorm). Als Optimierung verwende ich nur -Og um im Debugger noch was erkennen zu können, da sehe ich also auch keinen Unterschied.
:
Bearbeitet durch User
Einen großen Unterschied gibt es in meinem Projekt allerdings schon noch: die Erzeugung der Clocks. Die ist zugegebenermaßen etwas wirr, aber der einzige Weg, den ich gefunden habe, um intern getaktet auf 120 Mhz zu kommen (und nicht irgend einen krummen Takt von rund aber eben nicht exakt 120 MHz zu erhalten): 32 kHz Low Power internal Oscillator -> GCG3 -> DFLL48M mit 48 Mhz -> GCG1 mit Teiler 15 auf 3,2 Mhz (mehr lässt die folgende Stufe nicht zu) -> DPLL0 mit Faktor 36 und 16 auf 120 MHz -> GCG0 mit 120 Mhz -> Core Vom GCG1 zweigt auch noch der DPLL1 mit den 90 MHz für die SPIs ab. ICh hätte gerne was einfacheres, aber grundsätzlich sollte das ja nicht so seltsame Auswirkungen haben?
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.