Warning: Trying to access array offset on value of type null in /home/customer/www/grozeaion.com/public_html/libraries/src/Updater/Updater.php on line 330

Deprecated: version_compare(): Passing null to parameter #2 ($version2) of type string is deprecated in /home/customer/www/grozeaion.com/public_html/libraries/src/Updater/Updater.php on line 330
STM32 I2C Library for INA260 power monitor

STM32 I2C Library for INA260 power monitor

STM32 I2C library for INA260 power monitor

Please read Liability Disclaimer and License Agreement CAREFULLY

Before going further please read INA260 datasheet

 

INA260.h

 

#ifndef INA260_H_
#define INA260_H_

#ifdef __cplusplus
extern "C" {
#endif

    #include <stdint.h>
    #include "stm32f1xx_hal.h"
    // Number of samples to collect
    typedef enum {
        samples_1,        // = 0 (000b) -- default
        samples_4,        // = 1 (001b)
        samples_16,        // = 2 (010b)
        samples_64,        // = 3 (011b)
        samples_128,    // = 4 (100b)
        samples_256,    // = 5 (101b)
        samples_512,    // = 6 (110b)
        samples_1024,    // = 7 (111b)
    } ina260_sample_size_t;

    // Conversion time per sample for current and voltage
    typedef enum {
        time_140us,        // = 0 (000b)
        time_204us,        // = 1 (001b)
        time_332us,        // = 2 (010b)
        time_588us,        // = 3 (011b)
        time_1100us,    // = 4 (100b) -- default (voltage, current)
        time_2116us,    // = 5 (101b)
        time_4156us,    // = 6 (110b)
        time_8244us,    // = 7 (111b)
    } ina260_conversion_time_t;

    // Set measurement mode
    typedef enum {
        mode_Triggered,        // = 0 (000b)
        mode_Continuous,    // = 1 (001b) -- default
    } ina260_operating_mode_t;

    // specifies which measurements are performed for each conversion. you can
    // perform current-only, voltage-only, or both current and voltage. note the
    // bit patterns result in the following equalities:
    // iotShutdown    == 0
    // iotPower        == ( iotVoltage | iotCurrent )
    typedef enum {
        measure_Shutdown,    // = 0 (000b)
        measure_Current,    // = 1 (001b)
        measure_Voltage,    // = 2 (010b)
        measure_Power,        // = 3 (011b) -- default
    } ina260_operating_type_t;

    // format of the DEVICE_ID register (FFh)
    typedef union    {
        uint16_t u16;
        __packed struct {
            uint8_t revision :    4;
            uint16_t device    : 12;
        };
    } ina260_ID_t;
    
    typedef union {
        uint16_t u16;
        __packed struct {
            uint8_t  alert_latch_enable : 1; //  0
      uint8_t      alert_polarity : 1; //  1
      uint8_t       math_overflow : 1; //  2
      uint8_t    conversion_ready : 1; //  3
      uint8_t alert_function_flag : 1; //  4
      uint8_t                resv : 5; //  5 -  9
      uint8_t    alert_conversion : 1; // 10
      uint8_t    alert_over_power : 1; // 11
      uint8_t alert_under_voltage : 1; // 12
      uint8_t  alert_over_voltage : 1; // 13
      uint8_t alert_under_current : 1; // 14
      uint8_t  alert_over_current : 1; // 15
  };
} ina260_mask_enable_t;

// format of CONFIGURATION register (00h)
typedef union {
        uint16_t u16;
        __packed struct {
            ina260_operating_type_t   type : 2; //  0 -  1
            ina260_operating_mode_t   mode : 1; //  2
            ina260_conversion_time_t ctime : 3; //  3 -  5
            ina260_conversion_time_t vtime : 3; //  6 -  8
            ina260_sample_size_t     ssize : 3; //  9 - 11
            uint8_t                   resv : 3; // 12 - 14
            uint8_t                  reset : 1; // 15
  };
} ina260_configuration_t;

    typedef HAL_StatusTypeDef ina260_status_t;
    #define DEFAULT_CONF    0x6127
    #define BUFFER_LEN       2

    // 7-bit I2C addresses see Table 2 in datasheet
    #define INA_ADDR        (0x40 << 1)
    // Check 8.5.3.3.1 High-Speed I2C Mode in datasheet
    #define INA_FastMode    0x08

    ina260_status_t ina260_ready(void);
    ina260_status_t ina260_wait_until_ready(uint32_t timeout);
    ina260_status_t ina260_set_config(ina260_operating_type_t operating_type, ina260_operating_mode_t operating_mode, ina260_conversion_time_t current_ctime, ina260_conversion_time_t voltage_ctime, ina260_sample_size_t sample_size);
    ina260_status_t ina260_start(void);
    ina260_status_t ina260_set_operating_type(ina260_operating_type_t operating_type);
    ina260_status_t ina260_set_operating_mode(ina260_operating_mode_t operating_mode);
    ina260_status_t ina260_set_conversion_time(ina260_conversion_time_t time);
    ina260_status_t ina260_set_current_conversion_time(ina260_conversion_time_t time);
    ina260_status_t ina260_set_voltage_conversion_time(ina260_conversion_time_t time);
    ina260_status_t ina260_set_sample_size(ina260_sample_size_t sample_size);
    ina260_status_t ina260_reset(uint8_t init);
    ina260_status_t ina260_conversion_ready(void);
    ina260_status_t ina260_conversion_start(void);
    ina260_status_t ina260_get_current(float *current);
    ina260_status_t ina260_get_voltage(float *voltage);
    ina260_status_t ina260_get_power(float *power);
    ina260_status_t ina260_get_reg(uint8_t reg, uint16_t *conf);
    ina260_status_t ina260_set_int(void);
#ifdef __cplusplus
}
#endif

#endif /* INA260_H_ */

 

INA260.c

 

#include "INA260.h"
#include "i2c.h"
#include <stdio.h>

// convert value at addr to little-endian (16-bit)
#define byteSwap(x) ((x << 8) | (x >> 8))
/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_SEPARATOR
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i)    \
    (((i) & 0x80ll) ? '1' : '0'), \
    (((i) & 0x40ll) ? '1' : '0'), \
    (((i) & 0x20ll) ? '1' : '0'), \
    (((i) & 0x10ll) ? '1' : '0'), \
    (((i) & 0x08ll) ? '1' : '0'), \
    (((i) & 0x04ll) ? '1' : '0'), \
    (((i) & 0x02ll) ? '1' : '0'), \
    (((i) & 0x01ll) ? '1' : '0')
#define PRINTF_BINARY_PATTERN_INT16 \
    PRINTF_BINARY_PATTERN_INT8               PRINTF_BINARY_SEPARATOR              PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
    PRINTF_BYTE_TO_BINARY_INT8((i) >> 8),   PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
    PRINTF_BINARY_PATTERN_INT16              PRINTF_BINARY_SEPARATOR              PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
    PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64    \
    PRINTF_BINARY_PATTERN_INT32              PRINTF_BINARY_SEPARATOR              PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
    PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */

static uint16_t const TIMEOUT_MS = 500;

// INA260 register addresses
static uint8_t const INA260_REG_CONFIG  = 0x00;
static uint8_t const INA260_REG_CURRENT = 0x01;
static uint8_t const INA260_REG_VOLTAGE = 0x02;
static uint8_t const INA260_REG_POWER   = 0x03;
static uint8_t const INA260_REG_MASK_EN = 0x06;
static uint8_t const INA260_REG_ALRTLIM = 0x07;
static uint8_t const INA260_REG_MFG_ID  = 0xFE;
static uint8_t const INA260_REG_DEV_ID  = 0xFF;

// INA260 register LSB values for A, V, W, not mA, MV, mW 
// Same for voltage and current
static float const INA260_LSB_CV    =  0.00125F; //1.25F;
static float const INA260_LSB_POWER    = 0.01F; //10.00F;

static ina260_configuration_t config, newConf;

// -- pre-defined device ID per datasheet */
static ina260_ID_t const INA260_DEVICE_ID = {
    .revision = 0x00,
    .device   = 0x227
};

static ina260_status_t ina260_i2c_read(uint8_t mem_addr, uint16_t *buff_dst);
static ina260_status_t ina260_write_config(void);
static ina260_status_t ina260_read_mask_enable(ina260_mask_enable_t *mask_en);

ina260_status_t ina260_ready(void) {
    ina260_ID_t id;
    ina260_status_t status = ina260_i2c_read(INA260_REG_DEV_ID, &(id.u16));
    if (status != HAL_OK){
        return status; }
    // INA260 returns MSB first
    id.u16 = byteSwap(id.u16);
    if (INA260_DEVICE_ID.u16 != id.u16) {
        return HAL_ERROR; }
    return HAL_OK;
}

ina260_status_t ina260_wait_until_ready(uint32_t timeout) {
    uint32_t start = HAL_GetTick();
    while (ina260_ready() != HAL_OK) {
            if (((HAL_GetTick() - start) > timeout)) {
                return HAL_TIMEOUT;
            }
    }
    return HAL_OK;
}

ina260_status_t ina260_set_config(ina260_operating_type_t operating_type, ina260_operating_mode_t operating_mode, ina260_conversion_time_t current_ctime, ina260_conversion_time_t voltage_ctime, ina260_sample_size_t sample_size) {
    config.type = operating_type;
    config.mode  = operating_mode;
    config.ctime  = current_ctime;
    config.vtime  = voltage_ctime;
    config.ssize  = sample_size;
    return ina260_write_config();
}

ina260_status_t ina260_start(void) {
    config.u16  = DEFAULT_CONF;
    ina260_ID_t id;
    //Initiate High speed - see 8.5.3.3.1 High-Speed I2C Mode in datasheet
    HAL_I2C_Master_Transmit(&hi2c1, INA_ADDR, (uint8_t *)INA_FastMode, 1, TIMEOUT_MS);
    HAL_Delay(1);
    if (ina260_i2c_read(INA260_REG_DEV_ID, &(id.u16)) != HAL_OK){
        return HAL_ERROR;
    } else {
        id.u16 = byteSwap(id.u16);
        if (INA260_DEVICE_ID.u16 != id.u16){
            return HAL_ERROR;
        }
    }
    ina260_write_config();
    return HAL_OK;
}

ina260_status_t ina260_set_operating_type(ina260_operating_type_t operating_type) {
    config.type = operating_type;
    return ina260_write_config();
}

ina260_status_t ina260_set_operating_mode(ina260_operating_mode_t operating_mode) {
    config.mode = operating_mode;
    return ina260_write_config();
}

ina260_status_t ina260_set_conversion_time(ina260_conversion_time_t time) {
    config.ctime = time;
    config.vtime = time;
    return ina260_write_config();
}

ina260_status_t ina260_set_current_conversion_time(ina260_conversion_time_t time) {
    config.ctime = time;
    return ina260_write_config();
}

ina260_status_t ina260_set_voltage_conversion_time(ina260_conversion_time_t time) {
    config.vtime = time;
    return ina260_write_config();
}

ina260_status_t ina260_set_sample_size(ina260_sample_size_t sample_size) {
    config.ssize = sample_size;
    return ina260_write_config();
}

ina260_status_t ina260_reset(uint8_t init) {
    config.reset = 1;
    ina260_status_t status = ina260_write_config();
    if (status != HAL_OK) {
        return status;
    }
    if (init == 0U) {
        config.u16  = DEFAULT_CONF;
        return HAL_OK;
    }
    else {
        return ina260_write_config();
    }
}

ina260_status_t ina260_conversion_ready(void) {
    ina260_mask_enable_t mask_en;
    ina260_status_t status = ina260_read_mask_enable(&mask_en);
    if (status != HAL_OK) {
        return status;
    }
    if (mask_en.conversion_ready == 0U) {
        return HAL_BUSY;
    } else {
        return HAL_OK;
    }
}

ina260_status_t ina260_conversion_start(void) {
//    if (config.mode == mode_Continuous) {
//        return HAL_BUSY;
//    }
    return ina260_write_config();
}

ina260_status_t ina260_get_current(float *current) {
    uint16_t u;
    int16_t c, tmp;
    ina260_status_t status = ina260_i2c_read(INA260_REG_CURRENT, &u);
    if (status != HAL_OK) {
        return status;
    }
    tmp = u;
    tmp = byteSwap(tmp);
    c = (int16_t)byteSwap(u);
    *current = (float)c * INA260_LSB_CV;
    return HAL_OK;
}

ina260_status_t ina260_get_voltage(float *voltage) {
    uint16_t v;
    ina260_status_t status = ina260_i2c_read(INA260_REG_VOLTAGE, &v);
    if (status != HAL_OK) {
        return status;
    }
    v = byteSwap(v);
    *voltage = (float)v * INA260_LSB_CV;
    return HAL_OK;
}

ina260_status_t ina260_get_power(float *power) {
    uint16_t p;
    ina260_status_t status = ina260_i2c_read(INA260_REG_POWER, &p);
    if (status != HAL_OK) {
        return status;
    }
    p = byteSwap(p);
    *power = (float)p * INA260_LSB_POWER;
    return HAL_OK;
}

ina260_status_t ina260_get_reg(uint8_t reg, uint16_t *conf) {
    uint16_t r = 0;
    ina260_status_t status = ina260_i2c_read(reg, &r);
    if (status != HAL_OK) {
        return status;
    }
    *conf = byteSwap(r);
    return HAL_OK;
}

ina260_status_t ina260_set_int(void) {
    ina260_status_t status = ina260_wait_until_ready(TIMEOUT_MS);
    uint16_t p = INA_FastMode;
    newConf.u16 = byteSwap(p);
    if (HAL_OK == status) {
        //status = ina260_i2c_write(INA260_REG_CONFIG, &(config));
        status = HAL_I2C_Mem_Write(&hi2c1, INA_ADDR, (uint16_t)INA260_REG_MASK_EN, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&newConf, BUFFER_LEN, TIMEOUT_MS);
    }
    return status;
}

static ina260_status_t ina260_i2c_read(uint8_t mem_addr, uint16_t *buff_dst) {
    ina260_status_t status;
    while (HAL_BUSY == (status = HAL_I2C_Mem_Read(&hi2c1, INA_ADDR, (uint16_t)mem_addr, I2C_MEMADD_SIZE_8BIT, (uint8_t *)buff_dst, BUFFER_LEN, TIMEOUT_MS))) {
        // should not happen, unless during IRQ routine
        HAL_I2C_DeInit(&hi2c1);
        HAL_I2C_Init(&hi2c1);
    }
    return status;
}

static ina260_status_t ina260_write_config(void) {
    ina260_status_t status = ina260_wait_until_ready(TIMEOUT_MS);
    //printf("Config " PRINTF_BINARY_PATTERN_INT16 "\r\n", PRINTF_BYTE_TO_BINARY_INT16(config.u16));
    newConf.u16 = byteSwap(config.u16);
    //printf("Con--- " PRINTF_BINARY_PATTERN_INT16 "\r\n", PRINTF_BYTE_TO_BINARY_INT16(newConf.u16));
    if (HAL_OK == status) {
        //status = ina260_i2c_write(INA260_REG_CONFIG, &(config));
        status = HAL_I2C_Mem_Write(&hi2c1, INA_ADDR, (uint16_t)INA260_REG_CONFIG, I2C_MEMADD_SIZE_8BIT, (uint8_t *)&newConf, BUFFER_LEN, TIMEOUT_MS);
    }
    return status;
}

static ina260_status_t ina260_read_mask_enable(ina260_mask_enable_t *mask_en) {
  ina260_mask_enable_t me;
  ina260_status_t status = ina260_i2c_read(INA260_REG_MASK_EN, &(me.u16));
  if (status != HAL_OK) {
        return status;
    }
  mask_en->u16 = byteSwap(me.u16);
  return HAL_OK;
}

 

Comments powered by CComment

Who’s online

We have 132 guests and no members online