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