TinyCLR OS 2.2.0.5.1 Release Update

We squeezed in one more bug fix into the latest release. This refresh only updates the firmware. Everything else is in good standing. Be sure to update to the newest firmware.

Check out the release notes for details.

2 Likes

In this release I can`t use software i2c

var sda = GpioController.GetDefault().OpenPin(SC20260.GpioPin.PB9/*pin63*/);
var scl = GpioController.GetDefault().OpenPin(SC20260.GpioPin.PF9/*pin62*/);
try
{
    this.controller = I2cController.FromName(SC20260.I2cBus.Software, sda, scl, true);
}
catch (Exception ex)
{
    Debug.WriteLine(ex.Message);
}
    #### Exception System.NotImplementedException - 0x00000000 (1) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerSoftwareProvider::set_Timeout [IP: 0003] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cController::set_Timeout [IP: 0008] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cController::FromName [IP: 0019] ####
    #### GHIElectronics.TinyCLR.Devices.I2c.I2cController::FromName [IP: 0007] ####
    #### Tools.ADP5588::.ctor [IP: 005d] ####
    #### SK6_23.Program::Main [IP: 00de] ####
Exception: "System.NotImplementedException" in GHIElectronics.TinyCLR.Devices.I2c.dll
Exception was thrown: System.NotImplementedException

Did it work on 2.2.0.4200?

It work in 2.1.0.6400. I`m not test it on 2.2.0.4200

I tested software i2c on 2.2.0.4200 in other project - it also not work :frowning:

Hi, thanks. There are three options:

  1. Wait for us to fix
  2. If you know how to rebuild library, go I2c.cs, line 718, change to
public TimeSpan Timeout { get ; set ; }
  1. Or just use the the fixed below as external class
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.I2c.Provider;
using System;

namespace GHIElectronics.TinyCLR.Devices.I2c
{
    public class I2cControllerSoftwareProvider2 : II2cControllerProvider
    {
        private readonly bool usePullups;
        private readonly GpioPin sda;
        private readonly GpioPin scl;
        private byte writeAddress;
        private byte readAddress;
        private bool start;

        static string NotSupported = "Not supported.";

        public struct I2cTransferResult2
        {
            public I2cTransferStatus Status { get; }
            public int BytesWritten { get; }
            public int BytesRead { get; }

            public int BytesTransferred => this.BytesWritten + this.BytesRead;

            internal I2cTransferResult2(I2cTransferStatus status, int bytesWritten, int bytesRead)
            {
                this.Status = status;
                this.BytesWritten = bytesWritten;
                this.BytesRead = bytesRead;
            }
        }

        public event ErrorReceivedEventHandler ErrorReceived
        {
            add
            {
                throw new NotSupportedException(NotSupported);
            }

            remove => throw new NotSupportedException(NotSupported);
        }
        public event FrameReceivedEventHandler FrameReceived
        {
            add
            {
                throw new NotSupportedException(NotSupported);
            }
            remove
            {
                throw new NotSupportedException(NotSupported);
            }
        }

        public I2cControllerSoftwareProvider2(GpioPin sdaPin, GpioPin sclPin) : this(sdaPin, sclPin, true) { }

        public I2cControllerSoftwareProvider2(GpioPin sdaPin, GpioPin sclPin, bool usePullups)
        {
            this.usePullups = usePullups;

            this.sda = sdaPin;
            this.scl = sclPin;
        }

        public void Dispose()
        {
            this.sda.Dispose();
            this.scl.Dispose();
        }

        public void SetActiveSettings(I2cConnectionSettings connectionSettings)
        {
            if (connectionSettings.AddressFormat != I2cAddressFormat.SevenBit) throw new NotSupportedException();
            if (connectionSettings.Mode == I2cMode.Slave) throw new NotSupportedException();

            this.writeAddress = (byte)(connectionSettings.SlaveAddress << 1);
            this.readAddress = (byte)((connectionSettings.SlaveAddress << 1) | 1);
            this.start = false;

            this.ReleaseScl();
            this.ReleaseSda();
        }

        public I2cTransferStatus WriteRead(byte[] writeBuffer, int writeOffset, int writeLength, byte[] readBuffer, int readOffset, int readLength, out int written, out int read)
        {
            written = 0;
            read = 0;

            try
            {
                var res = this.Write(writeBuffer, writeOffset, writeLength, true, readLength == 0);

                written = res.BytesWritten;
                read = res.BytesRead;

                if (res.Status == I2cTransferStatus.FullTransfer && readLength != 0)
                {
                    res = this.Read(readBuffer, readOffset, readLength, true, true);

                    written += res.BytesWritten;
                    read += res.BytesRead;
                }

                this.ReleaseScl();
                this.ReleaseSda();

                return res.Status;

            }
            catch (I2cClockStretchTimeoutException)
            {
                return I2cTransferStatus.ClockStretchTimeout;
            }
        }

        private I2cTransferResult2 Write(byte[] buffer, int offset, int length, bool sendStart, bool sendStop)
        {
            if (!this.Send(sendStart, length == 0, this.writeAddress))
                return new I2cTransferResult2(I2cTransferStatus.SlaveAddressNotAcknowledged, 0, 0);

            for (var i = 0; i < length; i++)
                if (!this.Send(false, i == length - 1 && sendStop, buffer[i + offset]))
                    return new I2cTransferResult2(I2cTransferStatus.PartialTransfer, i, 0);

            return new I2cTransferResult2(I2cTransferStatus.FullTransfer, length, 0);
        }

        private I2cTransferResult2 Read(byte[] buffer, int offset, int length, bool sendStart, bool sendStop)
        {
            if (!this.Send(sendStart, length == 0, this.readAddress))
                return new I2cTransferResult2(I2cTransferStatus.SlaveAddressNotAcknowledged, 0, 0);

            for (var i = 0; i < length; i++)
                if (!this.Receive(i < length - 1, i == length - 1 && sendStop, out buffer[i + offset]))
                    return new I2cTransferResult2(I2cTransferStatus.PartialTransfer, 0, i);

            return new I2cTransferResult2(I2cTransferStatus.FullTransfer, 0, length);
        }

        private void ClearScl()
        {
            this.scl.SetDriveMode(GpioPinDriveMode.Output);
            this.scl.Write(GpioPinValue.Low);
        }

        private void ClearSda()
        {
            this.sda.SetDriveMode(GpioPinDriveMode.Output);
            this.sda.Write(GpioPinValue.Low);
        }

        private void ReleaseScl()
        {
            this.scl.SetDriveMode(this.usePullups ? GpioPinDriveMode.InputPullUp : GpioPinDriveMode.Input);
            this.ReadScl();
        }

        private void ReleaseSda()
        {
            this.sda.SetDriveMode(this.usePullups ? GpioPinDriveMode.InputPullUp : GpioPinDriveMode.Input);
            this.ReadSda();
        }

        private bool ReadScl()
        {
            this.scl.SetDriveMode(this.usePullups ? GpioPinDriveMode.InputPullUp : GpioPinDriveMode.Input);
            return this.scl.Read() == GpioPinValue.High;
        }

        private bool ReadSda()
        {
            this.sda.SetDriveMode(this.usePullups ? GpioPinDriveMode.InputPullUp : GpioPinDriveMode.Input);
            return this.sda.Read() == GpioPinValue.High;
        }

        private void WaitForScl()
        {
            const long TimeoutInTicks = 1000 * 1000 * 10; // Timeout: 1 second
            const long DelayInTicks = (1000000 / 2000) * 10; // Max frequency: 2KHz

            var currentTicks = DateTime.Now.Ticks;
            var timeout = true;

            while (DateTime.Now.Ticks - currentTicks < DelayInTicks / 2) ;

            while (timeout && DateTime.Now.Ticks - currentTicks < TimeoutInTicks)
            {
                if (this.ReadScl()) timeout = false;
            }

            if (timeout)
                throw new I2cClockStretchTimeoutException();

            var periodClockInTicks = DateTime.Now.Ticks - currentTicks;

            currentTicks = DateTime.Now.Ticks;

            while (DateTime.Now.Ticks - currentTicks < periodClockInTicks) ;
        }

        private bool WriteBit(bool bit)
        {
            if (bit)
                this.ReleaseSda();
            else
                this.ClearSda();

            this.WaitForScl();

            if (bit && !this.ReadSda())
                return false;

            this.ClearScl();

            return true;
        }

        private bool ReadBit()
        {
            this.ReleaseSda();

            this.WaitForScl();

            var bit = this.ReadSda();

            this.ClearScl();

            return bit;
        }

        private bool SendStart()
        {
            if (this.start)
            {
                this.ReleaseSda();

                this.WaitForScl();
            }

            if (!this.ReadSda())
                return false;

            this.ClearSda();

            this.ClearScl();

            this.start = true;

            return true;
        }

        private bool SendStop()
        {
            this.ClearSda();

            this.WaitForScl();

            if (!this.ReadSda())
                return false;

            this.start = false;

            return true;
        }

        private bool Send(bool sendStart, bool sendStop, byte data)
        {
            if (sendStart)
                this.SendStart();

            for (var bit = 0; bit < 8; bit++)
            {
                this.WriteBit((data & 0x80) != 0);

                data <<= 1;
            }

            var nack = this.ReadBit();

            if (sendStop)
                this.SendStop();

            return !nack;
        }

        private bool Receive(bool sendAck, bool sendStop, out byte data)
        {
            data = 0;

            for (var bit = 0; bit < 8; bit++)
                data = (byte)((data << 1) | (this.ReadBit() ? 1 : 0));

            var res = this.WriteBit(!sendAck);

            return (!sendStop || this.SendStop()) && res;
        }

        private class I2cClockStretchTimeoutException : Exception
        {

        }

        public int WriteBufferSize { get => throw new NotSupportedException(NotSupported); set => throw new NotSupportedException(NotSupported); }
        public int ReadBufferSize { get => throw new NotSupportedException(NotSupported); set => throw new NotSupportedException(NotSupported); }
        public int BytesToWrite => throw new NotSupportedException(NotSupported);
        public int BytesToRead => throw new NotSupportedException(NotSupported);

        public TimeSpan Timeout { get ; set ; }

        public void ClearWriteBuffer() => throw new NotSupportedException(NotSupported);
        public void ClearReadBuffer() => throw new NotSupportedException(NotSupported);
    }
}

usage: same, but here just in case.

var sda = GpioController.GetDefault().OpenPin(sdaPin);
var scl = GpioController.GetDefault().OpenPin(sclPin);

var provider = new I2cControllerSoftwareProvider2(sda, scl, true);

 var i2cControllers = I2cController.FromProvider(provider);
  1. Wait for us to fix

when will this be released

We are busy on different project for now. I guess a new release will be soon in next couple weeks.