www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR - SPI im MasterMode auch ohne Int-Flag erlaubt?


Autor: Joan P. (joan)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi..

Ich guck mir grad die SPI Schnittstelle von einem ATmega1281 (Meshnetics 
ZigBit Modul) und dessen Datenaustausch mit dem RadioChip AT86RF230 an.

Initialisierung der SPI Schnittstelle ohne Interrupt Flag:
  // SPI Config: Interrupt OFF, SPI ON, MSB first, MasterMode, SPI-Mode 0, Clock Rate F_OSC/2
  SPCR = (0<<SPIE)|(1<<SPE)|(0<<DORD)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA)|(0<<SPR1)|(0<<SPR0);
  SPSR = (1<<SPI2X);

Der Mega1281 läuft mit 1MHz.. dh. die SPI dann mit 500kHz.
Der RF230 kann asynchron bis 7,5MHz sampeln und versteht bisher auch 
alles.
Wenn ich die CKDIV8-Fuse disable, läuft der Mega1281 mit 8MHz und 
SPI-SCK mit 4MHz.. alles astrein soweit.

So, nun zur eigentlichen Frage.
Ich hab nach dem Schreiben des Bytes in das SPDR 16 clockcycles gewartet 
(mit dem Oszi sieht man, dass er dann fertig ist) und schreib dann das 
nächste Byte rein <<< IST DAS ERLAUBT?

Das ganze sieht folgendermassen aus (GCC):
PORTB &= ~(1<<PB0); // SEL low
SPDR = 0x8B; // SPI - byte #1

__asm__ __volatile__ (" nop \n" :: ); // NOP 1
__asm__ __volatile__ (" nop \n" :: ); // NOP 2
__asm__ __volatile__ (" nop \n" :: ); // NOP 3
__asm__ __volatile__ (" nop \n" :: ); // NOP 4
__asm__ __volatile__ (" nop \n" :: ); // NOP 5
__asm__ __volatile__ (" nop \n" :: ); // NOP 6
__asm__ __volatile__ (" nop \n" :: ); // NOP 7
__asm__ __volatile__ (" nop \n" :: ); // NOP 8
__asm__ __volatile__ (" nop \n" :: ); // NOP 9
__asm__ __volatile__ (" nop \n" :: ); // NOP 10
__asm__ __volatile__ (" nop \n" :: ); // NOP 11
__asm__ __volatile__ (" nop \n" :: ); // NOP 12
__asm__ __volatile__ (" nop \n" :: ); // NOP 13
__asm__ __volatile__ (" nop \n" :: ); // NOP 14
__asm__ __volatile__ (" nop \n" :: ); // NOP 15
__asm__ __volatile__ (" nop \n" :: ); // NOP 16

SPDR = 0xAA; // SPI - byte #2..

__asm__ __volatile__ (" nop \n" :: ); // NOP 1
__asm__ __volatile__ (" nop \n" :: ); // NOP 2
__asm__ __volatile__ (" nop \n" :: ); // NOP 3
__asm__ __volatile__ (" nop \n" :: ); // NOP 4
__asm__ __volatile__ (" nop \n" :: ); // NOP 5
__asm__ __volatile__ (" nop \n" :: ); // NOP 6
__asm__ __volatile__ (" nop \n" :: ); // NOP 7
__asm__ __volatile__ (" nop \n" :: ); // NOP 8
__asm__ __volatile__ (" nop \n" :: ); // NOP 9
__asm__ __volatile__ (" nop \n" :: ); // NOP 10
__asm__ __volatile__ (" nop \n" :: ); // NOP 11
__asm__ __volatile__ (" nop \n" :: ); // NOP 12
__asm__ __volatile__ (" nop \n" :: ); // NOP 13
__asm__ __volatile__ (" nop \n" :: ); // NOP 14
__asm__ __volatile__ (" nop \n" :: ); // NOP 15
__asm__ __volatile__ (" nop \n" :: ); // NOP 16

SPDR = 0x44; // SPI - byte #3

__asm__ __volatile__ (" nop \n" :: ); // NOP 1
__asm__ __volatile__ (" nop \n" :: ); // NOP 2
__asm__ __volatile__ (" nop \n" :: ); // NOP 3
__asm__ __volatile__ (" nop \n" :: ); // NOP 4
__asm__ __volatile__ (" nop \n" :: ); // NOP 5
__asm__ __volatile__ (" nop \n" :: ); // NOP 6
__asm__ __volatile__ (" nop \n" :: ); // NOP 7
__asm__ __volatile__ (" nop \n" :: ); // NOP 8
__asm__ __volatile__ (" nop \n" :: ); // NOP 9
__asm__ __volatile__ (" nop \n" :: ); // NOP 10
__asm__ __volatile__ (" nop \n" :: ); // NOP 11
__asm__ __volatile__ (" nop \n" :: ); // NOP 12
__asm__ __volatile__ (" nop \n" :: ); // NOP 13
__asm__ __volatile__ (" nop \n" :: ); // NOP 14
__asm__ __volatile__ (" nop \n" :: ); // NOP 15
__asm__ __volatile__ (" nop \n" :: ); // NOP 16

PORTB |= (1<<PB0); // SEL high

Ich hab nun schon ein paar Datenblätter durchwühlt.. auch App-Notes.. 
aber ich finde nirgends Angaben (bin ich blind?) darüber, wann man 
wieder an das SPDR ran darf.. :(

Mittels Interrupt oder SPIF-pollen dauerts mir zu lange, bis ich das 
nächste byte rausschieben darf. Da ist dann immer so viel Leere Zeit wo 
ich schon die nächsten Befehle übertragen könnte..

Grüsse
Joan

PS: die angehängten Bilder zeigen die obige Sequenz einmal mit F_osc 
1Mhz (SPI 500kHz) und einmal mit F_osc 8MHz (SPI 4MHz).

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich hab nach dem Schreiben des Bytes in das SPDR 16 clockcycles gewartet
>(mit dem Oszi sieht man, dass er dann fertig ist) und schreib dann das
>nächste Byte rein <<< IST DAS ERLAUBT?

Ja, wieso nicht. Hab ich auch schon so gemacht.
Ich meine aber das ich 17 clockcycles warten musste
bevor ich wieder in SPDR schreiben konnte. Kann mich aber
auch verzählt haben.

Autor: Joan P. (joan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger wrote:
> Ja, wieso nicht. Hab ich auch schon so gemacht.

Hehe.. ok. Aber irgendwo muss das doch stehen, dass man mehr als 8x2 
clock cycles warten soll und dann ohne Flag SPDR neu laden kann?
Sämtliche Beispiele sind mit Polling oder ISR.. :(
Nirgendwo etwas über.. "if you want to send x-bytes in a row, do this.."

> Ich meine aber das ich 17 clockcycles warten musste
> bevor ich wieder in SPDR schreiben konnte. Kann mich aber
> auch verzählt haben.

Jau, die restlichen cycles werden bei mir schon irgendwo in dem "SPDR = 
xyz;" Befehl stecken, muss ich mir mal den Assembler Code zu angucken, 
damit ich mir sicher bin.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hehe.. ok. Aber irgendwo muss das doch stehen, dass man mehr als 8x2
>clock cycles warten soll und dann ohne Flag SPDR neu laden kann?

Warum sollte das irgendwo stehen ? Das SPI Modul braucht
halt mindestens 8 * 2 clock cycles. Nach SPDR=xy; kannst du ja auch
einfach ein Delay1ms(200); oder eine ähnlich dumme Warteschleife
einfügen. Funktionieren tut es trotzdem. Die Abfrage von SPIF ist
nicht zwingend notwendig.

Die ganze Geschichte mit den 16 clock cyles funktioniert natürlich
nur wenn das SPI Modul auf F_CPU/2 konfiguriert ist.

Also Kinder: Bitte nicht nachmachen wenn ihr nicht wisst wie
euer SPI Modul eingestellt ist !

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joan P. wrote:

> Mittels Interrupt oder SPIF-pollen dauerts mir zu lange, bis ich das
> nächste byte rausschieben darf.

Dass ein SPI-Interrupt bei voller Datenrate sinnlos ist, ist klar.
Aber warum denkst du, dass deine NOPs schneller sind als das Pollen
des SPIF?  Die Zeit abwarten musst du so oder so.  Dafür fällt das
Pollen wohl unter ,,defensive Programmierung'': wenn mal jemand die
Datenrate der SPI-Schnittstelle umstellt (warum auch immer), geht
das trotzdem noch (nur langsamer).

Die SPI-Schnittstelle ist bei 4 MHz übrigens deutlich schneller als
die Luftschnittstelle, insofern ist sie gar nicht der Flaschenhals,
und es kommt auf einen Takt mehr gar nicht an.  Falls du noch einen
AT86RF230 rev A hast, musst du ja ohnehin auch noch die CRC-16 mit
berechnen beim Empfang, das kann man bequem parallel mit jedem neu
gelesenene Byte ausführen, ohne dass man dadurch insgesamt langsamer
wird.  Beim rev B gibt's dann ein "CRC OK"-Bit, da muss man das nicht
mehr selbst machen.  Ob du einen rev A oder B in deinem ZigBit hast,
erfährst du aus dem Versionsregister.

Autor: Joan P. (joan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger wrote:
> Die Abfrage von SPIF ist nicht zwingend notwendig.

Gut, dann fühl ich mich jetzt bestätigt genug, dass ich das als 
'gesichert' verwenden kann.. wie gesagt, ich hab nirgends was dazu 
gefunden - auch nicht beim stöbern in diversen Threads mit den 
Suchwörtern und Kombinationen daraus: "AVR SPI Geschwindigkeit Latenz 
Byte Flag ISR..." ;)

> Die ganze Geschichte mit den 16 clock cyles funktioniert natürlich
> nur wenn das SPI Modul auf F_CPU/2 konfiguriert ist.

jup, is klar.

Jörg Wunsch wrote:
> Dass ein SPI-Interrupt bei voller Datenrate sinnlos ist, ist klar.
> Aber warum denkst du, dass deine NOPs schneller sind als das Pollen
> des SPIF? Die Zeit abwarten musst du so oder so. Dafür fällt das
> Pollen wohl unter ,,defensive Programmierung'': wenn mal jemand die
> Datenrate der SPI-Schnittstelle umstellt (warum auch immer), geht
> das trotzdem noch (nur langsamer).

Die NOPs sind nur testweise.. keine Angst. Das füll ich schon noch mit 
sinnvollem Code auf.

> Die SPI-Schnittstelle ist bei 4 MHz übrigens deutlich schneller als
> die Luftschnittstelle, insofern ist sie gar nicht der Flaschenhals,
> und es kommt auf einen Takt mehr gar nicht an.

Jau.. ich will auch nur Zeit gewinnen.. RF230 initialisieren in Null 
Komma nix und dann ab die Lutzi.. rumschweinsen kann ich dann später 
immer noch, wenns dann Richtung Wiederholung und Kanalwechsel geht.
Geht nur um wenige Bit, aber relativ störsicher und schnell soll es 
werden.

> Falls du noch einen AT86RF230 rev A hast, musst du ja ohnehin auch noch
> die CRC-16 mit berechnen beim Empfang, das kann man bequem parallel mit
> jedem neu gelesenene Byte ausführen, ohne dass man dadurch insgesamt
> langsamer wird.  Beim rev B gibt's dann ein "CRC OK"-Bit, da muss man das
> nicht mehr selbst machen.  Ob du einen rev A oder B in deinem ZigBit
> hast, erfährst du aus dem Versionsregister.

Danke für den Hinweis.

------------------------------------
Allgemein muss ich halt sagen, kams mir auf dem Oszi so vor, als würde 
ich die SPI 'knüppeln', wenn ich nicht erst auf das Flag warte.. die 
Version mit Flag (ISR oder Polling) hatte meistens mehr wie 3x1 Byte 
Pause dazwischen, wo nix anderes passierte. Und da wollte ich mich mal 
erkundigen, ob das Vorgehen 'normal' ist, weil eben nirgends 
dokumentiert.

Grüsse und Danke
Joan

Autor: Joan P. (joan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
btw: hab Revision A

Autor: Udo S. (udo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hier haste schon mal geschaut?
http://www.matuschek.net/atmega-spi/

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joan P. wrote:

> Die NOPs sind nur testweise.. keine Angst. Das füll ich schon noch mit
> sinnvollem Code auf.

Dann wäre aber Abfrage des SPIF noch besser, da die tatsächliche
Länge des ausgeführten Codes nicht mehr ausgezählt werden muss.

Geht's dir ums Senden oder Empfangen?  Beim Senden bist du eigentlich
auch aus dem kritischen Bereich, wenn du die Übertragung einfach
erst einmal startest (durch Impuls an SLP_TR) und erst danach die
Daten runterfütterst.  Der Chip muss nämlich erstmal die Präambel
rauspusten (4 + 1 Bytes, also 160 µs), bevor er deine Daten benötigt.
Du hast dann gewissermaßen alle Zeit der Welt, ihm die Daten
nachzureichen...

Autor: Joan P. (joan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke @Udo.. die kannte ich noch nicht. Gleich mal den Link abspeichern.

Jörg Wunsch wrote:
> Geht's dir ums Senden oder Empfangen? Beim Senden bist du eigentlich
> auch aus dem kritischen Bereich, wenn du die Übertragung einfach
> erst einmal startest (durch Impuls an SLP_TR) und erst danach die
> Daten runterfütterst.  Der Chip muss nämlich erstmal die Präambel
> rauspusten (4 + 1 Bytes, also 160 µs), bevor er deine Daten benötigt.
> Du hast dann gewissermaßen alle Zeit der Welt, ihm die Daten
> nachzureichen...

So schnell wie möglich initialisieren, also Kanal, dB usw.. Ich weiß 
halt noch nicht, wie oft ich das brauch. Deswegen wär halt je schneller 
um so besser. Ist alles noch tlw im Kopf und nicht auf Papier ;)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die PLL braucht vermutlich länger zum Abgleich der Mittenfrequenz
als deine paar Takte.

Nimm ruhig das SPIF-Flag, dann bist du immer auf der sicheren
Seite.

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.