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:
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):
1
PORTB&=~(1<<PB0);// SEL low
2
SPDR=0x8B;// SPI - byte #1
3
4
__asm____volatile__(" nop \n"::);// NOP 1
5
__asm____volatile__(" nop \n"::);// NOP 2
6
__asm____volatile__(" nop \n"::);// NOP 3
7
__asm____volatile__(" nop \n"::);// NOP 4
8
__asm____volatile__(" nop \n"::);// NOP 5
9
__asm____volatile__(" nop \n"::);// NOP 6
10
__asm____volatile__(" nop \n"::);// NOP 7
11
__asm____volatile__(" nop \n"::);// NOP 8
12
__asm____volatile__(" nop \n"::);// NOP 9
13
__asm____volatile__(" nop \n"::);// NOP 10
14
__asm____volatile__(" nop \n"::);// NOP 11
15
__asm____volatile__(" nop \n"::);// NOP 12
16
__asm____volatile__(" nop \n"::);// NOP 13
17
__asm____volatile__(" nop \n"::);// NOP 14
18
__asm____volatile__(" nop \n"::);// NOP 15
19
__asm____volatile__(" nop \n"::);// NOP 16
20
21
SPDR=0xAA;// SPI - byte #2..
22
23
__asm____volatile__(" nop \n"::);// NOP 1
24
__asm____volatile__(" nop \n"::);// NOP 2
25
__asm____volatile__(" nop \n"::);// NOP 3
26
__asm____volatile__(" nop \n"::);// NOP 4
27
__asm____volatile__(" nop \n"::);// NOP 5
28
__asm____volatile__(" nop \n"::);// NOP 6
29
__asm____volatile__(" nop \n"::);// NOP 7
30
__asm____volatile__(" nop \n"::);// NOP 8
31
__asm____volatile__(" nop \n"::);// NOP 9
32
__asm____volatile__(" nop \n"::);// NOP 10
33
__asm____volatile__(" nop \n"::);// NOP 11
34
__asm____volatile__(" nop \n"::);// NOP 12
35
__asm____volatile__(" nop \n"::);// NOP 13
36
__asm____volatile__(" nop \n"::);// NOP 14
37
__asm____volatile__(" nop \n"::);// NOP 15
38
__asm____volatile__(" nop \n"::);// NOP 16
39
40
SPDR=0x44;// SPI - byte #3
41
42
__asm____volatile__(" nop \n"::);// NOP 1
43
__asm____volatile__(" nop \n"::);// NOP 2
44
__asm____volatile__(" nop \n"::);// NOP 3
45
__asm____volatile__(" nop \n"::);// NOP 4
46
__asm____volatile__(" nop \n"::);// NOP 5
47
__asm____volatile__(" nop \n"::);// NOP 6
48
__asm____volatile__(" nop \n"::);// NOP 7
49
__asm____volatile__(" nop \n"::);// NOP 8
50
__asm____volatile__(" nop \n"::);// NOP 9
51
__asm____volatile__(" nop \n"::);// NOP 10
52
__asm____volatile__(" nop \n"::);// NOP 11
53
__asm____volatile__(" nop \n"::);// NOP 12
54
__asm____volatile__(" nop \n"::);// NOP 13
55
__asm____volatile__(" nop \n"::);// NOP 14
56
__asm____volatile__(" nop \n"::);// NOP 15
57
__asm____volatile__(" nop \n"::);// NOP 16
58
59
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).
>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.
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.
>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 !
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.
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
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...
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 ;)
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.