Speed of multiple I2C sensors

While working through some speed issues trying to read multiple I2C sensors I have come to some interesting findings.

The step up is NETMF 4.4 running on an STM32F405 sampling an ADXL355 3 axis accel, a MCP9803 temp sensor and a MS5637 pressure sensor.

The legacy code loop reading the sensors is maxing out at around 56 Hz which seems a little tardy.

After turning on Debug.EnableGCMessages(true); there was a glaring issue in that the GC was running like a ferret high on cocaine which was of course slowing down the reading of the sensors.

The code for the 3 sensors use the very handy AbstractI2CDevice class to help manage the multiple devices on the one bus. The issue is that the way it is written it creates a lot of GC calls.

Eg:

        public byte[] Read(byte addressToReadFrom, int responseLength = 1) 
        {
            var buffer = new byte[responseLength];
            I2CDevice.I2CTransaction[] transaction;
            transaction = new I2CDevice.I2CTransaction[]
            {
                I2CDevice.CreateWriteTransaction(new byte[] { addressToReadFrom }),
                I2CDevice.CreateReadTransaction(buffer)
            };
            int result = I2CBus.Execute(myConfig, transaction, Timeout);
            return buffer;
        }

Each Read creates new byte[]’s and int’s etc which makes the GC go wild.

So a quick change was to create a reusable xAction object

        public byte[] Read(byte[] addressToReadFrom, byte[] data)
        {
            xAction[0] = I2CDevice.CreateWriteTransaction(addressToReadFrom);
            xAction[1] = I2CDevice.CreateReadTransaction(data);

            I2CBus.Execute(myConfig, xAction, Timeout);
            return data;
       }

Now the interesting thing here is that the GC was now running only occasionally but was not releasing any resources – ie the output was always the same.

Hmm…

Calls to
I2CDevice.CreateWriteTransaction(addressToReadFrom);
and
I2CDevice.CreateReadTransaction(data);

Are the culprit which is interesting in that the GC doesn’t seem to do much with them but was running every 5-10 secs.

So….

Creating static I2CDevice.CreateWriteTransaction’s in each sensor driver and running

        public byte[] Read(I2CDevice.I2CTransaction[] xAction, int index = 1)
        {
            I2CBus.Execute(myConfig, xAction, Timeout);
            return xAction[index].Buffer;
        }

Causes zero calls to the GC

Net result?

Sensors are now running at 1200 Hz :blush:

8 Likes