Forum: Compiler & IDEs EEPROM auslesen - "lvalue required as unary '&' operand" Fehler


von Philipp W. (phiwa)


Lesenswert?

Moin Moin,

ich möchte einen AT90CAN128 MUC mit dem AVR Studeio 4 programmieren und 
dabei in einem Bootloader eine Variable im EEPROM speichern.

Teil der Bootloader.c
1
#include <avr/io.h>
2
#include <avr/eeprom.h>
3
#include <avr/boot.h>
4
5
6
#define EEPROM_SECTION  __attribute__ ((section (".eeprom")))
7
unsigned int  CAN_CONTROLLER_MASK_ID  EEPROM_SECTION  =  0x00000100;

Im eigentlichen Programm was ich aufflashe (beginnend nach der 
geschützten Bootsection) soll diese  Variable aus dem EEPROM gelesen 
werden und eine Variable mit dem Wert versehen werden.

Teil der Steuerung.c
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/signal.h>
4
#include <avr/eeprom.h>
5
#include <avr/boot.h>
6
7
8
int main(void)
9
{
10
// Maske aus EEPROM laden
11
unsigned int CAN_CONTROLLER_MASK_ID_FW  =  eeprom_read_byte((unsigned int*)&(CAN_CONTROLLER_MASK_ID));
12
CAN_CONTROLLER_MASK_ID = CAN_CONTROLLER_MASK_ID_FW; // unsigned int  CAN_CONTROLLER_MASK_ID  = 0x00000100; in Steuerung.h
13
}

in der Steuerung.h sollen weitere Defines mit der aus dem EEPROM 
geladenen Maske "zusammengebaut" werden
Folgendermaßen:
1
#define CONTROLLER_SWITCH_1_ON       (CAN_CONTROLLER_MASK_ID|0x00000001)

Dabei gibt der Compiler die Fehler aus:
1
../Steuerung.c:504:76: error: lvalue required as unary '&' operand
2
../Steuerung.c:505:25: error: lvalue required as left operand of assignment

Der Syntax der  eeprom_read_byte() ider doch so richtig oder?

: Bearbeitet durch User
von NurEinGast (Gast)


Lesenswert?

Verstehe ich nicht

Du schreibst ->

#define CAN_CONTROLLER_MASK_ID  0x00000100   in Steuerung.h

Und nun willst du dieser festen Zahl eine neue zuweisen ?

CAN_CONTROLLER_MASK_ID = CAN_CONTROLLER_MASK_ID_FW
ist ja
0x00000100 = CAN_CONTROLLER_MASK_ID_FW

hmmmm.


Und weiter oben willst Du die Adresse eine Zahl haben ?

&(CAN_CONTROLLER_MASK_ID)
ist ja
&(0x00000100 )

von Karl H. (kbuchegg)


Lesenswert?

Philipp Wagner schrieb:

> Im eigentlichen Programm was ich aufflashe

....


> #define  CAN_CONTROLLER_MASK_ID  0x00000100

das ist aber etwas vollkommen anderes!
Du solltest mal ein C-Buch lesen. ernsthaft!

Das hier legt keine Variable an bzw. definiert oder deklariert auch 
keine, sondern sorgt einfach nur dafür, dass der Präprozessor im Code 
den Text CAN_CONTROLLER_MASK_ID  duirch den Text 0x00000100 ersetzt.

Nach dem Präprozessor lauf, steht also in deinem Programm
1
  ... eeprom_read_byte((unsigned int*)&(0x00000100));
2
3
...
4
  0x00000100 = CAN_CONTROLLER_MASK_ID_FW;
5
...

und das das QUatsch ist, brauch ich wohl nicht extra zu betonen.
Genau das meint 'l-value'. Das 'l' steht für 'left' und gemeint ist 
damit der linke Teil in einer Zuweisung
1
   a = ausdruck;
a muss logischerweise etwas sein, was etwas speichern kann. Eine 
Variable zum Beispiel. 0x00000100 ist aber ganz sicher keine Variable. 
0x00000100  ist einfach nur eine Zahlenkonstante. Und der kann man 
nichts neues zuweisen. Genausowenig wie eine Zahlenkonstante keine 
Adresse im Speicher hat, die man mit & feststellen könnte. Eine 
Zahlenkonstante ist daher kein l-Value.


PS: Ich denke auch, dass du hier
1
unsigned int  CAN_CONTROLLER_MASK_ID  EEPROM_SECTION  =  0x00000100;
etwas machst, was du gar nicht beabsichtigt hast. Die Angabe 0x00000100 
ist der Initialiwert, den diese EEPROM Zelle haben soll. Sie ist NICHT 
die Adresse im EEPROM, an der diese Variable lokalisiert sein soll.
D.h. selbst wenn du deine syntaktischen Probleme ausräumst, wird nicht 
das passieren, was du dir vorstellst.

: Bearbeitet durch User
von Philipp W. (phiwa)


Lesenswert?

Ich hatte mich geirrt beim Tippen, in der Headerdatei  ist die
1
unsigned int  CAN_CONTROLLER_MASK_ID  = 0x00000100;
angelegt worden, nicht definiert.
Mir ist durchaus bewusst wozu die #define's da sind und das an dieser 
Stelle keine Sinn gemacht hätte.

In der EEPROM Sektion soll diese Variable genau diesen Wert haben
1
unsigned int  CAN_CONTROLLER_MASK_ID  EEPROM_SECTION  =  0x00000100;
Wie kann ich die Adresse der Variablen bestimmen, damit ich in der 
Steuerung.c den Inhalt der CAN_CONTROLLER_MASK_ID aus dem EEPROM 
(0x00000100) abrufen kann?

von NurEinGast (Gast)


Lesenswert?

Die Zeile
1
CAN_CONTROLLER_MASK_ID = CAN_CONTROLLER_MASK_ID_FW;
will direkt in das EEprom schreiben.
(unsigned int  CAN_CONTROLLER_MASK_ID  EEPROM_SECTION)

Das geht aber nicht direkt sondern mit eeprom_update_byte(..) und 
Konosorten.

von NurEinGast (Gast)


Lesenswert?

... ausserdem hast Du jetzt anscheinend Dein ursprüngliches Posting 
geändert.
Plötzlich steht da :
1
unsigned int  CAN_CONTROLLER_MASK_ID  = 0x00000100; in Steuerung.h
statt
1
#define CAN_CONTROLLER_MASK_ID  0x00000100   in Steuerung.h
vorher

Ist die CAN_CONTROLLER_MASK_ID jetzt plötzlich doch nicht mehr im EEPROM 
?
Ich geb's auf. Wenn sich die Vorgaben der alten Postings plötzlich 
ändern, dann wird der ganze Thread vollkommen unduchschaubar.

von Karl H. (kbuchegg)


Lesenswert?

NurEinGast schrieb:

>
1
unsigned int  CAN_CONTROLLER_MASK_ID  = 0x00000100; in 
2
> Steuerung.h
> statt
>
1
#define CAN_CONTROLLER_MASK_ID  0x00000100   in Steuerung.h 
2
>
> vorher

?
Den #define hab ich aus dem Kommentar herausisoliert.

Im Original war es immer schon eine Variable im Bootloader-Programm und 
(anscheinend) ein #define im eigentlichen Programm.

von Philipp W. (phiwa)


Lesenswert?

Karl Heinz schrieb:
> NurEinGast schrieb:
>
>>
1
unsigned int  CAN_CONTROLLER_MASK_ID  = 0x00000100; in
2
>> Steuerung.h
>> statt
>>
1
#define CAN_CONTROLLER_MASK_ID  0x00000100   in Steuerung.h
2
>>
>> vorher
>
> ?
> Den #define hab ich aus dem Kommentar herausisoliert.
>
> Im Original war es immer schon eine Variable im Bootloader-Programm und
> (anscheinend) ein #define im eigentlichen Programm.

Genau, weil ich mich vertippt habe, hab ich es geändert.

Im Bootloader-Programm ist eine Variable angelegt worden.
Im Steuerungsprgramm möchte ich diese Variable nur auslesen und damit 
neue Variablen zusammenstellen, in etwar so:
1
unsigned int CONTROLLER_SWITCH_1_ON   = (CAN_CONTROLLER_MASK_ID|0x00000001);
Mir ist aufgefallen, dass ich im Steuerungsprgramm dafür keine defines 
mehr nutzen kann, da die Werte auch nach dem compilieren geändert werden 
müssen.

Der Sinn hinter diesem Aufwand ist, dass ich die Bootloader in der 
CAN_CONTROLLER_MASK_ID  angepasst, nur einmal auf je einen 
Mikrocontroller aufflashe und später die Steuersoftware mittels bereits 
implementieretem Flashprogramm per CAN Bus flasche ohne jeweils im 
Steuerungsprogramm die IDs des jeweiligen Mikrocontrollers zu ändern.

von NurEinGast (Gast)


Lesenswert?

1
unsigned int  CAN_CONTROLLER_MASK_ID  EEPROM_SECTION  =  0x00000100; 
2
unsigned int  CAN_CONTROLLER_MASK_ID_FW;
3
unsigned int  CONTROLLER_SWITCH_1_ON;
4
5
CAN_CONTROLLER_MASK_ID_FW  =  eeprom_read_word(&CAN_CONTROLLER_MASK_ID);
6
CONTROLLER_SWITCH_1_ON     =  CAN_CONTROLLER_MASK_ID_FW | 0x0001;

geht nicht ?

Dabei muss die CAN_CONTROLLER_MASK_ID Variable im Hauptprogramm und im 
Bootloader halt auf der gleiche EeProm Speicherzelle liegen.



Noch ein paar Dinge :


- Du hast CAN_CONTROLLER_MASK_ID als unsigned int definiert ( 16 Bit )
- Dann willst Du sie mit 0x00000100 vorbelgen (32 Bit)
- Und Du willst die CAN_CONTROLLER_MASK_ID mit eeprom_read_byte() lesen 
( 8 Bit )

von Karl H. (kbuchegg)


Lesenswert?

Philipp Wagner schrieb:

> Im Bootloader-Programm ist eine Variable angelegt worden.

Davon wirst du Abstand nehmen müssen.
Denn oberste Priorität hat, dass in beiden Programmen immer dieselbe 
Speicherzelle benutzt wird. Die Adresse kennst du aber so nicht, bzw. 
kannst sie nicht einfach von einem Programm zum anderen übertragen.


In diesem Fall wirst du die Kontrolle über die Adresse komplett selber 
übernehmen müssen. Zumindest würde ich das so machen

D.h. die Variable wird als Variable aus dem Bootloader ausgebaut und 
durch eine ansonsten unbenutzte EEPROM Adresse ersetzt. Vorzugsweise am 
Ende des EEPROM, da der Linker (andere) Variablen von vorne beginnend im 
EEPROM allokiert und du nicht mit diesen kollidieren willst
1
// Adresse im EEPROM an der die Daten gespeichert sind
2
// der dort gespeicherte Wert ist als
3
// unsigned int aufzufassen
4
5
#define  CAN_CONTROLLER_MASK_ADDR ((unsigned int*)0xFE)  
6
                                                         
7
                                                         
8
9
10
...
11
12
13
  unsigned int CanControllerMask;
14
15
  CanControllerMask = eeprom_read_word( CAN_CONTROLLER_MASK_ADDR );
16
17
18
  ....
19
20
  eeprom_write_word( CAN_CONTROLLER_MASK_ADDR, CanControllerMask );
und das dann gleichermassen im Bootloader bzw. im Anwendungsprogramm zu 
benutzen.


Eine andere Möglickeit wäre es, eine eigene Linker-Section für diese 
Variable anzulegen und dann in beiden Programmen den Linker jeweils die 
Variable in genau diese Section vom EEPROM legen zu lassen.

: Bearbeitet durch User
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.