Digipots refactor / cleanup (#19690)

This commit is contained in:
Scott Lahteine
2020-10-11 14:58:35 -05:00
committed by GitHub
parent 349465b168
commit 492ba2a111
23 changed files with 240 additions and 187 deletions

View File

@ -32,16 +32,18 @@
#include "../../inc/MarlinConfig.h"
#if ENABLED(DAC_STEPPER_CURRENT)
#if ENABLED(HAS_MOTOR_CURRENT_DAC)
#include "dac_mcp4728.h"
xyze_uint_t mcp4728_values;
MCP4728 mcp4728;
xyze_uint_t dac_values;
/**
* Begin I2C, get current values (input register and eeprom) of mcp4728
*/
void mcp4728_init() {
void MCP4728::init() {
Wire.begin();
Wire.requestFrom(I2C_ADDRESS(DAC_DEV_ADDRESS), uint8_t(24));
while (Wire.available()) {
@ -50,7 +52,7 @@ void mcp4728_init() {
loByte = Wire.read();
if (!(deviceID & 0x08))
mcp4728_values[(deviceID & 0x30) >> 4] = word((hiByte & 0x0F), loByte);
dac_values[(deviceID & 0x30) >> 4] = word((hiByte & 0x0F), loByte);
}
}
@ -58,9 +60,9 @@ void mcp4728_init() {
* Write input resister value to specified channel using fastwrite method.
* Channel : 0-3, Values : 0-4095
*/
uint8_t mcp4728_analogWrite(const uint8_t channel, const uint16_t value) {
mcp4728_values[channel] = value;
return mcp4728_fastWrite();
uint8_t MCP4728::analogWrite(const uint8_t channel, const uint16_t value) {
dac_values[channel] = value;
return fastWrite();
}
/**
@ -68,12 +70,12 @@ uint8_t mcp4728_analogWrite(const uint8_t channel, const uint16_t value) {
* This will update both input register and EEPROM value
* This will also write current Vref, PowerDown, Gain settings to EEPROM
*/
uint8_t mcp4728_eepromWrite() {
uint8_t MCP4728::eepromWrite() {
Wire.beginTransmission(I2C_ADDRESS(DAC_DEV_ADDRESS));
Wire.write(SEQWRITE);
LOOP_XYZE(i) {
Wire.write(DAC_STEPPER_VREF << 7 | DAC_STEPPER_GAIN << 4 | highByte(mcp4728_values[i]));
Wire.write(lowByte(mcp4728_values[i]));
Wire.write(DAC_STEPPER_VREF << 7 | DAC_STEPPER_GAIN << 4 | highByte(dac_values[i]));
Wire.write(lowByte(dac_values[i]));
}
return Wire.endTransmission();
}
@ -81,7 +83,7 @@ uint8_t mcp4728_eepromWrite() {
/**
* Write Voltage reference setting to all input regiters
*/
uint8_t mcp4728_setVref_all(const uint8_t value) {
uint8_t MCP4728::setVref_all(const uint8_t value) {
Wire.beginTransmission(I2C_ADDRESS(DAC_DEV_ADDRESS));
Wire.write(VREFWRITE | (value ? 0x0F : 0x00));
return Wire.endTransmission();
@ -89,7 +91,7 @@ uint8_t mcp4728_setVref_all(const uint8_t value) {
/**
* Write Gain setting to all input regiters
*/
uint8_t mcp4728_setGain_all(const uint8_t value) {
uint8_t MCP4728::setGain_all(const uint8_t value) {
Wire.beginTransmission(I2C_ADDRESS(DAC_DEV_ADDRESS));
Wire.write(GAINWRITE | (value ? 0x0F : 0x00));
return Wire.endTransmission();
@ -98,16 +100,16 @@ uint8_t mcp4728_setGain_all(const uint8_t value) {
/**
* Return Input Register value
*/
uint16_t mcp4728_getValue(const uint8_t channel) { return mcp4728_values[channel]; }
uint16_t MCP4728::getValue(const uint8_t channel) { return dac_values[channel]; }
#if 0
/**
* Steph: Might be useful in the future
* Return Vout
*/
uint16_t mcp4728_getVout(const uint8_t channel) {
uint16_t MCP4728::getVout(const uint8_t channel) {
const uint32_t vref = 2048,
vOut = (vref * mcp4728_values[channel] * (_DAC_STEPPER_GAIN + 1)) / 4096;
vOut = (vref * dac_values[channel] * (_DAC_STEPPER_GAIN + 1)) / 4096;
return _MIN(vOut, defaultVDD);
}
#endif
@ -115,15 +117,15 @@ uint16_t mcp4728_getVout(const uint8_t channel) {
/**
* Returns DAC values as a 0-100 percentage of drive strength
*/
uint8_t mcp4728_getDrvPct(const uint8_t channel) { return uint8_t(100.0 * mcp4728_values[channel] / (DAC_STEPPER_MAX) + 0.5); }
uint8_t MCP4728::getDrvPct(const uint8_t channel) { return uint8_t(100.0 * dac_values[channel] / (DAC_STEPPER_MAX) + 0.5); }
/**
* Receives all Drive strengths as 0-100 percent values, updates
* DAC Values array and calls fastwrite to update the DAC.
*/
void mcp4728_setDrvPct(xyze_uint8_t &pct) {
mcp4728_values *= 0.01 * pct * (DAC_STEPPER_MAX);
mcp4728_fastWrite();
void MCP4728::setDrvPct(xyze_uint8_t &pct) {
dac_values *= 0.01 * pct * (DAC_STEPPER_MAX);
fastWrite();
}
/**
@ -131,11 +133,11 @@ void mcp4728_setDrvPct(xyze_uint8_t &pct) {
* DAC Input and PowerDown bits update.
* No EEPROM update
*/
uint8_t mcp4728_fastWrite() {
uint8_t MCP4728::fastWrite() {
Wire.beginTransmission(I2C_ADDRESS(DAC_DEV_ADDRESS));
LOOP_XYZE(i) {
Wire.write(highByte(mcp4728_values[i]));
Wire.write(lowByte(mcp4728_values[i]));
Wire.write(highByte(dac_values[i]));
Wire.write(lowByte(dac_values[i]));
}
return Wire.endTransmission();
}
@ -143,10 +145,10 @@ uint8_t mcp4728_fastWrite() {
/**
* Common function for simple general commands
*/
uint8_t mcp4728_simpleCommand(const byte simpleCommand) {
uint8_t MCP4728::simpleCommand(const byte simpleCommand) {
Wire.beginTransmission(I2C_ADDRESS(GENERALCALL));
Wire.write(simpleCommand);
return Wire.endTransmission();
}
#endif // DAC_STEPPER_CURRENT
#endif // HAS_MOTOR_CURRENT_DAC

View File

@ -65,13 +65,18 @@
// DAC_OR_ADDRESS defined in pins_BOARD.h file
#define DAC_DEV_ADDRESS (BASE_ADDR | DAC_OR_ADDRESS)
void mcp4728_init();
uint8_t mcp4728_analogWrite(const uint8_t channel, const uint16_t value);
uint8_t mcp4728_eepromWrite();
uint8_t mcp4728_setVref_all(const uint8_t value);
uint8_t mcp4728_setGain_all(const uint8_t value);
uint16_t mcp4728_getValue(const uint8_t channel);
uint8_t mcp4728_fastWrite();
uint8_t mcp4728_simpleCommand(const byte simpleCommand);
uint8_t mcp4728_getDrvPct(const uint8_t channel);
void mcp4728_setDrvPct(xyze_uint8_t &pct);
class MCP4728 {
public:
static void init();
static uint8_t analogWrite(const uint8_t channel, const uint16_t value);
static uint8_t eepromWrite();
static uint8_t setVref_all(const uint8_t value);
static uint8_t setGain_all(const uint8_t value);
static uint16_t getValue(const uint8_t channel);
static uint8_t fastWrite();
static uint8_t simpleCommand(const byte simpleCommand);
static uint8_t getDrvPct(const uint8_t channel);
static void setDrvPct(xyze_uint8_t &pct);
};
extern MCP4728 mcp4728;

View File

@ -26,7 +26,7 @@
#include "../../inc/MarlinConfig.h"
#if ENABLED(DAC_STEPPER_CURRENT)
#if ENABLED(HAS_MOTOR_CURRENT_DAC)
#include "stepper_dac.h"
#include "../../MarlinCore.h" // for SP_X_LBL...
@ -35,56 +35,53 @@ bool dac_present = false;
constexpr xyze_uint8_t dac_order = DAC_STEPPER_ORDER;
xyze_uint8_t dac_channel_pct = DAC_MOTOR_CURRENT_DEFAULT;
int dac_init() {
StepperDAC stepper_dac;
int StepperDAC::init() {
#if PIN_EXISTS(DAC_DISABLE)
OUT_WRITE(DAC_DISABLE_PIN, LOW); // set pin low to enable DAC
#endif
mcp4728_init();
mcp4728.init();
if (mcp4728_simpleCommand(RESET)) return -1;
if (mcp4728.simpleCommand(RESET)) return -1;
dac_present = true;
mcp4728_setVref_all(DAC_STEPPER_VREF);
mcp4728_setGain_all(DAC_STEPPER_GAIN);
mcp4728.setVref_all(DAC_STEPPER_VREF);
mcp4728.setGain_all(DAC_STEPPER_GAIN);
if (mcp4728_getDrvPct(0) < 1 || mcp4728_getDrvPct(1) < 1 || mcp4728_getDrvPct(2) < 1 || mcp4728_getDrvPct(3) < 1 ) {
mcp4728_setDrvPct(dac_channel_pct);
mcp4728_eepromWrite();
if (mcp4728.getDrvPct(0) < 1 || mcp4728.getDrvPct(1) < 1 || mcp4728.getDrvPct(2) < 1 || mcp4728.getDrvPct(3) < 1 ) {
mcp4728.setDrvPct(dac_channel_pct);
mcp4728.eepromWrite();
}
return 0;
}
void dac_current_percent(uint8_t channel, float val) {
if (!dac_present) return;
NOMORE(val, 100);
mcp4728_analogWrite(dac_order[channel], val * 0.01 * (DAC_STEPPER_MAX));
mcp4728_simpleCommand(UPDATE);
}
void dac_current_raw(uint8_t channel, uint16_t val) {
void StepperDAC::set_current_value(const uint8_t channel, uint16_t val) {
if (!dac_present) return;
NOMORE(val, uint16_t(DAC_STEPPER_MAX));
mcp4728_analogWrite(dac_order[channel], val);
mcp4728_simpleCommand(UPDATE);
mcp4728.analogWrite(dac_order[channel], val);
mcp4728.simpleCommand(UPDATE);
}
static float dac_perc(int8_t n) { return 100.0 * mcp4728_getValue(dac_order[n]) * RECIPROCAL(DAC_STEPPER_MAX); }
static float dac_amps(int8_t n) { return mcp4728_getDrvPct(dac_order[n]) * (DAC_STEPPER_MAX) * 0.125 * RECIPROCAL(DAC_STEPPER_SENSE); }
void StepperDAC::set_current_percent(const uint8_t channel, float val) {
set_current_value(channel, _MIN(val, 100.0f) * (DAC_STEPPER_MAX) / 100.0f);
}
uint8_t dac_current_get_percent(const AxisEnum axis) { return mcp4728_getDrvPct(dac_order[axis]); }
void dac_current_set_percents(xyze_uint8_t &pct) {
static float dac_perc(int8_t n) { return 100.0 * mcp4728.getValue(dac_order[n]) * RECIPROCAL(DAC_STEPPER_MAX); }
static float dac_amps(int8_t n) { return mcp4728.getDrvPct(dac_order[n]) * (DAC_STEPPER_MAX) * 0.125 * RECIPROCAL(DAC_STEPPER_SENSE); }
uint8_t StepperDAC::get_current_percent(const AxisEnum axis) { return mcp4728.getDrvPct(dac_order[axis]); }
void StepperDAC::set_current_percents(xyze_uint8_t &pct) {
LOOP_XYZE(i) dac_channel_pct[i] = pct[dac_order[i]];
mcp4728_setDrvPct(dac_channel_pct);
mcp4728.setDrvPct(dac_channel_pct);
}
void dac_print_values() {
void StepperDAC::print_values() {
if (!dac_present) return;
SERIAL_ECHO_MSG("Stepper current values in % (Amps):");
SERIAL_ECHO_START();
@ -94,9 +91,9 @@ void dac_print_values() {
SERIAL_ECHOLNPAIR_P(SP_E_LBL, dac_perc(E_AXIS), PSTR(" ("), dac_amps(E_AXIS), PSTR(")"));
}
void dac_commit_eeprom() {
void StepperDAC::commit_eeprom() {
if (!dac_present) return;
mcp4728_eepromWrite();
mcp4728.eepromWrite();
}
#endif // DAC_STEPPER_CURRENT
#endif // HAS_MOTOR_CURRENT_DAC

View File

@ -27,10 +27,15 @@
#include "dac_mcp4728.h"
int dac_init();
void dac_current_percent(uint8_t channel, float val);
void dac_current_raw(uint8_t channel, uint16_t val);
void dac_print_values();
void dac_commit_eeprom();
uint8_t dac_current_get_percent(AxisEnum axis);
void dac_current_set_percents(xyze_uint8_t &pct);
class StepperDAC {
public:
static int init();
static void set_current_percent(const uint8_t channel, float val);
static void set_current_value(const uint8_t channel, uint16_t val);
static void print_values();
static void commit_eeprom();
static uint8_t get_current_percent(AxisEnum axis);
static void set_current_percents(xyze_uint8_t &pct);
};
extern StepperDAC stepper_dac;

View File

@ -21,5 +21,13 @@
*/
#pragma once
void digipot_i2c_set_current(const uint8_t channel, const float current);
void digipot_i2c_init();
//
// Header for MCP4018 and MCP4451 current control i2c devices
//
class DigipotI2C {
public:
static void init();
static void set_current(const uint8_t channel, const float current);
};
DigipotI2C digipot_i2c;

View File

@ -24,6 +24,8 @@
#if ENABLED(DIGIPOT_MCP4018)
#include "digipot.h"
#include <Stream.h>
#include <SlowSoftI2CMaster.h> // https://github.com/stawel/SlowSoftI2CMaster
@ -68,7 +70,7 @@ static SlowSoftI2CMaster pots[DIGIPOT_I2C_NUM_CHANNELS] = {
#endif
};
static void i2c_send(const uint8_t channel, const byte v) {
static void digipot_i2c_send(const uint8_t channel, const byte v) {
if (WITHIN(channel, 0, DIGIPOT_I2C_NUM_CHANNELS - 1)) {
pots[channel].i2c_start(((DIGIPOT_I2C_ADDRESS_A) << 1) | I2C_WRITE);
pots[channel].i2c_write(v);
@ -77,12 +79,12 @@ static void i2c_send(const uint8_t channel, const byte v) {
}
// This is for the MCP4018 I2C based digipot
void digipot_i2c_set_current(const uint8_t channel, const float current) {
void DigipotI2C::set_current(const uint8_t channel, const float current) {
const float ival = _MIN(_MAX(current, 0), float(DIGIPOT_MCP4018_MAX_VALUE));
i2c_send(channel, current_to_wiper(ival));
digipot_i2c_send(channel, current_to_wiper(ival));
}
void digipot_i2c_init() {
void DigipotI2C::init() {
LOOP_L_N(i, DIGIPOT_I2C_NUM_CHANNELS) pots[i].i2c_init();
// Init currents according to Configuration_adv.h
@ -94,7 +96,7 @@ void digipot_i2c_init() {
#endif
;
LOOP_L_N(i, COUNT(digipot_motor_current))
digipot_i2c_set_current(i, pgm_read_float(&digipot_motor_current[i]));
set_current(i, pgm_read_float(&digipot_motor_current[i]));
}
#endif // DIGIPOT_MCP4018

View File

@ -24,6 +24,8 @@
#if ENABLED(DIGIPOT_MCP4451)
#include "digipot.h"
#include <Stream.h>
#include <Wire.h>
@ -61,7 +63,7 @@ static void digipot_i2c_send(const byte addr, const byte a, const byte b) {
}
// This is for the MCP4451 I2C based digipot
void digipot_i2c_set_current(const uint8_t channel, const float current) {
void DigipotI2C::set_current(const uint8_t channel, const float current) {
// These addresses are specific to Azteeg X3 Pro, can be set to others.
// In this case first digipot is at address A0=0, A1=0, second one is at A0=0, A1=1
const byte addr = channel < 4 ? DIGIPOT_I2C_ADDRESS_A : DIGIPOT_I2C_ADDRESS_B; // channel 0-3 vs 4-7
@ -75,7 +77,7 @@ void digipot_i2c_set_current(const uint8_t channel, const float current) {
digipot_i2c_send(addr, addresses[channel & 0x3], current_to_wiper(_MIN(float(_MAX(current, 0)), DIGIPOT_I2C_MAX_CURRENT)));
}
void digipot_i2c_init() {
void DigipotI2C::init() {
#if MB(MKS_SBASE)
configure_i2c(16); // Set clock_option to 16 ensure I2C is initialized at 400kHz
#else
@ -90,7 +92,7 @@ void digipot_i2c_init() {
#endif
;
LOOP_L_N(i, COUNT(digipot_motor_current))
digipot_i2c_set_current(i, pgm_read_float(&digipot_motor_current[i]));
set_current(i, pgm_read_float(&digipot_motor_current[i]));
}
#endif // DIGIPOT_MCP4451