Hallo liebe Gemeinde,
nach dem mein Account wohl nach einigen Jahren gelöscht wurde nun ein
aktuelles Problem, bei dem ich eure Hilfe benötige.
Zwei ATMEGAs sind per SPI miteinander verbunden und der Master kann auch
schon einen Befehl absenden, den der Slave (8515) erkennt und
entsprechend ausführt.
Nun setze ich das SPDR-Register des Slave "vor" dem Senden des 2. Byte
der Übertragung mit einem Rückgabewert, damit dieses während der 2.
Übertragung zurück an den Master gesendet wird.
Mittels Logic-Analyzer habe ich leider feststellen müssen, dass wie
Werte scheinbar mit dem vom Master übertragenen Byte "verODERt" werden
und erst beim 3. Byte des Masters der Wert gesendet wird, den ich vor
dem 2. Byte schon gesetzt habe.
Und nun der Code:
Ich bin langsam echt ratlos. Und nein, es ist nicht mein erstes Projekt
und ja, ich habe das sch... Manual schon fünf mal nach Anhaltspunkten
durchsucht.
ATMEGA8515,
F_CPU ist 16MHz,
SPI-Clock ist Fosc/16
Bin über jede Idee dankbar.
Gruß
der Hobbybastler
Andreas K. schrieb:> Zwei ATMEGAs sind per SPI miteinander verbunden und der Master kann auch> schon einen Befehl absenden, den der Slave (8515) erkennt und> entsprechend ausführt.
Fein soweit.
> Nun setze ich das SPDR-Register des Slave "vor" dem Senden des 2. Byte> der Übertragung mit einem Rückgabewert, damit dieses während der 2.> Übertragung zurück an den Master gesendet wird.
Das kannst du mit einiger Wahrscheinlichkeit nicht tun. Der Slave kann
nämlich garnix aktiv senden. Er kann nur (hoffentlich rechtzeitig) eine
Antwort bereitstellen, BEVOR der Master das Antwortbyte abruft.
Wenn der Slave aber erst nach Eintrudeln des ersten Bytes vom Master
irgendwelche, wer weiß wie verfrickelten Sachen ausführt, dann hat er
mit einiger Wahrscheinlichkeit das Ergebnis noch nicht parat, wenn der
Master das nächste Byte abruft. Es sei denn, der Master kennt seine
Slaves und WEISS das er erstmal eine Pause machen muss, nachdem er das
Kommando abgesondert hat.
> Mittels Logic-Analyzer habe ich leider feststellen müssen, dass wie> Werte scheinbar mit dem vom Master übertragenen Byte "verODERt" werden
Da wird nix verodert. Der Slave war einfach noch nicht soweit. Der
Master empfängt in diesem Fall schlicht das Byte, was er zuletzt
gesendet hat.
Du hast offensichtlich nicht begriffen, wie SPI-Kommunikation
funktioniert. Das ist immer gleichzeitiger "Austausch" von Information.
Und da die Kausalität unseres Universums dazu zwingt, dass die Wirkung
nicht vor der Ursache passieren kann, wird das Zeitfenster sehr eng...
Sprich: dein Slave müsste innerhalb von weniger als 1.5 SPI-Bitzeiten
(wenn der Master ein ATMega ist, bei richtigen SPI-Mastern innerhalb von
weniger als 0.5 SPI-Bitzeiten) das Ergebnis bereitstellen. Du hörst dich
nicht so an, als wärest du in der Lage, Code zu produzieren, der das
könnte...
Also musst du entweder den Master nach dem Kommando eine Pause machen
lassen, oder ihm beibringen, dass nicht nur das erste, sondern auch das
zweite empfangene Byte Bullshit ist.
So einfach ist das. Wenn man weiß, was man da eigentlich tut...
So viel Text - ich staune immer wieder über die Mühe, die Sie sich
manchmal machen, c-hater.
Aber ich wollte Ihnen noch erklären, weshalb ich die vielen Klammern
schreibe, ist mir erst später eingefallen, wie das vor zwei Jahrzehnten
so kam: wie erwähnt schreibe ich im Zehn-Finger-System, und da stört
dieses '|' den Fluss ganz enorm; stattdessen verwende ich '+' und nehme
die dann nötigen Klammern in Kauf, die kommen quasi
fließend-automatisch.
Andreas K. schrieb:> Nun setze ich das SPDR-Register des Slave "vor" dem Senden des 2. Byte> der Übertragung mit einem Rückgabewert, damit dieses während der 2.> Übertragung zurück an den Master gesendet wird.
Was heisst "vor" dem Senden?
Woher soll der Slave wissen, wann dieser Byte gesendet wird?
ATMEL sagt folgendes:
D.h. du hast Zeit erstes empfangenes Byte zu lesen bis zweites Byte
(fast) komplett empfangen wird, aber gesendet wird das, was sich beim
Start des zweiten Bytes im Slave-SPDR befindet.
Insofern hat c-hater Recht - da ist wahrscheinlich nicht genug Zeit
zwischen Bytes.
1
Schritt 1:
2
SLAVE stellt Antwort Nr.1 bereit.
3
MASTER sendet Byte Nr.1 und empfängt bereitgestellte Antwort.
4
5
Schritt x:
6
MASTER schreibt empfangenes Byte irgendwo, holt sich Byte Nr.x
7
und schreibt dieses in SPDR.
8
SLAVE schreibt empfangenes Byte irgendwo, holt sich Antwort Nr.x
9
und schreibt diese in SPDR.
Falls der SLAVE Schritt x genauso schnell oder etwas schneller als
der MASTER abarbeiten kann, gibt es keine Probleme.
Falls nicht, passiert das, was bei dir passiert ist...
S. Landolt schrieb:> So viel Text - ich staune immer wieder über die Mühe, die Sie sich> manchmal machen, c-hater.
Kommt auf den Frager an. Der hier war offensichtlich wirklich
interessiert daran, zu verstehen, warum das so passiert, wie es passiert
und er hatte auch bereits selber etwas unternommen, um dahinter zu
kommen, warum es nicht so läuft, wie erwartet. Das ist offensichtlich
Fleiß und Wißbegier. Sowas muss man belohnen. Da kann man schonmal etwas
weiter ausholen und selbst triviale Sachen auch mal etwas erklären. Na
ja, ich bin sicher kein guter Pädagoge, ich hoffe aber, dass es dem TO
trotzdem irgendwie geholfen hat.
> Aber ich wollte Ihnen noch erklären, weshalb ich die vielen Klammern> schreibe, ist mir erst später eingefallen, wie das vor zwei Jahrzehnten> so kam: wie erwähnt schreibe ich im Zehn-Finger-System, und da stört> dieses '|' den Fluss ganz enorm; stattdessen verwende ich '+' und nehme> die dann nötigen Klammern in Kauf, die kommen quasi> fließend-automatisch.
Potentiell gefährliches Konzept, jedenfall meiner Meinung nach. "|"
macht nicht dasselbe wie '+'. Bei '+' besteht potentiell das Risiko,
einen Übertrag in's nächsthöherwertige Bit zu befördern. Das sollte
natürlich bei der Verknüpfung von einzelnen zu setzenden Bits nicht
passieren. Aber was, wenn man z.B. durch C&P versehentlich ein Bit
doppelt setzt...
BTW: Ich schreibe auch mit zehn Fingern. Aber nach einem völlig anderen
System, als man es früher(tm) in Schreibmaschinenkursen vermittelt
bekommen hat. Das System ist durch reine Benutzung der Tastatur zu
Programmieraufgaben aus einem anfänglichen Zweifinger-"Adler-Suchsystem"
durch unbewußte (oder unterbewußte?) Optimierung quasi von selbst
entstanden. Ich könnte nicht systematisch aufdröseln, wie es eigentlich
funktioniert, ich weiß also diesbezüglich nicht wirklich, was ich da
eigentliche tue. Egal, es funktioniert immerhin ganz gut...
Jedenfalls, solange ich an einer PC-Tastatur mit deutschem
Standard-Layout sitze...
> ... potentiell das Risiko, einen Übertrag ...
Ich kann mich an einen solchen Fall nicht erinnern, und selbst wenn: mit
zunehmendem Alter traue ich mir selbst immer weniger, soll heißen, ich
teste recht ausgiebig.
S. Landolt schrieb:> Ich kann mich an einen solchen Fall nicht erinnern
Ist aber absolut realistisch. Siehst du sofort den Fehler in:
ldi Rn,(1<<CS10)+(1<<CS10)
Ja klar, jetzt schon, weil du ja sozusagen psychologisch vorbereitet
bist, den Fehler zu sehen.
Aber finde den mal unvorbereitet...
Und: es gibt Sachen, die sich viel schwerer testen lassen, als die
Tatsache, ob ein blöder Timer richtig tickt...
Das ist eine deutlich reduzierte Test-Version des eigentlichen Programm
gewesen.
Da die Antwort nicht funktioniert hat erst mal alles raus, was für die
SPI nicht notwendig ist.
MISO ist natürlich als Ausgang gesetzt.
Zur Zeitkontrolle habe ich in der Funktion noch einen Ausgang des 8515
kurz getriggert, nach dem SPDR mit der Antwort auf das zuvor empfangene
Byte gesetzt wurde. Zwischen SPDR = dataout und erstem Clock des
nächsten vom Master übertragenen Byte sind ca. 50us. Sollte also genug
"Pufferzeit" sein.
Dass der Master die erste "richtige" Antwort erst während dem 2. Byte
bekommt ist klar. Daher wird ja auch vor dem ersten Empfang das SPDR des
Slave mit 0x00 gesetzt. Beim Master kommt aber 0x05 an.
Wenn z.B. ein 0x0C empfangen wird, wird das SPDR zur Bestätigung 0x0C
gesetzt. 50us später kommt das 2.Byte vom Master (0x00). Bei diesem Byte
sendet der Slave aber ein 0x0F. Dann wird SPDR mit 0x00 gefüttert.
Wieder 50us Später kommt das 3.Byte (0x00) vom Master, während der Slave
0x0C sendet.
Eine Beispielübertragung hatte ich ja oben geposted.
Das SPI-Protokoll ist bekannt und später wird das auch in einer
Interrupt-Routine empfangen und sofort das nächste Antwort-Byte in SPDR
geschrieben, das an entsprechender Stelle in einem Array liegt.
Wie geschrieben, das obige Programm ist eine Hau-Ruck zusammenkürzung um
alle möglichen Fehlerquellen zu eliminieren. Daher auch die für manche
eventuell umständliche Schreibweise. Ist halt einfacher zu überfliegen
wie &=~1<<PB4.
Hoffe eine*r hat noch eine Idee.
Gruß
der Hobbybastler
Andreas K. schrieb:> Da die Antwort nicht funktioniert hat erst mal alles raus, was für die> SPI nicht notwendig ist.Andreas K. schrieb:> Hoffe eine*r hat noch eine Idee.
Ja, ich.
Vollständigen Code für Master und Slave als Datei anhängen.
Glaubst du das ein einziges Codeschnipsel für Master und Slave, dazu
noch ohne init und mit fehlenden Deklarationen, mit Erklärungen und
Behauptungen wie:
Das funktioniert, das ist OK, der Fehler kann hier nicht sein, der
Slave hat genug Zeit u.s.w. bei der Fehlersuche helfen?
Marc V. kann ich nur zustimmen, aber im Gegensatz zu ihm verabschiede
ich mich, mir fallen die Schultern runter und ich pfeife durch die Nase.
Zuerst war ich noch versucht, Watzlawicks Betrunkenen anzuführen, aber
nein, wäre nur weitere vertane Zeit.
Allein schon dies:
> ... erst mal alles raus, was für die SPI nicht notwendig ist.
Und dann:
> MISO ist natürlich als Ausgang gesetzt.
Marc V. schrieb:> ATMEL sagt folgendes:The system is single buffered in the transmit> direction and double buffered in the receive direction
Da steht aber noch mehr:
"The system is single buffered in the transmit direction and double
buffered in the receivedirection. This means that bytes to be
transmitted cannot be written to the SPI DataRegister before the entire
shift cycle is completed. When receiving data, however, areceived
character must be read from the SPI Data Register before the next
characterhas been completely shifted in. Otherwise, the first byte is
lost."
Anders gesagt, der Autor widerspricht sich selbst, da ist kein
Sendepuffer und auch nur ein Byte Empfangspuffer.
Der Slave hat ein WCOL-Bit, was ihm zeigt, daß das Schreiben in die Hose
gegangen ist. Nur kann sich der Master nichts dafür kaufen.
Keine Ahnung, was die damals bei Atmel geraucht haben müssen, um so ein
vergurktes SPI zu entwickeln.
Nur wenige neuere AVRs haben einen Puffermodus, den man aber erst
einschalten muß, z.B. Attiny817:
"
• Unbuffered mode:
The default mode is unbuffered in the transmit direction and single
buffered in the receive direction.
This means that bytes to be transmitted cannot be written to the
SPI.DATA register before the entire
shift cycle is completed. When receiving data, a received character must
be read from the
SPI.DATA register before the next character has been completely shifted
in. Otherwise, the first
byte will be lost.
• Buffered mode with dummy transfer:
The SPI peripheral is single buffered in the transmit direction and
double buffered in the receive
direction. A byte written to the transmit register will be copied to the
shift register when a full
character has been received. When receiving data, a received character
must be read from the
SPI.DATA register before the third character has been completely shifted
in to avoid losing data.
• Buffered mode without dummy transfer:
The SPI peripheral is single buffered in the transmit direction and
double buffered in the receive
direction. A byte written to the transmit register will be copied to the
shift register when the SPI is
enabled and SS is high."