Prozessorauslastung bei SPI

Gast #618427
Lesenswert?

Halloo

Angenommen, ich schreiben Bytes über SPI zu einem Slave.
Der Master (hier der µC) schreibt byteweise in ein SPI-Datenregister und 
setzt danach ein Tx-Request. Dann sollten doch mit dem SCK-Takt über die 
MISO und MOSI Leitungen die Bits weitergeschoben werden.

Frage ist nun: Zu dem Zeitpunkt, nachdem das Byte in das SPI-Register 
geschrieben wurde, wer kümmert sich um die Übertragung via SCK? Wird das 
über einen Bypass erledigt oder muss die MCU direkt ran?
Ich will, dass die MCU so wenig wie nötig mit der SPI Sache belastet 
wird, denn dann bleiben andere Anwendungen in der Zeit der Übertragung 
hinterher.
Gast #618466
Lesenswert?

> das Byte in das SPI-Register
>geschrieben wurde, wer kümmert sich um die Übertragung via SCK?

Hä? Was?

Du solltest dir zuerst mal in aller Ruhe eine SPI Verbindung in einem 
Datenblatt ansehen. Wie ist das verschaltet, was passiert dort, was muss 
die Software machen..
Gast #618480
Lesenswert?

ich kenn SPI.
Nur wollte ich mal weiter ins Detail.

Aber es scheint als wenn nach Setzen des TxReq-Bit sich die CPU von der 
Sache abwenden kann und anderes machen kann. Bis eben ein INT auftritt.
Oder mann wartet nach Start der Übertragung im Poll-Verfahren auf 
SPIF-Bit.
Gast #618491
Lesenswert?

SPI kennen, heisst das Detail kennen. Interrupts lohnen sich bei den 
maximalen transferraten uebigens kaum. Bei Clk/2 vergehen 16 clocks, 
wenn man da in der interruptrouting etwas pusht und popt ist die Zeit 
auch schon um.
Persönliche Seite #618494
Lesenswert?

Nullpainter wrote:
> Bei Clk/2 vergehen 16 clocks,

Ich hab mal irgendwo gelesen, dass es genaugenommen 18 Clocks sind, bis 
das nächste Byte wieder ins Register geladen werden darf.

Trotz allem geb ich dir Recht ;) Ich hab auch bei meinen 
SD-Karten-Fullspeed-sources (Clk/2) keine Interruptgesteuerte SPI 
Schnittstelle. Das lohnt sich einfach nicht. Die paar takte kann man 
eben auch warten.

Absolut gesehen sind das bei 20MHz weniger als eine µS.
Gast #618509
Lesenswert?

Bei mir hat die Zeitbetrachtung folgenden Grund:

Ich sende dem ENC28J60-Baustein über SPI @ 8MHz genau 122 Byte 
Stack-Daten. (42+80 UDP)

Bei dieser SPI-Geschwindigkeit wird also 1 MegaByte/s übertragen. Oder 
anders: 1 Byte/µs
Auf meine 122 Byte wären das dann 122µs an Zeit die vergehe würde, bis 
der Datenstrom im ENC ist.

Am Oszi mess ich aber: 380µs.
Ist der Rest alles Warte-Zeit?
Ich hab schon überlegt via DMA die Daten in das SPI-Register zu 
schieben. Ich weis nicht ob das Abhilfe schafft.
Gast #618524
Lesenswert?

Das beste ist, du guckst dir während der Übertragung die SCK Leitung auf 
nem Oszi an. Am besten als Triggerung den Beginn (oder kurz vorher) der 
Übertragung des ersten Bytes. zB mit CS=Low, oder per extra Pin.
Dort siehst du sofort, wie "effektiv" deine Übertragung ist. Also wie 
groß die Pausen zwischen den Bytes sind... Somit siehst du, obs am 
Programm zwischen den ausgaben (zB Daten aus RAM.. holen) liegt, oder 
obs am Programmeinsprung.. liegt...
Gast #618535
Lesenswert?

Wenn man's nicht in ASM macht kann schon was an Zeit verplemepert 
werden. Wenn mn zB Wartet bis das SPI fertig ist, und dann erst das byte 
holengeht, mit Arrayindexrechnung und so, ist einiges moeglich. Ich 
wuerd diesen Ladeprozess mal im simulator laufen lassen, oder falls das 
nicht geht, am Objekt selbst mit einem puls an einem Debugpin jeweils.
#618676
Lesenswert?

@ Horst (Gast)

>Aber es scheint als wenn nach Setzen des TxReq-Bit sich die CPU von der
>Sache abwenden kann und anderes machen kann. Bis eben ein INT auftritt.

Ja. Das Generieren von SCK und rausschieben der Bits macht das SPI-Modul 
allein.

>Oder mann wartet nach Start der Übertragung im Poll-Verfahren auf
>SPIF-Bit.

Genau. Sinnvollereise wird man erst dan nächste Datenbyte laden und dann 
pollen.

MFG
Falk
Gast #619142
Lesenswert?

Hallo, so jetzt gehts weiter..

ich habe also mal das SCK Signal über den gesamten Vorgang aufgenommen.
Es ist also deutlich zu sehen: Lücken zwischen den Bytes.

90% der Daten sind mein Stack der übertragen wird. Die Funktion zum 
Schreiben des Stack ist die folgende:

1
void enc28j60WriteBuffer(uint16_t len, uint8_t* data)  // Länge (Byte), Startadresse Data
2
{
3
  // assert CS
4
  ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
5
  // issue write command
6
  SPDR = ENC28J60_WRITE_BUF_MEM;
7
  while(!(SPSR & (1<<SPIF)));
8
  while(len--)
9
  {
10
    // write data
11
    SPDR = *data++;
12
    while(!(SPSR & (1<<SPIF)));  
13
  }  
14
  // release CS
15
  ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
16
}

Der Code ist vielermals im Netz zu finden, ich habe den eben auch 
genommen. Die Daten werden per Zeiger  zugewiesen, was doch schon sehr 
zügig sein sollte.

Hier konnte ich dann mit einem Debug-Pin die Wartezeiten feststellen.

Für das erste Bild gilt:
1
  while(len--)
2
  {
3
    // write data
4
    SPDR = *data++;
5
    PORTC = 1;
6
    while(!(SPSR & (1<<SPIF)));  
7
                PORTC = 0;
8
  }
Hier ist also die Poll-Zeit des SPIF-Bit aufgezeichnet.

Für das zweite Bild:
1
  while(len--)
2
  {
3
    // write data
4
    PORTC = 1;
5
    SPDR = *data++;
6
    PORTC = 0;
7
    while(!(SPSR & (1<<SPIF)));  
8
  }
Hier also das Schreiben eines Bytes in das SPI Register. Aber wieso 
inklusive SCK-Taktung?


Ich denke mal die Warte-Zeit auf das SPIF kann ich nicht verringern. 
Beim Transferieren der Daten in das SPI-Datenregister jedoch müsste doch 
was machbar sein. Evtl. DMA?
Angehängte Dateien:
Gast #619146
Lesenswert?

Die COdes wurden wohl nicht korrekt übertragen. Nochmal:

Das PORTC-Bit0 ist der Debug Pin.

Für das erste Bild gilt:
1
while(len--)
2
{
3
// write data
4
SPDR = *data++;
5
PORTC = 1;
6
while(!(SPSR & (1<<SPIF)));  
7
PORTC = 0;
8
}


Für das zweite Bild:
1
while(len--)
2
{
3
// write data
4
PORTC = 1;
5
SPDR = *data++;
6
PORTC = 0;
7
while(!(SPSR & (1<<SPIF)));  
8
}
Persönliche Seite #619147
Lesenswert?

Horst wrote:
> Ich denke mal die Warte-Zeit auf das SPIF kann ich nicht verringern.
> Beim Transferieren der Daten in das SPI-Datenregister jedoch müsste doch
> was machbar sein. Evtl. DMA?

Hm, auf welcher Optimierungsstufe ist das kompiliert? Hast du eventuell 
mal Assembler-code von der Write-Funktion? Komisch, dass das laden und 
inkrementieren so "lange" braucht. Wobei das so lange ja garnicht ist ;)

Wenn ich mich nicht irre handelt es sich doch um einen 8-Bit AVR, die 
haben doch garkeine DMA Unterstützung.
#619151
Lesenswert?

@ Horst (Gast)

>ich habe also mal das SCK Signal über den gesamten Vorgang aufgenommen.
>Es ist also deutlich zu sehen: Lücken zwischen den Bytes.

Yep.

>void enc28j60WriteBuffer(uint16_t len, uint8_t* data)  // Länge (Byte), 
Startadresse Data
>{
>  // assert CS
>  ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
>  // issue write command
>  SPDR = ENC28J60_WRITE_BUF_MEM;
>  while(!(SPSR & (1<<SPIF)));
>  while(len--)
>  {
>    // write data
>    SPDR = *data++;
>    while(!(SPSR & (1<<SPIF)));
>  }
>  // release CS
>  ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
>}

>Der Code ist vielermals im Netz zu finden, ich habe den eben auch
>genommen. Die Daten werden per Zeiger  zugewiesen, was doch schon sehr
>zügig sein sollte.

Naja, hier wird man wohl um Assembler nicht rumkommen. Der Trick ist, 
während die alte Übertragung läuft schon die neuen Daten zu holen. In C 
ist es nicht sehr einfach zu garantieren, dass der Compiler das nicht in 
die flasche Richtung optimiert.

Versuch mal das.

void enc28j60WriteBuffer(uint16_t len, uint8_t* data)  // Länge (Byte), 
Startadresse Data
{
  uint8_t tmp;

  // assert CS
  ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS);
  // issue write command
  SPDR = ENC28J60_WRITE_BUF_MEM;
  while(!(SPSR & (1<<SPIF)));
  while(len--)
  {
    // write data
  tmp = *data++;
  while(!(SPSR & (1<<SPIF)));
    SPDR = tmp;
  }
  // release CS
  ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS);
}

>Ich denke mal die Warte-Zeit auf das SPIF kann ich nicht verringern.

Kaum, das SPI-Interface muss ja die Daten erstmal übertragen, bevor neue 
reingeschrieben werden können.

>Beim Transferieren der Daten in das SPI-Datenregister jedoch müsste doch
>was machbar sein. Evtl. DMA?

Assembler + Knoff Hoff!

MFG
Falk
Gast #619175
Lesenswert?

interessante Links! Danke

mit einer Optimierung O1 konnte ich eben 40% Zeitersparnis erreichen :-)
DIe anderen Optimierungen brachten dann nichts mehr.

@Falk, guter Tipp. Aber erscheint dann am while zu hängen da die 
Bedingung bein ersten Mal wohl nicht erfpllt ist.
Gast #619184
Lesenswert?

Mir ist es mal gelungen, 24Bytes innerhalb einer ext. Int. ISR 
herauszutakten. Das ganze hat für den kompletten Aufruf(einsprung+push), 
Bearbung und Beenden(pop) etwa 35Mikrosekunden gedauert. Das Ganze auf 
nem mega128@16MHz.
Persönliche Seite #619251
Lesenswert?

Die Frage ist, ob man überhaupt Pollen sollte...

while(!(SPSR & (1<<SPIF)));
 17c:  77 9b         sbis  0x0e, 7
 17e:  fe cf         rjmp  .-4

Oben drüber ist das "out". Wenn ich richtig gezählt habe, dann fällt der 
16. Takt danach direkt auf das sbis.
Da erst mit dem 17. Takt die Transmission beendet ist, wird nicht 
übersprungen und der rjmp wird ausgeführt. Dann dauert es nochmal 4 
Takte, bis man aus der Schleife draußen ist, da rjmp=2 + aktives_sbis=2.

Wenn man jedoch einfach 16 Takte durch nops verliert (oder 
Platzsparender rjmp +0), dann wäre man eigentlich genau richtig im 
Timing.

Die zweite Frage ist, ob das auch so hinhaut. Hat das jemand mal 
ausprobiert oder willst du das mal ausprobieren Horst?
Gast #619284
Lesenswert?

>Die zweite Frage ist, ob das auch so hinhaut. Hat das jemand mal
>ausprobiert oder willst du das mal ausprobieren Horst?

Ja, hab ich. das geht.
Hab aber statt der nops immer einen temp.ausgabepuffer geladen und 
andere dinge gemacht. und das ganze komplett ohne schleife..
Gast #619334
Lesenswert?

@ Matthias L. (lippy)

>Hab aber statt der nops immer einen temp.ausgabepuffer geladen und
>andere dinge gemacht. und das ganze komplett ohne schleife..

Ohne Schleife? Wie willst du da variable Datenblöcke übertragen?

MfG
Falk

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren