Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

One I2C write transaction split into 2


  • Please log in to reply
6 replies to this topic

#1 CThor

CThor

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationFremont California

Posted 15 January 2012 - 11:28 PM

Hello all, I'm having a snag with some I2C code that I wrote. I think my problems are related to an assumption that I have about what happens when I call I2CDevice.Execute(). I am hoping someone can clarify something for me. Lets say I build an I2CWriteTransaction with 2 bytes in the array. This I2CWriteTransaction instance is then used as the only element in the I2CTransaction array. I then pass the instance of the I2CTransaction to I2CDevice.Execute(). In short...I want 1 I2C write transaction to result in 2 consecutive bytes on the wire. It seems that 99% of the time, this is what happens, but every once and a while, I end up with 2 separate write transactions each with one byte. When this happens, the device I am talking to gets confused. This behavior seems to be taking place within the call to I2CDevice.Execute(). I've attached two pictures from my logic analyzer that shows the two behaviors. So, my question is should I expect this behavior and plan my interface code accordingly, or is there something I can do to get consistent behavior? In the picture of the expected behavior, my byte array is {0x9, 0xC4} and it's all transmitted in a single write transaction. In the unexpected behavior, my byte array is {0x9, 0xC0}, but as you can see, two write transactions resulted. In both cases, the call to I2CDevice.Execute() returned that it transmitted 2 bytes. Thanks for any help or feedback, -Chris On a different note, if you are ever looking for a good entry level USB logic analyzer, the Logic-16 from Saleae is AWESOME!! I used it to debug this issue. The attached pictures are from their software application.

Attached Files



#2 CThor

CThor

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationFremont California

Posted 18 January 2012 - 04:36 AM

Anybody able to add anything to this post? I could really use some help or feedback.

#3 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 18 January 2012 - 05:19 AM

Hello Chris. I'm having some difficulty (as you, however) to figure out where the problem actually is. The best thing you can do is posting some code, so that much more people can analyze it, and maybe test it. Also, please tell me what version of the firmware are you using: 4.1 or 4.2 beta? Cheers
Biggest fault of Netduino? It runs by electricity.

#4 CThor

CThor

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationFremont California

Posted 18 January 2012 - 06:16 AM

Hi Mario,

Thanks so much for replying. I have included a code snippet from the class and I have also attached the cs file that the class is defined in.

So, all the higher level public methods in my class call the following Write() method.

/// <summary>
        /// Attempts to write an array of command bytes on the I2C bus
        /// </summary>
        /// <param name="commands">A byte array of command bytes</param>
        private void Write(byte[] commands)
        {
            int transferred;
            I2CDevice.I2CTransaction[] transaction = new I2CDevice.I2CTransaction[]
            {
                I2CDevice.CreateWriteTransaction(commands),
            };
            Monitor.Enter(this.criticalSection);
                this.GetBus();
                transferred = this.Execute(transaction);
                if (transferred != commands.Length)
                {
                    this.ReleaseBus();
                    throw new System.IO.IOException("Write transaction failed");
                }

                this.ReleaseBus();
            Monitor.Exit(this.criticalSection);
        }

The line in the above code transferred = this.Execute(transaction); is as follows.

/// <summary>
        /// Execute an I2C transaction on the bus.
        /// </summary>
        /// <param name="transaction">An array of I2CTransaction objects.</param>
        /// <returns>The number of bytes transferred.</returns>
        private int Execute(I2CDevice.I2CTransaction[] transaction)
        {
            int transferred = this.bus.Execute(transaction, 1000);
            return transferred;  
        }

A few more points:
-- The images in my original post both came from the same public method in my class calling the Write() method show above. -- Both calls pass in a 2 element byte array.
-- As you can see from the images, one transaction was as I expected... start>>commandByte>>byte1>>byte2>>stop.
-- The other image shows what I didn't expect...start>>commandByte>>byte1>>stop---start>>commandByte>>byte2>>stop.
-- The I2C device I am communicating with expects the sequential behavior, not the byte mode behavior.

All of the above is with 4.1 firmware.

Hope this helps and thanks again.
-Chris

Attached Files



#5 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 18 January 2012 - 12:54 PM

The behavior is quite strange. Is that repetitive? Or either looks as random? What if you change byte pattern?
Biggest fault of Netduino? It runs by electricity.

#6 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 18 January 2012 - 03:03 PM

So, my question is should I expect this behavior and plan my interface code accordingly, or is there something I can do to get consistent behavior?

I have not verified it on the hardware, but IMVHO the I2C write operation could be split in case a higher priority interrupt occurred. AT91SAM7X microcontroller has "Transmit Holding Register" (TWI_THR), which can hold [only] 1 byte, so it is not really possible to transfer multiple bytes at once ("transaction" is perhaps a little bit misleading here). According to the datasheet, "When no more data is written into the TWI_THR, the master generates a stop condition to end the transfer" - thus, if an interrupt occurs after transmitting the first byte and its processing suspends the I2C module for time long enough to detect there is "no more data written into the TWI_THR" register, the end of transfer is automatically generated; then when interrupt processing finishes and the I2C transaction is resumed, the second byte is written into TWI_THR register and a new I2C write sequence begins.

If you have control over the device, you might consider NACK-ing single byte write sequence, when the second byte is mandatory, master (Nedtuino) will get the exception and can re-transmit. Otherwise, you'd need to somehow avoid such interrupts, at least during the time I2C transmission is active - the question is, whether this is possible...

#7 CThor

CThor

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationFremont California

Posted 18 January 2012 - 06:00 PM

Hi CW2, Thanks for the explanation. It definitely seems in line with what I am seeing. Unfortunately, it complicates things. I guess the next question is if this behavior (and the ability to control it) is part of the I2C driver provided SecretLabs, or something even lower. Anyway, thanks again. You've put me on to something. It's going to be painful on my end, but I think I can write some code to deal with this. I'd rather deal with it at the driver level though...;-) Mario, Thanks again for your feedback. It definitely help kick start the discussion! -Chris




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.