Jag har skrivit av denna kod från C++ kod till C kod. Jag får inte det fungera med konstruktörens (mcp4728_init) adress.
Är det vanligt att man måste bitbanga för I2C?
Jag menar, det är en ren svaghet från ST's sida om de inte uppfyller att dom ej kan ta allas I2C protokoll. Det skall ju vara samma!
https://github.com/BenoitSchillings/mcp4728
Source.
Kod: Markera allt
/* _____PROJECT INCLUDES_____________________________________________________ */
#include "mcp4728.h"
/* ____PRIVATE FIELDs__________________________________________________________*/
static I2C_HandleTypeDef *_i2c;
static uint8_t _dev_address;
static uint8_t _deviceID;
static uint8_t _intVref[4] = {0};
static uint8_t _gain[4] = {0};
static uint8_t _powerDown[4] = {0};
static uint16_t _values[4] = {0};
static uint16_t _valuesEp[4] = {0};
static uint8_t _intVrefEp[4] = {0};
static uint8_t _gainEp[4] = {0};
static uint8_t _powerDownEp[4] = {0};
static uint16_t _vOut[4] = {0};
static uint16_t _vdd;
/* _____PRIVATE FUNCTIONS_____________________________________________________ */
/*
Get current values (input register and eeprom) of mcp4728
*/
static void getStatus(){
uint8_t pData[24];
HAL_I2C_Master_Receive(_i2c, _dev_address, pData, sizeof(pData), 100);
uint8_t deviceID = pData[0];
uint8_t hiByte = pData[1];
uint8_t loByte = pData[2];
//Serial.print("did ");Serial.println(deviceID);
//Serial.println(hiByte);
//Serial.println(loByte);
uint8_t isEEPROM = (deviceID & 0b00001000) >> 3;
uint8_t channel = (deviceID & 0b00110000) >> 4;
//Serial.println(isEEPROM);
//Serial.println(channel);
if (isEEPROM == 1) {
_intVrefEp[channel] = (hiByte & 0b10000000) >> 7;
_gainEp[channel] = (hiByte & 0b00010000) >> 4;
_powerDownEp[channel] = (hiByte & 0b01100000) >> 5;
_valuesEp[channel] = (hiByte & 0b00001111) << 8 | loByte;
}
else {
_intVref[channel] = (hiByte & 0b10000000) >> 7;
_gain[channel] = (hiByte & 0b00010000) >> 4;
_powerDown[channel] = (hiByte & 0b01100000) >> 5;
_values[channel] = (hiByte & 0b00001111) << 8 | loByte;
}
}
/*
FastWrite input register values - All DAC ouput update. refer to DATASHEET 5.6.1
DAC Input and PowerDown bits update.
No EEPROM update
*/
static void fastWrite() {
uint8_t pData[2];
for (uint8_t channel=0; channel <= 3; channel++) {
pData[0] = _values[channel] >> 8;
pData[1] = _values[channel];
HAL_I2C_Master_Transmit(_i2c, _dev_address, pData, sizeof(pData), 10);
}
}
/*
MultiWrite input register values - All DAC ouput update. refer to DATASHEET 5.6.2
DAC Input, Gain, Vref and PowerDown bits update
No EEPROM update
*/
static void multiWrite() {
uint8_t pData[3];
for (uint8_t channel=0; channel <= 3; channel++) {
pData[0] = MULTIWRITE | (channel << 1);
pData[1] = _intVref[channel] << 7 | _powerDown[channel] << 5 | _gain[channel] << 4 | (_values[channel] >> 8);
pData[1] = _values[channel];
HAL_I2C_Master_Transmit(_i2c, _dev_address, pData, sizeof(pData), 10);
}
}
/*
SingleWrite input register and EEPROM - a DAC ouput update. refer to DATASHEET 5.6.4
DAC Input, Gain, Vref and PowerDown bits update
EEPROM update
*/
static void singleWrite(uint8_t channel) {
uint8_t pData[3];
pData[0] = SINGLEWRITE | (channel << 1);
pData[1] = _intVref[channel] << 7 | _powerDown[channel] << 5 | _gain[channel] << 4 | (_values[channel] >> 8);
pData[2] = _values[channel];
HAL_I2C_Master_Transmit(_i2c, _dev_address, pData, sizeof(pData), 10);
}
/*
SequencialWrite input registers and EEPROM - ALL DAC ouput update. refer to DATASHEET 5.6.3
DAC Input, Gain, Vref and PowerDown bits update
EEPROM update
*/
static void seqWrite() {
uint8_t preData[1] = {SEQWRITE};
HAL_I2C_Master_Transmit(_i2c, _dev_address, preData, sizeof(preData), 10);
uint8_t pData[2];
for (uint8_t channel=0; channel <= 3; channel++) {
pData[0] = _intVref[channel] << 7 | _powerDown[channel] << 5 | _gain[channel] << 4 | (_values[channel] >> 8);
pData[1] = _values[channel];
HAL_I2C_Master_Transmit(_i2c, _dev_address, pData, sizeof(pData), 10);
}
}
/*
Write Voltage reference setting to input registers. refer to DATASHEET 5.6.5
No EEPROM update
*/
static void writeVref() {
uint8_t pData[1];
pData[0] = VREFWRITE | _intVref[0] << 3 | _intVref[1] << 2 | _intVref[2] << 1 | _intVref[3];
HAL_I2C_Master_Transmit(_i2c, _dev_address, pData, sizeof(pData), 10);
}
/*
Write Gain setting to input registers. refer to DATASHEET 5.6.7
No EEPROM update
*/
static void writeGain() {
uint8_t pData[1];
pData[0] = GAINWRITE | _gain[0] << 3 | _gain[1] << 2 | _gain[2] << 1 | _gain[3];
HAL_I2C_Master_Transmit(_i2c, _dev_address, pData, sizeof(pData), 10);
}
/*
Write PowerDown setting to input registers. refer to DATASHEET 5.6.6
No EEPROM update
*/
static void writePowerDown() {
uint8_t pData[2];
pData[0] = POWERDOWNWRITE | _powerDown[0] << 2 | _powerDown[1];
pData[1] = _powerDown[2] << 6 | _powerDown[3] << 4;
HAL_I2C_Master_Transmit(_i2c, _dev_address, pData, sizeof(pData), 10);
}
/*
Calculate Voltage out based on current setting of Vref and gain
No EEPROM update
*/
static void writeVout(){
for (uint8_t channel=0; channel <= 3; channel++) {
if (_intVref[channel] == 1) {
_values[channel] = _vOut[channel] / (_gain[channel] + 1) * 2;
}
else {
_values[channel] = (_vOut[channel] * 4096) / _vdd ;
}
}
fastWrite();
}
/*
Common function for simple genenral commands
*/
static void simpleCommand(uint8_t command) {
uint8_t pData[1] = {command};
HAL_I2C_Master_Transmit(_i2c, GENERALCALL, pData, sizeof(pData), 10);
}
/* _____PUBLIC FUNCTIONS_____________________________________________________ */
/**
Constructor. Creates class object. Initialize buffers
*/
void mcp4728_init(I2C_HandleTypeDef *i2c, uint8_t deviceID){
_deviceID = deviceID;
_dev_address = (BASE_ADDR | _deviceID);
_vdd = defaultVDD;
_i2c = i2c;
getStatus();
}
/*
General Call Reset of mcp4728 - EEPROM value will loaded to input register. refer to DATASHEET 5.4.1
*/
void mcp4728_reset() {
simpleCommand(RESET);
}
/*
General Call Wake-Up of mcp4728 - Reset Power-Down bits (PD0,PD1 = 0,0). refer to DATASHEET 5.4.2
*/
void mcp4728_wake() {
simpleCommand(WAKE);
}
/*
General Call Software update of mcp4728 - All DAC ouput update. refer to DATASHEET 5.4.3
*/
void mcp4728_update() {
simpleCommand(UPDATE);
}
/*
Write input register values to each channel using fastwrite method.
Values : 0-4095
*/
void mcp4728_analogWrite(uint16_t value1, uint16_t value2, uint16_t value3, uint16_t value4) {
_values[0] = value1;
_values[1] = value2;
_values[2] = value3;
_values[3] = value4;
fastWrite();
}
/*
Write input resister value to specified channel using fastwrite method.
Channel : 0-3, Values : 0-4095
*/
void mcp4728_analogWriteFastWriteSpecific(uint8_t channel, uint16_t value) {
_values[channel] = value;
fastWrite();
}
/*
Write a value to specified channel using singlewrite method.
This will update both input register and EEPROM value
Channel : 0-3, Values : 0-4095
*/
void mcp4728_eepromWriteSpecific(uint8_t channel, uint16_t value) {
_values[channel] = value;
_valuesEp[channel] = value;
singleWrite(channel);
}
/*
Write values to each channel using SequencialWrite method.
This will update both input register and EEPROM value
Channel : 0-3, Values : 0-4095
*/
void mcp4728_eepromWriteMultiple(uint16_t value1, uint16_t value2, uint16_t value3, uint16_t value4) {
_valuesEp[0] = _values[0] = value1;
_valuesEp[1] = _values[1] = value2;
_valuesEp[2] = _values[2] = value3;
_valuesEp[3] = _values[3] = value4;
seqWrite();
}
/*
Write all input resistor values to EEPROM using SequencialWrite method.
This will update both input register and EEPROM value
This will also write current Vref, PowerDown, Gain settings to EEPROM
*/
void mcp4728_eepromWriteAll(){
seqWrite();
}
/*
Reset EEPROM and input register to factory default. Refer datasheet TABLE 4-2
Input value = 0, Voltage Reference = 1 (internal), Gain = 0, PowerDown = 0
*/
void mcp4728_eepromReset(){
_values[0] = _values[1] = _values[2] = _values[3] = 0;
_intVref[0] = _intVref[1] = _intVref[2] = _intVref[3] = 1;
_gain[0] = _gain[1] = _gain[2] = _gain[3] = 0;
_powerDown[0] = _powerDown[1] = _powerDown[2] = _powerDown[3] = 0;
seqWrite();
}
/*
Write Voltage reference settings to input regiters
Vref setting = 1 (internal), Gain = 0 (x1) ==> Vref = 2.048V
Vref setting = 1 (internal), Gain = 1 (x2) ==> Vref = 4.096V
Vref setting = 0 (external), Gain = ignored ==> Vref = VDD
*/
void mcp4728_setVrefMultiple(uint8_t value1, uint8_t value2, uint8_t value3, uint8_t value4) {
_intVref[0] = value1;
_intVref[1] = value2;
_intVref[2] = value3;
_intVref[3] = value4;
writeVref();
}
/*
Write Voltage reference setting to a input regiter
*/
void mcp4728_setVrefSpecific(uint8_t channel, uint8_t value) {
_intVref[channel] = value;
writeVref();
}
/*
Write Gain settings to input regiters
Vref setting = 1 (internal), Gain = 0 (x1) ==> Vref = 2.048V
Vref setting = 1 (internal), Gain = 1 (x2) ==> Vref = 4.096V
Vref setting = 0 (external), Gain = ignored ==> Vref = VDD
*/
void mcp4728_setGainMultiple(uint8_t value1, uint8_t value2, uint8_t value3, uint8_t value4) {
_gain[0] = value1;
_gain[1] = value2;
_gain[2] = value3;
_gain[3] = value4;
writeGain();
}
/*
Write Gain setting to a input register
*/
void mcp4728_setGainSpecific(uint8_t channel, uint8_t value) {
_gain[channel] = value;
writeGain();
}
/*
Write Power-Down settings to input regiters
0 = Normal , 1-3 = shut down most channel circuit, no voltage out and saving some power.
1 = 1K ohms to GND, 2 = 100K ohms to GND, 3 = 500K ohms to GND
*/
void mcp4728_setPowerDownMultiple(uint8_t value1, uint8_t value2, uint8_t value3, uint8_t value4) {
_powerDown[0] = value1;
_powerDown[1] = value2;
_powerDown[2] = value3;
_powerDown[3] = value4;
writePowerDown();
}
/*
Write Power-Down setting to a input register
*/
void mcp4728_setPowerDownSpecific(uint8_t channel, uint8_t value) {
_powerDown[channel] = value;
writePowerDown();
}
/*
Return Device ID (up to 8 devices can be used in a I2C bus, Device ID = 0-7)
*/
uint8_t mcp4728_getId(){
return _deviceID;
}
/*
Return Voltage Rerference setting
*/
uint8_t mcp4728_getVref(uint8_t channel){
return _intVref[channel];
}
/*
Return Gain setting
*/
uint8_t mcp4728_getGain(uint8_t channel){
return _gain[channel];
}
/*
Return PowerDown setting
*/
uint8_t mcp4728_getPowerDown(uint8_t channel){
return _powerDown[channel];
}
/*
Return Input Regiter value
*/
uint16_t mcp4728_getValue(uint8_t channel){
return _values[channel];
}
/*
Return EEPROM Voltage Rerference setting
*/
uint8_t mcp4728_getVrefEp(uint8_t channel){
return _intVrefEp[channel];
}
/*
Return EEPROM Gain setting
*/
uint8_t mcp4728_getGainEp(uint8_t channel){
return _gainEp[channel];
}
/*
Return EEPROM PowerDown setting
*/
uint8_t mcp4728_getPowerDownEp(uint8_t channel){
return _powerDownEp[channel];
}
/*
Return EEPROM value
*/
uint16_t mcp4728_getValueEp(uint8_t channel){
return _valuesEp[channel];
}
/*
Set VDD for Vout calculation
*/
void mcp4728_vdd(uint16_t currentVdd){
_vdd = currentVdd;
}
/*
Return Vout
*/
uint16_t mcp4728_getVout(uint8_t channel){
uint32_t vref;
if (_intVref[channel] == 1) {
vref = 2048;
}
else {
vref = _vdd;
}
uint32_t vOut = (vref * _values[channel] * (_gain[channel] + 1)) / 4096;
if (vOut > _vdd) {
vOut = _vdd;
}
return vOut;
}
/*
write to input register of DAC. Value(mV) (V < VDD)
*/
void mcp4728_voutWriteSpecific(uint8_t channel, uint16_t vout){
_vOut[channel] = vout;
writeVout();
}
/*
write to input registers of DACs. Value(mV) (V < VDD)
*/
void mcp4728_voutWriteMultiple(uint16_t value1, uint16_t value2, uint16_t value3, uint16_t value4){
_vOut[0] = value1;
_vOut[1] = value2;
_vOut[2] = value3;
_vOut[3] = value4;
writeVout();
}
Header
Kod: Markera allt
/*
* mcp4728.h
*
* Created on: May 1, 2022
* Author: danie
*/
#ifndef SRC_MCP4728_MCP4728_H_
#define SRC_MCP4728_MCP4728_H_
#include "main.h"
#include <stdbool.h>
#include <stdint.h>
#define defaultVDD 3300
#define BASE_ADDR 0x60
#define RESET 0b00000110
#define WAKE 0b00001001
#define UPDATE 0b00001000
#define MULTIWRITE 0b01000000
#define SINGLEWRITE 0b01011000
#define SEQWRITE 0b01010000
#define VREFWRITE 0b10000000
#define GAINWRITE 0b11000000
#define POWERDOWNWRITE 0b10100000
#define GENERALCALL 0b0000000
#define GAINWRITE 0b11000000
void mcp4728_init(I2C_HandleTypeDef *i2c, uint8_t deviceID);
void mcp4728_reset();
void mcp4728_wake();
void mcp4728_update();
void mcp4728_analogWrite(uint16_t value1, uint16_t value2, uint16_t value3, uint16_t value4);
void mcp4728_analogWriteFastWriteSpecific(uint8_t channel, uint16_t value);
void mcp4728_eepromWriteSpecific(uint8_t channel, uint16_t value);
void mcp4728_eepromWriteMultiple(uint16_t value1, uint16_t value2, uint16_t value3, uint16_t value4);
void mcp4728_eepromWriteAll();
void mcp4728_eepromReset();
void mcp4728_setVrefMultiple(uint8_t value1, uint8_t value2, uint8_t value3, uint8_t value4);
void mcp4728_setVrefSpecific(uint8_t channel, uint8_t value);
void mcp4728_setGainMultiple(uint8_t value1, uint8_t value2, uint8_t value3, uint8_t value4);
void mcp4728_setGainSpecific(uint8_t channel, uint8_t value);
void mcp4728_setPowerDownMultiple(uint8_t value1, uint8_t value2, uint8_t value3, uint8_t value4);
void mcp4728_setPowerDownSpecific(uint8_t channel, uint8_t value);
uint8_t mcp4728_getId();
uint8_t mcp4728_getVref(uint8_t channel);
uint8_t mcp4728_getGain(uint8_t channel);
uint8_t mcp4728_getPowerDown(uint8_t channel);
uint16_t mcp4728_getValue(uint8_t channel);
uint8_t mcp4728_getVrefEp(uint8_t channel);
uint8_t mcp4728_getGainEp(uint8_t channel);
uint8_t mcp4728_getPowerDownEp(uint8_t channel);
uint16_t mcp4728_getValueEp(uint8_t channel);
void mcp4728_vdd(uint16_t currentVdd);
uint16_t mcp4728_getVout(uint8_t channel);
void mcp4728_voutWriteSpecific(uint8_t channel, uint16_t vout);
void mcp4728_voutWriteMultiple(uint16_t value1, uint16_t value2, uint16_t value3, uint16_t value4);
#endif /* SRC_MCP4728_MCP4728_H_ */