RobTillaart/FRAM_I2C

Issues with FRAM's that use Page Addressing

nospamsam2011 opened this issue · 15 comments

Good day,

This is a great library, well done! That said, it does not work with a number FRAM devices that use page addressing such as those from Cypress/Infineon 24CLxx or the Fujistu MB85RCxx devices. To address this, I made some changes to your fram.cpp and fram.h files and they are attached. Effectively I created a private variable called _usesMemAddressPages that when set changes the _writeBlock and _readBlock functions to correctly access those FRAM devices that use page addressing.

To use, all one has to do is call the "setUsesAddressPages(true)" function and the appropriate page addressing I2C sequences are followed. If the "setUsesAddressPages" is not called then your original library functions like before.

Cheers,

Sam

ModifiedFramFiles.zip

Thanks for the issue, (and a solution)

Do you have links to the data sheets of Cypress/Infineon 24CLxx or the Fujistu MB85RCxx you used?
So I can understand the differences

Rob

@nospamsam2011
Have you tried to run FRAM32_MB85RC1MT_test.ino for the Fujistu MB85RCxx devices?


Can you tell which FRAM chips you actually tested? (as mem size affects protocol #bytes used.)


Wrt the code additions.

I do not understand why the following lines are in the code

line 420 FRAM.cpp     _wire->endTransmission();

line 50 FRAM.h        void     write8S2(uint16_t memaddr, uint8_t value);  
line 58 FRAM.h        uint8_t  read8S2(uint16_t memaddr);

The latter two have no implementation, not in the .h and not in the .cpp file

The first has no data to send so makes no sense to me.


A derived class might be a better solution:

  • no need to set the flag (as that is hard coupled with class)
  • would keep both classes small
  • does not affect existing code / performance

Opinion?

@nospamsam2011

Both _readBlock() / _writeBlock()

      DeviceAddrWithPageBits = _address | ((memaddr & 0x0700) >> 7);   <<<<<< should that not be 8?

      _wire->beginTransmission(DeviceAddrWithPageBits);
      _wire->write((uint8_t) (memaddr & 0xFF));    <<<<<<<<<  as here 8 bits are used...

Data sheet might provide the answer.

Good day Rob,

You are most welcome and sorry about the fram.h having function declarations that have been removed. I used these initially to verify that everything worked as expected and then cleaned up the code later. Attached are the files I am using.

The datasheets are also included too. The big difference in these FRAM devices is that they use page bits instead of an absolute memory address. The page bits are comprised of bits 3..1 of the lower nibble of the I2C address. They are not shifted by "8" because Bit 0 is reserved for the R/W# bit as part of the I2C process.

The result is that when setting the memory address of the FRAM device, only one I2C write is needed (after the I2C address... which now contains the memory address page bits). This is also true for reads too. Your library would write two bytes for the memory address... one byte for the upper nibble and one for the lower. This type of addressing will not work with many of the newer FRAM devices.

That said, the fram files I attached are what I am using and everything works perfectly. However, I never tested anything other than write8 and read8 functions and so more testing could be done.

I hope the above explains things, but the attached datasheets show the various I2C transactions that you can refer to.

Cheers,

Sam

ModifiedFramFiles2.zip

MB85RC16_DS501_00001_11v0_E-2329168.pdf
CYPR_S_A0011126722_1-3004838.pdf

OK thanks for the update,
I will dive into this, might take a few days to read the datasheets

What platform did you test? UNO, ESP32 8266 STM ?

@nospamsam2011

(as I do not have the hardware)
Can you check if getSize() works as expected or is it wrong by a factor X ?

Quick look in the Cypress shows no info.

Good day Rob,

My apologies for not being platform specific! For smaller projects I almost always use the ESP32 modules (pre-certified) with my own custom hardware... and so I forget that others use different platforms. For medium or larger projects I use the NXP RT family of processors that are amazing... but require a lot more support infrastructure... but clock around 600Mhz and the newer-ish RT1176's clock at 1GHz has also includes smaller processor clocking around 400 if I remember correctly... but I digress...

I did not check or verify any of the other functions... just the read8 and write8, as these are what I needed for a quick prototype/demo for a customer.

Cheers,

Sam

Good day again Rob,

I will check the other functions like manufacturer ID, etc and will report back later today with the results and any changes needed. The Cypress parts are on my hardware now, but also have the Fujitsu ones that I can try later today as well. I will also provide the exact part numbers of the ones I am using and have tried.

Cheers,

Sam

Hi Sam,

OK, now having some background information I shall give it some priority.

Did a quick code check and the write16() etc all call the _writeBlock() you patched. (read idem)
So I expect that all these functies work with the Cypress FRAM and your code.

As far as I can see the Cypress has no metadata read. So expect those to fail.

@nospamsam2011

MB85RC04_DS501_00057_1v0_E-2329111.pdf

Just downloaded another data sheet of an FRAM that uses another scheme - 9 bit addresses instead of 11
So those won't work with your enhanced code. (not difficult to make it work)

What I need to think of is how to include support for these different types of addressing.
Think your boolean flag needs to become an int.

drawback is that it adds to footprint of the library if one wants to integrate it all in one class.
So I propose making a derived class FRAM11 for the 11 bit addresses and an FRAM9.

90% of the class is identical, only the _readBlock and _writeBlock differs.
Should not be too difficult (I don't have hardware to test but that will comoe in time.)

Updating the readme is a bit more work I think.

(have to attend some other tasks)

@nospamsam2011

Hi Sam,

I redesigned the code of your proposal into a separate class named FRAM11 as that seems the way to go for the 24LC16
It allowed me to implement an easy fix for the getSize() and getSizeBytes() problems as the chip has no device info.

In the same effort I created FRAM9 class for the MB85RC04 which has a 9 bit address.

I created a develop branch - https://github.com/RobTillaart/FRAM_I2C/tree/develop -
This branch has two examples for testing the classes / device, to see if values written are also values read.

Can you please verify the FRAM11 class as you have hardware for that?
Please also test the example to verify the write/read code is working as it should.

The other metadata info does not works as it should, will be fixed in near future.

@nospamsam2011
Created Pull Request - #29 - to include FRAM11 and FRAM9 into the library.

@nospamsam2011

Good day again Rob,

I will check the other functions like manufacturer ID, etc and will report back later today with the results and any changes needed. The Cypress parts are on my hardware now, but also have the Fujitsu ones that I can try later today as well. I will also provide the exact part numbers of the ones I am using and have tried.

Cheers,

Sam

Any progress with testing?

@nospamsam2011
Merged PR and released 0.5.0

@nospamsam2011
Please note that PR #36 will fix an issue in getSize() for FRAM11 -
if the change introduces problems, please let me know.