0.3.7 MCP4725

This commit is contained in:
Rob Tillaart 2023-08-26 11:31:04 +02:00
parent 7a35e28ddd
commit 87b2588e4a
8 changed files with 275 additions and 33 deletions

View File

@ -5,13 +5,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/). and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.3.7] - 2023-08-25
- fix #27 - support for multiple MCP4725
- add two examples.
- update readme.md
- minor edits
## [0.3.6] - 2023-07-19 ## [0.3.6] - 2023-07-19
- fix #25 - buffer overflow in examples - fix #25 - buffer overflow in examples
- update keywords.txt - update keywords.txt
- moved code to .cpp - moved code to MCP4725.cpp
- minor edits - minor edits
## [0.3.5] - 2023-01-17 ## [0.3.5] - 2023-01-17
- update GitHub actions - update GitHub actions
- update license - update license

View File

@ -2,10 +2,8 @@
// FILE: MCP4725.cpp // FILE: MCP4725.cpp
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// PURPOSE: Arduino library for 12 bit I2C DAC - MCP4725 // PURPOSE: Arduino library for 12 bit I2C DAC - MCP4725
// VERSION: 0.3.6 // VERSION: 0.3.7
// URL: https://github.com/RobTillaart/MCP4725 // URL: https://github.com/RobTillaart/MCP4725
//
// HISTORY see changelog.md
#include "MCP4725.h" #include "MCP4725.h"
@ -31,6 +29,7 @@ MCP4725::MCP4725(const uint8_t deviceAddress, TwoWire *wire)
#if defined(ESP8266) || defined(ESP32) #if defined(ESP8266) || defined(ESP32)
bool MCP4725::begin(const uint8_t dataPin, const uint8_t clockPin) bool MCP4725::begin(const uint8_t dataPin, const uint8_t clockPin)
{ {
_wire = &Wire; _wire = &Wire;
@ -48,8 +47,10 @@ bool MCP4725::begin(const uint8_t dataPin, const uint8_t clockPin)
} }
return false; return false;
} }
#endif #endif
#if defined (ARDUINO_ARCH_RP2040) #if defined (ARDUINO_ARCH_RP2040)
bool MCP4725::begin(int sda, int scl) bool MCP4725::begin(int sda, int scl)
@ -129,6 +130,17 @@ int MCP4725::writeDAC(const uint16_t value, const bool EEPROM)
} }
// ready checks if the last write to EEPROM has been written.
// until ready all writes to the MCP4725 are ignored!
bool MCP4725::ready()
{
yield();
uint8_t buffer[1];
_readRegister(buffer, 1);
return ((buffer[0] & 0x80) > 0);
}
uint16_t MCP4725::readDAC() uint16_t MCP4725::readDAC()
{ {
while(!ready()); while(!ready());
@ -181,7 +193,7 @@ uint8_t MCP4725::readPowerDownModeEEPROM()
uint8_t MCP4725::readPowerDownModeDAC() uint8_t MCP4725::readPowerDownModeDAC()
{ {
while(!ready()); // TODO needed? while(!ready()); // TODO needed?
uint8_t buffer[1]; uint8_t buffer[1];
_readRegister(buffer, 1); _readRegister(buffer, 1);
uint8_t value = (buffer[0] >> 1) & 0x03; uint8_t value = (buffer[0] >> 1) & 0x03;
@ -195,7 +207,7 @@ uint8_t MCP4725::readPowerDownModeDAC()
int MCP4725::powerOnReset() int MCP4725::powerOnReset()
{ {
int rv = _generalCall(MCP4725_GC_RESET); int rv = _generalCall(MCP4725_GC_RESET);
_lastValue = readDAC(); // update cache to actual value; _lastValue = readDAC(); // update cache to actual value;
return rv; return rv;
} }
@ -206,7 +218,7 @@ int MCP4725::powerOnReset()
int MCP4725::powerOnWakeUp() int MCP4725::powerOnWakeUp()
{ {
int rv = _generalCall(MCP4725_GC_WAKEUP); int rv = _generalCall(MCP4725_GC_WAKEUP);
_powerDownMode = readPowerDownModeDAC(); // update to actual value; _powerDownMode = readPowerDownModeDAC(); // update to actual value;
return rv; return rv;
} }
@ -215,7 +227,7 @@ int MCP4725::powerOnWakeUp()
int MCP4725::_writeFastMode(const uint16_t value) int MCP4725::_writeFastMode(const uint16_t value)
{ {
uint8_t l = value & 0xFF; uint8_t l = value & 0xFF;
uint8_t h = ((value / 256) & 0x0F); // set C0 = C1 = 0, no PDmode uint8_t h = ((value / 256) & 0x0F); // set C0 = C1 = 0, no PDmode
h = h | (_powerDownMode << 4); h = h | (_powerDownMode << 4);
_wire->beginTransmission(_deviceAddress); _wire->beginTransmission(_deviceAddress);
@ -225,17 +237,6 @@ int MCP4725::_writeFastMode(const uint16_t value)
} }
// ready checks if the last write to EEPROM has been written.
// until ready all writes to the MCP4725 are ignored!
bool MCP4725::ready()
{
yield();
uint8_t buffer[1];
_readRegister(buffer, 1);
return ((buffer[0] & 0x80) > 0);
}
// PAGE 19 DATASHEET // PAGE 19 DATASHEET
// reg = MCP4725_DAC | MCP4725_EEPROM // reg = MCP4725_DAC | MCP4725_EEPROM
int MCP4725::_writeRegisterMode(const uint16_t value, uint8_t reg) int MCP4725::_writeRegisterMode(const uint16_t value, uint8_t reg)
@ -261,9 +262,9 @@ uint8_t MCP4725::_readRegister(uint8_t* buffer, const uint8_t length)
{ {
_wire->beginTransmission(_deviceAddress); _wire->beginTransmission(_deviceAddress);
int rv = _wire->endTransmission(); int rv = _wire->endTransmission();
if (rv != 0) return 0; // error if (rv != 0) return 0; // error
// readbytes will always be equal or smaller to length // readBytes will always be equal or smaller to length
uint8_t readBytes = _wire->requestFrom(_deviceAddress, length); uint8_t readBytes = _wire->requestFrom(_deviceAddress, length);
uint8_t cnt = 0; uint8_t cnt = 0;
while (cnt < readBytes) while (cnt < readBytes)
@ -277,7 +278,7 @@ uint8_t MCP4725::_readRegister(uint8_t* buffer, const uint8_t length)
// name comes from datasheet // name comes from datasheet
int MCP4725::_generalCall(const uint8_t gc) int MCP4725::_generalCall(const uint8_t gc)
{ {
_wire->beginTransmission(0); // _deviceAddress _wire->beginTransmission(0); // _deviceAddress
_wire->write(gc); _wire->write(gc);
return _wire->endTransmission(); return _wire->endTransmission();
} }

View File

@ -3,7 +3,7 @@
// FILE: MCP4725.h // FILE: MCP4725.h
// AUTHOR: Rob Tillaart // AUTHOR: Rob Tillaart
// PURPOSE: Arduino library for 12 bit I2C DAC - MCP4725 // PURPOSE: Arduino library for 12 bit I2C DAC - MCP4725
// VERSION: 0.3.6 // VERSION: 0.3.7
// URL: https://github.com/RobTillaart/MCP4725 // URL: https://github.com/RobTillaart/MCP4725
// //
@ -12,7 +12,7 @@
#include "Arduino.h" #include "Arduino.h"
#define MCP4725_VERSION (F("0.3.6")) #define MCP4725_VERSION (F("0.3.7"))
// CONSTANTS // CONSTANTS
@ -41,7 +41,9 @@ public:
explicit MCP4725(const uint8_t deviceAddress, TwoWire *wire = &Wire); explicit MCP4725(const uint8_t deviceAddress, TwoWire *wire = &Wire);
#if defined(ESP8266) || defined(ESP32) #if defined(ESP8266) || defined(ESP32)
bool begin(const uint8_t dataPin, const uint8_t clockPin); bool begin(const uint8_t dataPin, const uint8_t clockPin);
#endif #endif
#if defined (ARDUINO_ARCH_RP2040) #if defined (ARDUINO_ARCH_RP2040)
@ -60,16 +62,22 @@ public:
uint16_t getValue(); uint16_t getValue();
// 0..100.0% - no input check. // 0..100.0% - input checked.
// will set the closest integer value in range 0..4095
int setPercentage(float percentage = 0); int setPercentage(float percentage = 0);
// due to rounding the returned value can differ slightly.
float getPercentage(); float getPercentage();
// unfortunately it is not possible to write a different value
// to the DAC and EEPROM simultaneously or write EEPROM only.
int writeDAC(const uint16_t value, const bool EEPROM = false); int writeDAC(const uint16_t value, const bool EEPROM = false);
// ready checks if the last write to EEPROM has been written.
// until ready all writes to the MCP4725 are ignored!
bool ready(); bool ready();
uint16_t readDAC(); uint16_t readDAC();
uint16_t readEEPROM(); uint16_t readEEPROM();
uint32_t getLastWriteEEPROM(); uint32_t getLastWriteEEPROM(); // returns timestamp
// experimental // experimental

View File

@ -2,8 +2,11 @@
[![Arduino CI](https://github.com/RobTillaart/MCP4725/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) [![Arduino CI](https://github.com/RobTillaart/MCP4725/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/MCP4725/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/MCP4725/actions/workflows/arduino-lint.yml) [![Arduino-lint](https://github.com/RobTillaart/MCP4725/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/MCP4725/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/MCP4725/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/MCP4725/actions/workflows/jsoncheck.yml) [![JSON check](https://github.com/RobTillaart/MCP4725/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/MCP4725/actions/workflows/jsoncheck.yml)
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/MCP4725.svg)](https://github.com/RobTillaart/MCP4725/issues)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/MCP4725/blob/master/LICENSE) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/MCP4725/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/MCP4725.svg?maxAge=3600)](https://github.com/RobTillaart/MCP4725/releases) [![GitHub release](https://img.shields.io/github/release/RobTillaart/MCP4725.svg?maxAge=3600)](https://github.com/RobTillaart/MCP4725/releases)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/MCP4725.svg)](https://registry.platformio.org/libraries/robtillaart/MCP4725)
# MCP4725 # MCP4725
@ -23,6 +26,10 @@ of 2.7V .. 5.5V. Check datasheet for the details.
## Interface ## Interface
```cpp
#include "MCP4725.h"
```
### Constructor ### Constructor
- **MCP4725(uint8_t deviceAddress, TwoWire \*wire = &Wire)** Constructor, needs I2C address, optional set Wire bus - **MCP4725(uint8_t deviceAddress, TwoWire \*wire = &Wire)** Constructor, needs I2C address, optional set Wire bus
@ -32,7 +39,7 @@ Returns true if deviceAddress can be found on the I2C bus.
- **bool isConnected()** returns true if device (address) can be seen on the I2C bus. - **bool isConnected()** returns true if device (address) can be seen on the I2C bus.
### base ### Base
- **int setValue(uint16_t value = 0)** value = 0 .. 4095. - **int setValue(uint16_t value = 0)** value = 0 .. 4095.
Uses writeFastMode and does not write to EEPROM. Uses writeFastMode and does not write to EEPROM.
@ -114,9 +121,44 @@ Check RP2040 Pinout for compatible pins.
When Wire1 is used, it needs to be specified in the constructor with "&Wire1" When Wire1 is used, it needs to be specified in the constructor with "&Wire1"
## Operation ## Multi devices on one I2C bus
See examples Normal one can have 1 to 8 MCP4725 on a I2C bus. This depends on the right
choice of devices as 2 address bits are hard coded in the device.
See paragraph 7.2 datasheet + address notes section above.
But one cannot always order the right devices.
Especially breakout boards often have the same address-range.
#### TCA9548 I2C multiplexer
Use an I2C multiplexer to create multiple "I2C channels" which allows then
up to 8 devices per channel. Selecting the right devices includes setting
the I2C multiplexer to the right channel to address the right device.
This implies access is a bit slower and uses more code.
One (TCA9548) multiplexer allows one to control up to 64 MCP4725's.
- https://github.com/RobTillaart/TCA9548
Note that other multiplexers do exist.
#### Use A0 address pin as a SELECT pin
(Experimental)
Need to do more tests to see how this solution behaves in practice.
Verified to work - see https://forum.arduino.cc/t/using-digital-pins-to-control-two-mcp4725-modules/1161482/7.
The assumption here is that the devices are all from the same address range.
You can control multiple MCP4725 over the hardware I2C bus with an extra IO pin per device.
- Connect the address pin of every MCP4725 to an IO pin which will work as a **SELECT** pin.
- Keep all IO pins **LOW** so the all have effectively the same address == 0x60.
- To select a specific MCP4725 you set the related IO pin to **HIGH** and that one will have address == 0x61.
- Now you can access and control the associated MCP4725 with address 0x61.
- See **mcp4725_multiple.ino** and **mcp4725_multiple_minimal.ino**
## Future ## Future
@ -128,9 +170,18 @@ See examples
#### Should #### Should
- test the powerDown modes / functions. - test the powerDown modes / functions.
- test A0 (address bit) as SELECT pin.
#### Could #### Could
- extend unit tests - extend unit tests
## Support
If you appreciate my libraries, you can support the development and maintenance.
Improve the quality of the libraries by providing issues and Pull Requests, or
donate through PayPal or GitHub sponsors.
Thank you,

View File

@ -0,0 +1,92 @@
//
// FILE: mcp4725_multiple.ino
// AUTHOR: Rob Tillaart
// PURPOSE: test MCP4725 lib
// URL: https://github.com/RobTillaart/MCP4725
//
// simple example to control more than 2 devices over
// a single I2C bus without multiplexer.
// The A0 address pin is used as a SELECT pin.
//
// Every MCP device has its own object and can be
// accessed accordingly.
//
// To be tested / confirmed working with hardware.
#include "Wire.h"
#include "MCP4725.h"
// assume the 4 devices have the same A1 and A2
// hard-coded address bits. (par 7.2 datasheet)
// we will access all devices with as 0x63.
MCP4725 MCP0(0x63);
MCP4725 MCP1(0x63);
MCP4725 MCP2(0x63);
MCP4725 MCP3(0x63);
// connect the select pins to the A0 pins
// of the four MCP4725's
uint8_t selectPin[4] = { 4, 5, 6, 7 };
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MCP4725_VERSION: ");
Serial.println(MCP4725_VERSION);
for (int i = 0; i < 4; i++)
{
pinMode(selectPin[i], OUTPUT);
digitalWrite(selectPin[i], LOW);
}
select(0);
MCP0.begin();
select(1);
MCP1.begin();
select(2);
MCP2.begin();
select(3);
MCP3.begin();
}
void select(uint8_t nr)
{
for (int i = 0; i < 4; i++)
{
if (i != nr) digitalWrite(selectPin[i], LOW);
else digitalWrite(selectPin[i], HIGH);
}
}
void loop()
{
int x = analogRead(A0); // to create an output value.
// select one DAC and set the value.
select(0);
MCP0.setValue(x);
delay(250);
select(1);
MCP1.setValue(x * 2);
delay(250);
select(2);
MCP2.setValue(x * 3);
delay(250);
select(3);
MCP3.setValue(x * 4);
delay(250);
}
// -- END OF FILE --

View File

@ -0,0 +1,84 @@
//
// FILE: mcp4725_multiple_minimal.ino
// AUTHOR: Rob Tillaart
// PURPOSE: test MCP4725 lib
// URL: https://github.com/RobTillaart/MCP4725
//
// simple example to control more than 2 devices over
// a single I2C bus without multiplexer.
// The A0 address pin is used as a SELECT pin.
//
// One MCP4725 object is used to control 4 different devices.
// drawback is that you can only read back the last write.
//
// To be tested / confirmed working with hardware.
#include "Wire.h"
#include "MCP4725.h"
// assume the 4 devices have the same A1 and A2
// hard-coded address bits. (par 7.2 datasheet)
// we will access all devices with as 0x63.
MCP4725 MCP(0x63); // 0x62 or 0x63
// connect the select pins to the A0 pins
// of the four MCP4725's
uint8_t selectPin[4] = { 4, 5, 6, 7 };
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MCP4725_VERSION: ");
Serial.println(MCP4725_VERSION);
for (int i = 0; i < 4; i++)
{
pinMode(selectPin[i], OUTPUT);
digitalWrite(selectPin[i], LOW);
}
select(0);
MCP.begin();
}
void select(uint8_t nr)
{
for (int i = 0; i < 4; i++)
{
if (i != nr) digitalWrite(selectPin[i], LOW);
else digitalWrite(selectPin[i], HIGH);
}
}
void loop()
{
int x = analogRead(A0); // to create an output value.
// select one DAC and set the value.
select(0);
MCP.setValue(x);
delay(250);
select(1);
MCP.setValue(x * 2);
delay(250);
select(2);
MCP.setValue(x * 3);
delay(250);
select(3);
MCP.setValue(x * 4);
delay(250);
}
// -- END OF FILE --

View File

@ -15,9 +15,9 @@
"type": "git", "type": "git",
"url": "https://github.com/RobTillaart/MCP4725.git" "url": "https://github.com/RobTillaart/MCP4725.git"
}, },
"version": "0.3.6", "version": "0.3.7",
"license": "MIT", "license": "MIT",
"frameworks": "arduino", "frameworks": "*",
"platforms": "*", "platforms": "*",
"headers": "MCP4725.h" "headers": "MCP4725.h"
} }

View File

@ -1,5 +1,5 @@
name=MCP4725 name=MCP4725
version=0.3.6 version=0.3.7
author=Rob Tillaart <rob.tillaart@gmail.com> author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com> maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for 12 bit I2C DAC - MCP4725 sentence=Arduino library for 12 bit I2C DAC - MCP4725