mirror of
https://github.com/Architeuthis-Flux/Jumperless.git
synced 2024-12-18 10:15:55 +01:00
455 lines
13 KiB
C++
455 lines
13 KiB
C++
/*!
|
|
@file mcp4725.cpp
|
|
@author Gavin Lyons
|
|
@brief MCP4725 DAC library cpp file.
|
|
*/
|
|
|
|
#include "mcp4725.hpp"
|
|
|
|
|
|
/*!
|
|
@brief Constructor for class MCP4725_PIC0
|
|
@param refV The the reference voltage to be set in Volts.
|
|
*/
|
|
MCP4725_PICO::MCP4725_PICO(float refV)
|
|
{
|
|
setReferenceVoltage(refV);
|
|
}
|
|
|
|
/*!
|
|
@brief Init & config i2c
|
|
@param addr I2C address 8 bit address 0x6?.
|
|
@param i2c_type I2C instance of port, IC20 or I2C1.
|
|
@param CLKspeed I2C Bus Clock speed in Kbit/s. see 7.1 datasheet
|
|
@param SDApin I2C Data GPIO
|
|
@param SCLKpin I2C Clock GPIO
|
|
@return true if success , false for failure
|
|
*/
|
|
bool MCP4725_PICO::begin(MCP4725_I2C_Addr_e addr, i2c_inst_t* i2c_type, uint16_t CLKspeed, uint8_t SDApin, uint8_t SCLKpin)
|
|
{
|
|
uint8_t rxData = 0;
|
|
|
|
// init I2c pins and interface
|
|
_i2cAddress = addr;
|
|
_i2c = i2c_type;
|
|
_SClkPin = SCLKpin;
|
|
_SDataPin = SDApin;
|
|
_CLKSpeed = CLKspeed;
|
|
gpio_set_function(_SDataPin, GPIO_FUNC_I2C);
|
|
gpio_set_function(_SClkPin, GPIO_FUNC_I2C);
|
|
gpio_pull_up(_SDataPin);
|
|
gpio_pull_up(_SClkPin);
|
|
i2c_init(_i2c, _CLKSpeed * 1000);
|
|
busy_wait_ms(50);
|
|
// check connection?
|
|
return isConnected();
|
|
}
|
|
|
|
/*!
|
|
@brief Switch off the I2C interface and return I2C GPIO to default state
|
|
*/
|
|
void MCP4725_PICO::deinitI2C()
|
|
{
|
|
gpio_set_function(_SDataPin, GPIO_FUNC_NULL);
|
|
gpio_set_function(_SClkPin, GPIO_FUNC_NULL);
|
|
i2c_deinit(_i2c);
|
|
}
|
|
|
|
/*!
|
|
@brief Checks if DAC is connected.
|
|
@return true if DAC is connected , false if not
|
|
*/
|
|
bool MCP4725_PICO::isConnected()
|
|
{
|
|
int ReturnCode = 0;
|
|
uint8_t rxData = 0;
|
|
// check connection?
|
|
ReturnCode = i2c_read_timeout_us(_i2c, _i2cAddress , &rxData, 1, false, MCP4725_I2C_DELAY);
|
|
if (ReturnCode < 1){ // no bytes read back from device or error issued
|
|
if (_serialDebug == true)
|
|
{
|
|
printf("1202 PICO_MCP4725::is connected: \r\n");
|
|
printf("Check Connection, Return code :: %d ,RX data :: %u \r\n", ReturnCode , rxData);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
@brief Sets the reference voltage.
|
|
@param voltage the reference voltage to be set, called from constructor.
|
|
*/
|
|
void MCP4725_PICO::setReferenceVoltage(float voltage)
|
|
{
|
|
if (voltage == 0)
|
|
_refVoltage = MCP4725_REFERENCE_VOLTAGE;
|
|
else
|
|
_refVoltage = voltage;
|
|
|
|
_bitsPerVolt = (float)MCP4725_STEPS / _refVoltage;
|
|
}
|
|
|
|
/*!
|
|
@brief Gets the reference voltage.
|
|
@return The reference voltage in volts.
|
|
*/
|
|
float MCP4725_PICO::getReferenceVoltage(){return _refVoltage;}
|
|
|
|
/*!
|
|
@brief Set voltage out based on DAC input code.
|
|
@param InputCode 0 to MCP4725_MAX_VALUE.
|
|
@param mode MCP4725DAC mode, see enum MCP4725_CmdType_e.
|
|
@param powerType MCP4725DAC power type, see enum MCP4725_PowerType_e
|
|
@return output of writeCommand method, true for success, false for failure.
|
|
*/
|
|
bool MCP4725_PICO::setInputCode(uint16_t InputCode, MCP4725_CmdType_e mode, MCP4725_PowerDownType_e powerType)
|
|
{
|
|
if (_safetyCheck == true)
|
|
{
|
|
if (InputCode > MCP4725_MAX_VALUE)
|
|
InputCode = MCP4725_MAX_VALUE;
|
|
}
|
|
|
|
return writeCommand(InputCode, mode, powerType);
|
|
}
|
|
|
|
/*!
|
|
@brief Set voltage out based on voltage input in volts.
|
|
@param voltage 0 to_MCP4725_REFERENCE_VOLTAGE, voltage out
|
|
@param mode MCP4725DAC mode, see enum MCP4725_CmdType_e.
|
|
@param powerType MCP4725DAC power type, see enum MCP4725_PowerType_e
|
|
@return output of writeCommand method, true for success, false for failure.
|
|
*/
|
|
bool MCP4725_PICO::setVoltage(float voltage, MCP4725_CmdType_e mode, MCP4725_PowerDownType_e powerType)
|
|
{
|
|
uint16_t voltageValue = 0;
|
|
|
|
// Convert voltage to DAC bits
|
|
//xx,xx,xx,xx,D11,D10,D9,D8 ,D7,D6,D4,D3,D2,D9,D1,D0
|
|
if (_safetyCheck == true)
|
|
{
|
|
if (voltage >= _refVoltage)
|
|
voltageValue = MCP4725_MAX_VALUE;
|
|
else if (voltage <= 0)
|
|
voltageValue = 0; //make sure value never below zero
|
|
else
|
|
voltageValue = voltage * _bitsPerVolt;
|
|
}
|
|
else if (_safetyCheck == false)
|
|
{
|
|
voltageValue = voltage * _bitsPerVolt;
|
|
}
|
|
|
|
return writeCommand(voltageValue, mode, powerType);
|
|
}
|
|
|
|
|
|
/*!
|
|
@brief get current DAC InputCode from DAC register
|
|
@return DAC InputCode :or 0xFFFF if I2C error
|
|
*/
|
|
uint16_t MCP4725_PICO::getInputCode()
|
|
{
|
|
uint16_t inputCode = readRegister(MCP4725_ReadDACReg);
|
|
// InputCode = D11,D10,D9,D8,D7,D6,D5,D4, D3,D2,D1,D0,x,x,x,x
|
|
|
|
if (inputCode != MCP4725_ERROR)
|
|
return inputCode >> 4; //0,0,0,0,D11,D10,D9,D8, D7,D6,D5,D4,D3,D2,D1,D0
|
|
else
|
|
return inputCode; // i2c Error return 0xFFFF
|
|
}
|
|
|
|
|
|
/*!
|
|
@brief get DAC inputCode from DAC register & convert to volts
|
|
@return DAC voltage or 0xFFFF if I2C error
|
|
*/
|
|
float MCP4725_PICO::getVoltage()
|
|
{
|
|
float InputCode = getInputCode();
|
|
if (InputCode != MCP4725_ERROR)
|
|
return InputCode / _bitsPerVolt;
|
|
else
|
|
return InputCode; // i2c Error return 0xFFFF
|
|
}
|
|
|
|
/*!
|
|
@brief Read DAC inputCode from EEPROM
|
|
@return stored EEPROM inputcode value or 0xFFFF if I2C error
|
|
*/
|
|
uint16_t MCP4725_PICO::getStoredInputCode()
|
|
{
|
|
uint16_t inputCode = readRegister(MCP4725_ReadEEPROM);
|
|
//InputCode = x,PD1,PD0,x,D11,D10,D9,D8, D7,D6,D5,D4,D3,D2,D1,D0
|
|
|
|
if (inputCode != MCP4725_ERROR)
|
|
return inputCode & 0x0FFF; //0,0,0,0,D11,D10,D9,D8, D7,D6,D5,D4,D3,D2,D1,D0
|
|
else
|
|
return inputCode; // i2c Error return 0xFFFF
|
|
}
|
|
|
|
|
|
/*!
|
|
@brief Read stored DAC InputCode from EEPROM & convert to voltage
|
|
@return stored EEPROM voltage or 0xFFFF if I2C error
|
|
*/
|
|
float MCP4725_PICO::getStoredVoltage()
|
|
{
|
|
float InputCode = getStoredInputCode();
|
|
|
|
if (InputCode != MCP4725_ERROR)
|
|
return InputCode / _bitsPerVolt;
|
|
else
|
|
return InputCode;
|
|
}
|
|
|
|
/*!
|
|
@brief Get current power type from DAC register
|
|
@return power type or 0xFFFF if I2C error
|
|
@note Power type corresponds to enum MCP4725_PowerDownType_e
|
|
*/
|
|
uint16_t MCP4725_PICO::getPowerType()
|
|
{
|
|
uint16_t powerTypeValue = readRegister(MCP4725_ReadSettings);
|
|
//powerTypeValue = BSY,POR,xx,xx,xx,PD1,PD0,xx
|
|
|
|
if (powerTypeValue != MCP4725_ERROR){
|
|
powerTypeValue &= 0x0006; //00,00,00,00,00,PD1,PD0,00
|
|
return powerTypeValue >> 1; //00,00,00,00,00,00,PD1,PD0
|
|
}else{
|
|
return powerTypeValue;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
@brief Get stored power type from EEPROM
|
|
@return EEPROM power type or 0xFFFF if I2C error
|
|
@note Power type corresponds to enum MCP4725_PowerDownType_e
|
|
*/
|
|
uint16_t MCP4725_PICO::getStoredPowerType()
|
|
{
|
|
uint16_t powerTypeValue = readRegister(MCP4725_ReadEEPROM);
|
|
//powerTypeValue = x,PD1,PD0,xx,D11,D10,D9,D8,D7,D6,D5,D4,D3,D2,D1,D0
|
|
|
|
if (powerTypeValue != MCP4725_ERROR)
|
|
{
|
|
powerTypeValue = powerTypeValue << 1; //PD1,PD0,xx,D11,D10,D9,D8,D7,D6,D5,D4,D3,D2,D1,D0,00
|
|
return powerTypeValue >> 14; //00,00,00,00,00,00,00,00,00,00,00,00,00,00,PD1,PD0
|
|
}else
|
|
{
|
|
return powerTypeValue;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
@brief get EEPROM writing status from DAC register
|
|
@return 1 for completed or 0( busy or I2C error)
|
|
@note The BSY bit is low (during the EEPROM writing)
|
|
*/
|
|
bool MCP4725_PICO::getEEPROMBusyFlag()
|
|
{
|
|
uint16_t registerValue = readRegister(MCP4725_ReadSettings);
|
|
//register value = BSY,POR,xx,xx,xx,PD1,PD0,xx
|
|
bool ReturnValue = false;
|
|
if (registerValue != MCP4725_ERROR)
|
|
{
|
|
ReturnValue = ((registerValue >> 7) & 0x01);
|
|
return ReturnValue; //1 - Not Busy, 0 - Busy
|
|
}else
|
|
{
|
|
return ReturnValue; // I2C error
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
@brief Writes data to DAC register or EEPROM
|
|
@param inputCode 0 to MCP4725_MAX_VALUE input code
|
|
@param mode MCP4725DAC mode, see enum MCP4725_CmdType_e.
|
|
@param PowerType MCP4725 power type, see enum MCP4725_PowerType_e
|
|
@return true for success, false for failure.
|
|
*/
|
|
bool MCP4725_PICO::writeCommand(uint16_t inputCode, MCP4725_CmdType_e mode, MCP4725_PowerDownType_e powerType)
|
|
{
|
|
uint8_t dataBuffer[3];
|
|
uint8_t lowByte = 0;
|
|
uint8_t highByte = 0;
|
|
int ReturnCode = 0;
|
|
|
|
switch (mode)
|
|
{
|
|
case MCP4725_FastMode:
|
|
//C2=0,C1=0,PD1,PD0,D11,D10,D9,D8,D7,D6,D5,D4,D3,D2,D1,D0
|
|
lowByte = (uint8_t)(inputCode & 0x00FF);
|
|
highByte = (uint8_t)((inputCode >> 8) & 0x00FF);
|
|
dataBuffer[0] = mode | (powerType << 4) | highByte; //C2,C1,PD1,PD0,D11,D10,D9,D8
|
|
dataBuffer[1] = lowByte; //D7,D6,D5,D4,D3,D2,D1,D0
|
|
ReturnCode = i2c_write_timeout_us(_i2c, _i2cAddress, dataBuffer, 2 , false, MCP4725_I2C_DELAY);
|
|
if (ReturnCode < 1)
|
|
{
|
|
if (_serialDebug == true)
|
|
{
|
|
printf("1203 : I2C error :: WriteCommand 1 \r\n");
|
|
printf("Tranmission code : %d \r\n", ReturnCode );
|
|
busy_wait_ms(100);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
|
|
case MCP4725_RegisterMode:
|
|
//C2=0,C1=1,C0=0,x,x,PD1,PD0,x,D11,D10,D9,D8,D7,D6,D5,D4,D3,D2,D1,D0,x,x,x,x
|
|
case MCP4725_EEPROM_Mode:
|
|
//C2=0,C1=1,C0=1,x,x,PD1,PD0,x,D11,D10,D9,D8,D7,D6,D5,D4,D3,D2,D1,D0,x,x,x,x
|
|
inputCode = inputCode << 4; //D11,D10,D9,D8,D7,D6,D5,D4,D3,D2,D1,D0,x,x,x,x
|
|
lowByte = (uint8_t)(inputCode & 0x00FF);
|
|
highByte = (uint8_t)((inputCode >> 8) & 0x00FF);
|
|
dataBuffer[0] = mode | (powerType << 1); // C2,C1,C0,x,x,PD1,PD0,x
|
|
dataBuffer[1] = highByte; // D11,D10,D9,D8,D7,D6,D5,D4
|
|
dataBuffer[2] = lowByte; // D3,D2,D1,D0,x,x,x,x
|
|
ReturnCode = i2c_write_timeout_us(_i2c, _i2cAddress, dataBuffer, 3 , false, MCP4725_I2C_DELAY);
|
|
if (ReturnCode < 1)
|
|
{
|
|
if (_serialDebug == true)
|
|
{
|
|
printf("1204 : I2C error :: writeCommand 2 \r\n");
|
|
printf("Tranmission code : %d \r\n", ReturnCode );
|
|
busy_wait_ms(100);
|
|
}
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (mode == MCP4725_EEPROM_Mode)
|
|
{
|
|
if (getEEPROMBusyFlag() == true)
|
|
return true;
|
|
busy_wait_ms(MCP4725_EEPROM_WRITE_TIME); //typical EEPROM write time 25 mSec
|
|
if (getEEPROMBusyFlag() == true)
|
|
return true;
|
|
busy_wait_ms(MCP4725_EEPROM_WRITE_TIME); //maximum EEPROM write time 25*2 mSec
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
@brief Read DAC register
|
|
@param mode MCP4725DAC datatype 1 3 or 5, see enum MCP4725_ReadType_e.
|
|
@return Requested value of read or type 0XFFFF if I2c error
|
|
*/
|
|
uint16_t MCP4725_PICO::readRegister(MCP4725_ReadType_e readType)
|
|
{
|
|
uint16_t dataWord = readType;
|
|
uint8_t dataBuffer[6];
|
|
int ReturnCode = 0;
|
|
|
|
/*Format of read data :
|
|
== Settings data one byte
|
|
BSY,POR,xx,xx,xx,PD1,PD0,xx,
|
|
== DAC register data 3 byte(1st 1 don't care)
|
|
D11,D10,D9,D8,D7,D6,D5,D4, D3,D2,D1,D0,xx,xx,xx,xx,
|
|
== EEPROM data 5 byte (1st 3 don't care)
|
|
xx,PD1,PD0,xx,D11,D10,D9,D8, D7,D6,D5,D4,D3,D2,D1,D0
|
|
*/
|
|
switch (readType)
|
|
{
|
|
case MCP4725_ReadSettings: // Read one byte settings
|
|
ReturnCode = i2c_read_timeout_us(_i2c, _i2cAddress, dataBuffer, 1, false, MCP4725_I2C_DELAY);
|
|
dataWord = dataBuffer[0];
|
|
break;
|
|
|
|
case MCP4725_ReadDACReg: // Read 3 bytes DAC register data, skip first 1 don't care
|
|
ReturnCode = i2c_read_timeout_us(_i2c, _i2cAddress, dataBuffer, 3, false, MCP4725_I2C_DELAY);
|
|
dataWord = dataBuffer[1];
|
|
dataWord = (dataWord << 8) | dataBuffer[2];
|
|
break;
|
|
|
|
case MCP4725_ReadEEPROM: // Read 5 bytes EEPROM data , first 3 don't care
|
|
ReturnCode = i2c_read_timeout_us(_i2c, _i2cAddress, dataBuffer, 5, false, MCP4725_I2C_DELAY);
|
|
dataWord = dataBuffer[3];
|
|
dataWord = (dataWord << 8) | dataBuffer[4];
|
|
break;
|
|
}
|
|
|
|
if (ReturnCode < 1)
|
|
{ // no bytes read back from device or error issued
|
|
if (_serialDebug == true)
|
|
{
|
|
printf("1205 I2C Error readRegister : \r\n");
|
|
printf("Tranmission Code :: %d\r\n", ReturnCode);
|
|
busy_wait_ms(100);
|
|
}
|
|
return MCP4725_ERROR;
|
|
}else{
|
|
return dataWord;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
@brief Setter for serial debug flag
|
|
@param onOff Turns or or off the serial debug flag
|
|
*/
|
|
void MCP4725_PICO::setSerialDebugFlag(bool onOff){_serialDebug = onOff;}
|
|
|
|
/*!
|
|
@brief Gets the serial Debug flag value
|
|
@return The serial Debug flag value
|
|
*/
|
|
bool MCP4725_PICO::getSerialDebugFlag(void){return _serialDebug;}
|
|
|
|
/*!
|
|
@brief Setter for safety Check flag
|
|
@param onOff Turns or or off the safety check flag
|
|
*/
|
|
void MCP4725_PICO::setSafetyCheckFlag(bool onOff){_safetyCheck = onOff;}
|
|
|
|
/*!
|
|
@brief Gets the safety Check flag value
|
|
@return The safety Check flag value
|
|
*/
|
|
bool MCP4725_PICO::getSafetyCheckFlag(){return _safetyCheck;}
|
|
|
|
|
|
/*!
|
|
@brief General Call, name from datasheet section 7.3
|
|
@param typeCall Reset or wakeup see MCP4725_GeneralCallType_e.
|
|
@return True on success, false on I2c error OR wrong input(GeneralCallAddress)
|
|
@note
|
|
1. Reset MCP4725 & upload data from EEPROM to DAC register.
|
|
Immediately after reset event, uploads contents of EEPROM into the DAC reg.
|
|
2. Wake up & upload value from DAC register,
|
|
Current power-down bits are set to normal, EEPROM power-down bit are not affected
|
|
*/
|
|
bool MCP4725_PICO::GeneralCall(MCP4725_GeneralCallType_e typeCall){
|
|
|
|
if (typeCall == MCP4725_GeneralCallAddress) {return false;}
|
|
|
|
int ReturnCode = 0;
|
|
uint8_t dataBuffer[1];
|
|
|
|
dataBuffer[0] = (uint8_t)typeCall;
|
|
// Note I2c address is MCP4725_GENERAL_CALL_ADDRESS
|
|
ReturnCode = i2c_write_timeout_us(_i2c, (uint8_t)MCP4725_GeneralCallAddress, dataBuffer, 1 , false, MCP4725_I2C_DELAY);
|
|
|
|
if (ReturnCode < 1)
|
|
{ // no bytes read back from device or error issued
|
|
if (_serialDebug == true)
|
|
{
|
|
printf("1206 I2C Error General Call : \r\n");
|
|
printf("Tranmission Code :: %d\r\n", ReturnCode);
|
|
busy_wait_ms(100);
|
|
}
|
|
return false;
|
|
}else{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// ------------------ EOF ------------------------
|