mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik SPI Codetuning


Autor: usul27 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mich heute etwas mit der Datenübertragung über SPI
herumgeschlagen. Dabei war es recht interessant zu beobachten, was
kleine Änderungem am C-Code für Auswirkungen haben können.

Da das ganze recht lang ist und auch ein paar Bilder dabei sind, werde
ich das nicht hier reinkopieren, sondern verweise mal auf:
 http://www.matuschek.net/atmega-spi.0.html

Wenn jemand noch zusätzliches Optimierungspotenzial sieht, würde mich
das unbedingt interessieren!

Autor: usul27 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe gerade festgestellt, dass der Code in Beispiel 2 und 3 doch
noch einen Fehler hat. Am Ende fehlt nach der Schleife noch eine
Abfrage des SPIF-Bits. An den Timings ändert das aber nichts.

Autor: Michael U. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

mal so als Denkaufgabe:

SPI mit dem Maximum, also CLK/2. Senden von 1 Byte = 8Bit
Macht also 16 Takte für ein Byte. Länger darf also die SPI-Schleife
nicht werden, wenn er ohne Pause senden soll.
Reicht zum Datenbyte holen, auf SPI frei warten, raus zum SPI, Zähler
-1 und zurück, wenn nicht Ende.
Eigentlich muß man da garnicht auf das "fertig" warten, sondern
könnte die Takte mit NOP ausgleichen. Macht durchaus Sinn, wenn man
einen Datenburst z.B. zum ENC schickt, sowieso nichts sinnvolles in
dieser Zeit machen kann und notfalls ein paar Zeilen inline.ASM
einbindet.

Gruß aus Berlin
Michael

Autor: Aufreger deluxe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@usu127

Welchen Logikanalysator benutzt du?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist mir auch ein Rätsel, warum die AVRs kein gepuffertes SPI haben, wie
z.B. der AT89LP4052 oder C8051F330.

Da kann man dann das nächste Byte schon schreiben, während das alte
noch rausgeschoben wird.


Peter

Autor: Andreas W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: usul27 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Michael U:

Die Variante mit den NOPs habe ich auch erwähnt. Da im ATMega-Datenblatt 
aber keine Informationen enthalten sind, die sagen, dass ein 
Datentransfer immer eine bestimmte Anzahl Taktzyklen nach Beschreiben 
des Datenregisters braucht, ist mir das etwas riskant. Wenn aus 
irgendeinem Grund nur einen Takt später gestartet wird, geht das zu 
sendende Byte verloren.

Autor: Michael U. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@usul27:

ich will es mal so ausdrücken: ein AVR würfelt nicht. ;)

SPI und Takt sind fest verknüpft. Entweder er startet mit dem Takt nach 
dem Schreiben oder evtl. einen Takt später aufgrund des internen 
Aufbaus.
Ich bin mir aber sicher, daß er das immer gleich macht, könnte man also 
testen.

Gruß aus Berlin
Michael

Autor: usul27 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da ich den Innenaufbau eines AVRs nicht kenne und nicht 100%ig sicher 
bin, dass es garantiert keine Abhängigkeiten zu anderer Peripherie gibt, 
ist mir die Vorstellung, dass es höchstwahrscheinlich immer gleich 
läuft, einfach zu wenig. Ich habe einfach schon zu viele Programme 
erlebt, die von falschen Annahmen ausgingen und dann Mist produzierten, 
daher verlasse ich mich da wirklich voll und ganz auf das, was im 
Datenblatt steht.

Autor: Dirk Broßwick (sharandac)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

interessant das jemand die gleichen Probleme findet. Ich hatte das schon 
mal vor ca 1 Monat gehabt in Verbindung mit einen ENC28j60 und habe mir 
Routinen geschrieben die dieses Problem bewältigen.
Hier ein auszug aus meinen Sourcen, habe dann die gleiche lösung 
gefunden.
/* -----------------------------------------------------------------------------------------------------------*/
/*! Eine schnelle MEM->SPI Blocksende Routine mit optimierungen auf Speed.
 * \param  buffer    Zeiger auf den Puffer der gesendet werden soll.
 * \param  Datalenght  Anzahl der Bytes die gesedet werden soll.
 */
/* -----------------------------------------------------------------------------------------------------------*/
void SPI_FastMem2Write( unsigned char * buffer, unsigned int Datalenght )
{
  unsigned int Counter = 0;
  unsigned char data;
  
  // erten Wert senden
  SPDR = buffer[ Counter++ ];
  while( Counter < Datalenght )
  {
    // Wert schon mal in Register holen, schneller da der Wert jetzt in einem Register steht und nicht mehr aus dem RAM geholt werden muss
    // nachdem das senden des vorherigen Wertes fertig ist,
    data = buffer[ Counter ];
    // warten auf fertig
    while(!(SPSR & (1<<SPIF)));
    // Wert aus Register senden
    SPDR = data;
    Counter++;
  }
  while(!(SPSR & (1<<SPIF)));
  return;
}

Autor: ulm8bit (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@usul27

Ein echt interessanter Logikanalyser. Und auch der günstige Preis mit
34 Kanälen.
Ich habe fragen zu dem Teil, weil ich plane einen
Logicanalyser zukaufen.
- Bei aufzeichnen von Pegeln, kann man da sofort das am Bildschirm
  mitverfolgen?
- Ist die Aufzeichnung auf eine bestimmte Zeit beschränkt. Also das man
  75s auf Stück aufzeichnen kann.
- In der Beschreibung habe es schon zum Teil gelesen. Kann man
  einstellen ab welcher Spannung es als HIGH und wann es als LOW
  angezeigt werden soll?
         - Signal 1  bis 0,5V LOW  ab 2,5V HIGH
         - Signal 2  bis 0,8V LOW  ab 4,5V HIGH
         - Signal 3 ...
         - ...
     oder
         - Signal 1  bis 2V LOW  ab 2V HIGH
         - Signal 2  bis 4V LOW  ab 4V HIGH
         - Signal 3 ....
         - ...

Das SPI Tuning ist auch eine interessante Sache. Bei SD Card auch
enorm wichtig.
Eine SUPER Homepage von dir. Ich schreib am WE etwas in dein Gästebuch 
rein.

PS Du kannst da auch einen neuen Thread dazu aufmachen. Verlink ihn dann 
aber.

Autor: usul27 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ulm8bit:

Ist zwar etwas o.T., aber trotzdem mal zum Logic Analyzer
- Man sieht den aktuellen Pegel direkt am Bildschirm. Macht aber bei den 
üblicherweise hohen Frequenzen nicht viel her.
- Aufzeichnung ist auf 2kSamples/Kanal begrenzt, da aber nur 
State-Changes gespeichert werden, kann das bei langsamen Sachen (z.B. 
RS232) recht lange reichen.
- High/Low Pegelschwelle kann eingestellt werden, ist aber für alle 
Kanäle gleich
Wenn man aber z.B. 1.5V wählt, kann man trotzdem problemlos 3.3V und 
5V-Sachen gleichzeitig messen

Wenn du mehr zu dem Ding wissen willst, such mal nach "34-Kanal Logic 
Analyzer", da gab es vor 1-2 Wochen einen längeren Thread.

@Dirk:

Sieht wirklich so aus, als wäre deine Lösung im Prinzip gleich. Der Code 
sieht zwar etwas anders aus, aber der erzeugte Maschinencode dürfte 
vermutlich nahezu gleich sein.
Da ich bisher nur den Write implementiert habe, würde mich auch mal 
deine READ-Routine interessieren. Laut Datenblatt, müsste dann noch 
schlimmer werden, da man erst das letzte empfangene Byte lesen muss und 
dann wieder eins schreiben muss, um einen neuen Takt auf der 
Clock-Leitung zu erzeugen. Also ist wohl die Pause zwischen 2 Bytes noch 
einen Takt länger - oder?

Autor: Dirk Broßwick (sharandac)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der tat ist hier di optimierung etwas schwerer. Wie man untern sieht 
gibt eigentlich nur zwei möglichkeiten. Auf einen ATmega32 gehen beide. 
Standartkonform ist aber nur eine bei der zuerst SPDR ausgelesen wird 
und dann das nächste dummy gesendet wird. Man kann das auch anders herum 
machen, zuerst SDPR bescheiben und gleich danach den Puffer auslesen. 
Interessantweise geht das auf besagten Controller, aber wie es auf 
anderen aussieht weis ich nicht.
Anbei der Code.
/* -----------------------------------------------------------------------------------------------------------*/
/*! Eine schnelle SPI->MEM Blockempfangroutine mit optimierungen auf Speed.
 * \warning Auf einigen Controller laufen die Optimierungen nicht richtig. Bitte teil des Sourcecode der dies verursacht ist auskommentiert.
 * \param  buffer    Zeiger auf den Puffer wohin die Daten geschrieben werden sollen.
 * \param  Datalenght  Anzahl der Bytes die empfangen werden sollen.
 */
/* -----------------------------------------------------------------------------------------------------------*/
void SPI_FastRead2Mem( unsigned char * buffer, unsigned int Datalenght )
{
  unsigned int Counter = 0;
  unsigned char data;
  
  // dummywrite
  SPDR = 0x00;

  while( Counter < Datalenght )
  {
    // warten auf fertig
    while(!(SPSR & (1<<SPIF)));

    // einfache Optimierung
    // Daten einlesen in Register
    data = SPDR;
    // dummy-write
    SPDR = 0x00;    

/*    // bessere Optimierung, aber nicht auf jeden controller
    // dummy-write
    SPDR = 0x00;    
    // Daten einlesen in Register
    data = SPDR;
*/
    // Register speichern
    buffer[ Counter++ ] = data;
  }
  while(!(SPSR & (1<<SPIF)));
  return;
}

Autor: usul27 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So in etwas hatte ich mir das auch vorgestellt. Ich werde mal die 
Variante ohne Optimierung nehmen, ich bleibe gerne auf der sicheren 
Seite.

Autor: Dirk Broßwick (sharandac)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mal geschaut und überlegt, die richtige Optimierung sollte auch 
gehen. Wenn SPI mit halben Controller-Takt läuft hat man genau 2 
Taktzyklen Zeit bis das erste Bit in den SPI-Puffer geshiftet wird, 
sollte also gemnach auf jeden Controller gehen.

Autor: Petr Tomášek (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ATmega48/88/168 hat "USART in SPI Mode" das doppelt-gepuffert ist (sage 
ich das richtig auf Deutch?), also könnte theoretisch schneller 
werden...

Autor: Torsten R. (tom365)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,habe die Variante mit den NOPs  getestet.
Nach dem Senden eines Bytes(16 Takte) muß 2 Takte gewartet werden ehe 
das nächste Byte gesendet werden kann. Sonst verschluckt sich das 
SPI-Interface Macht am Ende 18 CPU-Takte pro Byte.

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.