I2C pull-up resistors

Hi All,

I have got an evaluation board from Freescale for the MMA8453Q MEMS accelerator, datasheet here:

According to the datasheet, the pull-up resistors on the SCL/SDA I2C lines should be 4.7K whereas on the FEZ Domino which I am using, I understand them to be 2.2K. After wiring up the eval board to a bread board according to the schematic in the datasheet, I cannot communicate with it at all, and the only thing that is of any significant difference remaining is the pull-up resistors. Is there an easy way for me to increase the the value of the pull-up resistors on the FEZ Domino?

Thanks for your help.

I wouldn’t bother changing the resistors, 4.7K, 2.2K or even 1K should be fine!

-which pins on the domino are you using?
-what does not work?
-do you get exceptions?
-some code maybe?

If you call the doctor and just tell him you have pain, he won’t be able to tell you what drug to take.

No exceptions. Using the simplest code to read the device ID for example - this is just the code from the GHI Beginner’s book modified to read the “device ID” register:

//create I2C object
I2CDevice.Configuration con = new I2CDevice.Configuration(0x38, 400);
I2CDevice MyI2C = new I2CDevice(con);
//create transactions (we need 2 in this example)
I2CDevice.I2CTransaction[] xActions =
new I2CDevice.I2CTransaction[2];
// create write buffer (we need one byte)
byte[] RegisterNum = new byte[1] { 0x0D };
xActions[0] = I2CDevice.CreateWriteTransaction(RegisterNum);
// create read buffer to read the register
byte[] RegisterValue = new byte[1];
xActions[1] = I2CDevice.CreateReadTransaction(RegisterValue);
// Now we access the I2C bus and timeout in one second
// if no response
int i = MyI2C.Execute(xActions, 1000);
Debug.Print("Register value: " + RegisterValue[0].ToString());

All the code executes fine, I just don’t get any values back (both “i” and RegisterValue[0] are 0).

Oh and in answer to your question about the pins I am using Di2 and Di3 for I2C SDA/SCL respectively

I don’t think your code is right. (btw, use the code tag, makes your code readable)

From the datasheet:

[quote]
Single Byte Read

The Master (or MCU) transmits a start condition (ST) to the MMA8453Q, slave address ($1D), with the R/W bit
set to 0 for a write, and the MMA8453Q sends an acknowledgement. Then the Master (or MCU) transmits the address of the
register to read and the MMA8453Q sends an acknowledgement. The Master (or MCU) transmits a repeated start condition (SR)
and then addresses the MMA8453Q ($1D) with the R/W bit set to 1 for a read from the previously selected register. The Slave
then acknowledges and transmits the data from the requested register.[/quote]

Actually, there is a mistake in there, I am using slave address 0x1C (SA0 pin low), the rest of the code is as written. Are you advising that it was just the address that was wrong or also that I should issue the write and read transactions independently? I’ll try that now.

No, you can’t just send the address to the slave. The address byte is composed of 7 bits (the address) + 8 bit (0 for write, 1 for read)

[quote]
From the datasheet:

The next byte of data transmitted after START contains the slave address in the first 7 bits, and the eighth bit tells whether
the Master is receiving data from the slave or transmitting data to the slave.[/quote]

In order to read back a single byte, you have to send 3 bytes.
1- 0x38 (address with write bit set to 1)
2- 0x0D (Device ID)
3- 0x39 (address with write bit set to 0)

so you code has to be along the lines of:


//create I2C object
I2CDevice.Configuration con = new I2CDevice.Configuration(0x38, 400);
I2CDevice MyI2C = new I2CDevice(con);
//create transactions (we need 2 in this example)
I2CDevice.I2CTransaction[] xActions =
new I2CDevice.I2CTransaction[2];
// create write buffer (we need one byte)
byte[] RegisterNum = new byte[3] { 0x38, 0x0D, 0x39 };
xActions[0] = I2CDevice.CreateWriteTransaction(RegisterNum);
// create read buffer to read the register
byte[] RegisterValue = new byte[1];
xActions[1] = I2CDevice.CreateReadTransaction(RegisterValue);
// Now we access the I2C bus and timeout in one second
// if no response
int i = MyI2C.Execute(xActions, 1000);
Debug.Print("Register value: " + RegisterValue[0].ToString());

Hope that helps

Eric

Hi Eric

Thanks for your help. You are definitely on the right tracks, because after trying out your last post (it did not work), I found this bit of C code from the freescale web site (I don’t have a sample of the particular eval board this runs on, but no doubt it works)


/*********************************************************\
* IIC Read Register
\*********************************************************/
byte IIC_RegRead(byte address, byte reg)
{
  byte b;
  IICC_TX = 1;                                  // Transmit Mode
  IIC_Start();                                  // Send Start
  IIC_CycleWrite(address);                      // Send IIC "Write" Address
  IIC_CycleWrite(reg);                          // Send Register
  IIC_RepeatStart();                            // Send Repeat Start
  IIC_CycleWrite(address+1);                    // Send IIC "Read" Address
  b = IIC_CycleRead(1);                         // *** Dummy read: reads "IIC_ReadAddress" value ***
  b = IIC_CycleRead(1);                         // Read Register Value
  IIC_Stop();                                   // Send Stop
  return b;
}

Anyway, I tried to emulate the above as best I could with this:


 I2CDevice.Configuration con = new I2CDevice.Configuration(0x38, 400);
            I2CDevice MyI2C = new I2CDevice(con);


            I2CDevice.I2CTransaction[] xActions =
            new I2CDevice.I2CTransaction[4];

            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[2] { 0x38, 0x0D } );
            xActions[1] = I2CDevice.CreateWriteTransaction(new byte[1] { 0x39 });
 
            byte[] b = new byte[1];
            xActions[2] = I2CDevice.CreateReadTransaction(b);
            byte[] b2 = new byte[1];
            xActions[3] = I2CDevice.CreateReadTransaction(b);

            int i = MyI2C.Execute(xActions, 1000);
            Debug.Print("b value: " + b[0].ToString());
            Debug.Print("b2 value: " + b2[0].ToString());

That doesn’t work either - I get the impression I need to be as close to the C code as possible, in which case I need to be able to do a “I2C Repeat Start” which from what I can tell must be the same as a “Start” (of a transaction) which would also indicate that the final write and two reads must be in the same transaction for it to work?

Or have I lost the plot completely? ??? Seeing as the C# I2C constructs don’t allow multiple reads of the same register in one transaction as far as I can see, [italic]and[/italic] I cannot combine Write and Reads in the same transaction either it looks like I am on a hiding to nothing??!!

After reading [url]http://www.i2c-bus.org/repeated-start-condition/[/url] try this:


            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[1] { 0x0D } );
            xActions[1] = I2CDevice.CreateWriteTransaction(new byte[1] { 0x39 }); //This is the I2C Repeated Start (address + readbit)

and you had an typo, your second CreateReadTransaction needs to have b2 instead of b


            byte[] b = new byte[1];
            xActions[2] = I2CDevice.CreateReadTransaction(b);
            byte[] b2 = new byte[1];
            xActions[3] = I2CDevice.CreateReadTransaction(b2);


Thanks for catching the typo. Nope. Still no joy anyway. :frowning:

what if you try them in 1 writetransaction ?

Nope. Nothing. Trying all sorts of combinations right now - still dead.

did you tried reading the ack’s in between? Look at the first drawing (Single Byte Read) on page 20 of the datasheet. Try to recreate that as close as possible.

The ack appears to take place within the transaction and netmf I2C implementation does not provide facility for you to do this. I have learnt that the .net I2C interface does some stuff under the hood for you like set the 0/1 RW bit on the address when you do the “Create[R/W]Transaction” call since my last post, which would indicate that the original code I posted based on the sample int the GHI NETMF beginner book, being closest to correct, the problem I have now is how to do two reads in one transaction.

I think this:


/*********************************************************\
* IIC Read Register
\*********************************************************/
byte IIC_RegRead(byte address, byte reg)
{
  byte b;
  IICC_TX = 1;                                  // Transmit Mode
  IIC_Start();                                  // Send Start
  IIC_CycleWrite(address);                      // Send IIC "Write" Address
  IIC_CycleWrite(reg);                          // Send Register
  IIC_RepeatStart();                            // Send Repeat Start
  IIC_CycleWrite(address+1);                    // Send IIC "Read" Address
  b = IIC_CycleRead(1);                         // *** Dummy read: reads "IIC_ReadAddress" value ***
  b = IIC_CycleRead(1);                         // Read Register Value
  IIC_Stop();                                   // Send Stop
  return b;
}

Is functionally equivalent to this:


            I2CDevice.Configuration con = new I2CDevice.Configuration(0x1C, 400);       //7 bit address is 0x1C as per datasheet
                                                                                        //.NET does the rest during the R/W calls
            I2CDevice MyI2C = new I2CDevice(con);

            I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[2];
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[1] { 0x0D });   //Send IIC "Write" Address // Send Register

            byte[] b = new byte[1];
            xActions[1] = I2CDevice.CreateReadTransaction(b);   //Send Repeat Start //Send IIC "Read" Address // *** Dummy read: reads "IIC_ReadAddress" value ***

            int i = MyI2C.Execute(xActions, 1000);
            Debug.Print("b value: " + b[0].ToString());



Except that at the end, only one read is done where two is needed. Creating a new ReadTransaction would issue another I2C Repeat Start so that does not work either. So far this is what I have deduced and unless I have low-level access to the I2C bus via RLP or something I’m stuffed I think.

I’m not following what your actually trying to accomplish. Are you just trying to read more than one byte per read? If so than just pass an array of size 2 in your CreateReadTransaction.

No, I am not trying to do a two byte read, I am trying to emulate what the C code from Freescale does. That code is part of their evaluation kit and works, but it looks like what it does cannot be emulated verbatim in c#. For brevity, here’s the code. Bear in mind that the device slave address is 0x1C 7bit. The 8bit slave address is either 0x38 for write and 0x39 for read- but all those gory details are done for us in the Create[R/W]Transaction calls in .NET:


/*********************************************************\
* IIC Read Register
\*********************************************************/
byte IIC_RegRead(byte address, byte reg)
{
  byte b;
  IICC_TX = 1;                                  // Transmit Mode
  IIC_Start();                                  // Send Start
  IIC_CycleWrite(address);                      // Send IIC "Write" Address
  IIC_CycleWrite(reg);                          // Send Register
  IIC_RepeatStart();                            // Send Repeat Start
  IIC_CycleWrite(address+1);                    // Send IIC "Read" Address
  b = IIC_CycleRead(1);                         // *** Dummy read: reads "IIC_ReadAddress" value ***
  b = IIC_CycleRead(1);                         // Read Register Value
  IIC_Stop();                                   // Send Stop
  return b;
}

Finally - if you’re interested, here’s the datasheet:

(See page 19 for the description of a single byte read)

But what are YOU trying to accomplish? Trying to do something exactly as it is done in C in C# seldom works out correctly; it is kind of like doing a literal translation between spoken languages (the result very seldome makes sense). It is usually better to try and port across the functionality not rewrite the same code in a different syntax.

Why does the function you list need to do two reads? Is it an artifact on how their I2C implementation works? Are you actually reading the register value when you do your read? If not what are you reading.

Have a look at the Software I2C ( [url]http://www.tinyclr.com/forum/1/1647/[/url] )
You can customize that to your needs.

Jeff Birt. If you read the thread you will see quite clearly what IIII am trying to do.