I2CBlocking other threads on timeout

I have a problem where a I2C timeout appears to block other threads.
I am using:
SC20100S Dev Rev C with
Firmware 2.1.0.6400
VS2019
TinyCLR OS Project System V 1.0.5139.0
'TinyCLR.Devices.I2c V2.1.0

I have created the smallest project that demonstrates the apparent problem.
There are two very simple threads:

 Thread_1 - I2C thread 
  while true
    Prints "Before Write"
    Writes a byte to I2C device
    Prints "After Write"
    Sleep 1000 mS
  
Thread 2
   While true
     Prints  "Print Thread - " + date and time
     Sleep 250 mS

With an I2C device connected (PCF8574T) this all works as expected. debug printout looking like

    I2C Before Write 
    I2C After Write 
    Print_Thread - 01/01/2021 00:00:26
    Print_Thread - 01/01/2021 00:00:26
    Print_Thread - 01/01/2021 00:00:26
    Print_Thread - 01/01/2021 00:00:26
    I2C Before Write 
    I2C After Write 
    Print_Thread - 01/01/2021 00:00:27
    Print_Thread - 01/01/2021 00:00:27
    Print_Thread - 01/01/2021 00:00:27
    Print_Thread - 01/01/2021 00:00:27
    I2C Before Write 
    I2C After Write ..................

If I disconnect the I2C device then the print sequence looks like below with the "Print Thread now only printing every two seconds.

I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:09
Print_Thread - 01/01/2021 00:00:09
Print_Thread - 01/01/2021 00:00:09
Print_Thread - 01/01/2021 00:00:09
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:11
Print_Thread - 01/01/2021 00:00:11
Print_Thread - 01/01/2021 00:00:11
Print_Thread - 01/01/2021 00:00:11
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:13
Print_Thread - 01/01/2021 00:00:13
Print_Thread - 01/01/2021 00:00:13
Print_Thread - 01/01/2021 00:00:13
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:15
Print_Thread - 01/01/2021 00:00:15
Print_Thread - 01/01/2021 00:00:15
Print_Thread - 01/01/2021 00:00:15

What appears to be happenning is the I2C blocks the “Print Thread” for the timeout period.

The code for the project is

using System;
using System.Diagnostics;
using System.Threading;
using GHIElectronics.TinyCLR.Devices.I2c;
using GHIElectronics.TinyCLR.Devices.Rtc;
using GHIElectronics.TinyCLR.Native;

namespace TinyCLR_I2C_Test
{
  class Program
  {
    static void Main()
    {
      //Setup Real Time Clock
      var rtc = RtcController.GetDefault();

      var MyTime = new DateTime(2021, 01, 01, 00, 0, 00);

      rtc.Now = MyTime;
      SystemTime.SetTime(MyTime);




      Thread Thread_1 = new Thread(I2C_Thread);
      Thread_1.Start();
     
      Thread Thread_2 = new Thread(Print_Thread);
      Thread_2.Start();

    }
    static void Print_Thread()
    { 
    

      while (true)
      {
        

        Debug.WriteLine("Print_Thread - " + DateTime.Now);
        Thread.Sleep(250);
      }
   
    }

      static void I2C_Thread()
    {
      try
      {
       
        byte device_address = 39;
        
        I2cDevice i2cDevice;
        I2cController i2cController = I2cController.FromName(GHIElectronics.TinyCLR.Pins.SC20100.I2cBus.I2c1);
        I2cConnectionSettings i2cConnectionSettings = new I2cConnectionSettings(device_address, 100_000);  // bus speed was 1_000

        i2cDevice = i2cController.GetDevice(i2cConnectionSettings);
        


        while (true)
        {
          Debug.WriteLine("I2C Before Write ");

          //write byte
          I2C_Write_Byte(ref i2cDevice, 0);
                   
          Debug.WriteLine("I2C After Write ");

          Thread.Sleep(1000);
        }
      }

      catch (System.Exception error)
      {
        Debug.WriteLine(error.Message);
      }

    }

    private static void I2C_Write_Byte(ref I2cDevice wb_i2c, byte byte_to_write)
    {
      try
      {
        //send byte
        wb_i2c.Write(new byte[] { byte_to_write });
      }
      catch
      {

      }
    }

  }
}

The complete debug output is

Create TS.

Loading Deployment Assemblies.

Attaching deployed file.

   Assembly: mscorlib (2.1.0.0)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Native (2.1.0.0)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Devices.I2c (2.1.0.0)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Devices.Gpio (2.1.0.0)  Attaching deployed file.

   Assembly: GHIElectronics.TinyCLR.Devices.Rtc (2.1.0.0)  Attaching deployed file.

   Assembly: TinyCLR_I2C_Test (1.0.0.0)  Resolving.

The debugging target runtime is loading the application assemblies and starting execution.
Ready.

'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'C:\Projects TinyCLR\I2C_Test\TinyCLR_I2C_Test\bin\Debug\pe\..\GHIElectronics.TinyCLR.Native.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'C:\Projects TinyCLR\I2C_Test\TinyCLR_I2C_Test\bin\Debug\pe\..\GHIElectronics.TinyCLR.Devices.Gpio.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'C:\Projects TinyCLR\I2C_Test\TinyCLR_I2C_Test\bin\Debug\pe\..\GHIElectronics.TinyCLR.Devices.I2c.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'C:\Projects TinyCLR\I2C_Test\TinyCLR_I2C_Test\bin\Debug\pe\..\GHIElectronics.TinyCLR.Devices.Rtc.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.dll' (Managed): Loaded 'C:\Projects TinyCLR\I2C_Test\TinyCLR_I2C_Test\bin\Debug\pe\..\TinyCLR_I2C_Test.exe', Symbols loaded.
The thread '<No Name>' (0x2) has exited with code 0 (0x0).
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:00
The thread '<No Name>' (0x1) has exited with code 0 (0x0).
Print_Thread - 01/01/2021 00:00:00
Print_Thread - 01/01/2021 00:00:00
Print_Thread - 01/01/2021 00:00:00
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:01
Print_Thread - 01/01/2021 00:00:01
Print_Thread - 01/01/2021 00:00:01
Print_Thread - 01/01/2021 00:00:01
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:02
Print_Thread - 01/01/2021 00:00:02
Print_Thread - 01/01/2021 00:00:02
Print_Thread - 01/01/2021 00:00:02
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:03
Print_Thread - 01/01/2021 00:00:03
Print_Thread - 01/01/2021 00:00:03
Print_Thread - 01/01/2021 00:00:03
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:04
Print_Thread - 01/01/2021 00:00:04
Print_Thread - 01/01/2021 00:00:04
Print_Thread - 01/01/2021 00:00:04
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:05
Print_Thread - 01/01/2021 00:00:05
Print_Thread - 01/01/2021 00:00:05
Print_Thread - 01/01/2021 00:00:05
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:06
Print_Thread - 01/01/2021 00:00:06
Print_Thread - 01/01/2021 00:00:06
Print_Thread - 01/01/2021 00:00:06
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:07
Print_Thread - 01/01/2021 00:00:07
Print_Thread - 01/01/2021 00:00:07
Print_Thread - 01/01/2021 00:00:07
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:08
Print_Thread - 01/01/2021 00:00:08
Print_Thread - 01/01/2021 00:00:08
Print_Thread - 01/01/2021 00:00:08
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:09
Print_Thread - 01/01/2021 00:00:09
Print_Thread - 01/01/2021 00:00:09
Print_Thread - 01/01/2021 00:00:09
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:11
Print_Thread - 01/01/2021 00:00:11
Print_Thread - 01/01/2021 00:00:11
Print_Thread - 01/01/2021 00:00:11
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:13
Print_Thread - 01/01/2021 00:00:13
Print_Thread - 01/01/2021 00:00:13
Print_Thread - 01/01/2021 00:00:13
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:15
Print_Thread - 01/01/2021 00:00:15
Print_Thread - 01/01/2021 00:00:15
Print_Thread - 01/01/2021 00:00:15
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:17
Print_Thread - 01/01/2021 00:00:17
Print_Thread - 01/01/2021 00:00:17
Print_Thread - 01/01/2021 00:00:17
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:19
Print_Thread - 01/01/2021 00:00:19
Print_Thread - 01/01/2021 00:00:19
Print_Thread - 01/01/2021 00:00:19
I2C Before Write 
    #### Exception System.Exception - CLR_E_TIMEOUT (3) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0027] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
    #### TinyCLR_I2C_Test.Program::I2C_Write_Byte [IP: 000f] ####
    #### TinyCLR_I2C_Test.Program::I2C_Thread [IP: 002c] ####
I2C After Write 
Print_Thread - 01/01/2021 00:00:21
Print_Thread - 01/01/2021 00:00:21
Print_Thread - 01/01/2021 00:00:21
Print_Thread - 01/01/2021 00:00:21
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:22
Print_Thread - 01/01/2021 00:00:22
Print_Thread - 01/01/2021 00:00:22
Print_Thread - 01/01/2021 00:00:22
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:23
Print_Thread - 01/01/2021 00:00:23
Print_Thread - 01/01/2021 00:00:23
Print_Thread - 01/01/2021 00:00:23
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:24
Print_Thread - 01/01/2021 00:00:24
Print_Thread - 01/01/2021 00:00:24
Print_Thread - 01/01/2021 00:00:24
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:25
Print_Thread - 01/01/2021 00:00:25
Print_Thread - 01/01/2021 00:00:25
Print_Thread - 01/01/2021 00:00:25
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:26
Print_Thread - 01/01/2021 00:00:26
Print_Thread - 01/01/2021 00:00:26
Print_Thread - 01/01/2021 00:00:26
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:27
Print_Thread - 01/01/2021 00:00:27
Print_Thread - 01/01/2021 00:00:27
Print_Thread - 01/01/2021 00:00:27
I2C Before Write 
I2C After Write 
Print_Thread - 01/01/2021 00:00:28
Print_Thread - 01/01/2021 00:00:28
The program '[5] TinyCLR application: Managed' has exited with code 0 (0x0).

It’s probably not blocking so much as the eating up all of the CPU time polling for data. WE had this happen on a version of our hardware with some IO that wasn’t connected, so I just went ahead and made a setting in the UI that turns off the function calls when the module isn’t being used.

Yes, during transaction, i2c will block other threads till return. I believe same for SPI as well.

Isn’t there a hardware interrupt for timeout on the I2C interface? Or does using hardware interrupts for that raise a whole lot of other complicated issues?

We can do that in the future.

Thanks @Dat_Tran - is it possible to adjust the timeout period?

I2C: Add timeout property in setting · Issue #1109 · ghi-electronics/TinyCLR-Libraries (github.com)