Can't write to i2c device with MAX5812L and Leonardo

Hi,
I have a MAX5812L I2C Dac converter and I'm trying to use it with an arduino Leonardo. Here is my simple program:

#include <Wire.h>

int i = 0;

void setup(void) {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("Hello!");

  Wire.begin();
}

void loop(void) {

    int output = pow(2, i++) + 1;
    if(i > 12)
      i = 0;
    Serial.print("output: ");
    Serial.println(output);

    Wire.beginTransmission(0x10); 
    // début de la transmission au périphérique d'adresse #16 (0x10) 
    Wire.write(output );                    
    // envoi d'un octet val  
    byte error = Wire.endTransmission(); 
    Serial.print("error: ");
    Serial.println(error);
    delay(1000);
}

Here are my outputs:
error: 3
error: 3
error: 3
error: 3
error: 3
error: 3
error: 3
error: 3
error: 3
error: 3
error: 0
error: 3

As you can see, The 2048th value is sent without error, but why ? Do you have any idea ?
There is communication between Leonardo and my device because this is not the error 2 (bad address), so I guess the way I send data is wrong but how can I do ?
Thanks

I cannot see that. Wire.write() accepts a byte parameter, so any integer parameter will be converted into a byte before processing.

BTW, the output you've shown isn't from your sketch as there must be "output: " lines between the error lines if you used above code.

1 Like

It is the good outputs, I've just hide then for this forum because this is not essential.

Here are the error code significations from Wire library:
0: success.
1: data too long to fit in transmit buffer.
2: received NACK on transmit of address.
3: received NACK on transmit of data.
4: other error.
5: timeout

So, almost value failed to transmit except the penultimate which is sent successfully.
Sended values are :
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096

dac_test.pdf (943,6 Ko)
More strange, I made a similar program to send values between 0 and 4096 that return me 0 when failed and 1 when success (linked the file). There is a pattern of 20 failed for 12 success at the begginning and then 16 failed for 16 success.
I'm using the Adafruit_MCP4725 library for this exemple, I think this is not optimised for my DAC but I don't know how to adapt it so It's working perfectly.
Here is my program;

#include <Wire.h>
#include <Adafruit_MCP4725.h>

Adafruit_MCP4725 dac;

void setup(void) {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("Hello!");

  // For Adafruit MCP4725A1 the address is 0x62 (default) or 0x63 (ADDR pin tied to VCC)
  // For MCP4725A0 the address is 0x60 or 0x61
  // For MCP4725A2 the address is 0x64 or 0x65
  dac.begin(0x10);

  Serial.println("Generating a sine wave");
}

void loop(void) {
    uint16_t i;

	for (i = 0; i < 4096; i++)
	{
		Serial.print(dac.setVoltage(i, false));
		Serial.print(";");
	}
	Serial.print("\n\nEND\n\n");
    
}

I hope this is clear enough :slight_smile:

Bad idea! We decide what is essential and what not. If you just hide information without even telling us we just waste our time trying to help you.

I don't believe that, not with above code! That code would produce values 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 1025, 2049, 4097 and sent the values 1, 2, 3, 5, 9, 17, 33, 65, 129, 1, 1, 1, 1.

Maybe the pow() function did a calculation error and produced a valid command byte because I would expect the chip to return NAK if the command byte is invalid.

So, I made some research, and here is my theory.
Every unpair values from upper data bits or lower data bits are not sent. For exemple:

  • pair values from 0 to 255 are sent because the upper data bit is 0x00
  • pair and unpair values from 256 to 512 aren't sent because the upper data bit is 0x01

I attached you the values in an excel so it's clearly visible, my new program and a screenshot of the program's results.

So, as you can see, this is not a beautiful triangle signal because there is many missing values...

Do you have any ideas why the unpair values aren't sent ?

#include <Wire.h>
uint16_t output4096 = 0;
byte error;    
bool isGoingUp4096 = true;

void setup() {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("Hello!");
  Wire.begin(); 
  Wire.beginTransmission(0x10); 
  Wire.write(0x40);               //Power up device
  error = Wire.endTransmission(); 
  Serial.print("error begin: ");
  Serial.println(error);
}

void loop() {
    if(isGoingUp4096){
      output4096 += 1;
    }else{
      output4096 -= 1;
    }
    if(output4096 >= 4096){
      isGoingUp4096 = false;
      output4096 = 4096;
    }else if(output4096 <= 0){
      isGoingUp4096 = true;
      output4096 = 0;      
    }
    
    // début de la transmission au périphérique d'adresse #16 (0x10)
    Wire.beginTransmission(0x10); 
    Wire.write(0xC0 + highByte(output4096));               //upper 8-bit data for DAC
    Wire.write(lowByte(output4096));               //lower 8-bit data for DAC
    error = Wire.endTransmission(); 
    Serial.print("error on: ");
    Serial.print(output4096);
    Serial.print(";error: ");
    Serial.println(error);
}

And a quick look at the output:

Hello!
error begin: 0
error on: 1;error: 3
error on: 2;error: 0
error on: 3;error: 3
error on: 4;error: 0
error on: 5;error: 3
error on: 6;error: 0
error on: 7;error: 3
error on: 8;error: 0
error on: 9;error: 3
[...]
error on: 4087;error: 3
error on: 4088;error: 3
error on: 4089;error: 3
error on: 4090;error: 3
error on: 4091;error: 3
error on: 4092;error: 3
error on: 4093;error: 3
error on: 4094;error: 3
error on: 4095;error: 3
error on: 4096;error: 0

dac_test.ino (1,2 Ko)

dac_results.pdf (529,4 Ko)

Please show a sketch in a readable way, between code tags in your post.
Show the results as well in your post (you can put them between code tags as well).

I see some improvements. You need a 100% working sketch, and you are now at 1%. That's how to look at it.

Your sketch has no delay in the loop(). It fills the I2C bus and continuously bothers the DAC. At least put a delay at the end of the loop().

I have not read the datasheet thorough yet.

Thanks for your answer !
I've updated my post and will try now your advices and keep you in touch
EDIT
I've put a delay of 5, 10 and 50 ms but it's the same result, many values aren't sent...

Keep in mind that the DAC chip could be broken. Or the voltage of the Leonardo is too low. Or you have a breadboard with bad contacts. Or the 'ADD' pin is floating. Or you have SDA next to SCL in a cable. Or the wrong pullup resistors. Or one of the other basic problems. Could you show a photo with the wiring ?

Manufacturer's page of the MAX8512: https://www.maximintegrated.com/en/products/analog/data-converters/digital-to-analog-converters/MAX5812.html (with datasheet).

Code on Github, not for Arduino and very hard to read and it is unknown if that WriteMAX5812DAC() function is working: https://github.com/mmk-tsm/NBB_WIDTH_Ep_0/blob/master/I2CFuncs.cpp

Normally 2 data bytes are written and 2 data bytes are read. For a simple command, a single data byte is okay, so your single byte of 0x40 is okay for power up.

Let's not rush forward, because something very basic is very wrong.
I suggest to try to get rid of the error code by sending the power up command over and over again, with a delay(). That is a valid command, so let's fix the I2C bus with that command.

Here is my schema, I'm making a custom card based on an Arduino Leonardo, I wasn't able to test it on a breadboard...
There is others part in the board, ACCELERO, which is using I2C aswell, with an address of 0X0E. I've test it in another program and it seems to work.

In the DAC group, the CAY16-103J4LF is a group of resistor of 10K ohm, do you think it could be the source of my problem ?
I think the wiring is good because I can detect it with an I2C scanner and communicate with it. But maybe there is an obvious error I can't see, this is my first board ever :sweat_smile:

I'll check the github code.
Thanks for your help !

You wrote that you have a "Leonardo" board to make it simple for us, but we like to know everything. There are problems with the I2C bus on your board.

  • Where are the 100nF decoupling capacitors ?
  • You have 10k resistors in the signal path of SDA and SCL to the DAC. You are basically giving up on the I2C bus.
  • The capacitors "C8", "C9" and "C10" have the GND at the top and the 5V at the bottom. Please don't make a schematic like that.
  • The KXTJ3-1057 is a 3.3V sensor chip. That means it has a 3.3V I2C bus. The ATmega32U4 is running at 5V and it has therefor a 5V I2C bus. You connect those two I2C buses. The noise margin has gone and you are operating beyond the specifications in the datasheet.
  • The only pullup resistors on the I2C bus are the 10k near the KXTJ3-1057 to 3.3V. That is not okay for the ATmega32U4. It needs at least 3.5V at SDA and SCL to see it as a valid high level.

Thanks for your very interresting return and sorry for not having said everything.

  • I guess I forgot to put them but where do I have to put them ? There is only one missing after 5V of USB, right ?
  • I've understand that right after my post, so I unsold them and now every values are sent ! :grinning:
  • I'll change that
  • All right... So maybe the simpliest way is to change my sensor to have a 5V sensor ? Because I need a 5V output from DAC, I can't change that
  • The resistor near the KXTJ3-1057 are 2.2k but yes, I understand.

I've test a program with dac and accelero together, it's working but not very stable, I guess this is because of I2C conflicts

EDIT
Or maybe I can use a level shifter to communicate with the accelero like this picture ?
image

Decoupling capacitors of 100nF should be everywhere. At the power and GND of every noisy chip.

Yes, a level shifter is a good solution. Adafruit often includes a level shifter on the module itself.
The level shifter has 10k pullup on every side, that could be enough pullup, or you may add a little more.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.