I’m attempting to integrate the INA239 Power Monitor with Arduino UNO. Based on the datasheet I’ve setup all the register addresses and read / write functions. When I attempt a read operation I’m getting 0xFFFF, or incorrect data. This is not complete by any means, however, I must get SPI comms functioning before proceeding further.
Hardware has been configured as shown in figure 8-2 in the INA239 datasheet.
Any help is greatly appreciated!
#include <SPI.h>
//#define readMeasurements
#define SERIAL_DEBUG
//#define trxbuf_after_transfer
//#define trxbuf_initial_contents
//#define return_ret_contains
#define buf_contents
#define REGISTER_WRITE_READBACK_VALUE
//#define result_buffer
#define return_buf_contains
#define READ_8_BIT_REG_ADDRESS
#define READ_16_BIT_VALUE_CONTENTS
#define WRITE_16_BIT_REG_ADDRESS
// Define the SPI pins
#define CS_PIN 10 // Chip Select (CS) pin
#define CS_PIN_1 2 // Chip Select pin for second INA239
#define CS_PIN_2 3 // Chip Select pin for third INA239
#define SCLK_PIN 13 // Serial Clock (SCLK) pin
#define MOSI_PIN 11 // Master Out Slave In (MOSI) pin
#define MISO_PIN 12 // Master In Slave Out (MISO) pin
#define SPImode SPI_MODE2
#define SPI_CLOCK_FREQUENCY 1000000
#define SPI_DATA_ORDER MSBFIRST
#define LOOP_TIME_DELAY 5000
#define moduleSettleDelayTime 50
#define MISO_DELAY_TIME 10
// Define the register addresses
#define CONFIG_REG 0x00
#define ADC_CONFIG_REG 0x01
#define SHUNT_CAL_REG 0x02
#define SHUNT_VOLTAGE_REG 0x04
#define VBUS_REG 0x05
#define DIETEMP_REG 0x06
#define CURRENT_REG 0x07
#define POWER_REG 0x08
#define DIAG_ALRT_REG 0x0B
#define SHUNT_OVER_VOLTAGE_REG 0x0C
#define SUVL_REG 0x0D
#define BUS_OVER_VOLTAGE_REG 0x0E
#define MANUFACTURER_ID_REG 0x3E
#define DEVICE_ID_REG 0x3F
//const uint16_t CONFIG_REG_INIT = 0b0000000001000000;
const uint16_t CONFIG_REG_INIT_RESET = 0x8000;
const uint16_t CONFIG_REG_INIT = 0x0040;
//const uint16_t ADC_CONFIG_REG_INIT = 0b1011001001001100;
const uint16_t ADC_CONFIG_REG_INIT = 0xB24C;
//const uint16_t SHUNTcal_REG_INIT = 0b0001001110001000;
const uint16_t SHUNTcal_REG_INIT = 0x1388;
// Conversion constants
uint8_t MAX_CURRENT = 10; // Max Current Expected at input 10 Amps
float CURRENT_LSB = 0.000305; // Current LSB value
float SHUNT_RESISTOR = 0.02; // 20 milliohms
SPISettings mySetting(SPI_CLOCK_FREQUENCY, SPI_DATA_ORDER, SPImode);
void setup()
{
pinMode(CS_PIN, OUTPUT);
pinMode(CS_PIN_1, OUTPUT);
pinMode(CS_PIN_2, OUTPUT);
digitalWrite(CS_PIN, HIGH);
digitalWrite(CS_PIN_1, HIGH);
digitalWrite(CS_PIN_2, HIGH);
// Initialize Serial for debugging
Serial.begin(115200);
delay(100);
// Initialize SPI
SPI.begin();
delay(100);
// Initialize SPI communication with the INA239
configureINA239();
}
void loop()
{
// Read and print the MANUFACTURER_ID
uint16_t manufacturerID = read16BitRegister(MANUFACTURER_ID_REG);
Serial.print("MANUFACTURER_ID: 0x");
Serial.print(manufacturerID, HEX);
Serial.println();
/*
// Read and print the DEVICE_ID
uint16_t deviceID = read16BitRegister(DEVICE_ID_REG);
Serial.print("DEVICE_ID: ");
Serial.println(deviceID, HEX);
Serial.println();
*/
delay(LOOP_TIME_DELAY);
#if defined(readMeasurements)
// readMeasurements
int16_t shuntVoltageRaw = read16BitRegister(SHUNT_VOLTAGE_REG);
int16_t busVoltageRaw = read16BitRegister(VBUS_REG);
int16_t currentRaw = read16BitRegister(CURRENT_REG);
int16_t temperatureRaw = read16BitRegister(DIETEMP_REG);
uint32_t powerRaw = readRegister24(POWER_REG);
// Convert raw readings to actual values
float shuntVoltage = convertShuntVoltage(shuntVoltageRaw);
float busVoltage = convertBusVoltage(busVoltageRaw);
float current = convertCurrent(currentRaw);
float temperature = convertTemperature(temperatureRaw);
float power = convertPower(powerRaw);
// Print results
Serial.print("Shunt Voltage: ");
Serial.print(shuntVoltage);
Serial.println(" mV");
Serial.print("Bus Voltage: ");
Serial.print(busVoltage);
Serial.println(" V");
Serial.print("Current: ");
Serial.print(current);
Serial.println(" A");
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
Serial.print("Power: ");
Serial.print(power);
Serial.println(" W");
#endif
}
void configureINA239()
{
delay(moduleSettleDelayTime);
writeRegister16(CONFIG_REG, CONFIG_REG_INIT_RESET); // Reset the device
delay(moduleSettleDelayTime);
writeRegister16(CONFIG_REG, CONFIG_REG_INIT);
delay(moduleSettleDelayTime);
writeRegister16(ADC_CONFIG_REG, ADC_CONFIG_REG_INIT); // Continuous mode, specific settings
delay(moduleSettleDelayTime);
writeRegister16(SHUNT_CAL_REG, SHUNTcal_REG_INIT); // Shunt calibration
delay(moduleSettleDelayTime);
uint16_t adcConfigReg = read16BitRegister(ADC_CONFIG_REG);
Serial.println();
Serial.print("ADC_CONFIG_REG_Value: 0xB24C");
Serial.print(" READ / Write_VALUE: ");
Serial.print(adcConfigReg, HEX);
Serial.println();
delay(moduleSettleDelayTime);
uint16_t shuntCalibrationReg = read16BitRegister(SHUNT_CAL_REG);
Serial.println();
Serial.print("SHUNT_CAL_REG Value: 0x1388");
Serial.print(" READ_VALUE: ");
Serial.print(shuntCalibrationReg, HEX);
Serial.println();
}
uint16_t read16BitRegister(uint8_t registerAddress)
{
uint16_t value;
uint8_t cmd = (registerAddress << 2) | 0x01;
#if defined(READ_8_BIT_REG_ADDRESS)
Serial.println();
Serial.print("READ_8_BIT_REG_ADDRESS: ");
Serial.print(cmd, HEX);
Serial.println();
#endif
SPI.beginTransaction(mySetting);
digitalWrite(CS_PIN, LOW);
SPI.transfer(cmd);
//value = (SPI.transfer(0x00) << 8) | SPI.transfer(0x00);
value = SPI.transfer16(0x0000);
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
#if defined(READ_16_BIT_VALUE_CONTENTS)
Serial.println();
Serial.print("value_contents: ");
Serial.print(value, HEX);
Serial.println();
#endif
return value;
/*
uint8_t buf[2];
readData(registerAddress, buf, 2);
#if defined(return_buf_contains)
{
Serial.println();
Serial.print("return_buf_contains: 0x");
Serial.print(buf[0], HEX);
Serial.print(" 0x");
Serial.print(buf[1], HEX);
Serial.println();
}
#endif
//return (buf[0] << 8) | buf[1];
*/
}
uint32_t read24BitRegister(uint8_t registerAddress)
{
uint32_t ret = 0;
readData(registerAddress, (uint8_t*)&ret, 3);
return ret;
}
void readData(uint8_t registerAddress, uint8_t* buf, size_t len)
{
// Prepare the SPI command
uint8_t cmd = (registerAddress << 2) | 0x01; // 6-bit address + R/W bit set to 1 for read and padded 0 before the read / write bit
/*
SPI.beginTransaction(mySetting);
digitalWrite(CS_PIN, LOW);
// Send the command register byte
buf[0] = SPI.transfer(cmd);
// Read the response
for (int i = 1; i <= len; i++)
{
buf[i] = SPI.transfer(0x00); // Send dummy byte to receive data
//delay(MISO_DELAY_TIME);
}
SPI.endTransaction();
digitalWrite(CS_PIN, HIGH);
*/
#if defined(buf_contents)
{
Serial.println();
Serial.print("buf_contents_after_SPI_transaction: ");
for (size_t x = 0; x <= len; x++)
{
Serial.print(buf[x], HEX);
Serial.print(" ");
}
Serial.println();
}
#endif
}
void writeRegister16(uint8_t reg, uint16_t value)
{
// Create the command frame with the write bit set to 0
uint8_t cmd = (reg << 2);
#if defined(WRITE_16_BIT_REG_ADDRESS)
Serial.println();
Serial.print("READ_16_BIT_REG_ADDRESS: ");
Serial.print(reg, BIN);
Serial.println();
#endif
/*
// Start SPI transaction
SPI.beginTransaction(mySetting);
digitalWrite(CS_PIN, LOW);
SPI.transfer(cmd); // Send the command frame
SPI.transfer(value); // Send the 16-bit value
delay(MISO_DELAY_TIME);
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
delay(50);
*/
digitalWrite(CS_PIN, LOW);
SPI.beginTransaction(mySetting);
SPI.transfer(cmd);
SPI.transfer16(value);
//SPI.transfer(value >> 8);
//SPI.transfer(value & 0xFF);
SPI.endTransaction();
digitalWrite(CS_PIN, HIGH);
#if defined(REGISTER_WRITE_READBACK_VALUE)
{
// Read back the register value for verification
uint16_t register_value = read16BitRegister(reg);
Serial.println();
Serial.print("REGISTER WRITE READBACK VALUE: Reg = 0x");
Serial.print(reg, HEX);
Serial.print(" readValue = 0x");
Serial.print(register_value, HEX);
Serial.println();
}
#endif
}
//register calculations
float convertShuntVoltage(int16_t rawValue) {
return (float)rawValue * 0.000005; // 5 uV per LSB
}
float convertBusVoltage(int16_t rawValue) {
return (float)rawValue * 0.003125; // 3.125 mV per LSB
}
float convertCurrent(int16_t rawValue) {
return (float)rawValue * CURRENT_LSB;
}
float convertTemperature(int16_t rawValue) {
return (float)rawValue * 0.125; // 125 m°C per LSB
}
float convertPower(uint32_t rawValue) {
float power_LSB = CURRENT_LSB * 0.2;
return (float)rawValue * power_LSB;
}
a a is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.