Go Down

Topic: Casting data types in i2c code (Read 1 time) previous topic - next topic

dbfreq

Nov 11, 2013, 10:19 pm Last Edit: Nov 12, 2013, 05:18 am by dbfreq Reason: 1
Hi there, I'm trying to understand the code involved in reading and writing to a 24lc256 EEPROM chip via i2c. I'm use this code from http://www.hobbytronics.co.uk/arduino-external-eeprom:

Code: [Select]

#include <Wire.h>    

#define disk1 0x50    //Address of 24LC256 eeprom chip

void setup(void)
{
 Serial.begin(9600);
 Wire.begin();  

 unsigned int address = 0;

 writeEEPROM(disk1, address, 123);
 Serial.print(readEEPROM(disk1, address), DEC);
}

void loop(){}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{
 Wire.beginTransmission(deviceaddress);
 Wire.send((int)(eeaddress >> 8));   // MSB
 Wire.send((int)(eeaddress & 0xFF)); // LSB
 Wire.send(data);
 Wire.endTransmission();

 delay(5);
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
 byte rdata = 0xFF;

 Wire.beginTransmission(deviceaddress);
 Wire.send((int)(eeaddress >> 8));   // MSB
 Wire.send((int)(eeaddress & 0xFF)); // LSB
 Wire.endTransmission();

 Wire.requestFrom(deviceaddress,1);

 if (Wire.available()) rdata = Wire.receive();

 return rdata;
}


In it the variable eeaddress is defined as an unsigned int and set to 0. This variable is used to set the address in the EEPROM to write or read to. What I don't understand is why it is cast to an int when Wire.write is called? Why not define the eeaddress variable as int the first place?
Code: [Select]

Wire.beginTransmission(deviceaddress);
 Wire.send((int)(eeaddress >> 8));   // MSB
 Wire.send((int)(eeaddress & 0xFF)); // LSB
 Wire.send(data);
 Wire.endTransmission();

I've looked all over stackoverflow and can't seem to find an explanation that I understand, I'm a very novice programmer with a background in electronics. Can anyone enlighten me?

*edited for proper formatting of code examples!

nickgammon

See the smiley faces in your posted code?

Please use code tags.

Read this before posting a programming question
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

dbfreq

Woops, my bad! Thanks, I've edited my post.

nickgammon

Quote

What I don't understand is why it is cast to an int when Wire.write is called?


You mean Wire.send? That was what was in your code.

Anyway, Wire.write is the more modern form. I don't know why they would cast to an int as it takes a "byte" argument (uint8_t).

Code: [Select]

size_t TwoWire::write(uint8_t data)


This may help:

http://www.gammon.com.au/i2c
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

dbfreq

Yes, sorry, I am using Wire.write - the code I have copied from the page I linked to is outdated and has Wire.send.

Thanks, I have been looking at that page and will continue to try and puzzle it out.

dbfreq

Well, I've looked at it pretty extensively and I can't find a reason for that particular type casting. I've tried the program without the (int) casts and it still works, so it appears to be superfluous. If there were any reason in the first place it might be something to do with bitwise operations promoting the int variable to an unsigned int but given that the Wire.write function seems to automatically cast its arguments into 8 bit integers (a byte), well I don't see how that even matters. Also, I don't see how an EEPROM could have an -ve address so again, why cast it as an int... superfluous. I changed the code to use highByte and lowByte instead but if anyone can give a logical explanation for the int casting this in this example code I'd be interested to hear it. For what it's worth this works fine instead:

Code: [Select]

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((highByte(eeaddress)));   // MSB
  Wire.write((lowByte(eeaddress))); // LSB
  Wire.write(data);
  Wire.endTransmission();

  delay(5);
}

robtillaart

#6
Nov 13, 2013, 04:43 pm Last Edit: Nov 13, 2013, 04:48 pm by robtillaart Reason: 1
After reading this thread I saw that my I2C EEPROM class - http://playground.arduino.cc/Main/LibraryForI2CEEPROM - uses the same  (int) casting since its first version. I assume I picked it up from some other I2C example and never bothered.
I will make a note for a next version.

update:
The wire.h does contain a conditional section for the teensy which has an int as param and casts it to byte. So the int parameter might be something historical.
Code: [Select]
    void send(int n)                   { write((uint8_t)n); }
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

dbfreq

Yes, I haven't looked at the code for Wire.send - but given your update perhaps it is a hangover from that. BTW. Thanks for your i2c class mate, it really helped with my learning.

I will mention that the bitwise operation promoting an int to uint is not a given, that only happens when bitwising an int and a uint and none of the operations do that in the original code. I got confused by the '8' in the shift operation.

Go Up