Go Down

Topic: Ultra simple library for Adafruit DAC breakout board wont run on DUE (Read 803 times) previous topic - next topic

fxmech

Hi I have to use some DAC's from Adafruit on a project but the DUE does not like the library...
It is such a short library code that I thought maybe one of you could help spot the problem for me.
Thanks in Advance!

Adafruit_MCP4725.cpp library code:
Code: [Select]
/**************************************************************************/
/*!
   @file     Adafruit_MCP4725.cpp
   @author   K.Townsend (Adafruit Industries)
@license  BSD (see license.txt)

I2C Driver for Microchip's MCP4725 I2C DAC

This is a library for the Adafruit MCP4725 breakout
----> https://www.adafruit.com/products/???

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

@section  HISTORY

   v1.0 - First release
*/
/**************************************************************************/
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include <Wire.h>

#include "Adafruit_MCP4725.h"

/**************************************************************************/
/*!
   @brief  Instantiates a new MCP4725 class
*/
/**************************************************************************/
Adafruit_MCP4725::Adafruit_MCP4725() {
}

/**************************************************************************/
/*!
   @brief  Setups the HW
*/
/**************************************************************************/
void Adafruit_MCP4725::begin(uint8_t addr) {
 _i2caddr = addr;
 Wire.begin();

}

/**************************************************************************/
/*!
   @brief  Sets the output voltage to a fraction of source vref.  (Value
           can be 0..4095)

   @param[in]  output
               The 12-bit value representing the relationship between
               the DAC's input voltage and its output voltage.
   @param[in]  writeEEPROM
               If this value is true, 'output' will also be written
               to the MCP4725's internal non-volatile memory, meaning
               that the DAC will retain the current voltage output
               after power-down or reset.
*/
/**************************************************************************/
void Adafruit_MCP4725::setVoltage( uint16_t output, bool writeEEPROM )
{
 uint8_t twbrback = TWBR;
 TWBR = 12; // 400 khz
 Wire.beginTransmission(_i2caddr);
 if (writeEEPROM)
 {
   Wire.write(MCP4726_CMD_WRITEDACEEPROM);
 }
 else
 {
   Wire.write(MCP4726_CMD_WRITEDAC);
 }
 Wire.write(output / 16);                   // Upper data bits          (D11.D10.D9.D8.D7.D6.D5.D4)
 Wire.write((output % 16) << 4);            // Lower data bits          (D3.D2.D1.D0.x.x.x.x)
 Wire.endTransmission();
 TWBR = twbrback;
}


Adafruit_MCP4725.h library code:
Code: [Select]
/**************************************************************************/
/*!
   @file     Adafruit_MCP4725.h
   @author   K. Townsend (Adafruit Industries)
@license  BSD (see license.txt)

This is a library for the Adafruit MCP4725 breakout board
----> https://www.adafruit.com/products/???

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

@section  HISTORY

   v1.0  - First release
*/
/**************************************************************************/

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include <Wire.h>

#define MCP4726_CMD_WRITEDAC            (0x40)  // Writes data to the DAC
#define MCP4726_CMD_WRITEDACEEPROM      (0x60)  // Writes data to the DAC and the EEPROM (persisting the assigned value after reset)

class Adafruit_MCP4725{
public:
 Adafruit_MCP4725();
 void begin(uint8_t a);  
 void setVoltage( uint16_t output, bool writeEEPROM );

private:
 uint8_t _i2caddr;
};


SIMPLISTIC TEST SKETCH (Only errors out compiling for DUE):
Code: [Select]
/**************************************************************************/
/*!
    @file     trianglewave.pde
    @author   Adafruit Industries
    @license  BSD (see license.txt)

    This example will generate a triangle wave with the MCP4725 DAC.   

    This is an example sketch for the Adafruit MCP4725 breakout board
    ----> https://www.adafruit.com/products/???

    Adafruit invests time and resources providing this open source code,
    please support Adafruit and open-source hardware by purchasing
    products from Adafruit!
*/
/**************************************************************************/
#include <Wire.h>
#include <Adafruit_MCP4725.h>

Adafruit_MCP4725 dac;

void setup(void) {
  Serial.begin(9600);
  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(0x62);
   
  Serial.println("Generating a triangle wave");
}

void loop(void) {
    uint32_t counter;
    // Run through the full 12-bit scale for a triangle wave
    for (counter = 0; counter < 4095; counter=counter+5)
    {
      dac.setVoltage(counter, false);
   
    }
    for (counter = 4095; counter > 0; counter=counter-5)
    {
      dac.setVoltage(counter, false);
     
    }
}


ERROR MESSAGE (sketch errors out only on DUE):

C:\Users\fxmech\Documents\Arduino\libraries\Adafruit_MCP4725\Adafruit_MCP4725.cpp: In member function 'void Adafruit_MCP4725::setVoltage(uint16_t, bool)':
C:\Users\fxmech\Documents\Arduino\libraries\Adafruit_MCP4725\Adafruit_MCP4725.cpp:67: error: 'TWBR' was not declared in this scope

Docedison

I believe that your problem is timer specific to AVR code, Not ARM...
Quote
First:
This is I believe AVR code:
#if ARDUINO >= 100
#include "Arduino.h"   <------ for Ver 1.0 and greater
#else
#include "WProgram.h"    <-------For Ver 022/3 code
#endif
and Second: What's wrong with the DAC's in the Due except perhaps there are only two... 12 bit ones

I could be very wrong but I've seen others in this section warn about that..

Doc
--> WA7EMS <--
"The solution of every problem is another problem." -Johann Wolfgang von Goethe
I do answer technical questions PM'd to me with whatever is in my clipboard

noblepepper

TWBR is an AVR register that controls the data rate on the TWI interface. The wire library provides high level access to TWI but apparently Adafruit uses TWBR to get higher data rates.

You'll need to figure out an equivalent on the SAM3X to be able to get this to work. The Atmel Datasheet on the SAM3X should provide details.

fxmech

Thanks for the info... I thought it might just be a syntax type issue not processor related... I think the solution is beyond my current knowledge level.

As for the DACs I need 10 total so the two internals don't do it:(

noblepepper

If you are not trying to push the frequency capabilities of the units you should be able to just use these at the 100 KHz transfer rate instead of 400 KHz by commenting out the three lines that reference TWBR. Obviously this will take about 4 times as long to transfer data to the DAC but it may meet your needs.

It looks like this is all defined in hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/component/component_twi.h
for the Due, down around line 95.
Code: [Select]
#define TWI_CWGR_CKDIV(value) ((TWI_CWGR_CKDIV_Msk & ((value) << TWI_CWGR_CKDIV_Pos))) looks like it is the macro you would use.
Something like this:
Code: [Select]
*/
/**************************************************************************/
void Adafruit_MCP4725::setVoltage( uint16_t output, bool writeEEPROM )
{
#ifdef __AVR__
uint8_t twbrback = TWBR;
  TWBR = 12; // 400 khz
#endif
#ifdef __ARM__
uint8_t twbrback = TWI_CWGR_CKDIV;
TWI_CWGR_CKDIV(twbrback/4);
#endif
  Wire.beginTransmission(_i2caddr);
  if (writeEEPROM)
  {
    Wire.write(MCP4726_CMD_WRITEDACEEPROM);
  }
  else
  {
    Wire.write(MCP4726_CMD_WRITEDAC);
  }
  Wire.write(output / 16);                   // Upper data bits          (D11.D10.D9.D8.D7.D6.D5.D4)
  Wire.write((output % 16) << 4);            // Lower data bits          (D3.D2.D1.D0.x.x.x.x)
  Wire.endTransmission();
#ifdef __AVR__
TWBR = twbrback;
#endif
#ifdef __ARM__
TWI_CWGR_CKDIV(twbrback);
#endif
}


I just threw that last bit of code together as an example, I would be surprised if it even compiles without some changes, hopefully you get the idea though.

Go Up