Forum: Mikrocontroller und Digitale Elektronik C-Code optimieren


von Tarek T. (tarek_t)


Lesenswert?

Hallo,

ich habe einen AVR32UC3C0512C, der einen IR-Protokollstack über einen 
8-Bit Parallelbus anspricht. Im späteren Verlauf des Projektes wird der 
µController gewechselt (kleineres Package) bei dem die Pins dann zwar am 
selben Port hängen, aber wild verstreut (reicht von Pin 4 bis Pin 27). 
Nachdem die Kommunikation und alle Routinen grundsätzlich funktionieren, 
würde ich gerne die Geschwindigkeit der Lese- und Schreibroutinen 
erhöhen. Derzeit bin ich bei Übertragungsraten von 2,7 MBit/s von 
(theoretisch) maximalen 4 MBit/s. Nachfolgend der Code, den es zu 
optimieren gilt:
1
/* IPMS Controllerpins definieren */
2
#define GPIO_IPMS_DB0  AVR32_PIN_PD11
3
#define GPIO_IPMS_DB1  AVR32_PIN_PD12
4
#define GPIO_IPMS_DB2  AVR32_PIN_PD13
5
#define GPIO_IPMS_DB3  AVR32_PIN_PD14
6
#define GPIO_IPMS_DB4  AVR32_PIN_PD15
7
#define GPIO_IPMS_DB5  AVR32_PIN_PD16
8
#define GPIO_IPMS_DB6  AVR32_PIN_PD17
9
#define GPIO_IPMS_DB7  AVR32_PIN_PD18
10
11
...
12
13
uint8_t ipms_read_reg(uint8_t address)
14
{
15
  uint8_t data = 0;
16
  uint32_t temp_bitmask = 0;
17
18
  ...
19
20
  /* Pinzustände abfragen */
21
  temp_bitmask = AVR32_GPIO.port[IPMS_DB_PORT].pvr;
22
23
  /* Byte wieder zurecht biegen */
24
  if(temp_bitmask & (1 << (GPIO_IPMS_DB0 & 0x1F)))  data |= 1;
25
  if(temp_bitmask & (1 << (GPIO_IPMS_DB1 & 0x1F)))  data |= 2;
26
  if(temp_bitmask & (1 << (GPIO_IPMS_DB2 & 0x1F)))  data |= 4;
27
  if(temp_bitmask & (1 << (GPIO_IPMS_DB3 & 0x1F)))  data |= 8;
28
  if(temp_bitmask & (1 << (GPIO_IPMS_DB4 & 0x1F)))  data |= 16;
29
  if(temp_bitmask & (1 << (GPIO_IPMS_DB5 & 0x1F)))  data |= 32;
30
  if(temp_bitmask & (1 << (GPIO_IPMS_DB6 & 0x1F)))  data |= 64;
31
  if(temp_bitmask & (1 << (GPIO_IPMS_DB7 & 0x1F)))  data |= 128;
32
33
  ...
34
}

Wie kann ich hier Taktzyklen einsparen? Vor lauter Programmierarbeit, 
habe ich gerade keine Ideen mehr :) Vielleicht liegt es auch daran, dass 
es schon spät ist.....oder früh.

Gute Nacht und vielen Dank im voraus für eure Mühen

von ... (Gast)


Lesenswert?

Ist das eine datenbankspeicherplazbelegende Trollfrage, oder dein 
ernst??

Dein Bit0 fängt bei PinD11 an und Bit7 hört bei PinD18 auf. Durchweg.
du brauchst doch nur dein temp_bitmask um 11 bit nach unten verschieben 
und mit 0xff verunden.... fertig.

Du hast dir echt nichtmal eine Minute lang gedanken gemacht, wie man die 
Bitfummelei vereinfachen könnte, oder? :-( Das ist demütigend für jeden 
der hier antworten soll -.-

von Tarek T. (tarek_t)


Lesenswert?

> Im späteren Verlauf des Projektes wird der
> µController gewechselt (kleineres Package) bei dem die Pins dann zwar am
> selben Port hängen, aber wild verstreut (reicht von Pin 4 bis Pin 27).

Hier steht, dass es sich später nicht mehr so verhält wie im 
Codeschnipsel! Dass es zurzeit so geht, wie du es vorschlägst, ist mir 
klar.

von Rolf M. (rmagnus)


Lesenswert?

Tarek T. schrieb:
> Hier steht, dass es sich später nicht mehr so verhält wie im
> Codeschnipsel! Dass es zurzeit so geht, wie du es vorschlägst, ist mir
> klar.

Hier kann aber keiner in die Zukunft sehen und daher eher schlecht einen 
Vorschlag machen, wie Code, der später mal entstehen wird, optimiert 
werden könnte.

von Tarek T. (tarek_t)


Lesenswert?

Es geht mir auch eher um einen generellen Hinweis. Aber vielleicht 
sollte ich mal ein Beispiel reinstellen. Das momentane Design sieht 
folgende Pinbelegung vor:
1
  /* IPMS Controllerpins definieren */
2
  #define GPIO_IPMS_DB0  AVR32_PIN_PD11
3
  #define GPIO_IPMS_DB1  AVR32_PIN_PD13
4
  #define GPIO_IPMS_DB2  AVR32_PIN_PD14
5
  #define GPIO_IPMS_DB3  AVR32_PIN_PD21
6
  #define GPIO_IPMS_DB4  AVR32_PIN_PD27
7
  #define GPIO_IPMS_DB5  AVR32_PIN_PD28
8
  #define GPIO_IPMS_DB6  AVR32_PIN_PD29
9
  #define GPIO_IPMS_DB7  AVR32_PIN_PD30

von ein Gast (Gast)


Lesenswert?

Da es sich um 8bit handelt, würde ich die bytes per Tabelle übersetzen. 
Das sollte der uc3 ressourcentechnisch noch frei haben. Vermute ich mal.

mfg

von (prx) A. K. (prx)


Lesenswert?

ein Gast schrieb:
> Da es sich um 8bit handelt, würde ich die bytes per Tabelle übersetzen.
> Das sollte der uc3 ressourcentechnisch noch frei haben. Vermute ich mal.

Die Tabelle hat bei Bits 4..27 zusammen 24 Adressbits, benötigt also 
16MB. Müsste segmentiert werden, d.h. mindestens 2 Tabellen.

von (prx) A. K. (prx)


Lesenswert?

Tarek T. schrieb:
> Wie kann ich hier Taktzyklen einsparen?

Was kommt denn bisher hinten raus? Müsste sowas wie
  BLD  ...
  ORNE ...
sein, pro Bit.

Wird hier vielleicht keine grosse Rolle spielen, ist aber generell 
beachtenswert: Bei einer 32-Bit RISC-CPU sind lokale Variablen kleiner 
als 32 Bits summarum ineffizient.

von Peter D. (peda)


Lesenswert?

Tarek T. schrieb:
> Das momentane Design sieht
> folgende Pinbelegung vor:

Dann sind PD27..30 per Shift zu ermitteln und der Rest wie oben.
Das "& 0x1F" ist allerdings witzlos, es ergibt immer 0.

von Peter D. (peda)


Lesenswert?

A. K. schrieb:
> Bei einer 32-Bit RISC-CPU sind lokale Variablen kleiner
> als 32 Bits summarum ineffizient.

Merkbaren Overhead wird das kaum geben.
Wenn der Compiler erkennt, daß Bit 8..31 nicht geändert werden, wird der 
Code gleich groß sein.
Nur bei einem möglichen Überlauf wird er zum Schluß ein "& 0xFF" 
anfügen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tarek T. schrieb:

> Wie kann ich hier Taktzyklen einsparen?

Ist das denn ein reales Problem, daß der Code zu langsam ist?

Oder ein ästhetisches Problem mit der 8 Quellzeilen?

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

1
uint32_t  i = AVR32_GPIO.port[IPMS_DB_PORT].pvr;
2
Data = ((i >> 11) & 1) | ((i >> 12) & 6) | ((i >> 18) & 8) | ((i >> 23) & 0xF0);

von Achim M. (minifloat)


Lesenswert?

Johann L. schrieb:
> ein ästhetisches Problem
Vermute ich auch...

Tarek T. schrieb:
> /* Pinzustände abfragen */
Der Kommentar ist redundant. Wer sieht nicht, dass in der Folgezeile ein 
paar Pins eingelesen werden?

Tarek T. schrieb:
> /* Byte wieder zurecht biegen */
Das seh ich auch, dass da was zurechtgebogen-bitgefummelt wird.
Was ist der Zweck der Aktion?
Wenn dir das im Laufcode zu hässlich aussieht, schreib doch eine kleine 
Funktion, die dir das Pin-Einlesen/Zurechtbiegen erledigt. Oder eine 
Inline-Funktion oder ein Makro...

mfg mf

von MaWin (Gast)


Lesenswert?

> bei dem die Pins dann zwar am selben Port hängen, aber wild verstreut

Dann machst du ein mal einen Zugriff
1
temp_bitmask = AVR32_GPIO.port[IPMS_DB_PORT].pvr;
und codierst ein mal um
1
temp_bitmask = umcodier_tabelle[temp_bitmask];
dann sind die Bits dort wo du sie hinhaben willst.

Die Tabelle ist 256 Bytes lang,
du tauscht also die lange Laufzeit deines Programmstücks
1
if(temp_bitmask & (1 << (GPIO_IPMS_DB0 & 0x1F)))  data |= 1;
2
if(temp_bitmask & (1 << (GPIO_IPMS_DB1 & 0x1F)))  data |= 2;
3
if(temp_bitmask & (1 << (GPIO_IPMS_DB2 & 0x1F)))  data |= 4;
4
if(temp_bitmask & (1 << (GPIO_IPMS_DB3 & 0x1F)))  data |= 8;
5
if(temp_bitmask & (1 << (GPIO_IPMS_DB4 & 0x1F)))  data |= 16;
6
if(temp_bitmask & (1 << (GPIO_IPMS_DB5 & 0x1F)))  data |= 32;
7
if(temp_bitmask & (1 << (GPIO_IPMS_DB6 & 0x1F)))  data |= 64;
8
if(temp_bitmask & (1 << (GPIO_IPMS_DB7 & 0x1F)))  data |= 128;
gegen den Speicherplatz den die Tabelle benötigt
space vs. speed trade off
(die man übrigens von einem Hilfsprogramm erzeugen lässt,
bei viel RAM auch zu Beginn des Programms vom Programm
selbst erzeugen lassen kann
1
uint8_t umcodier_tabelle[256];
2
for(i=0;i<256;i++)
3
{
4
  temp_bitmask = i; data = 0;
5
  if(temp_bitmask & (1 << (GPIO_IPMS_DB0 & 0x1F)))  data |= 1;
6
  if(temp_bitmask & (1 << (GPIO_IPMS_DB1 & 0x1F)))  data |= 2;
7
  if(temp_bitmask & (1 << (GPIO_IPMS_DB2 & 0x1F)))  data |= 4;
8
  if(temp_bitmask & (1 << (GPIO_IPMS_DB3 & 0x1F)))  data |= 8;
9
  if(temp_bitmask & (1 << (GPIO_IPMS_DB4 & 0x1F)))  data |= 16;
10
  if(temp_bitmask & (1 << (GPIO_IPMS_DB5 & 0x1F)))  data |= 32;
11
  if(temp_bitmask & (1 << (GPIO_IPMS_DB6 & 0x1F)))  data |= 64;
12
  if(temp_bitmask & (1 << (GPIO_IPMS_DB7 & 0x1F)))  data |= 128;
13
  umcodier_tabelle[i] = data;
14
}

von Markus M. (Firma: EleLa - www.elela.de) (mmvisual)


Lesenswert?

@ MaWin
Bist Du Dir sicher, dass die umcodier_tabelle[] nicht doch besser 4GB 
groß sein sollte?

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:
> Merkbaren Overhead wird das kaum geben.

Je nach Quellcode kann das schon etwas ausmachen. Hier nicht unbedingt, 
was ich auch erwähnt hatte.

von (prx) A. K. (prx)


Lesenswert?

MaWin schrieb:
> Die Tabelle ist 256 Bytes lang,

Bei einem 32-Bit breiten Port eines AVR32 eher nicht. Und die später 
verwendeten Bits sind "wild verstreut (reicht von Pin 4 bis Pin 27)", 
was auf eine Spanne von 24 Bits rausläuft, also eine 16MB Tabelle.

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.