Fram I2C on Due

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
gigelavram
 
Posts: 3
Joined: Wed May 14, 2014 1:10 pm

Fram I2C on Due

Post by gigelavram »

Hello,
I can't seem to get the Fram I2C working on a Due. I just tested the same very unit on a Mega and works : so is not the unit.

Is it supposed to work with Due ?

I got a compilation error on Due : the AdaFruit_FRAM_i2C.cpp was looking for an util\delay.h. I commented out that #include and it compiled just fine, just does not work and gives a message saying "invalid manufacture id". I unplugged the fram altogether from the Due and I get the same error. The same library with that #include commented out works fine on Mega.

It such happens I have 4 small led matrix backpacks on the same Due (connected at the same time with the Fram) and those work fine. I actually need both the matrix and fram connected for the project. The addresses used by the matrix and fram are not overlapping so that should not be a problem IMO.

Any advice is much appreciated.

User avatar
Franklin97355
 
Posts: 23903
Joined: Mon Apr 21, 2008 2:33 pm

Re: Fram I2C on Due

Post by Franklin97355 »

Start by removing the backpacks and try again. If that does not work check to make sure the due can see and communicate to the i2c address.

User avatar
michaelmeissner
 
Posts: 1819
Joined: Wed Aug 29, 2012 12:40 am

Re: Fram I2C on Due

Post by michaelmeissner »

IIRC, the Due has 2 i2c buses. For whatever reason, the Arduino team decided to connect the upper left i2c pins to the 2nd bus. If you are using code that talks on i2c, it might be talking to the first i2c bus (pins 20/21 on the top right before the double row of pins). If you use Wire.<xxx>, it is the first i2c bus, while if you use Wire1.<xxx> it talks to the second i2c bus.

User avatar
gigelavram
 
Posts: 3
Joined: Wed May 14, 2014 1:10 pm

Re: Fram I2C on Due

Post by gigelavram »

Thank you for the responses.

I got it working now. For some reasons the check in the "AdaFruit_fram.begin" method does not work, but the actual read/write works just fine. That check in the begin method is asking for the Fram manufacture ID and contains some very special type of commands. Not clear how come that works on Mega and not on Due.
So I commented out that piece of code in the library and replaced it with a quick check : I write a random number at a location I'm not going to use, read it back and it matches I consider Fram was found and working.
So far it works as charm.
Thank you for the help.

User avatar
michaelmeissner
 
Posts: 1819
Joined: Wed Aug 29, 2012 12:40 am

Re: Fram I2C on Due

Post by michaelmeissner »

It may be due to poorly written code. As code gets ported to arm machines like the Due, DigiX, or Teensy 3.x, a frequent problem is trying to get a signed 16-bit number from i2c. The usual code looks something like.

Code: Select all

void Read_Accel()
{
  int i = 0;
  byte buff[6];
  
  Wire.beginTransmission(ACCEL_ADDRESS); 
  WIRE_SEND(0x32);  // Send address to read from
  Wire.endTransmission();
  
  Wire.beginTransmission(ACCEL_ADDRESS);
  Wire.requestFrom(ACCEL_ADDRESS, 6);  // Request 6 bytes
  while(Wire.available())  // ((Wire.available())&&(i<6))
  { 
    buff[i] = WIRE_RECEIVE();  // Read one byte
    i++;
  }
  Wire.endTransmission();
  
  if (i == 6)  // All bytes received?
  {
    // No multiply by -1 for coordinate system transformation here, because of double negation:
    // We want the gravity vector, which is negated acceleration vector.
    accel[0] = (((int) buff[3]) << 8) | buff[2];  // X axis (internal sensor y axis)
    accel[1] = (((int) buff[1]) << 8) | buff[0];  // Y axis (internal sensor x axis)
    accel[2] = (((int) buff[5]) << 8) | buff[4];  // Z axis (internal sensor z axis)
  }
  else
  {
    num_accel_errors++;
    if (output_errors) Serial.println("!ERR: reading accelerometer");
  }
}
The three lines with << (left shift) are a problem. Under AVR systems, int is a 16-bit type, while under ARM systems int is a 32-bit type. If you shift a byte value left 8 bits, or it in with another value, and store the result in an integer, you could get a rather large number on ARM instead of a negative number. The code in question should use an explicit int16_t cast:

Code: Select all

    accel[0] = (int16_t)((buff[3] << 8) | buff[2]);  // X axis (internal sensor y axis)
    accel[1] = (int16_t)((buff[1] << 8) | buff[0]);  // Y axis (internal sensor x axis)
    accel[2] = (int16_t)((buff[5] << 8) | buff[4]);  // Z axis (internal sensor z axis)
Or possibly:

Code: Select all

    accel[0] = (((signed char) buff[3]) << 8) | buff[2];  // X axis (internal sensor y axis)
    accel[1] = (((signed char) buff[1]) << 8) | buff[0];  // Y axis (internal sensor x axis)
    accel[2] = (((signed char) buff[5]) << 8) | buff[4];  // Z axis (internal sensor z axis)

User avatar
gigelavram
 
Posts: 3
Joined: Wed May 14, 2014 1:10 pm

Re: Fram I2C on Due

Post by gigelavram »

Below is the code from the Fram library I commented out :

Code: Select all

void Adafruit_FRAM_I2C::getDeviceID(uint16_t *manufacturerID, uint16_t *productID)
{
  uint8_t a[3] = { 0, 0, 0 };
  uint8_t results;
  Wire.beginTransmission(MB85RC_SLAVE_ID >> 1);
  Wire.write(i2c_addr << 1);
  results = Wire.endTransmission(false);
  Wire.requestFrom(MB85RC_SLAVE_ID >> 1, 3);
  a[0] = Wire.read();
  a[1] = Wire.read();
  a[2] = Wire.read();
  /* Shift values to separate manuf and prod IDs */
  /* See p.10 of http://www.fujitsu.com/downloads/MICRO/fsa/pdf/products/memory/fram/MB85RC256V-DS501-00017-3v0-E.pdf */
  *manufacturerID = (a[0] << 4) + (a[1]  >> 4);
  *productID = ((a[1] & 0x0F) << 8) + a[2];
}

User avatar
michaelmeissner
 
Posts: 1819
Joined: Wed Aug 29, 2012 12:40 am

Re: Fram I2C on Due

Post by michaelmeissner »

The types look safe, because unlike the the 9DOF example I posted, they are dealing with unsigned integers. So you likely will need the help of somebody who has a better understanding of the i2c protocol.

User avatar
mccrashman
 
Posts: 8
Joined: Sat Jan 31, 2015 12:07 pm

Re: Fram I2C on Due

Post by mccrashman »

For some days now, i have the same problem. The I2C FRAM doesn't work as it should. I don't know where the problem is. So o took a closer look in the "getDeviceID" methode. As describe by the MB85RC256 manual, i can see the sequence for getting the device and manufacturer id. I can see the 0xF8 followd by the slave address. The the 0xF9 is send but a "NACK" is send from the slave. So there is nothing more read from the due.

I have attached a screenshot from my oscilliscope, so everyone can see, that there is a problem. I hope someone can give me a hint on how to solve the problem.

Arduino Version 1.5.8
Attachments
I2cFRAM.png
I2cFRAM.png (9.07 KiB) Viewed 1460 times

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Fram I2C on Due

Post by adafruit_support_mike »

I2C uses active-low signals, so a high voltage is a 0 and low voltage is a 1.

The pulses between the cursors represent the value 0x03 rather than 0xf9.

User avatar
mccrashman
 
Posts: 8
Joined: Sat Jan 31, 2015 12:07 pm

Re: Fram I2C on Due

Post by mccrashman »

If so, then there is a big mistake in Wikipedia which says that:
Physical layer

At the physical layer, both SCL and SDA lines are of open-drain design, thus, pull-up resistors are needed. Pulling the line to ground is considered a logical zero while letting the line float is a logical one. This is used as a channel access method. High speed systems (and some others) also add a current source pull up, at least on SCL; this accommodates higher bus capacitance and enables faster rise times.
http://en.wikipedia.org/wiki/I%C2%B2C

The code which produces these timing is from Adafruit (Adafruit_FRAM_I2C.cpp):

Code: Select all

void Adafruit_FRAM_I2C::getDeviceID(uint16_t *manufacturerID, uint16_t *productID)
{
  uint8_t a[3] = { 0, 0, 0 };
  uint8_t results;
  
  Wire.beginTransmission(MB85RC_SLAVE_ID >> 1); // 0xf8
  Wire.write(i2c_addr << 1); // 0x50
  results = Wire.endTransmission(false);

  Wire.requestFrom(MB85RC_SLAVE_ID >> 1, 3); // 0xf9
  a[0] = Wire.read();
  a[1] = Wire.read();
  a[2] = Wire.read();

  /* Shift values to separate manuf and prod IDs */
  /* See p.10 of http://www.fujitsu.com/downloads/MICRO/fsa/pdf/products/memory/fram/MB85RC256V-DS501-00017-3v0-E.pdf */
  *manufacturerID = (a[0] << 4) + (a[1]  >> 4);
  *productID = ((a[1] & 0x0F) << 8) + a[2];
}

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Fram I2C on Due

Post by adafruit_support_mike »

You're right.. I'd mixed the data signals up with the control and ACK signals.

I think the problem might be in the repeated-start condition in the middle of the screen. It looks to me like there's one rising edge too many after the chip ACKs the 0x50 address byte.

The pulse itself is a stop condition (rising edge on SDA while SCL is high) followed by a start condition (falling edge on SDA while SCL is high). I think the stop condition is what's throwing off the response. SDA should go high before SCL pauses.

Try using 0x51 for the control byte. That will let SDA go high again as soon as the chip releases the ACK, which should be on the falling edge of the 9th SCL pulse.

User avatar
mccrashman
 
Posts: 8
Joined: Sat Jan 31, 2015 12:07 pm

Re: Fram I2C on Due

Post by mccrashman »

I have digged a little bit deeper into this problem. As far as i can see now, the stop condition after device id is the problem. The second start corndition must be correct.

I have testet the procedure with an SAM4S Xplained board an the behavior is the same as with the Arduino Due. The stop condition is done by the i2c hardware. At this point i don't now how to change this behavior.

Code: Select all

void getFramDeviceID(uint16_t *manufacturerID, uint16_t *productID)
{
	uint8_t a[3] = { 0, 0, 0 };
	uint8_t results;
	twi_packet_t fram_packet;
	uint32_t twi_status;
  
	fram_packet.addr[0] = (fram_i2c_address[0]);
	fram_packet.addr_length = 1;
	fram_packet.chip = MB85RC_SLAVE_ID >> 1;
	fram_packet.length = 1;
	twi_status = twi_master_write(TWI_PORT, &fram_packet);

	fram_packet.addr_length = 0;
	fram_packet.chip = MB85RC_SLAVE_ID >> 1;
	fram_packet.buffer = a;
	fram_packet.length = 3;
	twi_status = twi_master_read(TWI_PORT, &fram_packet);

	/* Shift values to separate manuf and prod IDs */
	/* See p.10 of http://www.fujitsu.com/downloads/MICRO/fsa/pdf/products/memory/fram/MB85RC256V-DS501-00017-3v0-E.pdf */
	*manufacturerID = (a[0] << 4) + (a[1]  >> 4);
	*productID = ((a[1] & 0x0F) << 8) + a[2];
}
If i can solve the problem, i will post my sollution.

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Fram I2C on Due

Post by adafruit_support_mike »

The stop condition is probably generated automatically at the end of the twi function call.

Let me check with one of our Due experts to see if there's a way to generate a repeated start.

User avatar
mccrashman
 
Posts: 8
Joined: Sat Jan 31, 2015 12:07 pm

Re: Fram I2C on Due

Post by mccrashman »

A few tests later i can say, that i don't see any solution for this specific problem. I have done some more investigations with the SAM4 Xplained board and the FRAM module.

The ASF from Atmel has an function to read data from a slave with repeated start condition. This function "twi_master_read" works in the following steps:

- send start condition
- send chip id with write bit
- send address bytes (1 to 3)
- send a repeated start condition
- send chip id with read bit
- read requested amount of bytes
- send stop condition

This procedure works perfectly for reading any bytes within address space of the fram. But for the manufacturer and product id reading the FRAM sends a NACK after the address bytes which causes the TWI interface to send a stop condition and return with an error (NACK received).

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Fram I2C on Due

Post by adafruit_support_mike »

When you look at the waveforms, do you still get the stop condition before the repeated start?

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”