C Programm zu langsam

Gast #2894872
Lesenswert?

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
void SPI_Send_LL_Word(unsigned long long int Word)
2
{
3
  for(unsigned char I=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.
#2894884
Lesenswert?

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.
#2895011
Lesenswert?

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
Gast #2896163
Lesenswert?

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
Gast #2896167
Lesenswert?

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
#2896238
Lesenswert?

1
void SPI_Send_LL_Word(uint64_t Word)
2
{
3
  uint8_t* bytes = (uint8_t*)(&Word);
4
  uint8_t i= 6; // 48bits = 6byte
5
  for( ; i!=0; --i, ++bytes)
6
  {
7
    SPI_Send_Byte(*bytes);
8
  }
9
  PORTB |=  (1 << RCK);
10
  PORTB &= ~(1 << RCK);
11
}

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
#2896383
Lesenswert?

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.
#2896444
Lesenswert?

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?
Gast #2896485
Lesenswert?

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 :-)
#2896504
Lesenswert?

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.
#2896507
Lesenswert?

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
#2896649
Lesenswert?

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 .
#2896986
Lesenswert?

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

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