Attiny85 - I2C - MCP4725 10 bits DAC

Messing around with an Attiny85 and a MCP4725 10 bits DAC breakout board I am confused and getting frustrated. As a test I am reading the ADC on pin 2 ( A3) from a Hall sensor. The output is a led connected to pin 6. As I twist the throttle the input voltage increases on pin 2 and the led becomes brighter. So far all is good.

While trying to do the same with the output voltage of the DAC module, the only reading I get is about half VCC. No matter how I twist or change the input voltage, the output remains the same while the led still follows the throttle movements. When I try a fixed value like 4095 directly on “outputValueMain” the DAC is returning VCC. So I think I hooked-up everything correctly.

What I don’t understand is that direct value input is giving me output values in relation, and when I try to make it dependend on the input voltage I do not get the expected output voltage of the DAC.

BTW this is for a smooth hubmotor throttle controll to prevent spinnig wheels when accelerating.
I hope someone can push me in the right direction. Thanks.

/*         TEST MCP4725 ATTINY85
 * 
 * sensor read ( hall sensor) pin 2
 * - OR - potentiometer pin to VCC pin to GND and the runner to pin 2
 * led on pin 6 with resistor to ground
 * 
*/

#include <avr/io.h>                               //allows for register commands to be understood
#include <TinyWireM.h>

#define dacMainController 0x60                    // address for main motor controller
#define outputPin 1

byte adcLoByte;

unsigned int adcRaw;
unsigned int analogData;                          // declare analogData variable
unsigned int mainBuffer[ 3];
unsigned int outputValueMain;


void setup() {
  pinMode( outputPin, OUTPUT);

  ADMUX = ( 0 << REFS1) |                         // sets ref. voltage to VCC, bit 1
          ( 0 << REFS0) |                         // sets ref. voltage to VCC, bit 0
          ( 0 << ADLAR) |                         // left shift result
          ( 0 << MUX3)  |                         // use ADC3 for input ( PB3), MUX bit 3
          ( 0 << MUX2)  |                         // use ADC3 for input ( PB3), MUX bit 2
          ( 1 << MUX1)  |                         // use ADC3 for input ( PB3), MUX bit 1
          ( 1 << MUX0);                           // use ADC3 for input ( PB3), MUX bit 0

  ADCSRA = (1 << ADEN)  |                         // enable ADC 
           (0 << ADPS2) |                         // set prescaler to 8, bit 2
           (1 << ADPS1) |                         // set prescaler to 8, bit 1
           (1 << ADPS0);                          // set prescaler to 8, bit 0 

}


void loop() {
  ADCSRA |= ( 1 << ADSC);                         // start adc measurement
  while( ADCSRA & ( 1 << ADSC));                  // wait till conversion complete

  adcLoByte = ADCL;
  adcRaw = ADCH << 8 | adcLoByte;

  analogData = adcRaw;                            // store data in analogData variable

  analogWrite( outputPin, analogData / 4)         // output led

//  outputValueMain = analogData * 4;
  outputValueMain = adcRaw * 4;
  mainBuffer[ 0] = 0b01000000;                    // control byte, bits 7 - 5 -> 010 write DAC
  mainBuffer[ 1] = outputValueMain >> 4;          // MSB 11-4 shift right 4 places
  mainBuffer[ 2] = outputValueMain << 4;          // LSB  3-0 shift left 4 places, bits 3 - 0 unused

  TinyWireM.beginTransmission( dacMainController);
  TinyWireM.write( mainBuffer[ 0]);               // pointer
  TinyWireM.write( mainBuffer[ 1]);               // the 8 most significant bits...
  TinyWireM.write( mainBuffer[ 2]);               // the 4 least significant bits...
  TinyWireM.endTransmission();
}

Is the build-in analogRead unavailable? It looks like you are doing the analog input a hard way.

Also, at a glance it looks odd to use the value so read divided by 4 in one place, presumably to scale 0-1023 to 0-255

but in another place use that value multiplied by 4 because why?

a7

The build-in analog read is available and returns, as far as I know, an 8 bits value. While using the analoRead the led re-starts three times. My guess it that the PWM value overflows ( 4x). To get a “normal” led brightness I need to divide the analogRead value by 4. But the led is only for “debugging”.

I want to read the analog input as 10 bits. To get a valid PWM value I think I need to do it the hard way.

Only for the a visualisation of the reading I put up the led as the Attiny has no serial.print. To have a valid range I need to divide it by 4? ( 10 bits to 8 bits).

You are right, the last place does not have to be multiplied by 4 because it is already a 10 bits value.

My google confirms my memory here, analogRead returns a value between 0 and 1023.

On a(n) UNO. I did not find yet whether it’s not the case on the Attiny85.

a7

Yeah, that’s a problem… I usually don’t take code that isn’t near perfect anywhere near the Attiny85 for that reason.

But in your case noodling around directly with the chip peripherals it is hard(er) to write and perfect a program on the UNO for deployment on an Attiny, e.g., that doesn’t need more than changing a few pin defines.

a7

It is working on a Nano but I can’t get it to work on the Attiny.
“Shrinkify” an arduino project is not always that simple.

I think I have found one problem… Instead of setting the reference voltage to VCC, I set it to AREF pin with an external capacitor of 10 uF on an Arduino NANO REFS1 = 0 REFS0 = 1.
This did not work on the nano either with REFS1 and REFS0 at 0 as I said before. My wrong.

So I need to tinker some more.

1 Like

Yeah you seems to be relative

Yeah… got it working, but I am not sure why it didn’t in the first place.
The code is not changed much… While testing I set the “outputValueMain” to 0b111111111111 ( 12 bits), and got a full reading on the output of the MCP4725. So I added to the declared variable 0x00.

unsigned int outputValueMain = 0x00;

I set REFS1 and REFS0 back to 0 because the attiny85 does not have an AREF pin.

Please find the code below that reads 10 bits analog input and returns 12 bits to the DAC ( MCP4725).

/*         TEST MCP4725 ATTINY85
 * 
 * sensor read ( hall sensor) pin 2
 * - OR - potentiometer pin to VCC pin to GND and the runner to pin 2
 * led on pin 6 with resistor to ground
 * SDA pin 5
 * SCL pin 7
 * 
*/

#include <TinyWireM.h>                            // Adafruit / Bro Hogan

#define dacMainController 0x60                    // address for main motor controller
#define outputPin 1

byte adcLoByte;

unsigned int adcRaw;
unsigned int analogData;                          // declare analogData variable
unsigned int mainBuffer[ 3];
unsigned int outputValueMain = 0x00;


void setup() {
//  pinMode( outputPin, OUTPUT);

  ADMUX = ( 0 << REFS1) |                         // sets ref. voltage to AREF, bit 1
          ( 0 << REFS0) |                         // sets ref. voltage to AREF, bit 0
          ( 0 << ADLAR) |                         // left shift result
          ( 0 << MUX3)  |                         // use ADC3 for input ( PB3), MUX bit 3
          ( 0 << MUX2)  |                         // use ADC3 for input ( PB3), MUX bit 2
          ( 1 << MUX1)  |                         // use ADC3 for input ( PB3), MUX bit 1
          ( 1 << MUX0);                           // use ADC3 for input ( PB3), MUX bit 0

  ADCSRA = (1 << ADEN)  |                         // enable ADC 
           (0 << ADPS2) |                         // set prescaler to 8, bit 2
           (1 << ADPS1) |                         // set prescaler to 8, bit 1
           (1 << ADPS0);                          // set prescaler to 8, bit 0 

  TinyWireM.begin();
}


void loop() {

  ADCSRA |= ( 1 << ADSC);                         // start adc measurement
  while( ADCSRA & ( 1 << ADSC));                  // wait till conversion complete

  adcLoByte = ADCL;
  adcRaw = ADCH << 8 | adcLoByte;

  analogData = adcRaw;                            // store data in analogData variable
  outputValueMain = analogData * 4;               // x 4 to get to 12 bits

  mainBuffer[ 0] = 0b01000000;                    // control byte, bits 7 - 5 -> 010 write DAC
  mainBuffer[ 1] = outputValueMain >> 4;          // MSB 11-4 shift right 4 places
  mainBuffer[ 2] = outputValueMain << 4;          // LSB  3-0 shift left 4 places, bits 3 - 0 unused

  TinyWireM.beginTransmission( dacMainController);
  TinyWireM.write( mainBuffer[ 0]);               // pointer
  TinyWireM.write( mainBuffer[ 1]);               // the 8 most significant bits...
  TinyWireM.write( mainBuffer[ 2]);               // the 4 least significant bits...
  TinyWireM.endTransmission();
}

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