Hallo zusammen,
ich hänge gerade am SPI mode vom USI in einem Tiny fest.
Grundsätzlich geht es schon mal und die Daten fahren Kreisverkehr.
>AAAHaber
wo kann ich mich im SlaveMode mit eigenen Daten einhängen? Geht das
überhaupt - ich dachte so läuft SPI
Also wenn bei jeden empfangenem byte via USI ein anderer Wert in USIDR
geschrieben wird.
So dachte ich mir das jedenfalls.
Im Moment komme ich von dem Loopback nicht weg.
viele Grüße!
Im Datenblatt das Bild 'Universal Serial Interface, Block Diagram' sowie das Programmteil 'SPI Slave Operation Example' sollten weiterhelfen. Wenn nicht, was wurde nicht verstanden, bzw. wie sieht das nicht funktionierende Programm aus?
Ja, die Teile im DB hab ich gelesen und auch noch mal genau, ob ich was finde, das von meinem intuitiven Verständnis abweicht. Hab ich ne AppNode gesichtet und einen anderen Beitrag hier. Ach ja, es sind keine Interrupts aktiviert. Der Code:
1 | slaveSelStatusNew = (PINB & 0b01000000);// read slave select Pin |
2 | if(slaveSelStatusNew != slaveSelStatusOld)//SS edge detect |
3 | {
|
4 | if(slaveSelStatusOld == 0)//jetzt SS IDLE - vorher also activ |
5 | {
|
6 | dummyChar = USIBR; //read buffer |
7 | USIDR = 'a' + charCntr; //create fake data to return |
8 | charCntr++; |
9 | if(charCntr >= 5) charCntr = 0; |
10 | }
|
11 | else
|
12 | {
|
13 | USIDR = 'a' + charCntr;//Griff nach dem Strohhalm |
14 | }
|
15 | }
|
16 | slaveSelStatusOld = slaveSelStatusNew; // part of edge detection |
Es tut mir leid, mit diesem Programmschnipsel kommt niemand weiter, es zeigt u.a. die USISR.USIOIF-Abfrage nicht.
Das USIOIF benutze ich nicht. Ich habe die Schnittstelle für mich so definiert, dass bei einer Rising Edge auf dem Software-SlaveSelect Pin von einer eingegangenen Übertragung ausgegangen wird. Ansonsten halte ich den Code für verständlich. Die Variablen haben selbstredende Namen, es gibt Kommentare und mit der Abfrage von PINB ist klar, dass der Abschnitt zyklisch aufgerufen werden muss und da auch nichts dazwischen funken kann, da wie beschrieben keine Interrupte aktiviert sind.
Das heißt, dass der Master pro SPI-Zyklus nur ein einziges Byte sendet? Und der gezeigte Programmteil ist in eine Schleife eingebettet? Wenn das alles ist, hätten Sie aber auch das komplette Slave-Programm zeigen können. Der Master sendet also 'irgendwas', und erhält im nächsten SPI-Zyklus eben dieses 'irgendwas' statt des erwarteten 'a' ('b' 'c' ...) - okay, dann muss ich passen, vielleicht sieht ein Anderer mehr.
>Das heißt, dass der Master pro SPI-Zyklus nur ein einziges Byte sendet? >Und der gezeigte Programmteil ist in eine Schleife eingebettet? >>genau >>genau Und das komische ist, die erste Ziffer der Fakedaten kommt zuverlässig.
Der "Strohhalm"-Zweig überschreibt Ihnen jedesmal das zuvor gesetzte UDR - stilllegen.
PS: Er schreibt in die laufende Übertragung hinein das UDR, das Resultat ist also davon abhängig, wie lange der Master benötigt vom Setzen des Slave-Select bis zum eigentlichen Übertragungsstart.
Jasson J. schrieb: > Also wenn bei jeden empfangenem byte via USI ein anderer Wert in USIDR > geschrieben wird. So macht man es auch. Dazu muß man aber USICNT entsprechend vorladen und dann auf USIOIF warten. Anders kann man das Ende eines Bytes nicht erkennen.
> Ansonsten halte ich den Code für verständlich.
Schon richtig, aber er ist nicht vollständig. Und das nötige
Vervollständigen hält mich Assemblerprogrammierer davon ab, das Ganze
mal eben schnell auszuprobieren. Der Fragesteller sollte es potenziellen
Helfern möglichst einfach machen - dazu gehört auch eine kurze
Beschreibung der Rahmenbedingungen, wie z.B. dass nur immer ein einziges
Byte übertragen wird.
>So macht man es auch. Dazu muß man aber USICNT entsprechend vorladen ja, Versuche mit Vorladen von USICNT hab ich gemacht, aber keine gezielten. Hab im Datenblatt nicht die Stelle gefunden, die z.B. sagt "Laden von USIDR geht nur, wenn USICNT = 'n' ist." In den ASM Beispielen im DB machen die das auch nicht. > Ansonsten: auf was lädt man USICNT vor? Vielleicht funktioniert meine Strategie einfach nicht: Wie gesagt, benutze ich das USIOIF nicht. Habe im Datenblatt nicht gefunden, dass man das unbedingt muss. Ich übertrage während jeder Activ-Zeit von SlaveSelect nur ein Byte und der Empfänger (USI Slave) geht davon aus, das bei der Flanke auf SlaveSelect->IDLE ein Byte eingegangen ist, liest USIBR aus und schreibt in USIDR rein. Grundsätzlich habe ich mich schon gefragt, dass man irgendwo den USICNT manuell rücksetzten sollte, weil es ja auch sein kann, dass die Statemachines (die es letztlich in Form der Shiftregister sind) mal aus dem Sync kommen können. Deswegen hatte ich mal versucht bei genannter Flanke von SlaveSelect auf IDLE USICNT=0 zu setzten. Ohne Erfolg.
1 | Das Zählregister zählt: Null, eins, |
2 | zwei, drei, vier, fünf, sechs, sieb'n und: keins; |
3 | das macht, es zählt oktal. |
4 | |
5 | Es ist beschränkt wie mancher Mann |
6 | der nur bis sieben zählen kann |
7 | und merkt es nicht einmal. |
KLEN, in memoriam Nachfolgendes Programm schickt an den Master: 0x00, 'a', 'b', 'c' ..., wie ursprünglich verlangt ganz ohne USIOIF oder USICNT.
1 | #define F_CPU 8000000
|
2 | #include <avr/io.h> |
3 | uint8_t slaveSelStatusNew,slaveSelStatusOld,dummyChar,charCntr; |
4 | int main(void) |
5 | {
|
6 | slaveSelStatusOld=1;charCntr=0; |
7 | DDRA=0b00000010; |
8 | USIPP=(1<<USIPOS); // optional |
9 | USICR=(1<<USIWM0)|(1<<USICS1); |
10 | while (1) |
11 | {
|
12 | slaveSelStatusNew = (PINB & 0b01000000);// read slave select Pin |
13 | if(slaveSelStatusNew != slaveSelStatusOld)//SS edge detect |
14 | {
|
15 | if(slaveSelStatusOld == 0)//jetzt SS IDLE - vorher also activ |
16 | {
|
17 | dummyChar = USIBR; //read buffer |
18 | USIDR = 'a' + charCntr; //create fake data to return |
19 | charCntr++; |
20 | if(charCntr >= 5) charCntr = 0; |
21 | }
|
22 | else
|
23 | {
|
24 | // USIDR = 'x'; //'a' + charCntr;//Griff nach dem Strohhalm
|
25 | }
|
26 | }
|
27 | slaveSelStatusOld = slaveSelStatusNew; // part of edge detection |
28 | }
|
29 | }
|
S. Landolt schrieb: > Nachfolgendes Programm schickt an den Master: 0x00, 'a', 'b', 'c' ..., [...] Ja, klar den Fehler erkannt. Die Sache läuft ja immer über zwei Toggles. Bei der steigenden Flanke werden die richtigen Daten bereitgestellt (aber nicht genutzt, da steigende Flanke ja den inaktiven Zustand einleitet), um dann bei fallender Flanke, wenn die Daten endlich ihrer Verwendung zugeführt werden würden, überschrieben zu werden, bevor es wirklich losgeht...
Jasson J. schrieb: > Ich übertrage während jeder > Activ-Zeit von SlaveSelect nur ein Byte Wozu soll das gut sein? Du verlierst damit die Synchronisation, d.h. der Empfänger weiß nicht mehr, welches Byte welche Bedeutung hat, weil er den Frameanfang nicht erkennen kann. Jedes Byte ist für den Empfänger quasi ein neuer Frame.
@c-hater ok, vll. liegt da der Fehler - welche Stellen meinst du genau? >Bei der steigenden Flanke werden die richtigen Daten bereitgestellt >>Zeile 18 mit USIDR = 'a' + charCntr; meinst du da? >aber nicht genutzt >> in wie fern nicht genutzt? Bei Zyklus n liegen (so dachte ich´s mir) noch die bei Zyklus n-1 rein geschriebenen Daten drin und gehen eben während Zyklus n auf die Reise >überschrieben zu werden >> An welcher Stelle / bzw. zu welchem Moment werden die überschrieben?
Jasson J. schrieb: > ok, vll. liegt da der Fehler Ganz sicher sogar. > - welche Stellen meinst du genau? Das hat doch der Herr Landolt schon getan, indem er den schädlichen Code auskommentiert hat. Man kann natürlich sinnvollerweise auch den kompletten else-Zweig dahin verschieben, wo er hingehört...
> Zyklus n-1 ...Zyklus n Nein: UDR ist ein Schieberegister, das mit 'UDR= ' parallel geladen wird, und zwar zum Zeitpunkt des Befehls, ohne jede Synchronisation. Landolt schrieb: > ... schreibt in die laufende Übertragung hinein ... je nach Zeitverhältnissen zwischen Master und Slave.
Konkret: Master mit Systemtakt von 20 MHz, SPI-Takt 1.25 MHz, Slave (ATtiny461) 8 MHz; ich reaktiviere die besagte Zeile mit
1 | USIDR = 'J'; |
dann dürfte der Master (schließen wir mal nichts aus) nur 0x61..0x65 (a..e) sowie 0x4A (J) sehen - es kommt aber z.B. 0x69 0x52 0x72 ...
Na, wie ich sehe, gewinne ich keinen Blumentopf. Dann sei wenigstens, zur allgemeinen Unterhaltung, KLENs Vorlage nachgetragen, Morgensterns Perlhuhn:
1 | Das Perlhuhn |
2 | |
3 | Das Perlhuhn zählt: Eins, zwei, drei, vier... |
4 | Was zählt es wohl, das gute Tier, |
5 | dort unter den dunklen Erlen? |
6 | |
7 | Es zählt, von Wissensdrang gejückt, |
8 | (die es sowohl wie uns entzückt:) |
9 | die Anzahl seiner Perlen. |
Guten Abend, allerseits
Ick hoab et... Die Chip Select Flanken waren zu nah um die Datentransmission. Hab beim SPI Master ein Delay 'nach' EnableChipSelect und 'vor' DisableChipSelect gesetzt. Vielen Dank an alle, die mit geschrieben haben!
Jasson J. schrieb: > Ick hoab et... > > Die Chip Select Flanken waren zu nah um die Datentransmission. > Hab beim SPI Master ein Delay 'nach' EnableChipSelect und 'vor' > DisableChipSelect gesetzt. Du hast es nicht wirklich. Die Lösung ist, was S. Landolt geposted hat. Delays könnten höchsten ZUSÄTZLICH nötig sein/werden. Allerdings: genau WENN sie das werden, zeigt das nur zu deutlich die prinzipielle Untauglichkeit des Konzepts...
Wie währ´s ob du es einfach mich selbst beurteilen lässt, ob etwas für meine Anwendung in Ordnung ist? Ich glaube, du verstehst den Kontext nicht. Ich HABE das was Landolt gepostet hat und er hatte Dinge zu meinem Code hinzugefügt. Das Problem war aber nicht im SPI Slave, sondern im Master, der zwischen den Select Flanken nicht genug Zeit zum Byte-Transmission gelassen hat. Mit einem Check auf´s USIOIF hätte es erstmal sicher funktioniert. Nur was ist, wenn auf der Taktleitung mal was schief geht? Es muss einen Mechanismus geben, der einen Sync herstellen kann. Das heißt für diesen Fall wird man ein Select Signal brauchen das man (wenn man USIOIF benutzt) zum manuellen Rücksetzten des Counters nehmen kann. Und dann hätte ich mich mit dem Timing wie es war auf die Nase gelegt. Und zwar nicht immer wie jetzt, wo es sofort auffällt, sondern nur super selten - eben wenn auf der CLK Leitung mal was schief geht. Dieses "super selten" ist ein Debug-Alptraum.
Jasson J. schrieb: > Wie währ´s ob du es einfach mich selbst beurteilen lässt, ob etwas für > meine Anwendung in Ordnung ist? Wenn dir dadurch besser wird... > Ich HABE das was Landolt gepostet hat und er hatte Dinge zu meinem Code > hinzugefügt. Er hat vor allem aber das, was definitiv VOLLKOMMEN FALSCH war und deshalb niemals funktionieren konnte, ausgemerzt. Das mag dir peinlich sein (sollte es vielleicht sogar), ist aber die objektive Wahrheit. Ob es dir passt oder nicht, ist angesichts der Allgewalt der objektiven Realität völlig irrelevant.
> er hatte Dinge zu meinem Code hinzugefügt.
Glauben Sie ihm kein Wort, c-hater: ich habe lediglich den fehlenden
Rahmen zu seinem Programmschnipsel ergänzt, ich musste das Ganze ja
durch den Compiler bringen. Wenn seine (nicht gezeigte) Initialisierung
anders aussieht, so ist das sein Problem, nicht meines.
Und jetzt endgültig - Gute Nacht
Jasson J. schrieb: > Die Chip Select Flanken waren zu nah um die Datentransmission. > Hab beim SPI Master ein Delay 'nach' EnableChipSelect und 'vor' > DisableChipSelect gesetzt. Damit hast Du den Hauptmangel der AVR-Slaves entdeckt, sie haben keinen Sendepuffer. Daher muß der Master an den entsprechenden Stellen Gedenkpausen einlegen, bis der Slave reagiert hat. Soll der Slave aber nicht nur Däumchen drehen, sondern auch andere Tasks ausführen, dann müssen die Gedenkpausen noch größer werden. Einige neuere AVRs haben da nachgelegt und einen Sendpuffer spendiert bekommen. Zusätzlich haben sie eine konfigurierbare Interruptpriorität, d.h. der SPI-Interrupt kann sich vordrängeln, ohne andere Interrupts abwarten zu müssen.
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.