Forum: Compiler & IDEs Optimierung SPI Ausgabe


von Christian U. (z0m3ie)


Lesenswert?

Ist es möglich diesen Code noch zu optimieren ?
Die SPI Ausgabe ist einfach zu langsam ich komme aber nicht weiter, 
letterptr ist der Anfang in einer lookup Tabelle, a stellt dann den 
index innerhalb der Tabelle dar. Das ganze aus dem Ram statt Flash zu 
machen scheint keinen Geschwindigkeitsvorteil zu bringen.
Ich bin nun absoulut kein Assembler Freak wäre es möglich da mit 
Assembler noch ein paar Takte rauszuholen ?

a = *textptr++;
nextbyte = pgm_read_byte(letterptr+a);
while (*textptr != 0)
  {
    a = *textptr++;
    SPDR = nextbyte;
    nextbyte = pgm_read_byte(letterptr+a);
    while(!(SPSR & (1<<SPIF)));
  }
SPDR = nextbyte;
while(!(SPSR & (1<<SPIF)));

von Falk B. (falk)


Lesenswert?

@ Christian Ulrich (z0m3ie)

>Ist es möglich diesen Code noch zu optimieren ?

Sicher.

>Die SPI Ausgabe ist einfach zu langsam ich komme aber nicht weiter,
>letterptr ist der Anfang in einer lookup Tabelle, a stellt dann den
>index innerhalb der Tabelle dar. Das ganze aus dem Ram statt Flash zu
>machen scheint keinen Geschwindigkeitsvorteil zu bringen.

Tut es auch nicht. Siehe hier.

AVR-Tutorial: Schieberegister

>Ich bin nun absoulut kein Assembler Freak wäre es möglich da mit
>Assembler noch ein paar Takte rauszuholen ?

Nicht wirklich. C wird schon brauchbar übersetzt, wenn man es richtig 
hinschreibt.

Etwa so.
1
a = *textptr++;
2
nextbyte = pgm_read_byte(letterptr+a);
3
while (a != 0)
4
  {
5
    while(!(SPSR & (1<<SPIF)));
6
    SPDR = nextbyte;
7
    a = *textptr++;
8
    nextbyte = pgm_read_byte(letterptr+a);
9
  }
10
while(!(SPSR & (1<<SPIF)));
11
SPDR = nextbyte;
12
while(!(SPSR & (1<<SPIF)));

Der Trick dabei ist, während die Übertragung läuft das nächste Byte zu 
holen und danach erst zu prüfen, ob sie zu Ende ist. In deinem Beispiel 
verplemperst du Zeit um auf das Ende der Übertragung zu warten und 
DANACH erst das nächste Byte zu holen.

MFG
Falk

von Uhu U. (uhu)


Lesenswert?

> Ich bin nun absoulut kein Assembler Freak wäre es möglich da mit
> Assembler noch ein paar Takte rauszuholen ?

Dazu müßte man sich den ASM-Code, den der Compiler erzeugt, mal näher 
ansehen und überlegen, was man besser machen kann. Dem C-Code sieht man 
das nicht an.

von Christian U. (z0m3ie)


Lesenswert?

Hallo Falk,

in der Zwischenzeit hatte ich das selbst schon gesehn und meinen Code so 
geändert:

a = *textptr++;
nextbyte = pgm_read_byte(letterptr+a);
while (*textptr != 0)
  {
    SPDR = nextbyte;
    a = *textptr++;
    nextbyte = pgm_read_byte(letterptr+a);
    while(!(SPSR & (1<<SPIF)));
  }
SPDR = nextbyte;
while(!(SPSR & (1<<SPIF)));

Damit sollte das ja wenn ich das richtig seh keinen unterschied mehr zu 
deinem code machen. Jedoch hat das nicht genug gebracht. ich hab immer 
noch lücken in der ausgabe die so groß sind wie die ausgabezeit selbst.

Ich hab auch schon mit dem Assemblercode geschaut und das vorher schon 
etwas optimiert nur programmiere ich nie in assembler und kann so 
schlecht einschätzen ob man das nicht inline optimaler lösen könnte.
ich poste montag mal den erzeugten code.

von Alexander H. (ill_son)


Lesenswert?

Hi,

probiers doch mal mit Interrupt. Dann musst das Programm nicht warten, 
bis die Übertragung fertig ist, sondern bekommst das per Interrupt 
mitgeteilt.

Gruß, Alex

von Christian U. (z0m3ie)


Lesenswert?

Ich fürchte das wird eher schlimmer da ich ja irgendwann die neuen daten 
holen muss. Das mach ich jetzt wärend der Ausgabe, dann kann ich das 
aber nicht mehr machen.

von Falk B. (falk)


Lesenswert?

@ Alexander Heß (ill_son)

>probiers doch mal mit Interrupt. Dann musst das Programm nicht warten,
>bis die Übertragung fertig ist, sondern bekommst das per Interrupt
>mitgeteilt.

Und? Wird es dann schneller? NEIN! Für maximale SPI Geschwindigkeit muss 
man pollen.


@ Christian Ulrich (z0m3ie)

>in der Zwischenzeit hatte ich das selbst schon gesehn und meinen Code so
>geändert:

Warum fragst du zweimal *textptr ab? Da muss der Compiler, wenn er es 
nicht erkennt, zweimal den Pointer defererenzieren, obwohl a den 
gleichen Inhalt hat.

>a = *textptr++;
>nextbyte = pgm_read_byte(letterptr+a);
>while (*textptr != 0)
>  {
>    SPDR = nextbyte;
>    a = *textptr++;
>    nextbyte = pgm_read_byte(letterptr+a);
>    while(!(SPSR & (1<<SPIF)));
>  }
>SPDR = nextbyte;
>while(!(SPSR & (1<<SPIF)));

Pssst soweit. Besser kann man es wahrscheinlich nicht machen. Und man 
muss sehen, dass da immerhin zwei Pointer dereferenziert werden müssen.

>    a = *textptr++;

Das ist recht einfach, daraus wird eine ld rx,z+

>    nextbyte = pgm_read_byte(letterptr+a);

Hier muss jedes mal letterptr geladen werden und der Offset a als 16 Bit 
Offset addiert werden, dann kommt lpm. Das dauert schon ein paar Takte.

>deinem code machen. Jedoch hat das nicht genug gebracht. ich hab immer
>noch lücken in der ausgabe die so groß sind wie die ausgabezeit selbst.

Naja, rechne mal. Bei SPI-Takt = CLK/2 bleiben gerade mal 16 Takte pro 
Byte. Das wird knapp mit den zwei Pointeroperationen.

>ich poste montag mal den erzeugten code.

OK.

MfG
Falk

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.