www.mikrocontroller.net

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

Autor: Joan P. (joan)
Datum: 04.04.2008 17:08
Dateianhang: Mega1281-SPI-4MHz.zip (73,3 KB, 11 Downloads)

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: 04.04.2008 17:58

>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: 04.04.2008 18:17

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: 04.04.2008 18:40

>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: 04.04.2008 21:55

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: 04.04.2008 22:30

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: 04.04.2008 22:45

btw: hab Revision A
Autor: Udo S. (udo)
Datum: 04.04.2008 22:51

hier haste schon mal geschaut?
http://www.matuschek.net/atmega-spi/
Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum: 04.04.2008 23:07

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: 04.04.2008 23:32

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: 04.04.2008 23:35

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 Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
  • Aussagekräftigen Betreff wählen
  • Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
  • JPEG-Dateien (.jpg) nur für Fotos und Scans verwenden
  • Schaltpläne, Screenshots usw. als PNG oder GIF anhängen

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel





Hinweis: der Originalbeitrag ist mehr als 6 Monate alt.

webmaster@mikrocontroller.netImpressumWerbung auf Mikrocontroller.net