Hallo,
mein C Programm ist sehr langsam.
Die Ursache liegt in der SPI_Send_LL_Word Routine,
ich habe mit dem Osko nachgemessen,
die SCK-Impulse kommen mit 45µs Abstand.
1
voidSPI_Send_LL_Word(unsignedlonglongintWord)
2
{
3
for(unsignedcharI=48;I;I--)
4
{
5
if(!(Word&0x01))
6
PORTB|=(1<<SER);
7
else
8
PORTB&=~(1<<SER);
9
10
PORTB|=(1<<SCK);
11
Word>>=1;
12
PORTB&=~(1<<SCK);
13
}
14
PORTB|=(1<<RCK);
15
PORTB&=~(1<<RCK);
16
}
Der µC ist ein ATtiny84.
CKDIV8 habe ich ausgeschaltet.
Peter Zz schrieb:> void SPI_Send_LL_Word(unsigned long long int Word)
Mach deinem AVR eine Freude und zwinge ihn nicht ...
> Word >>= 1;
... ständig 64 Bits durch die Gegend schaufeln zu müssen, bzw. ...
> if (!(Word & 0x01))
... mit 64 Bit hantieren zu müssen, wenns nicht sein muss.
einen unsigned long long kann man in 2 unsigned long aufteilen, die
wiederum in 2 Stück unsigned int und die in 2 unsigned char.
Prseäntier ihm alles in mungerechten Happen in seiner Lieblingsgröße (8
Bit), dann läuft der auch zu Hochform auf.
- Wenn man das Problem in 8 bits zerlegen kann, würde sich eine
Hardware-SPI anbieten, falls möglich und vorhanden.
- Alternativ manuelles Loop-unrolling etwas mehr bringen
- Vielleicht auch mal die Code-Optimierung auf max. einstellen.
uC Writer schrieb:> Wenn man das Problem in 8 bits zerlegen kann, würde sich eine> Hardware-SPI anbieten, falls möglich und vorhanden.
Der Tiny84 hat USI in Hardware, da nun nacheinander 4 8bit Werte aus'm
64bit reinzupacken sollte ja kein Thema sein ;-)
Peter Zz schrieb:> mein C Programm ist sehr langsam.Peter Zz schrieb:> void SPI_Send_LL_Word(unsigned long long int Word)
Welcher Compiler?
Die 64 Bit Operationen sind beim AVR-GCC nur sehr unwillig
implementiert, sogar mit double wärst Du schneller.
Ab AVR-GCC 4.7. ist einiges gepimmt worden, aber ein Schnellläufer ist
64 Bit trotzdem nicht.
Nimm ein Byte-Array und der AVR läuft Dir davon.
Peter
Karl Heinz Buchegger schrieb:> Präsentier ihm alles in mungerechten Happen in seiner Lieblingsgröße (8> Bit), dann läuft der auch zu Hochform auf.
Ich möchte wetten, das long long ist vorher extra zusammengebastelt
worden (z.B. weil Arrays so kompliziert sind).
MfG Klaus
kopfkratzer schrieb:> Der Tiny84 hat USI in Hardware, da nun nacheinander 4 8bit Werte aus'm> 64bit reinzupacken sollte ja kein Thema sein ;-)
Hat da jemand ein Beispiel dafür wie man diese UZI anspricht?
Peter Zz schrieb:> Hat da jemand ein Beispiel dafür wie man diese UZI anspricht?
Bevor du jetzt eine neue Baustelle aufmachst, probiers doch erstmal in
Software aber Byteweise. Ist ja vielleicht schon schnell genug. Dein
Code passt ja schon fast. Für die Hardware brauchst du sowieso einzelne
Bytes.
MfG Klaus
Hi
>Hat da jemand ein Beispiel dafür wie man diese UZI anspricht?
Kleiner Tip: Bei ATMEL gibt es AppNotes:
AVR319: Using the USI module for SPI communication on tinyAVR and
megaAVR devices
MfG Spess
uC Writer schrieb:> - Wenn man das Problem in 8 bits zerlegen kann, würde sich eine> Hardware-SPI anbieten, falls möglich und vorhanden.
Ja.
> - Alternativ manuelles Loop-unrolling etwas mehr bringen
Quatsch.
> - Vielleicht auch mal die Code-Optimierung auf max. einstellen.
Unsinn.
Spess53 schrieb:> Kleiner Tip: Bei ATMEL gibt es AppNotes:>> AVR319: Using the USI module for SPI communication on tinyAVR and> megaAVR devices
Leider ist dort kein Code-Beispiel, weder in ASM noch in C
Peter Zz schrieb:> Leider ist dort kein Code-Beispiel, weder in ASM noch in C
Programmieren bedeutet nicht Codebeispiele abzuschreiben oder zu
kopieren.
Hast du denn mal ausprobiert statt dem unsigned long long ein unsigned
char array zu benutzen?
wenn man weiß, dass der Zustand von RCK immer 0 ist, kann man das auch
optimieren:
PINB = (1 << RCK); // toggle einmal
PINB = (1 << RCK); // toggle noch einmal
Vlad Tepesch schrieb:> wenn man weiß, dass der Zustand von RCK immer 0 ist, kann man das auch> optimieren:> PINB = (1 << RCK); // toggle einmal> PINB = (1 << RCK); // toggle noch einmal
Was soll das bringen? In beiden Fällen wird nur ein Assemblerbefehl
draus! Ebend ein sbi bzw. cbi.
Klaus schrieb:> uC Writer schrieb:>> - Wenn man das Problem in 8 bits zerlegen kann, würde sich eine>> Hardware-SPI anbieten, falls möglich und vorhanden.>> Ja.>>> - Alternativ manuelles Loop-unrolling etwas mehr bringen>> Quatsch.>>> - Vielleicht auch mal die Code-Optimierung auf max. einstellen.>> Unsinn.
Selbstverständlich bringt manuelles Loop unrolling etwas, macht aber aus
einem Käfer kein Ferrari.
Und wenn man nicht manuell "loop unrolled" macht es vielleicht der
Compiler, wenn Optimierungen einschaltet sind.
kopfkratzer schrieb:> Der Tiny84 hat USI in Hardware,
ehrlich gesagt, die USI habe ich bisher noch nicht so richtig
verstanden.
Meinem Verständis gibt man der die Daten und muss dann trotzdem selbst
für jedes Bit, was rausgesendet werden soll einen Befehl ausführen.
Von Parallelität also keine Spur. Der einzige Vorteil ist, dass es ein
klein wenig schneller ist, als Bitbanging, aber sonst ein ziemlich
verkrüppeltes Interface. Oder hab ich nur das Datenblatt nicht
verstanden?
Vlad Tepesch schrieb:> Meinem Verständis gibt man der die Daten und muss dann trotzdem selbst> für jedes Bit, was rausgesendet werden soll einen Befehl ausführen.
Nö,
man stellt ein ob's SPI oder TwoWire ist, definiert ob Master oder Slave
und dann beschickt man das Register und wartet bis die Hardware den Rest
erledigt hat, um ein neues Datum einzutragen.
Ist vergleichbar dem ADC im FreeRunningMode :-)
kopfkratzer schrieb:> Vlad Tepesch schrieb:>> Meinem Verständis gibt man der die Daten und muss dann trotzdem selbst>> für jedes Bit, was rausgesendet werden soll einen Befehl ausführen.>> Nö,> man stellt ein ob's SPI oder TwoWire ist, definiert ob Master oder Slave> und dann beschickt man das Register und wartet bis die Hardware den Rest> erledigt hat, um ein neues Datum einzutragen.> Ist vergleichbar dem ADC im FreeRunningMode :-)
Das sieht hier
[Beitrag "SPI mit Attiny84"]
aber anders aus. Hab' aber USI nie benutzt.
Vlad Tepesch schrieb:> Meinem Verständis gibt man der die Daten und muss dann trotzdem selbst> für jedes Bit, was rausgesendet werden soll einen Befehl ausführen.
Pro Bit sind es 2 Befehle und damit kommt man schon auf F_CPU/2 als
SPI-Takt.
Schneller ist das ATmega-SPI auch nicht. Nur etwas weniger Code (keine
16 Out-Befehle nötig).
Im Datenblatt steht auch ein Assembler-Beispiel, leicht auf C
umzuschreiben:
14.3.2 SPI Master Operation Example
Man muß natürlich trotzdem die lahmen "long long" Variablen vermeiden,
sonst frißt das die gesparte Zeit fast wieder auf.
Peter
Peter Dannegger schrieb:> Pro Bit sind es 2 Befehle und damit kommt man schon auf F_CPU/2 als> SPI-Takt.> Schneller ist das ATmega-SPI auch nicht. Nur etwas weniger Code (keine> 16 Out-Befehle nötig).
die SPI mag genauso langsam sein, aber die macht es nebenbei, während
mein Prozessor was anderes rechnet (zb die nächsten Daten
zurechtpopelt).
Spi ist quasi fire-and-forget, während die USI eher sowas wie betreutes
Wohnen ist.
>> Im Datenblatt steht auch ein Assembler-Beispiel, leicht auf C> umzuschreiben:> 14.3.2 SPI Master Operation Example
genau das kenne ich .
Vlad Tepesch schrieb:> Spi ist quasi fire-and-forget, während die USI eher sowas wie betreutes> Wohnen ist.
Der Spruch ist geil, den muss ich mir merken :)
MfG Dennis
Vlad Tepesch schrieb:> die SPI mag genauso langsam sein, aber die macht es nebenbei, während> mein Prozessor was anderes rechnet (zb die nächsten Daten> zurechtpopelt).
Diese freien 16 Zyklen bringens natürlich, das ist der absolute Turbo.
Im Ernst, das wirst Du kaum merken.
Und SPI als Interrupt kostet ja schon >20 Zyklen Prolog+Epilog, da wirds
also sogar langsamer.
Ein merkbarer Unterschied wäre erst, wenn das SPI gepuffert wäre, am
besten gleich 16 Byte.
Dann könnte man auch SPI-Slave machen, ohne daß der Master immer nach
jedem Byte lange Gedenkpausen einlegen muß.
Peter