1

I'm am completing a project of mine that uses an MCP3424 i2c 18bit ADC and an arduino nano to measure temperature with an NTC thermistor but am having trouble with the arduino wire library. This is my first project using i2c so I'm not very knowledgeable about the subject but I have rigorously read the datasheet of the MCP3424 that can be found at (http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf) and tried many different ways to get it working. Also I'm new to posting on this stackexchange so pardon me if my syntax and what not is not right(I'm doing my best). Here is the code I have so far that is on my arduino.

#include<Wire.h>

#define ReadMode 0xDD //Device will output conversion data (7 bits, device address. 1 bit, Read/Write mode)
#define WriteMode 0xDC //Device expects config byte (7 bits, device address. 1 bit, Read/Write mode)
#define ConfigByte18 0x8c //PGA = 1, SPS = 3.75, One-Shot mode, channel 1, initiate new conversion.
#define ConfigByte16 0x88 //PGA = 1, SPS = 15, One-Shot mode, channel 1, initiate new conversion.

void setup() {
  Serial.begin(9600);//Initiate Connection to computer
  Wire.begin();//Initiate Wire library
  Wire.setClock(100000);//make sure clock speed is standard mode
  delay(500);//Allow boot up and settle of ADC
  Wire.beginTransmission(WriteMode);//begin transmission with ADC in Write mode
  Wire.write(ConfigByte18);//configure the ADC with settings found in "ConfigByte18"
  Wire.endTransmission();
  Serial.print("Everything worked\n");

}




void loop() {
  unsigned char x, y, z, a, b, c;
  //Serial.println("Bytes ready to be read:");
  Wire.begin();
  Wire.setClock(100000);//make sure clock speed is standard mode
  Wire.beginTransmission(ReadMode);//begin transmission with ADC in write mode
  Wire.requestFrom(0x6E, 6);//request 6 Bytes of information from MCP3424
  x = Wire.read();//read bytes
  delay(10);
  y = Wire.read();
  delay(10);
  z = Wire.read();
  delay(10);
  a = Wire.read();
  delay(10);
  b = Wire.read();
  delay(10);
  c = Wire.read();
  Serial.print(x);//print bytes
  Serial.print(", ");
  Serial.print(y);
  Serial.print(", ");
  Serial.print(z);
  Serial.print(", ");
  Serial.print(a, HEX);
  Serial.print(", ");
  Serial.print(b, HEX);
  Serial.print(", ");
  Serial.println(c, HEX);
  Wire.endTransmission();
  delay(1000);

}

So an explanation of my understanding: In the “void setup” section I begin transmission in write mode (see page 21 of datasheet to follow along with my explanation figure and table 5-3) in the begin transmission function I address the slave with 0xDC because the device address begins with 1101 (pre programmed) and then 110 as I have the two Adr pins tied to +5v and finally 0 as I want to change configuration settings. This translates to 0xDC in hexadecimal. Then I send the slave a byte of information for the configuration register (see page 18 section 5.2). I send 0x8C as I want my settings to be PGA = 1, SPS = 3.75, One-Shot mode, channel 1, initiate new conversion. Which should mean I need to send the slave 10001100 or 0x8c. This communication then ends as “Any byte sent after this second byte will be ignored” according to page 21. Then in the loop I begin transmission the same way apart from now I open transmission in read mode which is 0xDD as the last bit (R/W bit) is now 1. I then request six bytes of information and read the six bytes. If you now go to page 23 of the datasheet you can follow along again. Here I should get three data bytes from the slave and every subsequent byte should be the configuration register settings repeated. For now I am uninterested in the first three data bytes as I first of all just want to know how to change the configuration settings. What gets printed by the arduino instead is three data bytes from the slave, as expected, and then three of the exact same value, also as expected as they should all be the configuration settings. What is being printed in the second three bytes is “90”. Not what I expected. Now I’ve tried to figure out what has happened (hard without an oscilloscope). 90 converted from hex to binary is 10010000 and I believe the default settings are (which can be found on page 18) 00001001 could this be the default settings if so can anyone tell me whats going on and how to fix it? Thank you in advance for the help and thank you for taking the time to read my problem.

  • do not initialize the library in every loop. remove begin and setClock. and requestFrom should not be wrapped in transaction – Juraj Jul 14 at 5:57
  • @Juraj okay I will try without initialising the library ever loop and removing the set clock but I don't understand what you mean with the requestFrom being wrapped in transaction, could you explain a little more? – Asyu7 Jul 14 at 7:38
  • sorry transaction = beginTransmmition endTransmmition – Juraj Jul 14 at 8:12
  • @Juraj I have tried what you said but still I get the same result – Asyu7 Jul 14 at 8:45
  • use a library. for example github.com/bersch/MCP3424 – Juraj Jul 15 at 9:31
3

The problem is, that you misunderstood, how the Wire library handles addresses.

I2C uses an address byte, where the first 7 bits are the actual address and the last bit (Read/Write bit) dictates the direction of the communication. The Wire library gives you different functions for both directions (in your case: Wire.beginTransmission() for master write and Wire.requestFrom() for master read) and hides away the complexity of the Read/Write bit. So what you have to give as an address is the pure address of the device without the Read/Write bit. To write the configuration you used the address 0xDC, but the actual address of the device is 0x6E as you used it in the Wire.requestFrom() call.

Also in your loop() you try to start a master write with Wire.beginTransmission(), though you are starting a master read directly after it. Wire.beginTransmission() and Wire.endTransmission() are purely for master write transactions. So you should delete these lines here. For master read the call to Wire.requestFrom() and the corresponding reading is enough.

What happens in your code: In setup() you write the new configuration data to a wrong address (0xDC instead of 0x6E). The transmission fails, as there is most likely no device with this address at the bus, but you don't notice, since you are not checking the return value of Wire.endTransmission(), which would show an error code. Then in the loop() function you reinitialize and reconfigure the whole Wire library again, which makes no sense, as Juraj mentioned in his comments. Though it will only cost some cycles of computation time. Then the library get's set to master write mode (no actual I2C action here, just interal to the library) and then to master read mode (actual I2C action. The provided number of bytes get's read here from the slave). At the end you say to the library, that is should finish the master write transmission from before, which is not there anymore (since you've done a master read). So this will do nothing. Also you are doing many delays between the reads, which is not necessary. When the Wire.requestFrom() function returns, all the I2C communication is finished. The bytes, that could be received, are received and written into the libraries buffer. Wire.read() will only read the next value from the buffer, remove it from there and return the value. No I2C action at that point, so the delay(10) is useless

TL;DR:

  • Always use the correct address without Read/Write bit: 0x6E
  • Initialize and configure the Wire library only once in setup()
  • Remove Wire.beginTransmission() and Wire.endTransmission() from the loop() function, as you are only doing master read there.
  • Remove the delay(10); lines between the calls to Wire.read()
  • Thank you for the answer chrisl this clears up a lot! One more question if i may, to initiate a read from the MCP3424 I need to update a bit in the configuration register. Does that mean every time I want a reading I need to execute the three wire functions beginTransmission(0x6E), Wire.write() and endTransmission? – Asyu7 Jul 15 at 0:57
  • Yes, when in One Shot mode you need to always do beginTransmission(), write(), endTransmission(), requestFrom() and read() for every measurement. But as you currently are reading contineously from the ADC, you should consider to use the contineous measurement mode, so that the measurement is automatically started at a fixed interval and you only have to request the data from the ADC. – chrisl Jul 15 at 8:30
  • Okay I see how I could do that yes, but in the future I plan on reading from all 4 channels so I would have to change the config byte everytime and use all 5 commands every change anyway right? – Asyu7 Jul 15 at 9:07
  • Yes, when you change the channels on each request, you must use all the above commands to first set the correct config byte, start the conversion and then actually request the data. – chrisl Jul 15 at 9:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.