i2c c# documentation
Hello,
I'm trying to connect a distance sensor via the i2c bus to a metawearboard r pro. I'm having some trouble with the code, because the function mbl_mw_datasignal_read_with_parameters accepts only a signal and a pointer as arguments. I tried to use the c++ api, but I get a struct for the read-parameters. Unfortunately I'm not very familiar with c# coding, so I tried marshalling the struct into a pointer. Doing so I get an error message. It would be great if someone could help me! My code:
Param_ptr = new IntPtr();
I2C.ReadParameters read_params = new I2C.ReadParameters();
read_params.deviceAddr = 0x29;
read_params.registerAddr = 0x00;
Marshal.StructureToPtr(read_params, Param_ptr, true);
mbl_mw_datasignal_read_with_parameters(i2c_signal, Param_ptr);
I'm trying to connect a distance sensor via the i2c bus to a metawearboard r pro. I'm having some trouble with the code, because the function mbl_mw_datasignal_read_with_parameters accepts only a signal and a pointer as arguments. I tried to use the c++ api, but I get a struct for the read-parameters. Unfortunately I'm not very familiar with c# coding, so I tried marshalling the struct into a pointer. Doing so I get an error message. It would be great if someone could help me! My code:
Param_ptr = new IntPtr();
I2C.ReadParameters read_params = new I2C.ReadParameters();
read_params.deviceAddr = 0x29;
read_params.registerAddr = 0x00;
Marshal.StructureToPtr(read_params, Param_ptr, true);
mbl_mw_datasignal_read_with_parameters(i2c_signal, Param_ptr);
This discussion has been closed.
Comments
Now there are no error messages so it should work. Still there is a problem. I have to write to a register with the adress 0x208. If I'm correct this value exceeds the range of a byte, nevertheless the function mbl_mw_i2c_write only accepts bytes as register adress. Is there any way to extend the range of this function?
As you can see in the description of the quick setup guide, I have to write to register adresses that exceed the range of a byte.
https://www.pololu.com/product/2489/resources
template for my code, but I'm still having trouble with the read
function though. My read function looks like this:
public byte readReg(ushort reg)
{
var i2c_signal = mbl_mw_i2c_get_data_signal(cppBoard, 1, 0);
Fn_IntPtr i2cDataHandlerDelegate = new Fn_IntPtr(dataPtr =>
{
var data = Marshal.PtrToStructure<Data>(dataPtr);
byte value = Marshal.PtrToStructure<byte>(data.value);
ReadValue = value;
});
mbl_mw_datasignal_subscribe(i2c_signal, i2cDataHandlerDelegate);
byte regHigh = (byte)(reg >> 8);
byte regLow = (byte)reg;
byte[] val = { regLow };
I2C.ReadParameters read_params = new I2C.ReadParameters();
read_params.deviceAddr = i2caddress;
read_params.registerAddr = regHigh;
IntPtr i2cPointer = Marshal.AllocHGlobal(Marshal.SizeOf(read_params));
Marshal.StructureToPtr(read_params, i2cPointer, false);
mbl_mw_i2c_write(cppBoard, i2caddress, regHigh, val, 2);
mbl_mw_datasignal_read_with_parameters(i2c_signal, i2cPointer);
return ReadValue;
}
Is
there a more direct way to read the value of the register? I'm not sure
if I'm doing a mistake by marshalling the device and register address
into a pointer. On the other hand, the function
mbl_mw_datasignal_read_with_parameters only accepts pointers as values.
ReadValue
has been assigned a value by the time thereadReg
function is completed. Your function should not return until it has received the result ofmbl_mw_datasignal_read_with_parameters
.public byte readReg(ushort reg)
{
byte regHigh = (byte)(reg >> 8 & 0xFF);
byte regLow = (byte)(reg & 0xFF);
byte[] val = { regLow };
var i2c_signal = mbl_mw_i2c_get_data_signal(cppBoard, 2, i2caddress);
I2C.ReadParameters read_params = new I2C.ReadParameters();
read_params.deviceAddr = i2caddress;
read_params.registerAddr = regHigh;
IntPtr i2cPointer = Marshal.AllocHGlobal(Marshal.SizeOf(read_params));
Marshal.StructureToPtr(read_params, i2cPointer, false);
mbl_mw_i2c_write(cppBoard, i2caddress, regHigh, val, 2);
mbl_mw_datasignal_read_with_parameters(i2c_signal, i2cPointer);
i2cDataHandlerDelegate = new Fn_IntPtr(dataPtr =>
{
var data = Marshal.PtrToStructure<Data>(dataPtr);
byte value = Marshal.PtrToStructure<byte>(data.value);
ReadValue = value;
});
mbl_mw_datasignal_subscribe(i2c_signal, i2cDataHandlerDelegate);
return ReadValue;
}
I will try to rewrite my functions as asynchronous Tasks with results.
By the way I took a look on the new c# SDK and realised that the i2c connection (as well as many other things) is much easier to implement with this API. So I tried to rewrite my read and write function with this new API using the Tutorials as a Template.
By doing so I got this function(which by the way should by asynchronous):
public async Task<byte> readReg(ushort reg)
{
try
{
byte regHigh = (byte)(reg >> 8 & 0xFF);
byte regLow = (byte)(reg & 0xFF);
byte[] val = { regLow };
var serialPassthrough = metawear.GetModule<ISerialPassthrough>();
serialPassthrough.WriteI2C(i2caddress, regHigh, val);
byte[] result = await serialPassthrough.ReadI2CAsync(i2caddress, regHigh, 1);
Debug.WriteLine(result);
Debug.WriteLine(result[0]);
return result[0];
}
catch(Exception e)
{
Debug.WriteLine("Error in display click: " + e.Message);
return 0;
}
}
By using this Function I get an error message at the line:
byte[] result = await serialPassthrough.ReadI2CAsync(i2caddress, regHigh, 1);
telling: Reading i2c data timed out
I could rewrite my code using the new c# SDK, as long as my distance sensor works properly.
I have tried to implement the i2c communication for several weeks now, but there is still no result.
So I'm wondering if it is even possible to connect the pololu VL6180X to the MetaMotionR. Again if there is any advice you could give me on this issue in general (if there are other parts of the code that could be wrong) it would be great!
public async Task<byte> readReg(ushort reg)
{
try
{
byte regHigh = (byte)(reg >> 8 & 0xFF);
byte regLow = (byte)(reg & 0xFF);
byte[] val = { regLow };
var serialPassthrough = metawear.GetModule<ISerialPassthrough>();
serialPassthrough.I2C(i2caddress, 1);
serialPassthrough.WriteI2C(i2caddress, regHigh, val);
byte[] result = await serialPassthrough.ReadI2CAsync(i2caddress, regHigh, 1);
Debug.WriteLine(result);
return result[0];
}
catch(Exception e)
{
Debug.WriteLine("Error in display click: " + e.Message);
return 0;
}
}
var serialPassthrough = metawear.GetModule<ISerialPassthrough>();
byte[] result = await serialPassthrough.ReadI2CAsync(0x1c, 0x0d, 1);
Console.WriteLine("WHO_AM_I = " + result[0]);
I get two different types of error messages. Sometimes I get the message:
Exception thrown: 'System.TimeoutException:' in System.Private.CoreLib.ni.dll, as well as
System.TimeoutException: 'Reading i2c data timed out'.
Actually I get the same exception with the unchanged project freefall detector of the solution of the c# tutorial as well:
System.TimeoutException: 'Creating data processor timed out'
at the line:
await accelerometer.Acceleration.AddRouteAsync(source =>
source.Map(Function1.Rss).Average(4).Find(Threshold.Binary, 0.5f)
.Multicast()
.To().Filter(Comparison.Eq, -1).Log(data => System.Diagnostics.Debug.WriteLine("In FreeFall"))
.To().Filter(Comparison.Eq, 1).Log(data => System.Diagnostics.Debug.WriteLine("Not in FreeFall"))
);
Meanwhile, when using my older app, written entirely with the c++ API except the example code, (maybe there could be some interference while using both the c++ API and the c#SDK, even though there is no error when downloading both NUget Packages):
I get the error message:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
In the second case I tried to reference the byte[] result, but nevertheless I get the same error message again.
My MetaMotionR runs the latest firmware 1.3.3 and I'm using the Visual Studio 2017 Enterprise Edition with installed .NET framework 4.6.1 , 4.6.2 and 4.7 (so my c#compiler should support c# 7.0 features) and the Windows 10 SDK (10.0.15063.0) as required in the source code of your c# SDK
Still,
by just reading the first regiter I need from my distance sensor I got
the same error as before ('Reading i2c data timed out'):
var serialPassthrough = metawear.GetModule<ISerialPassthrough>();
byte[] result = await serialPassthrough.ReadI2CAsync(i2caddress, 0x024, 1);
Debug.WriteLine(result[0]);
So I assume that the Board cannot comunicate with the sensor?