Long version: tl;dr
I put together a quick and simple PCB for this ADC. Now I’m trying to get the code to work with it, but I’ve never worked with I2C directly. My initial coding attempts yield no return data from the first call.
I don’t want someone to write it for me, but to just provide some help in getting going.
If anyone is interested – either via email or here on the forum - I’d be very grateful.
I would also recommend grabbing a copy of the source code for one of the standard Gadgeteer I2C Modules like the Accelerometer and looking through that.
The module is MikroBus.NET based, but I would appreciate help to use it in .NETMF so I can use the chip elsewhere. I’m sure the logic is transferable.
This is what I came up thus far:
public ADC9(Hardware.Socket socket)
{
adc9 = new MBN_ADC9(socket, 0x035, Enums.ClockRatesI2C.Clock100KHz);
adc9.SetupADC();
}
const byte _address = 0x35;
public ADC9(Hardware.Socket socket, Byte address, ClockRatesI2C clockRateKHz)
{
try
{
// Checks if needed I²C pins are available. You can add other pins if needed.
Hardware.CheckPinsI2C(socket);
_socket = socket;
// Create the driver's I²C configuration
_config = new I2CDevice.Configuration(address, (Int32)clockRateKHz);
//TODO: implement the constructor here
}
// Catch only the PinInUse exception, so that program will halt on other exceptions
// Send it directly to the caller
catch (PinInUseException) { throw new PinInUseException(); }
}
var result = new Byte[1];
var actions = new I2CDevice.I2CTransaction[2];
actions[0] = I2CDevice.CreateWriteTransaction(new byte[] { (_address << 1) });
actions[1] = I2CDevice.CreateReadTransaction(result);
// Don't forget to use Hardware.I2CBus with the extension method, so that the configuration is correct
Hardware.I2CBus.Execute(_config, actions, 1000);
var retval = result[0];
This is an attempt to send the START.
retval had a value of 240; I should only be getting 1 acknowledgement bit in return.
@ mhectorgato. All MikroBusNet drivers are written in pure NETMF. So porting should not be an issue. However, the driver for the ADC Click is SPI based and not I2C. I do not know what MBN Driver that you selected to model your driver from, but this is probably not going to work.
scardinale - When I started VS, I selected the MBN I2C driver template. This isn’t for the ADC Click, but a custom board.
By standard .NETMF, I meant - I believe there are some helper/extension classes for I2C in MBN that wouldn’t directly be transferable. I’m probably mistaken.
Regardless, I still want to learn how to convert the datasheet into bits/bytes.
@ mhectorgato. The extension methods in the MBN Core Driver are simply wrappers around the NetMF I2C Bus and methods. You can simply use them with the methodology that you are comfortable with.
The I2C IC that you are using looks a little tricky but not impossible to master. However, it looks like an interesting IC and has loads of potential.
One thing obvious is that you have the I2C Clock speed wrong. Try with 400. From the datasheet.
High-Speed I2C-Compatible Serial Interface
400kHz Fast Mode
1.7MHz High-Speed Mode
@ scardinale - just now caught that (the speed) - thanks! I wanted to use this IC in another project, but wanted to simplify the board to learn it first. Then I noticed the ADC Click only has 4 channels.
To simplify things, I started a new Gadgeteer CerbBee project -
GTI.I2CBus i2c;
byte address = 0x035;
// This method is run when the mainboard is powered up or reset.
void ProgramStarted()
{
Socket socket = Socket.GetSocket(2, true, null, null);
byte[] val = new byte[1];
i2c = GTI.I2CBusFactory.Create(socket, 0x035, 400, null);
i2c.Write(new byte[] { (byte)(address << 1) });
var x = i2c.Read(val);
}
When I ran it I got 1 for x – is that the number of bytes read? val again is equal to 240.
First, if you are not going to create Gadgeteer module, why bother with Gadgeteer driver? I would go with pure NETMF implementation. If you are using hardware I2C: https://www.ghielectronics.com/docs/12/i2c
Second, there is a note on that page: “netmf i2cdevice configuration requires a 7-bit address! It set the 8th R/W bit automatically.”
However, looking at the sample code, how does one set the SCA/SCL pins?
Based on that code, I’ve come up with this (still in the Gadgeteet app):
byte address = 0x035;
// This method is run when the mainboard is powered up or reset.
void ProgramStarted()
{
I2CDevice.Configuration con = new I2CDevice.Configuration(address, 400);
I2CDevice MyI2C = new I2CDevice(con);
I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[2];
// create write buffer (we need one byte)
byte[] RegisterNum = new byte[1] { 105 };
xActions[0] = I2CDevice.CreateWriteTransaction(RegisterNum);
// create read buffer to read the register
byte[] RegisterValue = new byte[1];
xActions[1] = I2CDevice.CreateReadTransaction(RegisterValue);
if (MyI2C.Execute(xActions, 1000) == 0)
{
Debug.Print("Failed to perform I2C transaction");
}
else
{
Debug.Print("Register value: " + RegisterValue[0].ToString());
}
}
So based on the top table (in the attached image) - I want to read ADC4
So if I use an mCu that has multiple I2C buses (my Spider has 4 I ports), would I be able to select which one based on the code in Gadgeteer core - factor create code below?
Cpu.Pin reservedSclPin = socket.ReservePin(sclPin, module);
Cpu.Pin reservedSdaPin = socket.ReservePin(sdaPin, module);
Cpu.Pin nativeSclPin, nativeSdaPin;
HardwareProvider.HwProvider.GetI2CPins(out nativeSclPin, out nativeSdaPin);
// native implementation is preferred to an indirected one
if (reservedSdaPin == nativeSdaPin && reservedSclPin == nativeSclPin)
return new NativeI2CBus(socket, address, clockRateKhz, module);
else if (socket.I2CBusIndirector != null)
return socket.I2CBusIndirector(socket, sdaPin, sclPin, address, clockRateKhz, module);
else
return new SoftwareI2CBus(socket, sdaPin, sclPin, address, clockRateKhz, module);
edit — after re-reading it; it looks like it’s expecting only 1 set of pins to be the i2c pins. So then why are there 4 I sockets on my Spider? Are the others SoftwareI2C?
[quote=“mhectorgato”]So then why are there 4 I sockets on my Spider? Are the others SoftwareI2C?
[/quote]
You can connect many I2C slave devices on one I2C bus, that’s why you use specific address when you are communicating with your device.
You will see that all 4 “I” sockets have the same I2C pins IO11 and IO12, so you can have 4 devices on the same bus as longvas addresses of these devices are different as @ iamin has pointed out.
You do not need to send the address in the actions[] array. NETMF is smart enough to do it when you “Execute” the transaction, provided that you have sent the configuration before or, as you did, you used our extension methods that send it in the Execute() method.
So I would code like this :
var result = new Byte[1];
var actions = new I2CDevice.I2CTransaction[1];
actions[0] = I2CDevice.CreateReadTransaction(result);
// Don't forget to use Hardware.I2CBus with the extension method, so that the configuration is correct
Hardware.I2CBus.Execute(_config, actions, 1000);
var retval = result[0];
When you see such things in the datasheet (sending the address first), it is because other language, like C, need to do this, as they operate at a “lower” level.
You will also see the same thing with SPI where the datasheet will tell you to lower the CS line, then read/write on the SPI bus and then raise the CS line again. In NETMF, you do not have to bother with this because the SPI.Write() does this for you.
About I²C address shifting : as long as the address given in the datasheet is less than 127/0x7F, it is a 7 bits address and thus does not need any shifting and can be used as is.
If it is greater than 0x7F, then a right shift is needed because it is a 8 bits address.
Depending on the manufacturer, addresses are given in both forms, which is sometimes confusing.