2013-11-24 15:59:40 -05:00
|
|
|
//
|
|
|
|
// FILE: MCP4725.cpp
|
|
|
|
// AUTHOR: Rob Tillaart
|
2020-11-27 05:20:37 -05:00
|
|
|
// PURPOSE: Arduino library for 12 bit I2C DAC - MCP4725
|
2022-10-17 04:40:05 -04:00
|
|
|
// VERSION: 0.3.4
|
2020-11-27 05:20:37 -05:00
|
|
|
// URL: https://github.com/RobTillaart/MCP4725
|
2013-11-24 15:59:40 -05:00
|
|
|
//
|
2022-10-17 04:40:05 -04:00
|
|
|
// HISTORY see changelog.md
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2013-11-24 15:59:40 -05:00
|
|
|
|
|
|
|
#include "MCP4725.h"
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// registerMode
|
2020-11-27 05:20:37 -05:00
|
|
|
#define MCP4725_DAC 0x40
|
|
|
|
#define MCP4725_DACEEPROM 0x60
|
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// page 22
|
2020-11-27 05:20:37 -05:00
|
|
|
#define MCP4725_GC_RESET 0x06
|
|
|
|
#define MCP4725_GC_WAKEUP 0x09
|
|
|
|
|
2017-04-19 06:31:31 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
MCP4725::MCP4725(const uint8_t deviceAddress, TwoWire *wire)
|
2013-11-24 15:59:40 -05:00
|
|
|
{
|
2021-01-29 06:31:58 -05:00
|
|
|
_deviceAddress = deviceAddress;
|
|
|
|
_wire = wire;
|
|
|
|
_lastValue = 0;
|
|
|
|
_powerDownMode = 0;
|
2020-11-27 05:20:37 -05:00
|
|
|
_lastWriteEEPROM = 0;
|
2013-11-24 15:59:40 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2019-10-14 07:16:57 -04:00
|
|
|
#if defined(ESP8266) || defined(ESP32)
|
2021-01-29 06:31:58 -05:00
|
|
|
bool MCP4725::begin(const uint8_t dataPin, const uint8_t clockPin)
|
2019-10-14 07:16:57 -04:00
|
|
|
{
|
2021-01-29 06:31:58 -05:00
|
|
|
_wire = &Wire;
|
|
|
|
if ((dataPin < 255) && (clockPin < 255))
|
|
|
|
{
|
|
|
|
_wire->begin(dataPin, clockPin);
|
|
|
|
} else {
|
|
|
|
_wire->begin();
|
|
|
|
}
|
|
|
|
if (isConnected())
|
|
|
|
{
|
|
|
|
_lastValue = readDAC();
|
|
|
|
_powerDownMode = readPowerDownModeDAC();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2019-10-14 07:16:57 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
#if defined (ARDUINO_ARCH_RP2040)
|
|
|
|
|
|
|
|
bool MCP4725::begin(int sda, int scl)
|
|
|
|
{
|
|
|
|
_wire->setSDA(sda);
|
|
|
|
_wire->setSCL(scl);
|
|
|
|
_wire->begin();
|
|
|
|
|
|
|
|
if (isConnected())
|
|
|
|
{
|
|
|
|
_lastValue = readDAC();
|
|
|
|
_powerDownMode = readPowerDownModeDAC();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
bool MCP4725::begin()
|
2013-11-24 15:59:40 -05:00
|
|
|
{
|
2021-01-29 06:31:58 -05:00
|
|
|
_wire->begin();
|
|
|
|
if (! isConnected()) return false;
|
|
|
|
|
2019-10-14 07:16:57 -04:00
|
|
|
_lastValue = readDAC();
|
|
|
|
_powerDownMode = readPowerDownModeDAC();
|
2021-01-29 06:31:58 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool MCP4725::isConnected()
|
|
|
|
{
|
|
|
|
_wire->beginTransmission(_deviceAddress);
|
|
|
|
return (_wire->endTransmission() == 0);
|
2013-11-24 15:59:40 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2015-03-06 14:19:01 -05:00
|
|
|
int MCP4725::setValue(const uint16_t value)
|
2013-11-24 15:59:40 -05:00
|
|
|
{
|
2019-10-14 07:16:57 -04:00
|
|
|
if (value == _lastValue) return 0;
|
|
|
|
if (value > MCP4725_MAXVALUE) return MCP4725_VALUE_ERROR;
|
2020-11-27 05:20:37 -05:00
|
|
|
int rv = _writeFastMode(value);
|
2019-10-14 07:16:57 -04:00
|
|
|
if (rv == 0) _lastValue = value;
|
|
|
|
return rv;
|
2013-11-24 15:59:40 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2013-11-30 17:41:37 -05:00
|
|
|
uint16_t MCP4725::getValue()
|
|
|
|
{
|
2019-10-14 07:16:57 -04:00
|
|
|
return _lastValue;
|
2013-11-30 17:41:37 -05:00
|
|
|
}
|
|
|
|
|
2013-12-01 13:33:59 -05:00
|
|
|
|
2021-12-21 10:28:24 -05:00
|
|
|
int MCP4725::setPercentage(float percentage)
|
2021-06-07 02:28:17 -04:00
|
|
|
{
|
2021-12-21 10:28:24 -05:00
|
|
|
if ((percentage > 100) || (percentage < 0)) return MCP4725_VALUE_ERROR;
|
|
|
|
return setValue(round(percentage * (0.01 * MCP4725_MAXVALUE)));
|
2021-06-07 02:28:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// unfortunately it is not possible to write a different value
|
|
|
|
// to the DAC and EEPROM simultaneously or write EEPROM only.
|
2015-03-06 14:19:01 -05:00
|
|
|
int MCP4725::writeDAC(const uint16_t value, const bool EEPROM)
|
2013-11-24 15:59:40 -05:00
|
|
|
{
|
2019-10-14 07:16:57 -04:00
|
|
|
if (value > MCP4725_MAXVALUE) return MCP4725_VALUE_ERROR;
|
2020-11-27 05:20:37 -05:00
|
|
|
while(!ready());
|
|
|
|
int rv = _writeRegisterMode(value, EEPROM ? MCP4725_DACEEPROM : MCP4725_DAC);
|
2019-10-14 07:16:57 -04:00
|
|
|
if (rv == 0) _lastValue = value;
|
|
|
|
return rv;
|
2013-11-24 15:59:40 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2013-11-30 17:41:37 -05:00
|
|
|
uint16_t MCP4725::readDAC()
|
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
while(!ready());
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t buffer[3];
|
2020-11-27 05:20:37 -05:00
|
|
|
_readRegister(buffer, 3);
|
2019-10-14 07:16:57 -04:00
|
|
|
uint16_t value = buffer[1];
|
|
|
|
value = value << 4;
|
|
|
|
value = value + (buffer[2] >> 4);
|
|
|
|
return value;
|
2013-12-01 13:33:59 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2013-12-01 13:33:59 -05:00
|
|
|
uint16_t MCP4725::readEEPROM()
|
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
while(!ready());
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t buffer[5];
|
2020-11-27 05:20:37 -05:00
|
|
|
_readRegister(buffer, 5);
|
2019-10-14 07:16:57 -04:00
|
|
|
uint16_t value = buffer[3] & 0x0F;
|
|
|
|
value = value << 8;
|
|
|
|
value = value + buffer[4];
|
|
|
|
return value;
|
2013-12-01 13:33:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// depending on bool EEPROM the value of PDM is written to
|
|
|
|
// (false) DAC or
|
|
|
|
// (true) DAC & EEPROM,
|
2015-03-06 14:19:01 -05:00
|
|
|
int MCP4725::writePowerDownMode(const uint8_t PDM, const bool EEPROM)
|
2013-12-01 13:33:59 -05:00
|
|
|
{
|
2021-12-21 10:28:24 -05:00
|
|
|
_powerDownMode = (PDM & 0x03); // mask PDM bits only (written later low level)
|
2019-10-14 07:16:57 -04:00
|
|
|
return writeDAC(_lastValue, EEPROM);
|
2013-12-01 13:33:59 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2013-12-01 16:09:02 -05:00
|
|
|
uint8_t MCP4725::readPowerDownModeEEPROM()
|
2013-12-01 13:33:59 -05:00
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
while(!ready());
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t buffer[4];
|
2020-11-27 05:20:37 -05:00
|
|
|
_readRegister(buffer, 4);
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t value = (buffer[3] >> 5) & 0x03;
|
|
|
|
return value;
|
2013-12-01 16:09:02 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2013-12-01 16:09:02 -05:00
|
|
|
uint8_t MCP4725::readPowerDownModeDAC()
|
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
while(!ready()); // TODO needed?
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t buffer[1];
|
2020-11-27 05:20:37 -05:00
|
|
|
_readRegister(buffer, 1);
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t value = (buffer[0] >> 1) & 0x03;
|
|
|
|
return value;
|
2013-11-30 17:41:37 -05:00
|
|
|
}
|
2013-11-24 15:59:40 -05:00
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// PAGE 22 - experimental
|
|
|
|
// DAC value is reset to EEPROM value
|
|
|
|
// need to reflect this in cached value
|
2013-12-01 13:33:59 -05:00
|
|
|
int MCP4725::powerOnReset()
|
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
int rv = _generalCall(MCP4725_GC_RESET);
|
2019-10-14 07:16:57 -04:00
|
|
|
_lastValue = readDAC(); // update cache to actual value;
|
|
|
|
return rv;
|
2013-12-01 13:33:59 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// PAGE 22 - experimental
|
|
|
|
// _powerDownMode DAC resets to 0 -- PDM EEPROM stays same !!!
|
|
|
|
// need to reflect this in cached value
|
2013-12-01 13:33:59 -05:00
|
|
|
int MCP4725::powerOnWakeUp()
|
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
int rv = _generalCall(MCP4725_GC_WAKEUP);
|
2019-10-14 07:16:57 -04:00
|
|
|
_powerDownMode = readPowerDownModeDAC(); // update to actual value;
|
|
|
|
return rv;
|
2013-12-01 13:33:59 -05:00
|
|
|
}
|
2013-11-24 15:59:40 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// PAGE 18 DATASHEET
|
2020-11-27 05:20:37 -05:00
|
|
|
int MCP4725::_writeFastMode(const uint16_t value)
|
2013-11-24 15:59:40 -05:00
|
|
|
{
|
2021-01-29 06:31:58 -05:00
|
|
|
uint8_t l = value & 0xFF;
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t h = ((value / 256) & 0x0F); // set C0 = C1 = 0, no PDmode
|
|
|
|
h = h | (_powerDownMode << 4);
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
_wire->beginTransmission(_deviceAddress);
|
|
|
|
_wire->write(h);
|
|
|
|
_wire->write(l);
|
|
|
|
return _wire->endTransmission();
|
2013-11-24 15:59:40 -05:00
|
|
|
}
|
|
|
|
|
2013-12-01 13:33:59 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// ready checks if the last write to EEPROM has been written.
|
|
|
|
// until ready all writes to the MCP4725 are ignored!
|
2020-11-27 05:20:37 -05:00
|
|
|
bool MCP4725::ready()
|
2013-12-01 13:33:59 -05:00
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
yield();
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t buffer[1];
|
2020-11-27 05:20:37 -05:00
|
|
|
_readRegister(buffer, 1);
|
2019-10-14 07:16:57 -04:00
|
|
|
return ((buffer[0] & 0x80) > 0);
|
2013-12-01 13:33:59 -05:00
|
|
|
}
|
2013-11-30 17:41:37 -05:00
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// PAGE 19 DATASHEET
|
|
|
|
// reg = MCP4725_DAC | MCP4725_EEPROM
|
2020-11-27 05:20:37 -05:00
|
|
|
int MCP4725::_writeRegisterMode(const uint16_t value, uint8_t reg)
|
2013-11-30 17:41:37 -05:00
|
|
|
{
|
2020-11-27 05:20:37 -05:00
|
|
|
if (reg & MCP4725_DACEEPROM)
|
|
|
|
{
|
|
|
|
_lastWriteEEPROM = millis();
|
|
|
|
}
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t h = (value / 16);
|
|
|
|
uint8_t l = (value & 0x0F) << 4;
|
2021-01-29 06:31:58 -05:00
|
|
|
_wire->beginTransmission(_deviceAddress);
|
2019-10-14 07:16:57 -04:00
|
|
|
reg = reg | (_powerDownMode << 1);
|
2021-01-29 06:31:58 -05:00
|
|
|
_wire->write(reg);
|
|
|
|
_wire->write(h);
|
|
|
|
_wire->write(l);
|
|
|
|
return _wire->endTransmission();
|
2013-11-30 17:41:37 -05:00
|
|
|
}
|
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// PAGE 20 DATASHEET
|
|
|
|
// typical 3 or 5 bytes
|
2020-11-27 05:20:37 -05:00
|
|
|
uint8_t MCP4725::_readRegister(uint8_t* buffer, const uint8_t length)
|
2013-11-30 17:41:37 -05:00
|
|
|
{
|
2021-01-29 06:31:58 -05:00
|
|
|
_wire->beginTransmission(_deviceAddress);
|
|
|
|
int rv = _wire->endTransmission();
|
2019-10-14 07:16:57 -04:00
|
|
|
if (rv != 0) return 0; // error
|
2013-12-01 16:09:02 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// readbytes will always be equal or smaller to length
|
2021-01-29 06:31:58 -05:00
|
|
|
uint8_t readBytes = _wire->requestFrom(_deviceAddress, length);
|
2019-10-14 07:16:57 -04:00
|
|
|
uint8_t cnt = 0;
|
|
|
|
while (cnt < readBytes)
|
|
|
|
{
|
2021-01-29 06:31:58 -05:00
|
|
|
buffer[cnt++] = _wire->read();
|
2019-10-14 07:16:57 -04:00
|
|
|
}
|
|
|
|
return readBytes;
|
2013-11-30 17:41:37 -05:00
|
|
|
}
|
2013-12-01 13:33:59 -05:00
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
|
2022-10-17 04:40:05 -04:00
|
|
|
// name comes from datasheet
|
2020-11-27 05:20:37 -05:00
|
|
|
int MCP4725::_generalCall(const uint8_t gc)
|
2013-12-01 13:33:59 -05:00
|
|
|
{
|
2021-01-29 06:31:58 -05:00
|
|
|
_wire->beginTransmission(0); // _deviceAddress
|
|
|
|
_wire->write(gc);
|
|
|
|
return _wire->endTransmission();
|
2013-12-01 13:33:59 -05:00
|
|
|
}
|
|
|
|
|
2021-12-21 10:28:24 -05:00
|
|
|
|
2020-11-27 05:20:37 -05:00
|
|
|
// -- END OF FILE --
|
2021-12-21 10:28:24 -05:00
|
|
|
|