Code Optimierung

Gast #4402374
Lesenswert?

Ich habe einen ATtiny45 der mittels SPI Daten gefüttert bekommt, die die 
zwei PWM ausgänge steuern. Da es zu Doppelbelegung der Pins kommen würde 
nutze ich nicht die SPI Hardware Schnittstelle sondern toggle in 
Software, der Controller hat eh nichts anderes zu tun. Der Bus sollte am 
Ende natürlich schnellstmöglich sein. Ich frage mich vor allem bei 
folgendem Code ob man die Erkennung des Endes der Übertragung nicht noch 
verbessern kann. Ganz allgemein: Geht es schneller, gibt es 
optimierungen?

(Ich nutze den Arduino als Programmer und daher die IDE zum 
programmieren)
1
void setup() {
2
  //Pins 2,3 and 4 are input ports
3
  //DDRB2 is ChipSelect
4
  //DDRB3 is MOSI
5
  //DDRB4 is CLK
6
  DDRB &= ~( (1<<DDB4) | (1<<DDB3) | (1<<DDB2) );
7
  //Pins 0 and 1 are Output ports for PWM
8
  DDRB |= (1<<DDB1) | (1<<DDB0);
9

10
  //Set up timer to fast PWM operation (both Channels)
11
  TCCR0A = (1 << COM0A1) | (1<< COM0B1) | (1 << WGM00) | (1<<WGM01);
12
  //Top at 0xFF, noPrescaler
13
  TCCR0B = (1<<CS00);
14
}
15

16
void loop() {
17
  //While CS is low
18
  SPI_loop:
19
  while( !(PINB & (1<<PINB2)) ){
20
    //Wait for a rising edge at clk
21
    while( !(PINB & (1<<PINB4)) ){
22
      //Check again for CS low (end of transmission detection)
23
      if( PINB & (1<<PINB2) ){
24
        goto SPI_loop;
25
      }
26
    }
27
    //Move MOSI bit to data  
28
    data <<= 1;    
29
    data |= ( PINB >> PINB3 ) & 1;
30
    //Wait for a falling edge at clk
31
    while( PINB & (1<<PINB4) ){}  
32
  }
33
  //Refresh PWM
34
  OCR0A = 128; //50% duty cycle
35
  OCR0B =  63; //25% duty cycle
36
  
37
}
Gast #4402393
Lesenswert?

Naja ich möchte den Bus natürlich so schnell wie möglich laufen lassen, 
wenn der Mikrocontroller jedoch gerade in der behandlung der if 
bedingung steckt während der Takt kommt hab ich momentan sorge das er da 
Bits nicht erwischt.

Ich habe es aber tatsächlich noch nicht ausprobieren können, dachte mir 
aber ich frag direkt doch mal die Profis um Fehler direkt aus der Welt 
zu schaffen.
Gast #4402397
Lesenswert?

Wenn der controller eh nix anderes tut, ist optimieren irgendwie 
unsinnig.

Es gibt aber schon dinge, die deinen code lesbarer machen würden..

Defines für die pinfunktionen statt bezeichner der pins nutzen.

Kein goto für so eine simple Funktion verwenden. Ein Break sollte es da 
tun..?

Mehr könnte man eh erst sagen wenn der code auch sinnvoll wäre, so 
passiert ja nix. Streng genommen wäre das was du gepostet hast ja 
komplett wegoptimierbar, weil nie verwendet....
Gast #4402419
Lesenswert?

Moin,

Du benutzt den Arduino, den Arduino Bootloader, die Arduino IDE. Gibt's 
eigentlich einen tieferen Sinn, warum du dann nicht auch die API von 
Arduino benutzt?

Erscheint mir irgend wie unlogisch.

Grüße
Gast #4402423
Lesenswert?

nicht“Gast“ schrieb:
> Du benutzt den Arduino, den Arduino Bootloader, die Arduino IDE. Gibt's
> eigentlich einen tieferen Sinn, warum du dann nicht auch die API von
> Arduino benutzt?
>
> Erscheint mir irgend wie unlogisch.



Naja die IDE benutze ich da ich keinen anderen Programmer für den Attiny 
habe. Aber sowas wie digitalRead/digitalWrite ist einfach viel langsamer 
als die direkten Zugriffe auf die Ports/Register. Und hier kommt es 
nunmal auf Geschwindigkeit an
Gast #4402427
Lesenswert?

Dennis schrieb:
> Naja die IDE benutze ich da ich keinen anderen Programmer für den Attiny
> habe. Aber sowas wie digitalRead/digitalWrite ist einfach viel langsamer
> als die direkten Zugriffe auf die Ports/Register. Und hier kommt es
> nunmal auf Geschwindigkeit an

Du sollst ja auch nicht SPI mit digitalRead/Write implementieren. Da 
gibt's bereits weint Klasse für. Die sollte schon schnell genug sein.
Gast #4402589
Lesenswert?

Dennis schrieb:
> Das goto fand ich auch unschön, mir fiel aber keine bessere Lösung für
> die Endbedingung ein.

Ich würde sogar eine extra Statusvariable einführen um das goto 
loszuwerden, denn mit goto sollte man nicht zurück springen, nur 
vorwärts. Zudem ist das Problem auch ohne goto ganz gut lösbar, daher 
würde ich es ersetzen.
Gast #4403023
Lesenswert?

Ich schrieb:
> denn mit goto sollte man nicht zurück springen, nur
> vorwärts.
Bitte Quelle oder kurze Erläuterung dazu angeben, oder ist das eher nur 
soetwas wie eine "urbane Legende"? Habe noch nirgendwoe gelesen / gehört 
das man mit goto nicht zurück springen sollte.
Der Ensatz von goto wird ja im allgemeinen in einer "strukturierten" 
Sprache wie C ja eher vermieden da es sich in 99,999999% der Fälle mit 
einer der Kontrollstrukturen ersetzen läßt.
#4403091
Lesenswert?

> Bitte Quelle oder kurze Erläuterung dazu angeben, oder ist das eher nur
> soetwas wie eine "urbane Legende"? Habe noch nirgendwoe gelesen / gehört
> das man mit goto nicht zurück springen sollte.

Ich kenne das so als Merksatz auch nicht, aber ich kann mir denken, wie 
es zustandekommt:

Normalerweise programmiert man strukturiert, sprich, man nutzt für 
Schleifen, Verzweigungen und try-catch-finally-Konstrukte immer die 
entsprechenden Strukturen der verwendeten Programmiersprache und nur 
dann evtl. ein goto, wenn die Programmiersprache die gefragte 
Kontrollstruktur nicht bietet.

C bietet gleich 3 Schleifenkonstrukte, womit der Bedarf für 
"zurückspringende" gotos nicht gegeben sein dürfte. C (und schlanke 
C++-Implementierungen ohne Exceptions, etwa auf µC) bietet kein 
try-catch-finally, damit ist ein legitimer Bedarf für vorwärtsspringende 
gotos da.
Gast #4403238
Lesenswert?

Sebastian L. schrieb:
> C bietet gleich 3 Schleifenkonstrukte, womit der Bedarf für
> "zurückspringende" gotos nicht gegeben sein dürfte. C (und schlanke
> C++-Implementierungen ohne Exceptions, etwa auf µC) bietet kein
> try-catch-finally, damit ist ein legitimer Bedarf für vorwärtsspringende
> gotos da.

Genau so ist es. Try catch Ersatz ist auch im Grunde der einzige 
Einsatz, wo man goto sinnvoll verwenden kann. Aber auch das kann man mit 
einem do{}while(0); und entsprechenden breaks eleganter lösen, da die 
Sprunggrenzen hier enger gesteckt sind nämlich nur genau an das Ende der 
Schleife. Wildes zurückspringen im Code verhindert im Allgemeinen nur 
eine saubere Lesbarkeit.
Gast #4404097
Lesenswert?

Ich schrieb:
> Aber auch das kann man mit
> einem do{}while(0); und entsprechenden breaks eleganter lösen

Wenn man dann auch noch Statusveriablen dafür benötigt, finde ich ein 
goto kürzer und damit lesbarer und eleganter.

Das mit den gotos nach vorne steht übrigens in den neueren MISRA-Regeln. 
Ich meine es war 2008?
Gast #4404315
Lesenswert?

avr schrieb:
> Das mit den gotos nach vorne steht übrigens in den neueren MISRA-Regeln.
> Ich meine es war 2008?

Stimmt, sind die MISRA 2012 Regeln:
Rule 15.2
The goto statement shall jump to a label declared later in the same 
function

Als Erklärung steht im Prinzip das oben genannte, dass Sprachkonstrukte 
genutz werden sollten statt goto.
Gast #4404951
Lesenswert?

Daniel A. schrieb:
> Ich hatte bisher erst einen Anwendungsfall für gotos nach oben,
> bei
> welchem ich diese nicht sinvoll ersetzen konnte, das war hier:
> https://github.com/Daniel-Abrecht/DPA-UCS/blob/5e5...
> zeile 555
>
> Ich denke gewisse Dinge lassen sich einfach nur mit gotos schön lösen.
Meiner Meinung nach ist das nachbilden von Exceptions so ein Fall aber 
auch das kann man wie unten mit do{...}while(0); umschiffen

Bin mir nicht sicher, ob es das gleiche tut aber auf die Schnelle kam 
das raus:
1
  DPAUCS_tcp_fragment_t** it = tcb->fragments.first;
2
  {
3
    do {
4
      do
5
      {
6
        if( chunck_len <= offset ){
7
          offset -= chunck_len;
8
          continue;
9
        }else{
10
          chunck_len -= offset;
11
          payload = (char*)payload + offset;
12
          offset = 0;
13
        }
14
        tcp_processDatas( tcb, payload, chunck_len );
15
      }
16
      while(0);
17

18
      if(!it){
19
        break;
20
      }else{
21
        it=(*it)->next;
22
      }
23
      if(it){
24
        payload = DPAUCS_getFragmentData(&(*it)->fragment);
25
        chunck_len = (*it)->fragment.size;
26
      }else{
27
        payload = last_payload;
28
        chunck_len = last_length;
29
      }
30
      continue; // Nicht nötig
31
    }
32
    while(1);
33
  }
Gast #4405001
Lesenswert?

Das ist nicht wirklich besser. Continue um eine do ... while(0) Schleife 
verlassen ist nicht wirklich gut lesbar. Da sollte eher ein break hin.

Ich finde das ist eher ein gutes Beispiel für Spaghetti-Code. Die 
meisten gotos kann man gut eliminieren. Ein unschönes break bleibt, wenn 
die Umformung stimmt.
1
DPAUCS_tcp_fragment_t** it = tcb->fragments.first;
2
      while(1)
3
      {
4
        if( chunck_len <= offset ){
5
          offset -= chunck_len;
6
        }else{
7
          chunck_len -= offset;
8
          payload = (char*)payload + offset;
9
          offset = 0;
10
          tcp_processDatas( tcb, payload, chunck_len );
11
        }
12

13
        if(!it)
14
          break;
15
        it=(*it)->next;
16
        
17
        if(it){
18
          payload = DPAUCS_getFragmentData(&(*it)->fragment);
19
          chunck_len = (*it)->fragment.size;
20
        }else{
21
          payload = last_payload;
22
          chunck_len = last_length;
23
        }
24
      }

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