Forum: Compiler & IDEs Block_Read be externem I2C-EEPROM


von Michael Z. (incunabulum)


Lesenswert?

Moin!

Ich versuche gerade, für ein externes I2C-Eeprom, block-read und 
block-write zu implementieren. Byteweises schreiben & lesen 
funktioniert. Nur hapert es jetzt am C :-)

So sieht es im Main aus:
1
u16 value = 16;
2
i2cEepReadBlock(eepAddr, 20, 2, &value);

Aufbauend auf den Methodendefinitionen der avr-libcs (eeprom_read_block 
+ write) sieht meine ReadBlock methode aus wie folgt:
1
void  i2cEepReadBlock(u08 i2cAddr, u32 memAddr, u16 sizebytes, void *pData) {
2
// I2C Kram + 1. Adresse setzen
3
for (u08  i = 0; i < sizebytes; i++) {
4
  u08 tmp = i2cReadDataByte(I2C_ACK);
5
  *pData[i] = tmp;
6
} 
7
i2cReadDataByte(I2C_NACK);
8
}

In der for-Schleife lese ich nacheinander (auto-increment mode) die 
entsprechenden Bytes. Diese sollen nun byteweise nacheinander in der 
Variable "value" im Main geschrieben werden.

Nur wie? Pointer sind nicht meine Stärke. Der Compiler meckert 
jedenfalls über "'void*' is not a pointer-to-object type". Und da muss 
ich zur Zeit noch passen...

cu, Michael


von Falk (Gast)


Lesenswert?

@ Michael Z. (incunabulum)

>Ich versuche gerade, für ein externes I2C-Eeprom, block-read und
>block-write zu implementieren. Byteweises schreiben & lesen
>funktioniert. Nur hapert es jetzt am C :-)

>So sieht es im Main aus:

>u16 value = 16;
>i2cEepReadBlock(eepAddr, 20, 2, &value);

>Aufbauend auf den Methodendefinitionen der avr-libcs (eeprom_read_block
>+ write) sieht meine ReadBlock methode aus wie folgt:

>void  i2cEepReadBlock(u08 i2cAddr, u32 memAddr, u16 sizebytes, void *pData) {
>// I2C Kram + 1. Adresse setzen
>for (u08  i = 0; i < sizebytes; i++) {
>  u08 tmp = i2cReadDataByte(I2C_ACK);
>  *pData[i] = tmp;
>}
>i2cReadDataByte(I2C_NACK);
>}

>In der for-Schleife lese ich nacheinander (auto-increment mode) die
>entsprechenden Bytes. Diese sollen nun byteweise nacheinander in der
>Variable "value" im Main geschrieben werden.

Na das ist ein wenig sinnlos, da kannst du ja gleich einzelne Bytes 
lesen und ausgeben. Der Sinn von Blockzugriffen ist ja, dass man mehrere 
Bytes transportiert. Und dazu reichen einfache variablen nciht aus, du 
brauchst ein Array.

u16 value[16];

Dann natürlcih der Aufruf mit

i2cEepReadBlock(eepAddr, 20, 2, value);

Ohne Adrerssoperator vor value, denn bei Arrays ist der Name bereits ein 
Zeiger!

>Nur wie? Pointer sind nicht meine Stärke. Der Compiler meckert

Na dann solltest du mal schleunigst die Grundlagen nachholen.

>jedenfalls über "'void*' is not a pointer-to-object type". Und da muss
>ich zur Zeit noch passen...

Du würfelst ja auch einiges durcheinander. Ein einfaches

pData[i] = tmp;

ist hier vollkommen ausreichend. Durch den Index wird schon 
referenziert.

Ausserdem hast du noch einen kleinen logischen Bug drin. Du musst
in der Schleife ein Byte weniger lesen als per Funktionsaufruf 
gefordert,

  for (u08  i = 0; i < (sizebytes-1); i++) {

damit dann der letzte Zugriff den I2C Bus abschliesst (mit NAK). Und 
dann natürlich ein STOP auf dem I2C Bus.


MFG
Falk

Nochmal alles auf einen Blick

//Main

u16 value[16];    // 16 Byte Array
i2cEepReadBlock(eepAddr, 20, 2, value);

void  i2cEepReadBlock(u08 i2cAddr, u32 memAddr, u16 sizebytes, void 
*pData) {
// I2C Kram + 1. Adresse setzen
for (u08  i = 0; i < (sizebytes-1); i++) {
  pData[i] = i2cReadDataByte(I2C_ACK);
}
i2cReadDataByte(I2C_NACK);
// I2C STOP
}








von Andreas K. (a-k)


Lesenswert?

pData[i] bringt bei void* auch net viel ein. Statt void* unsigned char* 
verwenden.

von Michael Z. (incunabulum)


Lesenswert?

Danke erstmal für das Feedback!

Ich geb zu, dass Beispiel ist nicht besonders klug gewählt...

@Falk:
Was ich will, ist beliebige (!) Daten über die BlockRead + Write 
Funktionen schreiben zu können. Also unter anderem auch long int, float, 
structs etc. So ähnlich wie hier: 
Beitrag "uint32_t aus eeprom lesen/schreiben"

Schau dir mal die avr-libc eeprom_block_read Signatur an. Daher auch 
mein Ansatz, u. a. ein u16 als Array von 2 Bytes zu handhaben.

Der Einwand hinsichtlich des I2C_NACK und I2C_STOP ist allerdings 
berechtigt.

@Andreas
Unsigned char hatte ich zuerst. Nur was mach ich, wenn ich ein Struct 
lesen + Schreiben will? Bei "unsigned char" als Pointer meckert der 
Compiler auch, wenn ich ein long int verwenden will.

Kurz,
ich will für beliebige Datenstrukturen beliebigen Typs einen Pointer auf 
das erste Byte erzeugen, diesen an die Methode übergeben und dort dann 
entsprechend interativ die einzelnen Bytes beschreiben.



cu, Michael

von Florian D. (code-wiz)


Lesenswert?

1
void  i2cEepReadBlock(u08 i2cAddr, u32 memAddr, u16 sizebytes, void *pData) 
2
{
3
 // I2C Kram + 1. Adresse setzen
4
 for (u08  i = 0; i < sizebytes; i++) {
5
   u08 tmp = i2cReadDataByte(I2C_ACK);
6
   ((u08 *)pData)[i] = tmp;
7
 }
8
 i2cReadDataByte(I2C_NACK);
9
}

Abgesehen davon, dass i2cAddr und memAddr nicht verwendet werden, sollte 
die Änderung in der Zuweisung aus Deinem void  nun ein u08  machen und 
pro Durchlauf ein u08 in pData schreiben.

Das muss aber Fehler und/oder Warnungen gehagelt haben, einem void * 
einen Wert zuzuweisen, da der Compiler nicht wissen kann, wie groß der 
Zieltyp ist.

von Michael Z. (incunabulum)


Lesenswert?

Florian Demski wrote:
> Abgesehen davon, dass i2cAddr und memAddr nicht verwendet werden, sollte
> die Änderung in der Zuweisung aus Deinem void  nun ein u08  machen und
> pro Durchlauf ein u08 in pData schreiben.

Mit ((u08 *)pData)[i] = tmp; funktioniert dies, wie ich es mir 
vorstelle. Im nachhinein auch verständlich, da ansonsten der Compilier 
nicht weiss, wie lange ein Datenblock ist.... muss man erstmal 
draufkommen.

Danke dir! Michael

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.