How reliable is software I2C?

I was thinking… Let’s say you have a software I2C class that is purely written in managed code. How bulletproof can it be? Task scheduler can interrupt write or read transaction at any point in time and [em]lock[/em] (or [em]SyncLock[/em] in VB) is not going to help here. It seems to me there is no solution to this issue as long as you have more than one thread running simultaneously.

And now the interesting part. From 4.3, Gadgeteer offers software I2C support that is purely written in managed code. Therefore, you can use it when you are writing drivers for your modules.

GHI has its own software I2C class that is partially written in unmanaged code. Not only it should be much faster but it also should be much more reliable.

Should we avoid Gadgeteer software I2C and use GHI implementation instead?

Yes absolutely use ours, faster and more reliable… and we can fix if there are any issue. But I highly doubt there are issues as we have gone through it many times and fixed may issues in the past and we have not have any issues for months.

I like to add that the advantage of the managed version is that you can change it to fit your needs and fix it yourself if there are any issues. Still, if your versions does the job then this is the right thing to do.

I agree, managed class gives you more flexibility. However, if it is not stable - what is the point of flexibility. For example, I have a function that reads some data from IC over I2C, processes it, writes some data back and repeats this sequence multiple times in a row. If this whole procedure exceeds 20ms (thread priority is set to Normal), thread execution will be paused and that could happen during data transfer over I2C and thus could lead to data corruption. Isn’t that right?

I do understand what are the pros and cons of software vs hardware I2C. What I was trying to argue is that Gadgeteer software I2C implementation cannot be reliable.

If I have some free time, I will do a test to prove or disprove my argument.

I use software I2C on the G400 as the hardware one is not stable yet.

I have a data logger that samples analog inputs (8 of them) as fast as I can in a separate thread.

The I2C device is shared with the touch screen driver.

I’ve had units running non-stop for months with this system and no hang ups with the software I2C. Touch response is rock solid too.

@ Dave McLaughlin - Do you use your own I2C software implementation or one made by GHI or MS?

@ Dave McLaughlin - What do you mean by “I use software I2C on the G400 as the hardware one is not stable yet.” ?
Does it mean that some Exceptions raises which can stop whole application or it sometimes read wrongly etc.?
I am asking because my application (not completely finished yet) uses HW I2C on our G400 PCB for communication with I2C I/O expanders - PCF 8574. We do not use touch display.

Would it be possible(if we realize that the stability of HW I2C is not good enough) to use SW I2C on the same pins which are used for HW I2C?

Thanks.

There is details in the SDK release about it and there was some other chat about. I’ll need to look it up as it was some time ago.

I was using the hardware pins for it at first but it would fail a lot with errors so I switched to the software option using the same IO pins. Just make sure you don’t enable the hardware I2C in your code and software will.

I am doing some I2C stability and speed tests right now. I have made one interesting discovery.

When you see [em][MethodImpl(MethodImplOptions.InternalCall)][/em] you know that managed code is calling unmanaged code, right? So, just like with RLP calls, task scheduler cannot interrupt those calls, right? No!

When you call [em]Execute[/em] method within hardware I2C class, you are effectively calling unmanaged method. This call can be interrupted.


public int Execute(I2CDevice.I2CTransaction[] xActions, int timeout);

So, does this mean that at least in theory RLP calls could also be interruptable my managed code?

@ iamin - How did you discover it can be interrupted?

I was running 3 threads simultaneously. One was turning LED on for 20ms, one was turning it off for 20 ms and one was doing a huge data reading over I2C (in one instance) that was taking over 1 second to complete. I was expecting to see how LED stops blinking for 1 second during the period when data is being transferred, but it was not happening. And yes, the data I was receiving was not corrupted.

@ iamin - Are you sure it was only one call to Execute?

Yes, I am :slight_smile:

Private Const BytesToRead As Integer = 100000
Private ReadOnly ArrToFill(BytesToRead - 1) As Byte
Private ReadOnly XActions() As I2CDevice.I2CTransaction = {I2CDevice.CreateReadTransaction(ArrToFill)}

I2C_Hardware.Execute(XActions, 3000)

@ iamin - It looks like the I2C driver makes calls to allow the CLR to continue running. It sleeps while it waits for an I2C event. Not every native interop can wait like this so they block the system.

See line 120 inside MicroFrameworkPK_v4_3\CLR\Libraries\SPOT_Hardware\spot_hardware_native_Microsoft_SPOT_Hardware_I2CDevice.cpp

Very interesting. I am not C++ expert, could you please check how does SPI behave when you do large data transfers in one instance? Is it also not blocking?

@ iamin - SPI does not behave the same way, it looks like it’ll block.

What could it be? 8)

recursion in hardware ? :slight_smile:

I have completed my I2C testing. Actually, I have acquired all the needed data long time ago, but I have not found the time to write a summary.
I have tested hardware and both GHI and MS software I2C implementation. I will abbreviate those as HW, SW-GHI and SW-MS accordingly. I have used the following setup: I2C master - Cobra II, I2C slave - MSP430. When requested, I2C slave was sending a predefined sequence of bytes and I2C master was verifying that data. There were three simultaneous threads running on Cobra II, one of which was doing a constant I2C data reading. The other two consisted of infinite loops that were switching LED on and off. This way I had a visual indication whether I2C reading is blocking managed code or not. I was also testing if thread scheduling during data acquisition over I2C could introduce any data corruption.

[title]Speed[/title]I guess nobody will be surprised if I tell that hardware I2C was the fastest and SW-MS (implemented completely in managed code) was the slowest. But I bet at least some people will be amazed just how slow it was.

Cobra II running at 120 MHz and reading 50 kB of data in one instance:

  • Hardware (400 kHz): 1239 ms
  • Software-GHI: 6294 ms
  • Software-MS: 827172 ms

Same as above, but Cobra II is running at 60 MHz:

  • Hardware (400 kHz): 1284 ms
  • Software-GHI: 6416 ms
  • Software-MS: 1226988 ms

That is right - when Cobra II was running at 60 MHz the difference in speed between the fastest and slowest methods was 955 times!

[title]Other findings[/title]1. When you request to read 200 bytes of data from I2C slave device, but after reading 50 bytes I2C slave gets disconnected, the following happens: 51-200 bytes are filled with value 255 and you are not notified that some data could not be acquired. This behavior is shared between all three I2C implementations.

  1. When you request to read some data from I2C slave device and it is not working, you will be informed that requested data could not be acquired. This behavior is shared between all three I2C implementations. There is one thing to note here: unlike HW and SW-MS, SW-GHI will report that one byte was successfully acquired (the first byte will be 255 and all the rest will be 0). I guess it is a bug.

  2. When requested more than 80 bytes, SW-GHI correctly reads all the data but then notifies that only 80 bytes were acquired. I guess it is a bug.

  3. SW-GHI does not allow specifying whether to use internal pull-ups or not, while SW-MS does offer such an option. I believe this option would be handy because in some cases pull-ups could be already installed.

  4. SW-GHI is blocking managed code. I would like to be able to specify, whether to block it or not.

[line]
I would like GHI team to fix possible issues that I have listed under (2) and (3). I would also be happy if my suggestions (4) and (5) would be considered.

2 Likes