Simple EEPROM read/write
ypapelis
Posts: 99
Shouldn't the following piece of code read/write bytes to the upper 32k of the EEPROM, provided it is a 64k EEPROM?
I am getting back 0xFFs, no matter what the address
I am getting back 0xFFs, no matter what the address
#include <propeller.h> #include <i2c.h> static I2C_COGDRIVER i2c; static I2C* pI2c; static int scl = 28; static int sda = 29; int EEPROM_Init() { pI2c = i2cOpen(&i2c, scl, sda, 400000); if ( pI2c == 0 ) { return -1; } return 0; } uint8_t EEPROM_ReadByte(int addr) { uint8_t data[2] = { (addr >> 8) + 0x80, addr & 0xFF }; uint8_t value; i2cWrite(pI2c, 0xA0, data, 2, 0); i2cRead(pI2c, 0xA1, &value, 1, 1); return value; } void EEPROM_WriteByte(int addr, uint8_t value) { uint8_t data[2] = { (addr >> 8) + 0x80, addr & 0xFF }; i2cWrite(pI2c, 0xA0, data, 2, 0); i2cWrite(pI2c, 0xA0, &value, 1, 1); }
Comments
The pI2c pointer is returned by the call to EEPROM_Init, which calls the i2c device driver initialization. The actual structure is inside the driver, so I don't think this is the problem.
Gotcha. If I had a dollar everytime I got caught with that one.
Being an educator myself, I appreciate what you are trying to do. However, I have been away from the propeller universe for a while working on numerous other projects (all involving numerous details and facts of their own) and my old mind shifts out data as new information is shifted in. A year ago I would probably be able to pick up on the nuance of your answer, but at this point I can't.
I have seen the header file and the ony thing I came up with is that I should not set the 'Read' bit myself. This didn't work. I quickly looked through the EEPROM data sheet and I think I am sending the right sequence to write (EEPROM device address sent by the driver, 2 byte address plus 0x8000 to hit the upper 64k; no stop sequence, followed by the byte to write); also tried sending all three bytes (upper addr, low addr, byte to write) in one i2cWrite sequence to avoid the repeated start of the second call. Similarly for the read. And I realize that I am not polling the eeprom after writes, but I am using pretty large delays between writes at this point.
I could load the spin code that works, check out the clock/data lines with the scope and then do the same for the C program to figure out the mistake, but was hoping for something quicker.
Also, if you're using the boot eeprom you should probably use the i2cBootOpen() function since some boards don't have pullups on the boot eeprom. The code in the boot version of the i2c driver actively drives both pins.
Unless I am missing something, 0xA0 is the address of the on-board eeprom, and I am positive that the board I am using has pull-ups so there is no need to drive the pins.
I'm able to use your read routine to fetch values from both 0x0000 and 0x8000 in a 64KB device. The values in address 0 of a previously programmed EEPROM should be 0x00, 0xb4, 0xc4, 0x04. If the upper 64KB of the EEPROM has never been programmed the values will be 0xff for address 0x8000+.
Can you verify the bytes at address 0,1,2,3 ?
Here's the read I ended up using after a bit. Notice i don't add 0x8000 to the address and use 0xA0 in both ID parameters.
Hi Jazzed,
I did confirm that bytes at 0, 1, 2, 3 come across correctly; code works for upper 32k also. It was the read code that did not work.
I compared what it does to the good-old i2cObject and realized that the C version of the i2cWrite routine sends the device address each time it is called, as a result all the 'data' has to be sent in one call, not two like I was doing earlier. The code below works now!
In case someone wants to use this code, keep in mind that the EEPROM_WriteByte function does not check if the EEPROM is ready to receive more data so fast sequential writes may fail. Lazy solution to that is to put delays after each write; proper solution is to check if the EEPROM is ready, by checking for the ack bit.
It would be nice to be able to avoid using a COG after using the i2c simply to read some config variables from the eeprom.
So this works:
but this does not
Another thought, is it possible to shutdown the i2c driver and free the cog? I can see which cogs are free before and which are free after and use cogstop to force the shutdown but I was wondering if there is a 'nicer' way to do that.
I have not used the code other than testing some examples.
Thanks,
David