GP8413 Arduino ESP32 NO Library
by AfricanCNC in Circuits > Arduino
11 Views, 0 Favorites, 0 Comments
GP8413 Arduino ESP32 NO Library

Here is an English translation of the DataSheet!
Downloads

Comparison and Improvement of GP8413 DAC Implementation VS DGRobot Library.
This implementation demonstrates a good understanding of the GP8413 DAC control; however, let's compare my code with the DFRobot library approach and highlight the improvements that enhance reliability and improve generic I2C bus sharing.
Key Differences
Bitbanging vs Hardware I2C:
My code uses the hardware I2C (Wire library)
DFRobot library uses bitbanging (software I2C)
Register Handling:
My Code is directly written to registers
DFRobot library abstracts this with higher-level functions
Error Handling:
DFRobot adds robust error checking
Improved Implementation
My code is an enhanced version that maintains hardware I2C but adds better bus sharing capabilities:
cpp
#include <Wire.h>
#define GP8413_ADDRESS 0x59
//#define SDA_PIN 22 // if reversed uncomment
//#define SCL_PIN 21 // if reversed uncomment
// Register definitions
#define GP8413_REG_CONFIG 0x01
#define GP8413_REG_CH0 0x02
#define GP8413_REG_CH1 0x04
#define GP8413_REG_STORE 0x06
// Configuration values
#define OUTPUT_RANGE_5V 0x00
#define OUTPUT_RANGE_10V 0x01
class GP8413 {
public:
GP8413(uint8_t address) : _address(address) {}
bool begin() {
Wire.begin(SDA_PIN, SCL_PIN); // known I2C bus handling now we can share the bus with this DAC
Wire.setClock(400000); // 400kHz // Max speed being able to make an 1kHz PWM
// Verify device presence
if (!isConnected()) {
return false;
}
// Set default range (0-5V)
return setOutputRange(OUTPUT_RANGE_5V);
}
bool isConnected() {
Wire.beginTransmission(_address);
return (Wire.endTransmission() == 0);
}
bool setOutputRange(uint8_t range) {
if (range > OUTPUT_RANGE_10V) return false;
Wire.beginTransmission(_address);
Wire.write(GP8413_REG_CONFIG);
Wire.write(range);
return (Wire.endTransmission() == 0);
}
bool setVoltage(uint16_t millivolts, uint8_t channel) {
if (channel > 1) return false;
// Convert mV to DAC value (0-5V range)
uint16_t dacValue = map(millivolts, 0, 5000, 0, 32767);
return setDACValue(dacValue, channel);
}
bool setDACValue(uint16_t value, uint8_t channel) {
if (channel > 1) return false;
value = constrain(value, 0, 32767);
uint8_t reg = (channel == 0) ? GP8413_REG_CH0 : GP8413_REG_CH1;
uint8_t lsb = value & 0xFF;
uint8_t msb = (value >> 8) & 0xFF;
Wire.beginTransmission(_address);
Wire.write(reg);
Wire.write(lsb);
Wire.write(msb);
return (Wire.endTransmission() == 0);
}
bool storeSettings() {
Wire.beginTransmission(_address);
Wire.write(GP8413_REG_STORE);
Wire.write(0x01); // Store command
return (Wire.endTransmission() == 0);
}
private:
uint8_t _address;
};
GP8413 dac(GP8413_ADDRESS);
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Initializing GP8413 DAC...");
if (!dac.begin()) {
Serial.println("Failed to initialize DAC!");
while(1);
}
Serial.println("DAC initialized successfully");
// Test sequence
testDAC();
}
void testDAC() {
Serial.println("Starting test sequence...");
// Ramp up channel 0
for (uint16_t mv = 0; mv <= 5000; mv += 100) {
dac.setVoltage(mv, 0);
Serial.printf("Channel 0: %dmV\n", mv);
delay(50);
}
// Ramp up channel 1
for (uint16_t mv = 0; mv <= 5000; mv += 100) {
dac.setVoltage(mv, 1);
Serial.printf("Channel 1: %dmV\n", mv);
delay(50);
}
// Store current settings (0V on both channels)
dac.setVoltage(0, 0);
dac.setVoltage(0, 1);
dac.storeSettings();
Serial.println("Stored zero settings in DAC memory");
}
void loop() {
// Generate PWM-like output
static bool state = false;
state = !state;ยง
if (state) {
dac.setVoltage(5000, 0); // 5V
dac.setVoltage(2500, 1); // 2.5V
} else {
dac.setVoltage(0, 0);
dac.setVoltage(0, 1);
}
delay(10); // 0.5Hz PWM
}
Key Improvements:
Proper Class Implementation:
Encapsulates all DAC functionality in a clean class
Better separation of concerns
Enhanced Error Handling:
Methods return success/failure status
Input validation
Voltage-Level Interface:
Works in millivolts for easier use
Handles conversion to DAC values internally
Bus Sharing Friendly:
Uses the standard Wire library
Proper beginning/end transactions
Doesn't hold the bus unnecessarily
Non-Blocking:
No long delays in critical sections
Suitable for multi-device I2C buses
Configuration Storage:
Proper implementation of the store function
Recommendations for I2C Bus Sharing
Add Bus Recovery:
cpp
void recoverI2CBus() {
Wire.end();
pinMode(SDA_PIN, INPUT);
pinMode(SCL_PIN, INPUT);
}
Add Transaction Wrapper:
cpp
bool safeI2CTransaction(void (*transaction)(), uint8_t retries = 3) {
for (uint8_t i = 0; i < retries; i++) {
transaction();
if (Wire.endTransmission() == 0) {
return true;
}
delay(1);
}
recoverI2CBus();
return false;
}
This implementation provides the reliability of the DFRobot library while maintaining direct control over the I2C bus, which is crucial when sharing the bus with other devices, such as the INA228 and EEPROM or any other generic I2C device.