-
Notifications
You must be signed in to change notification settings - Fork 492
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
INA3221 driver + example
- Loading branch information
Showing
5 changed files
with
674 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
PROGRAM=ina3221_test | ||
EXTRA_COMPONENTS = extras/i2c extras/ina3221 | ||
include ../../common.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* | ||
* Example of using INA3221 | ||
* | ||
* Part of esp-open-rtos | ||
* Copyright (C) 2016 Zaltora | ||
* MIT Licensed as described in the file LICENSE | ||
*/ | ||
|
||
#include "espressif/esp_common.h" | ||
#include "FreeRTOS.h" | ||
#include "task.h" | ||
#include <esp/uart.h> | ||
#include <stdbool.h> | ||
#include "ina3221/ina3221.h" | ||
|
||
#define PIN_SCL 5 | ||
#define PIN_SDA 2 | ||
#define ADDR INA3221_ADDR_0 | ||
|
||
#define WARNING_CHANNEL 1 | ||
#define WARNING_CURRENT (40.0) | ||
|
||
//#define STRUCT_SETTING 0 | ||
#define MODE false // true : continuous measurements // false : trigger measurements | ||
|
||
void ina_measure(void *pvParameters) | ||
{ | ||
uint32_t measure_number = 0; | ||
float bus_voltage; | ||
float shunt_voltage; | ||
float shunt_current; | ||
bool warning = false ; | ||
|
||
// Create ina3221 device | ||
ina3221_t dev = { | ||
.addr = ADDR, | ||
.shunt = { 100 ,100 ,100 }, // shunt values are 100 mOhm for each channel | ||
.mask.mask_register = INA3221_DEFAULT_MASK, // Init | ||
.config.config_register = INA3221_DEFAULT_CONFIG, // Init | ||
}; | ||
|
||
#ifndef STRUCT_SETTING | ||
if(ina3221_setting(&dev ,MODE, true, true)) // mode selection , bus and shunt activated | ||
goto error_loop; | ||
if(ina3221_enableChannel(&dev , true, true, true)) // Enable all channels | ||
goto error_loop; | ||
if(ina3221_setAverage(&dev, INA3221_AVG_64)) // 64 samples average | ||
goto error_loop; | ||
if(ina3221_setBusConversionTime(&dev, INA3221_CT_2116)) // 2ms by channel | ||
goto error_loop; | ||
if(ina3221_setShuntConversionTime(&dev, INA3221_CT_2116)) // 2ms by channel | ||
goto error_loop; | ||
#else | ||
dev.config.mode = MODE; // mode selection | ||
dev.config.esht = true; // shunt enable | ||
dev.config.ebus = true; // bus enable | ||
dev.config.ch1 = true; // channel 1 enable | ||
dev.config.ch2 = true; // channel 2 enable | ||
dev.config.ch3 = true; // channel 3 enable | ||
dev.config.avg = INA3221_AVG_64; // 64 samples average | ||
dev.config.vbus = INA3221_CT_2116; // 2ms by channel (bus) | ||
dev.config.vsht = INA3221_CT_2116; // 2ms by channel (shunt) | ||
if(ina3221_sync(&dev)) | ||
goto error_loop; | ||
#endif | ||
|
||
ina3221_setWarningAlert(&dev, WARNING_CHANNEL-1, WARNING_CURRENT); //Set security flag overcurrent | ||
|
||
while(1) | ||
{ | ||
measure_number++; | ||
#if !MODE | ||
if (ina3221_trigger(&dev)) // Start a measure | ||
goto error_loop; | ||
printf("trig done, wait: "); | ||
do | ||
{ | ||
printf("X"); | ||
if (ina3221_getStatus(&dev)) // get mask | ||
goto error_loop; | ||
vTaskDelay(20/portTICK_PERIOD_MS); | ||
if(dev.mask.wf&(1<<(3-WARNING_CHANNEL))) | ||
warning = true ; | ||
} while(!(dev.mask.cvrf)); // check if measure done | ||
#else | ||
if (ina3221_getStatus(&dev)) // get mask | ||
goto error_loop; | ||
if(dev.mask.wf&(1<<(3-WARNING_CHANNEL))) | ||
warning = true ; | ||
#endif | ||
for (uint8_t i = 0 ; i < BUS_NUMBER ; i++) | ||
{ | ||
if(ina3221_getBusVoltage(&dev, i, &bus_voltage)) // Get voltage in V | ||
goto error_loop; | ||
if(ina3221_getShuntValue(&dev, i, &shunt_voltage, &shunt_current)) // Get voltage in mV and currant in mA | ||
goto error_loop; | ||
|
||
printf("\nC%u:Measure number %u\n",i+1,measure_number); | ||
if (warning && (i+1) == WARNING_CHANNEL) printf("C%u:Warning Current > %.2f mA !!\n",i+1,WARNING_CURRENT); | ||
printf("C%u:Bus voltage: %.02f V\n",i+1,bus_voltage ); | ||
printf("C%u:Shunt voltage: %.02f mV\n",i+1,shunt_voltage ); | ||
printf("C%u:Shunt current: %.02f mA\n\n",i+1,shunt_current ); | ||
|
||
} | ||
warning = false ; | ||
vTaskDelay(5000/portTICK_PERIOD_MS); | ||
} | ||
|
||
error_loop: | ||
printf("%s: error while com with INA3221\n", __func__); | ||
for(;;) | ||
{ | ||
vTaskDelay(2000/portTICK_PERIOD_MS); | ||
printf("%s: error loop\n", __FUNCTION__); | ||
} | ||
} | ||
|
||
void user_init(void) | ||
{ | ||
uart_set_baud(0, 115200); | ||
printf("SDK version:%s\n", sdk_system_get_sdk_version()); | ||
|
||
i2c_init(PIN_SCL,PIN_SDA); | ||
|
||
xTaskCreate(ina_measure, "Measurements_task", 512, NULL, 2, NULL); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Component makefile for extras/ina3221 | ||
|
||
# expected anyone using this driver includes it as 'ina3221/ina3221.h' | ||
INC_DIRS += $(ina3221_ROOT).. | ||
|
||
# args for passing into compile rule generation | ||
ina3221_SRC_DIR = $(ina3221_ROOT) | ||
|
||
$(eval $(call component_compile_rules,ina3221)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
/** | ||
* INA3221 driver for esp-open-rtos. | ||
* | ||
* Copyright (c) 2016 Zaltora (https://github.com/Zaltora) | ||
* | ||
* MIT Licensed as described in the file LICENSE | ||
* | ||
* @todo Interupt system for critical and warning alert pin | ||
*/ | ||
|
||
#include "ina3221.h" | ||
|
||
#ifdef INA3221_DEBUG | ||
#define debug(fmt, ...) printf("%s: " fmt "\n", "INA3221", ## __VA_ARGS__) | ||
#else | ||
#define debug(fmt, ...) | ||
#endif | ||
|
||
static int _wireWriteRegister (uint8_t addr, uint8_t reg, uint16_t value) | ||
{ | ||
i2c_start(); | ||
if (!i2c_write(addr<<1)) // adress + W | ||
goto error; | ||
if (!i2c_write(reg)) | ||
goto error; | ||
if (!i2c_write((value >> 8) & 0xFF)) | ||
goto error; | ||
if (!i2c_write(value & 0xFF)) | ||
goto error; | ||
i2c_stop(); | ||
debug("Data write to %02X : %02X+%04X\n",addr,reg,value); | ||
|
||
return 0 ; | ||
|
||
error: | ||
debug("Error while xmitting I2C slave\n"); | ||
i2c_stop(); | ||
return -EIO; | ||
} | ||
|
||
static int _wireReadRegister(uint8_t addr, uint8_t reg, uint16_t *value) | ||
{ | ||
uint8_t tampon[2] = { 0 } ; | ||
|
||
i2c_start(); | ||
if (!i2c_write(addr<<1)) // adress + W | ||
goto error; | ||
if (!i2c_write(reg)) | ||
goto error; | ||
i2c_stop(); | ||
i2c_start(); // restart condition | ||
if (!i2c_write((addr<<1) | 1)) // adress + R | ||
goto error; | ||
tampon[1] = i2c_read(0); | ||
tampon[0] = i2c_read(1); | ||
i2c_stop(); | ||
*value = tampon[1]<<8 | tampon[0] ; | ||
debug("Data read from %02X: %02X+%04X\n",addr,reg,*value); | ||
|
||
return 0; | ||
|
||
error: | ||
debug("Error while xmitting I2C slave\n"); | ||
i2c_stop(); | ||
return -EIO; | ||
} | ||
|
||
int ina3221_trigger(ina3221_t *dev) | ||
{ | ||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); | ||
} | ||
|
||
int ina3221_getStatus(ina3221_t *dev) | ||
{ | ||
return _wireReadRegister(dev->addr, INA3221_REG_MASK, &dev->mask.mask_register); | ||
} | ||
|
||
int ina3221_sync(ina3221_t *dev) | ||
{ | ||
uint16_t ptr_data; | ||
int err = 0; | ||
//////////////////////// Sync config register | ||
if ((err = _wireReadRegister(dev->addr, INA3221_REG_CONFIG, &ptr_data))) // Read config | ||
return err; | ||
if( ptr_data != dev->config.config_register) { | ||
if ((err = _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register))) // Update config | ||
return err; | ||
} | ||
//////////////////////// Sync mask register config | ||
if ((err = _wireReadRegister(dev->addr, INA3221_REG_MASK, &ptr_data))) // Read mask | ||
return err; | ||
if( (ptr_data & INA3221_MASK_CONFIG) != (dev->mask.mask_register & INA3221_MASK_CONFIG)) { | ||
if ((err = _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG))) // Update config | ||
return err; | ||
} | ||
return 0; | ||
} | ||
|
||
int ina3221_setting(ina3221_t *dev ,bool mode, bool bus, bool shunt) | ||
{ | ||
dev->config.mode = mode; | ||
dev->config.ebus = bus; | ||
dev->config.esht = shunt; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); | ||
} | ||
|
||
int ina3221_enableChannel(ina3221_t *dev ,bool ch1, bool ch2, bool ch3) | ||
{ | ||
dev->config.ch1 = ch1; | ||
dev->config.ch2 = ch2; | ||
dev->config.ch3 = ch3; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); | ||
} | ||
|
||
int ina3221_enableChannelSum(ina3221_t *dev ,bool ch1, bool ch2, bool ch3) | ||
{ | ||
dev->mask.scc1 = ch1; | ||
dev->mask.scc2 = ch2; | ||
dev->mask.scc3 = ch3; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG); | ||
} | ||
|
||
int ina3221_enableLatchPin(ina3221_t *dev ,bool warning, bool critical) | ||
{ | ||
dev->mask.wen = warning; | ||
dev->mask.cen = critical; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG); | ||
} | ||
|
||
int ina3221_setAverage(ina3221_t *dev, ina3221_avg_t avg) | ||
{ | ||
dev->config.avg = avg; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); | ||
} | ||
|
||
int ina3221_setBusConversionTime(ina3221_t *dev,ina3221_ct_t ct) | ||
{ | ||
dev->config.vbus = ct; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); | ||
} | ||
|
||
int ina3221_setShuntConversionTime(ina3221_t *dev,ina3221_ct_t ct) | ||
{ | ||
dev->config.vsht = ct; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); | ||
} | ||
|
||
int ina3221_reset(ina3221_t *dev) | ||
{ | ||
dev->config.config_register = INA3221_DEFAULT_CONFIG ; //dev reset | ||
dev->mask.mask_register = INA3221_DEFAULT_CONFIG ; //dev reset | ||
dev->config.rst = 1 ; | ||
return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); // send reset to device | ||
} | ||
|
||
int ina3221_getBusVoltage(ina3221_t *dev, ina3221_channel_t channel, float *voltage) | ||
{ | ||
int16_t raw_value; | ||
int err = 0; | ||
if ((err = _wireReadRegister(dev->addr,INA3221_REG_BUSVOLTAGE_1+channel*2, (uint16_t*)&raw_value))) | ||
return err; | ||
*voltage = raw_value*0.001 ; //V 8mV step | ||
return 0; | ||
} | ||
|
||
int ina3221_getShuntValue(ina3221_t *dev, ina3221_channel_t channel, float *voltage, float *current) | ||
{ | ||
int16_t raw_value; | ||
int err = 0; | ||
if ((err = _wireReadRegister(dev->addr,INA3221_REG_SHUNTVOLTAGE_1+channel*2, (uint16_t*)&raw_value))) | ||
return err; | ||
*voltage = raw_value*0.005; //mV 40uV step | ||
if(!dev->shunt[channel]) | ||
{ | ||
debug("No shunt configured for channel %u. Dev:%X\n",channel+1, dev->addr); | ||
return -EINVAL; | ||
} | ||
*current = (*voltage*1000.0)/dev->shunt[channel] ; //mA | ||
return 0; | ||
} | ||
|
||
int ina3221_getSumShuntValue(ina3221_t *dev, float *voltage) | ||
{ | ||
int16_t raw_value; | ||
int err = 0; | ||
if ((err = _wireReadRegister(dev->addr,INA3221_REG_SHUNT_VOLTAGE_SUM, (uint16_t*)&raw_value))) | ||
return err; | ||
*voltage = raw_value*0.02; //uV 40uV step | ||
return 0; | ||
} | ||
|
||
int ina3221_setCriticalAlert(ina3221_t *dev, ina3221_channel_t channel, float current) | ||
{ | ||
int16_t raw_value = current*dev->shunt[channel]*0.2; // format | ||
return _wireWriteRegister(dev->addr,INA3221_REG_CRITICAL_ALERT_1+channel*2, *(uint16_t*)&raw_value); | ||
} | ||
|
||
int ina3221_setWarningAlert(ina3221_t *dev, ina3221_channel_t channel, float current) | ||
{ | ||
int16_t raw_value = current*dev->shunt[channel]*0.2 ; // format | ||
return _wireWriteRegister(dev->addr,INA3221_REG_WARNING_ALERT_1+channel*2, *(uint16_t*)&raw_value); | ||
} | ||
|
||
int ina3221_setSumWarningAlert(ina3221_t *dev, float voltage) | ||
{ | ||
int16_t raw_value = voltage*50.0 ; // format | ||
return _wireWriteRegister(dev->addr,INA3221_REG_SHUNT_VOLTAGE_SUM_LIMIT, *(uint16_t*)&raw_value); | ||
} | ||
|
||
int ina3221_setPowerValidUpperLimit(ina3221_t *dev, float voltage) | ||
{ | ||
if(!dev->config.ebus) | ||
{ | ||
debug("Bus not enable. Dev:%X\n", dev->addr); | ||
return -ENOTSUP; | ||
} | ||
int16_t raw_value = voltage*1000.0; //format | ||
return _wireWriteRegister(dev->addr,INA3221_REG_VALID_POWER_UPPER_LIMIT, *(uint16_t*)&raw_value); | ||
} | ||
|
||
int ina3221_setPowerValidLowerLimit(ina3221_t *dev, float voltage) | ||
{ | ||
if(!dev->config.ebus) | ||
{ | ||
debug("Bus not enable. Dev:%X\n", dev->addr); | ||
return -ENOTSUP; | ||
} | ||
int16_t raw_value = voltage*1000.0; // round and format | ||
return _wireWriteRegister(dev->addr,INA3221_REG_VALID_POWER_LOWER_LIMIT, *(uint16_t*)&raw_value); | ||
} |
Oops, something went wrong.