Forum: Mikrocontroller und Digitale Elektronik SPI Geschwindigkeit XMega


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Christoph M. (chrito)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

hab zwei XMega 8e5, die über SPI kommunizieren.

Jetzt versuche ich die Geschwindigkeit bis zum Maximum hochzudrehen. 
Dazu habe ich den Modus mit Pufferung aktiviert (SPI_PORT.CTRLB = 
0b11000000).
Optimierung ist auf -O1. SPI-IRs haben höchste Priorität.

Die Datenübertragung ist sauber, die Werte kommen an. Auf dem Oszi sehe 
ich jetzt, dass zwischen den Bytes immer eine riesige Lücke ist. Also 
1µSek erstes Byte, dann 1,5µSek Loch, dann 1µSek zweites Byte, dann 
1,5µSek Loch und so weiter. Ich komme damit auf 400 kB pro Sekunde 
Maximum. Ist hier Ende Gelände? Im Datenblatt find ich nichts zur 
maximalen Geschwindigkeit.

Danke!
Christoph



Für alle, die es intressiert, hier der Code des Masters, der des Slave 
ist ähnlich:
1
ISR(SPIC_INT_vect)        // SPI-Interrupt
2
{  if (SPI_PORT.STATUS & 0b10000000)  // empfangenes Byte bereit zum Auslesen?
3
  {  SPI_Empfangspuffer[Index_Empfangen] = SPI_PORT.DATA;     // empfangenes Byte abholen    
4
    Index_Empfangen++;
5
    if (Index_Empfangen==3)
6
    {  
7
      asm("NOP");  // Assembler-Nop
8
    }
9
  }
10
  if (SPI_PORT.STATUS & 0b00100000)  // Sende-Puffer bereit?
11
  {  if (Index_Senden<3)
12
    {  SPI_PORT.DATA = SPI_Sendepuffer[Index_Senden];
13
      Index_Senden++;
14
    }
15
    else
16
    {  PORTC.OUTSET =0b00010000;    // Chip Select ausschalten
17
      SPI_PORT.INTCTRL &= ~0b00100000;   // deaktiviere Interrupts bei bereitem Sendepuffer
18
    }
19
  }
20
}
21
    
22
23
void initialisiere_SPI_Master(void)  // SPI an PORTC einstellen
24
{  cli();                // Interrupts deaktivieren
25
  SPI_PORT.CTRL =    0b01010000;    // SPI master, clock idle low, data setup on trailing edge, data sampled on leading edge, Geschw 32MHZ/4
26
  SPI_PORT.CTRLB   = 0b11000000;    // gepuffert Modus 1, sofort laden
27
  SPI_PORT.INTCTRL = 0b10000010;    // 00: aus, 01: niedrige, 10: mittelere, 11: hohe Priorität => mittlere, denn Master darf zwischendurch anhalten, Slave muss reagieren
28
  Pufferindex=0;
29
  sei();                // Interrupts aktivieren
30
}

von Bastian W. (jackfrost)


Bewertung
0 lesenswert
nicht lesenswert
Nur mit der ISR und dem Init wir dir hier kaum einer helfen können.

1,5 us sind bei 32 MHz 48 Takte. Schau einfach im dissambly was der 
xMega von Start vom senden bis zum nächsten Byte macht.

Gruß JackFrost

von Frickelfritze (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Wenn du jedes Byte per Interrupt holst wird das so langsam sein.
Die ISR verschlingt ja einiges an Zeit/Overhead.

Meine XMega128A1 konnten / können auch SPI mit Double Speed,
d.h. bei 32 MHz Taktfrequenz läuft das SPI mit maximal 16MHz
und nicht mit Clock/4.

von Dieter F. (Gast)


Bewertung
0 lesenswert
nicht lesenswert

von Frickelfritze (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christoph M. schrieb:
> Auf dem Oszi sehe ich jetzt ....  (Scheisse)

Sollen wir mal sammeln gehen für Tastköpfe?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Frickelfritze schrieb:
> Wenn du jedes Byte per Interrupt holst wird das so langsam sein.

Sehe ich genauso.  Interrupt bei SPI hat höchstens dann Sinn, wenn
man mit sehr niedriger SPI-Taktrate arbeitet.  Wenn man versucht, da
maximal Geschwindigkeit rauszuholen, geht das nur mit Polling.  Sind
ja eh nur ein paar CPU-Takte, die man damit verwartet.

Alternativ sollte Burst-SPI beim Xmega ja auch per DMA machbar sein,
sofern das mit dem Client auch passt.

von c-hater (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Jörg W. schrieb:

> Sehe ich genauso.  Interrupt bei SPI hat höchstens dann Sinn, wenn
> man mit sehr niedriger SPI-Taktrate arbeitet.  Wenn man versucht, da
> maximal Geschwindigkeit rauszuholen, geht das nur mit Polling.  Sind
> ja eh nur ein paar CPU-Takte, die man damit verwartet.

Das ist Unsinn. Wenn man SPI wirklich so ausnutzt, sind Interrupts 
tatsächlich nicht zielführend, dann braucht man aber auch kein Polling, 
sondern nur optimale (taktzyklengenaue) Ansteuerung, erst dann ergibt so 
ein Burst-Betrieb irgendeinen Sinn.

Ja, das geht nicht mit C, but who cares... In C geht es immerhin, wenn 
man DMA dafür benutzen kann. Aber am Ende jeder DMA-Sequenz steht dann 
doch wieder eine ISR...

Und wie wenig effizient in C implementierte ISRs sind, brauche ich ja 
wohl kaum noch zu erwähnen. Höchstens auf ausdrücklichen Wunsch...

von Dieter F. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
c-hater schrieb:
> Aber am Ende jeder DMA-Sequenz steht dann
> doch wieder eine ISR...

Kann es sein, dass man ab und an auch Daten "verarbeiten" will? Nur mal 
so gefragt ...

von c-hater (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Dieter F. schrieb:

> Kann es sein, dass man ab und an auch Daten "verarbeiten" will? Nur mal
> so gefragt ...

Natürlich, das ist sogar der absolute Normalfall.

Das geht am am Einfachsten, wenn man möglichst linear Code vor sich 
hinrödeln lassen kann. Das ist, wofür z.B. C-Compiler optimieren. Das 
können sie (inzwischen) sogar sehr gut.

Nur ist die böse Realität halt nie so gnädig, die Eingabe genau in dem 
Moment bereit zu stellen, wo der Code sie braucht und nur sehr selten 
ist sie so gnädig, das Ergebnis der Berechnungen instantan im vollen 
Umfang genau in dem Moment weiterleiten zu können, wenn sie vorliegen.

Kurz: die bösen IO-Erfordernisse sind oft der Knackpunkt, nicht die 
eigentliche Rechenaufgabe...

von Christoph M. (chrito)


Bewertung
0 lesenswert
nicht lesenswert
Frickelfritze schrieb:
> Wenn du jedes Byte per Interrupt holst wird das so langsam sein.
> Die ISR verschlingt ja einiges an Zeit/Overhead.

Ok, ihr meint also die ISR ist zu lahm... da ich mit den 
SPI-Hardware-Puffern arbeite, und die ISR während der Übertragung 
bereits nachlädt, hätte ich jetzt nicht darauf getippt.

Werde mal ausprobieren, die Daten in einer stupiden while-Schleife in 
die Hardware zu ballern, nur mal um zu gucken, ob es dann schneller 
wird.

VG

von Dieter F. (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Du kannst Dir ja auch mal die Verwendung des USART im SPI-Mode 
anschauen.

von Christoph M. (chrito)


Bewertung
0 lesenswert
nicht lesenswert
Danke für eure Tipps! Es ist tatsächlich die ISR, die alles ausbremst.

Mit dem Code unten bin ich bei ca. 1MB/Sekunde.
1
PORTC.OUTCLR = 0b00010000;  // Chip Select aktivieren
2
  
3
while (Index_Senden<3)
4
{  if (SPI_PORT.STATUS & 0b00100000)  // Sende-Puffer bereit?
5
  {   SPI_PORT.DATA = SPI_Sendepuffer[Index_Senden];
6
      Index_Senden++;
7
  }
8
}
9
    
10
PORTC.OUTSET =0b00010000;    // Chip Select ausschalten

Mit Overhead werden es wahrscheinlich um die 500 kBps. Muss wohl mal 
EDMA ausprobieren... Das sieht zwar kompliziert aus, aber wohl die 
einzige Lösung mit wenig CPU-Last und viel Geschwindigkeit!?

Danke noch mal! :)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Christoph M. schrieb:
> Es ist tatsächlich die ISR, die alles ausbremst.

Interruptannahme, Registersicherung etc. verplempert einfach viel
Zeit.

> Muss wohl mal EDMA ausprobieren... Das sieht zwar kompliziert aus, aber
> wohl die einzige Lösung mit wenig CPU-Last und viel Geschwindigkeit!?

Wenn man längere Sequenzen am Stück senden möchte, ist das die
sinnvollste Variante.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.