Forum: Mikrocontroller und Digitale Elektronik ATXMEGA und SLAVE SPI mit DMA


von Paul (Gast)


Lesenswert?

Hallo!

Ich möchte gerne mit einem ATXMEGA 64A3U Daten im Slave Modus mit einem 
externen Controller austauschen.
Es kommen alle 125 µs insgesamt 16 Bytes mit 2MHz Takt an.
Da ich nicht nach jedem Byte ein Interrupt verarbeiten kann, verwende 
ich DMA um die Daten vom SPI Register in ein Array zu kopieren. Das 
funktioniert auch ganz gut.
Jetzt möchte ich allerdings mit einem zweiten DMA Kanal in der gleichen 
Weise eine Antwort senden , welche ebenfalls in einem Array abgelegt 
ist. (klar, es ist die Antwort auf das vorangegangene Datenpaket, da 
full duplex) Das funktioniert allerdings nicht. Es kommt nur Blödsinn an 
bzw. das erste Byte sieht noch gut aus, danach sieht es so aus, als ob 
alle zwei Bytes ein um ein Byte verzögertes Echo der Empfangsdaten 
gesendet wird (also als ob der DMA nicht in das Register geschrieben 
hätte.)
Habt Ihr ein funktionierendes Beispiel?
Ich poste gerne, falls erforderlich, meinen Code zwecks Diskussion.

Ich habe die Kanäle 0 und 1 konfiguriert, 0 ist für den Empfang 
zuständig, 1 für das Aussenden. Beide haben als Modus Single shot, 1 
Byte Burst und 16 Byte Telegrammlänge. Beide bekommen als Trigger den 
Empfangsinterrupt von der SPI Schnittstelle.
Mache ich einen Denkfehler?

Viele Grüße,
Paul

von Jim M. (turboj)


Lesenswert?

Paul schrieb:
> Es kommen alle 125 µs insgesamt 16 Bytes mit 2MHz Takt an.

Welchen Takt hat der XMEGA? Der muss für den SPI Slave verdammt hoch 
sein, selbst für DMA.

von Anno (Gast)


Lesenswert?

Hatte auch schon das Problem mit mehreren DMA-Kanälen.
Die müssen den Datenbus benutzen und haben geringere Priorität als die 
CPU.
Also würde ich mal den Systemtakt auf 32MHz hoch, und in der 
main-Schleife etliche NOPs einstreuen, zwecks Datenbus frei machen...
PS:
Es sind doch 64µs bei 2MHz SPI-CLK? Nur so am Rande.

von Paul (Gast)


Lesenswert?

Jim M. schrieb :
> Welchen Takt hat der XMEGA? Der muss für den SPI Slave verdammt hoch
> sein, selbst für DMA.

Der XMEGA läuft mit 32 MHz.
Ich werde mal den Takt vom Master verlangsamen, mal sehen, ob sich etwas 
ändert.
Wenn beide DMA Kanäle den gleichen Trigger bekommen (0x4A für SPI C) und 
die Reihenfolge auf CH0-CH1-CH2-CH3 fest eingestellt ist (Priority 
Mode=3),sollte doch nach Wegkopieren des Empfangsbytes mit CH0 das 
Hinkopieren des Sendebytes via CH1 theoretisch funktionieren, oder?
Danke und Grüße!

von Anno (Gast)


Lesenswert?

>> als ob alle zwei Bytes ein um ein Byte verzögertes Echo der Empfangsdaten
gesendet wird (also als ob der DMA nicht in das Register geschrieben
hätte.)

Das verstehe ich nicht richtig. Kannst du das genauer erklären?

Du hast einen Puffer für Datenempfang und zum Senden?
Wie synchronisierst du die beiden?
Zum Senden nimmst du keine Slave-SPI?
Tipp: Die USART-MASTER-SPI ist besser, da Sendepuffer.

von Paul (Gast)


Lesenswert?

Hallo!

So, der Test mit 1MHz SPI Clock hat funktioniert.
Mir ist nur noch nicht klar, was da so lange braucht, dass es mit 2MHz 
nicht mehr geht. Der Prozessor ist mit 32MHz getaktet, die Datenbits 
kommen mit 2MHz rein, d.h. die Bytes stehen mit 250kHz an.
Alle 4 µs kommt also das Signal der SPI Schnittstelle, dass ein neues 
Byte da ist. Es sind demnach 4µs, die der DMA Controller hat die Daten 
von der SPI zu lesen (1 Byte), zwischenzuspeichern, die Adresse (3 Byte) 
aus seinen Registern zu lesen (und evtl schon zu inkrementieren)und auf 
den Adressbus zu legen, das Datenbyte aus dem Puffer zu speichern und 
dann den zweiten Kanal zu bearbeiten, welcher das Ganze in die andere 
Richtung macht.
4µs sind bei 32MHz 128 Takte, also ungefähr 64 Takte pro Richtung und 
Byte.

Ist das realistisch?
Es vergehen sicherlich auch noch Takte eh der Prozessor den Bus 
überhaupt freigibt, das kommt natürlich noch dazu.
Ich hätte ja gehofft, dass der Performancegewinn durch DMA im Vergleich 
zum Interrupt nach jedem Byte höher ist...
Interessanterweise ist jedes 2. gesendete Byte ok, das liegt wohl an der 
Taktung vom Master, welche nach jedem 16. Bit eine zusätzliche Pause von 
ca. 250ns einlegt (16 Bit Schieberegister, reload)
Mal sehen, ob eine künstliche Pause nach 8 Bit etwas hilft...

von Paul (Gast)


Lesenswert?

Ich glaub, ich muss mein Lesen/Schreiben in diesem Thread auch besser 
synchronisieren... :-)



Anno schrieb:
>>> als ob alle zwei Bytes ein um ein Byte verzögertes Echo der Empfangsdaten
> gesendet wird (also als ob der DMA nicht in das Register geschrieben
> hätte.)
>
> Das verstehe ich nicht richtig. Kannst du das genauer erklären?

Ich sende vom externen SPI Master (FPGA) alle 125µs (ist ein spezieller 
Systemtakt) ein Datenpaket mit 16 Bytes (momentan nur Dummy Daten) :

0x00, 0x01, 0x02, 0x03, 0x04, 0x05...0x0F. Der Slave liefert mir zurück:
0x0F, 0x00, 0x0D, 0x02, 0x0B, 0x04, 0x09, 0x06...0x00

Beides ist gleichzeitig mit einem SPI Analysator auf dem Bus 
aufgezeichnet.
Der ATXMEGA (Slave) hat zwei CHAR Arrays, eines mit den empfangenen 
Daten und eins mit den zu sendenden Daten. Die zu sendenden Daten habe 
ich mit einer absteigenden Folge von 0x0f..0x00 belegt, zum besseren 
Unterscheiden am Scope.
Wenn ich den Takt reduziere, sind die Daten vom Xmega auf dem Bus ok. 
Die Empfangsdaten (gebe ich per serieller Schnittstelle in einer Loop 
aus) sind immer ok.
NOPs sind mal ne gute Idee, werde ich probieren.

von Paul (Gast)


Lesenswert?

Anno schrieb:
> Du hast einen Puffer für Datenempfang und zum Senden?
> Wie synchronisierst du die beiden?
> Zum Senden nimmst du keine Slave-SPI?
> Tipp: Die USART-MASTER-SPI ist besser, da Sendepuffer.


Achso: Momentan ist mein FPGA der Master, ich könnte das eventuell noch 
drehen, würde mir das was bringen?
Senden und Empfangen wird beides gleichzeitig über SPI C gemacht. 
Synchronisieren mache ich mit der Chipselect Leitung (Interrupt-> DMA 
freigeben)

von Anno (Gast)


Lesenswert?

Sorry, aber du drückst dich immer zu unpräzise aus.
Irgendwie passen dein Aussagen nicht richtig zusammen.

- "...Der Slave liefert mir zurück...": Die Empfangs-SPI? Wohin 
"zurück"? Ist das der Empfangs-Speicherblock, der von der DMA 
beschrieben wird?

- "Beides ist gleichzeitig mit einem SPI Analysator auf dem Bus
aufgezeichnet."
Was genau ist da aufgezeichnet? Was die Slave-SPI intern empfängt,
ist ja nicht "auf dem Bus" zu sehen, sondern nur was der FPGA sendet!

Ist etwa die Empfangs- und Sende-SPI die selbe???
Was ist das zweite, vom Analysator aufgezeichnete Signal? Die Sende-SPI?

Wo liegt eigentlich dein Problem? Nach dem Empfangen (Speicherblock), 
oder beim Senden ("auf dem Bus")?
Wo werden die Daten falsch?
Wieso können Daten-Bytes vom Empfangspuffer auf der Sende-SPI ausgegeben 
werden???? Der Sendepuffer ist doch mit 0x0f..0x00 belegt???

Außerdem wäre gut, wenn du vor dem Test den Empfangspuffer löschst
und nurmal ein Datenpaket schickst und im Debugger anschaust,
was im Empfangs-Puffer liegt


PS:
Also ich habe mit dem XMega schon 4MBit(!) auf einer Slave-SPI mit DMA 
'rein, CRC-Berechnung und 280KByte/s auf einer USART-Master-SPI wieder
'raus (auch mit DMA) hinbekommen.

von Anno (Gast)


Lesenswert?

>> "Senden und Empfangen wird beides gleichzeitig über SPI C gemacht."
Oh je, wie soll das mit 2 DMAs gehen? Die SPI hat doch nur einen 
Interrupt!
Kann man mit einem Interrupt 2 DMAs gleichzeitig triggern?

Der erste Interupt kommt doch erst, nachdem das erste Byte empfangen 
wurde. Das erste Datenbyte müsstest du aber schon vor dem Empfang des 
des ersten Bytes in das Data-Reg. der SPI schreiben.
Da gibt es also einen Versatz von einem Byte...
Probiere es mit einer separaten USART-Master-SPI zum Senden!
Mit der ist es problemlos möglich die DMA zu triggern.

- "Synchronisieren mache ich mit der Chipselect Leitung (Interrupt-> DMA
freigeben)"
Hä, was für eine Chipselect Leitung? Die !SS-Leitung von der Slave-SPI?
Das synchronisiert nur die SPI.

von Paul (Gast)


Lesenswert?

Sorry, wenn meine Angaben etwas wirr klingen.

Vielleicht zum Hintergrund: Die Schaltung mit dem ATXmega dient als 
Analog Frontend (4*Analog Eingang, 4* Analog Ausgang), welches 
galvanisch getrennt über schnelle Koppler an einem FPGA hängt. SPI C vom 
ATxmega ist mit Clock, MOSI, MISO und SS (nicht CS :-) ) zum FPGA hin 
verbunden.
Es geht darum, mit festem Zeittakt die Analogeingänge am ATXMEGA 
einzulesen und Richtung FPGA zu senden und gleichzeitig Daten vom FPGA 
auf den Analogausgängen des ATXMEGA auszugeben. Die Daten haben also 
erstmal nix miteinander zu tun und sind von der zeitlichen Abfolge auch 
einen Zeittakt versetzt, das ist ok.
Dass der SPI Interrupt zwei DMA Kanäle triggert ist so gewollt, die SPI 
Schnittstelle ist ja schließlich dazu da, Daten zu empfangen und 
gleichzeitig zu senden.
Das ganze habe ich bisher mit 8 Bytes im Interruptbetrieb gemacht, hat 
gut funktioniert. Leider reichen 8 Bytes aber nicht mehr aus. Da der 
Zeittakt aber vorgegeben ist (125µs), machen mir bei mehr als 8 Bytes 
die Interruptzeiten Probleme.
Ich habe keinen durchgehenden Datenstrom, daher kann ich "relativ 
gemütlich" wenn das Slave Select Signal vom FPGA kommt das erste zu 
sendende Byte in das SPI Datenregister legen, das funktioniert auch. 
(ich sehe am Oszilloskop, dass die Daten korrekt auf der MISO Leitung 
ankommen)
Nur die nächsten Bytes sind kaputt, liegt wohl am timing wann genau der 
DMA auf das Datenregister schreibt.
Ich habe leider keine Möglichkeit eine zweite SPI Schnittstelle zum FPGA 
zu verdrahten, die Schaltung ist schon fertig.
Achso: das SS Signal triggert bei mir einen Interrupt der auch die DMA 
Logik resettet (und danach neu konfiguriert) das meinte ich mit 
Synchronisieren.

Viele Grüße und Danke!

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
Noch kein Account? Hier anmelden.