0
0
Fork 0
mirror of https://github.com/MarlinFirmware/Marlin.git synced 2025-03-15 02:36:19 +00:00

Initial INA3211 Support, Rework Existing INA226 Code to allow pin reassignment using SlowSoftI2CMaster, Remove Dependencies On Wire and INA226Lib.

This commit is contained in:
Dave Gateman 2024-05-23 02:40:54 -06:00
parent 3ee1248cf2
commit 91f04f448d
4 changed files with 126 additions and 23 deletions

View file

@ -3704,10 +3704,22 @@
//
// Laser I2C Ammeter (High precision INA226 low/high side module)
//
//#define I2C_AMMETER
#define I2C_AMMETER
#if ENABLED(I2C_AMMETER)
#define I2C_AMMETER_IMAX 0.1 // (Amps) Calibration value for the expected current range
#define I2C_AMMETER_SHUNT_RESISTOR 0.1 // (Ohms) Calibration shunt resistor value
#define I2C_AMMETER_SDA_PIN 66 // D66 (AUX2.9)
#define I2C_AMMETER_SCL_PIN 65 // D65 (AUX2.10)
#define I2C_AMMETER_ADDRESS 0x41
#define I2C_AMMETER_MONITOR_CHANNEL 3
#define I2C_AMMETER_WARN_CURRENT_MA 14 //Hardware Warn Level (INA3221 Only)
#define I2C_AMMETER_ALARM_CURRENT_MA 25 //Hardware Alarm Level
#define I2C_AMMETER_IMAX 0.5 // (Amps) Calibration value for the expected current range
#define I2C_AMMETER_SHUNT_RESISTOR 0.1 // (Ohms) Calibration shunt resistor value
//#define I2C_AMMETER_DEBUGGING
#endif
//

View file

@ -23,32 +23,124 @@
#include "../inc/MarlinConfig.h"
#if ENABLED(I2C_AMMETER)
#include "ammeter.h"
#ifndef I2C_AMMETER_SDA_PIN
#define I2C_AMMETER_SDA_PIN SDA
#endif
#ifndef I2C_AMMETER_SCL_PIN
#define I2C_AMMETER_SCL_PIN SCL
#endif
#ifndef I2C_AMMETER_ADDRESS
#define I2C_AMMETER_ADDRESS 0x40
#endif
#ifndef I2C_AMMETER_IMAX
#define I2C_AMMETER_IMAX 0.500 // Calibration range 500 Milliamps
#define I2C_AMMETER_IMAX 0.500 // Calibration range 500 Milliamps
#endif
INA226 ina;
#ifndef I2C_AMMETER_MONITOR_CHANNEL
#define I2C_AMMETER_MONITOR_CHANNEL 3
#endif
#define I2C_AMMETER_WARN_CURRENT_MA 14
#define I2C_AMMETER_ALARM_CURRENT_MA 25
Ammeter ammeter;
float Ammeter::scale;
float Ammeter::current;
uint32_t Ammeter::currentLSB;
int Ammeter::sensor_type = 0;
void Ammeter::init() {
ina.begin();
ina.configure(INA226_AVERAGES_16, INA226_BUS_CONV_TIME_1100US, INA226_SHUNT_CONV_TIME_1100US, INA226_MODE_SHUNT_BUS_CONT);
ina.calibrate(I2C_AMMETER_SHUNT_RESISTOR, I2C_AMMETER_IMAX);
SlowSoftI2CMaster si = SlowSoftI2CMaster(I2C_AMMETER_SDA_PIN, I2C_AMMETER_SCL_PIN, true);
uint16_t _ammeter_read_register(uint8_t reg)
{
if (!si.i2c_start((I2C_AMMETER_ADDRESS << 1) | I2C_WRITE))
return -1; // No ACK from slave
if (!si.i2c_write(reg))
return -2; // failed write
delayMicroseconds(600); // max 586us from datasheet
if (!si.i2c_rep_start((I2C_AMMETER_ADDRESS << 1) | I2C_READ))
return -3; // no ACK from slave on second transaction
int ret = (si.i2c_read(false) << 8 | si.i2c_read(true));
si.i2c_stop();
return ret;
}
float Ammeter::read() {
scale = 1;
current = ina.readShuntCurrent();
if (current <= 0.0001f) current = 0; // Clean up least-significant-bit amplification errors
if (current < 0.1f) scale = 1000;
return current * scale;
void _ammeter_write_register(uint8_t reg, uint16_t value)
{
if (!si.i2c_start((I2C_AMMETER_ADDRESS << 1) | I2C_WRITE))
return; // No ACK from slave
si.i2c_write(reg);
si.i2c_write((value >> 8) & 0xFF);
si.i2c_write(value & 0xFF);
si.i2c_stop();
}
void Ammeter::init()
{
if (si.i2c_init())
{
if (_ammeter_read_register(0xFE) == 0x5449)
{
uint16_t id = _ammeter_read_register(0xFF);
sensor_type = id;
#ifdef I2C_AMMETER_DEBUGGING
SERIAL_ECHO("TI I2C Device: 0x");
SERIAL_PRINT(id, PrintBase::Hex);
SERIAL_ECHO(" @ 0x");
SERIAL_PRINT(I2C_AMMETER_ADDRESS, PrintBase::Hex);
SERIAL_ECHOLNPGM(" OK ( SDA: ", I2C_AMMETER_SDA_PIN, " SCL: ", I2C_AMMETER_SCL_PIN, " )");
#endif
switch (sensor_type)
{
case 0x3220:
_ammeter_write_register(0x00, 0x927 | (0x8000 >> I2C_AMMETER_MONITOR_CHANNEL)); // [CH_x_EN, AVERAGES_256, BUS_CONV_TIME_1100US, SHUNT_CONV_TIME_1100US, MODE_SHUNT_BUS_CONT]
TERN_(I2C_AMMETER_WARN_CURRENT_MA, _ammeter_write_register(0x6 + (I2C_AMMETER_MONITOR_CHANNEL * 2), I2C_AMMETER_WARN_CURRENT_MA / I2C_AMMETER_IMAX);)
TERN_(I2C_AMMETER_ALARM_CURRENT_MA, _ammeter_write_register(0x5 + (I2C_AMMETER_MONITOR_CHANNEL * 2), I2C_AMMETER_ALARM_CURRENT_MA / I2C_AMMETER_IMAX);)
break;
case 0x2260:
{
currentLSB = ((I2C_AMMETER_IMAX / 32767) * 100000000);
currentLSB /= 100000000;
currentLSB /= 0.0001; // CHOP CHOP?
currentLSB = ceil(currentLSB);
currentLSB *= 0.0001;
_ammeter_write_register(0x00, 0x927); // [AVERAGES_256, BUS_CONV_TIME_1100US, SHUNT_CONV_TIME_1100US, MODE_SHUNT_BUS_CONT]
_ammeter_write_register(0x05, (uint16_t)((0.00512) / (currentLSB * I2C_AMMETER_SHUNT_RESISTOR)));
break;
}
}
}
}
}
float Ammeter::read()
{
switch (sensor_type)
{
case 0x3220: // INA3221
current = _ammeter_read_register((I2C_AMMETER_MONITOR_CHANNEL * 2) - 1) * (I2C_AMMETER_IMAX * I2C_AMMETER_SHUNT_RESISTOR);
break;
case 0x2260: // INA226
current = _ammeter_read_register(0x04) * currentLSB;
break;
default:
break;
}
return current;
}
#endif // I2C_AMMETER

View file

@ -22,14 +22,13 @@
#pragma once
#include "../inc/MarlinConfigPre.h"
#include <SlowSoftI2CMaster.h>
#include <Wire.h>
#include <INA226.h>
class Ammeter {
private:
static float scale;
static int sensor_type;
static uint32_t currentLSB;
public:
static float current;
static void init();

View file

@ -31,7 +31,7 @@ HAS_MOTOR_CURRENT_I2C = SlowSoftI2CMaster
LIB_INTERNAL_MAX31865 = build_src_filter=+<src/libs/MAX31865.cpp>
NEOPIXEL_LED = adafruit/Adafruit NeoPixel@~1.8.0
build_src_filter=+<src/feature/leds/neopixel.cpp>
I2C_AMMETER = peterus/INA226Lib@1.1.2
I2C_AMMETER = SlowSoftI2CMaster
build_src_filter=+<src/feature/ammeter.cpp>
USES_LIQUIDCRYSTAL = LiquidCrystal=https://github.com/MarlinFirmware/New-LiquidCrystal/archive/1.5.1.zip
USES_LIQUIDCRYSTAL_I2C = marcoschwartz/LiquidCrystal_I2C@1.1.4