Forum: Compiler & IDEs Avr-gcc Bitshift 32bit Variable geht nicht


von Philipp (Gast)


Lesenswert?

Hi,

ich bin dabei einen Fifo für den UART zu schreiben, der auch das 9. bit 
speichern kann. Um den RAM Verbrauch möglichst klein zu halten, sollen 
nicht einfach ein Array mit 16bit Variablen verwendet werden.

Ansatz: Da der Fifo nur 26 Zeichen speichern können soll, habe ich mir 
einfach eine 32bit Variable erstellt, und mit dem Index des jeweiligen 
Bytes im Fifo, kann dann in der 32bit Variable ausgelesen/geschrieben 
werden, ob das 9. bit gesetzt ist oder nicht.

Das funktioniert aber leider nicht so ganz.
1
typedef struct {
2
  uint8_t data[RINOBUS_FRAMELENGHT];
3
  uint32_t ninth_bit;
4
  uint8_t r_ptr,w_ptr;
5
  uint8_t pending;  
6
}t_fifo_rb;
1
int8_t
2
RinoBus_Fifo_Write(t_fifo_rb *fifo, uint16_t data)
3
{
4
  if(fifo->pending >= RINOBUS_FRAMELENGHT)
5
  {
6
    return -1;
7
  }
8
  
9
  fifo->w_ptr += 1;
10
  
11
  if(fifo->w_ptr >= RINOBUS_FRAMELENGHT)
12
  {
13
    fifo->w_ptr = 0;
14
  }
15
  
16
  fifo->data[fifo->w_ptr] = data;
17
  
18
  if(data & (1<<8))
19
  {
20
    fifo->ninth_bit |= (1<<fifo->w_ptr);
21
  }else
22
  {
23
    fifo->ninth_bit &= ~(1<<fifo->w_ptr);
24
  }
25
  
26
  fifo->pending += 1;
27
  
28
  return 1;  
29
}

Ich habe mir ein Testprogramm geschrieben:
Atmel Studio 6.2 im Simulator. Optimierung ausgeschaltet, aber keine 
Änderung bei aktivierter Optimierung.
1
for(uint8_t i=0;i<30;i++)
2
  {
3
    if((i%2) == 0)
4
    {
5
      ret[i] = RinoBus_Fifo_Write(&f,i|(1<<8));
6
    }else
7
    {
8
      ret[i] = RinoBus_Fifo_Write(&f,i);
9
    }
10
  }

Im Prinzip werden einfach die Zahlen 0-25 in den Fifo geschrieben und 
bei jeder geraden Zahl soll das 9. bit gesetzt werden.

Problem:
Ich habe das Programm Schritt für Schritt ablaufen lassen. Dass jedes 2. 
mal das 9. bit gesetzt werden funktioniert, aber sobald ich bei 16 bin, 
passiert nichts mehr. Also Bytes 16-31 kann ich nicht setzen. Es steht 
am Ende 0x00005555 in der Variable.
Wenn ich für jede ungerade Zahl das 9. bit setzen will, wird mit dem 15. 
bit auch bits 16-31 gesetzt. Ergebnis: 0xffffaaaa.

Es scheint so, als könnte ich auf Bits 16-31 nicht zugreifen, oder 
könnte das ein Fehler im Simulator sein?

Lg
Philipp

von Peter II (Gast)


Lesenswert?

Philipp schrieb:
> Also Bytes 16-31 kann ich nicht setzen

in C wird alles mit int gerechnet.

Und wie groß ist int auf dem avr? (16Bit)


1l<<fifo->w_ptr

sollte es beheben.

von Philipp (Gast)


Lesenswert?

Peter II schrieb:
> 1l<<fifo->w_ptr

Wenn du das so meinst, das gibt gar keine Änderung.
1
if(data & (1<<8))
2
  {
3
    fifo->ninth_bit |= (11<<fifo->w_ptr);
4
  }else
5
  {
6
    fifo->ninth_bit &= ~(11<<fifo->w_ptr);
7
  }

von sebi707 (Gast)


Lesenswert?

Im Beispiel von Peter steht 1L (<- kleines L hier), keine 11 (Elf). Das 
kleine L ist ein Literal und sorgt dafür, dass 1l den Typ long hat (der 
auf dem AVR 32bit groß ist) statt nur einem int.

von Philipp (Gast)


Lesenswert?

sebi707 schrieb:
> Im Beispiel von Peter steht 1L (<- kleines L hier), keine 11
> (Elf). Das
> kleine L ist ein Literal und sorgt dafür, dass 1l den Typ long hat (der
> auf dem AVR 32bit groß ist) statt nur einem int.

Ahhh mist. Nicht richtig drauf geachtet. Thx jetzt läufts.
Mich würde noch eure Meinung zu dieser Methode das 9. bit zu speichern 
interessieren. Und ob ihr vielleicht noch andere Ideen dazu habt.

von sebi707 (Gast)


Lesenswert?

Prinzipiell macht es schon Sinn nicht einfach Speicher zu verschenken. 
Die Implementierung ist allerdings etwas ungünstig, da der AVR nur 
maximal um 1 Bit shiften kann. Wenn der Shift also noch nicht im 
vornherein durch den Compiler ausgeführt werden kann (weil beide 
Operanden kostant sind) dann compiliert so etwas wie (1l<<fifo->w_ptr) 
zu einer Schleife die so oft durchlaufen wird wie geshifted wird.

Besser wäre daher eine Implementierung bei der man immer nur um ein Bit 
shifted. Allerdings fällt mir spontan keine Möglichkeit wie damit ein 
FIFO realisiert werden kann. (LIFO wäre einfach: Beim Hinzufügen von 
Elementen eins nach links shiften und neues Bit eintragen und beim 
Auslesen das erste Bit nehmen und alles eins nach rechts shiften).

Falls nicht noch jemand einen guten Einfall hat wie man einen FIFO mit 
Bits realisieren kann musst du dir wohl überlegen was dir wichtiger ist: 
Weniger Speicherverbrauch und dafür mehr Rechenaufwand oder umgekehrt.

von Philipp (Gast)


Lesenswert?

Mehr Rechenaufwand habe ich auch schon festgestellt. Der Disassemblierte 
Code ist ziemlich lang. Ich werde 2 Fifos mit jeweils 26 Bytes brauchen. 
Vielleicht macht es dann doch mehr Sinn, einfach 16bit Variablen zu 
nehmen.

von Peter D. (peda)


Lesenswert?

Ob sich der große Programmaufwand für nur 22 gesparte Byte SRAM auch 
lohnt?
Wie klein ist denn Dein AVR?

von Peter Z. (Gast)


Lesenswert?

1
unsigned long int fifo = 0;
2
3
4
5
if(Bit9)fifo != 0x00000001;
6
fifo <<= 1;
7
8
9
10
if(fifo & 0x04000000)     //Abfrage Bit26
So?

von Philipp (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Wie klein ist denn Dein AVR?

Es ist ein Atmega1284p mit 16k Ram. Genug Ram hat er eigentlich. Aber es 
handelt sich um einen Master eines RS485 Busses welcher erweiterbar sein 
soll. Also muss immer immer etwas Ram freibleiben.

Peter Zz schrieb:
> unsigned long int fifo = 0;
>
> if(Bit9)fifo != 0x00000001;
> fifo <<= 1;
>
> if(fifo & 0x04000000)     //Abfrage Bit26

Ob das weniger Leistung braucht bin ich mir nicht so sicher.

von Masl (Gast)


Lesenswert?

Du musst klar abwägen was dir wichtiger ist:

geringer RAM Verbrauch vs. geringe Rechenzeit + bessere Lesbarkeit
(ja, auch Lesbarkeit ist eine begrenzte Ressource)

Ich würde hier ganz klar auf einen 16-Bit Typen ausweichen.
Erweiterbarkeit hin oder her, wenn dir auf diesem Controller der RAM 
ausgeht ist mehr im Argen.
Dafür spricht auch, dass ein UART-FIFO gerne im Interrupt-Kontext 
befüllt wird. Da möchte man eher schnell fertig sein.

Außerdem, weisst du was es mit der premature optimization auf sich hat? 
:-)

von Peter D. (peda)


Lesenswert?

Philipp schrieb:
> Es ist ein Atmega1284p mit 16k Ram.

Dann sparst Du also damit gewaltige 0,13% RAM ein.
Da würd ich mir aber die Klimmzüge verkneifen und 16Bit je Zeichen 
nehmen.

Dieses Bitgehampel kostet nicht nur Haufen Code, sondern macht ihn auch 
unübersichtlich.
Nach ein paar Jahren stehst Du kopfschüttelnd davor und grübelst, was 
hab ich da nur verbrochen.

von Philipp (Gast)


Lesenswert?

Ich werde dann wohl erstmal die 16bit Typen nehmen. Sollte es wikrlich 
knapp mir Ram werden kann ich das immer noch ändern.

Masl schrieb:
> premature optimization

Nein das sagt mir nichts.

von Karl H. (kbuchegg)


Lesenswert?

Philipp schrieb:
> Ich werde dann wohl erstmal die 16bit Typen nehmen. Sollte es wikrlich
> knapp mir Ram werden kann ich das immer noch ändern.
>
> Masl schrieb:
>> premature optimization
>
> Nein das sagt mir nichts.

Donald. E. Knuth
"premature optimization is the root of all evil"
(vorzeitige Optimierung ist die Wurzel allen Übels)

von Falk B. (falk)


Lesenswert?


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.