Files
MSE-SoftwEng/pico-sensor/McuLib/src/McuINA260.c
2025-05-06 13:07:01 +00:00

313 lines
11 KiB
C

/**
* Copyright (c) 2023, Erich Styger
*
* SPDX-License-Identifier: BSD-3-Clause
*
* \brief Driver for the TI INA260 current/voltage sensor.
*/
#include "McuINA260.h"
#include "McuUtility.h"
#include "McuGenericI2C.h"
#define SwapBytes(u16) ((u16<<8)|(u16>>8))
/*!
* \brief Convert the 16bit current register value to micro amps
* \param value McuINA260_ADDR_CURRENT_REGISTER register value
* \return Current in micro amp
*/
static int32_t McuINA260_ConvertCurrentRegisterToMicroAmps(int16_t value) {
/* LSB == 1.25 mA == 1250 uA */
return value*1250;
}
/*!
* \brief Convert the voltage register value into miro volts
* \param value McuINA260_ADDR_BUS_VOLTAGE_REGISTER register value
* \return Voltage in micro volt
*/
static uint32_t McuINA260_ConvertBusVoltageRegisterToMicroVoltage(uint16_t value) {
/* LSB == 1.25 mV == 1250 uV */
return (uint32_t)value*1250;
}
/*!
* \brief Convert the power register value into miro volts
* \param value McuINA260_ADDR_POWER_REGISTER register value
* \return Voltage in milli watt
*/
static uint32_t McuINA260_ConvertPowerRegisterToMilliWatt(uint16_t value) {
/* LSB == 10 mW */
return (uint32_t)value*10;
}
uint8_t McuINA260_ReadRegister(INA260_REG_e reg, uint16_t *value) {
uint8_t res;
uint16_t data;
res = McuGenericI2C_ReadWordAddress8(McuINA260_CONFIG_I2C_ADDRESS, reg, &data);
if (res!=ERR_OK) {
return res;
}
*value = SwapBytes(data);
return ERR_OK;
}
uint8_t McuINA260_WriteRegister(INA260_REG_e reg, uint16_t value) {
uint8_t res;
uint16_t data;
data = SwapBytes(value);
res = McuGenericI2C_WriteWordAddress8(McuINA260_CONFIG_I2C_ADDRESS, reg, data);
if (res!=ERR_OK) {
return res;
}
return ERR_OK;
}
uint8_t McuINA260_ReadConfigRegister(uint16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_CONFIGURATION_REGISTER, value);
}
uint8_t McuINA260_WriteConfigRegister(uint16_t value) {
return McuINA260_WriteRegister(McuINA260_ADDR_CONFIGURATION_REGISTER, value);
}
uint8_t McuINA260_WriteResetBit(void) {
return McuINA260_WriteConfigRegister(1<<15);
}
uint8_t McuINA260_ReadCurrentRegister(int16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_CURRENT_REGISTER, (uint16_t*)value);
}
uint8_t McuINA260_ReadBusVoltageRegister(uint16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_BUS_VOLTAGE_REGISTER, value);
}
uint8_t McuINA260_ReadPowerRegister(uint16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_POWER_REGISTER, value);
}
uint8_t McuINA260_ReadMaskEnableRegister(uint16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_MASK_ENABLE_REGISTER, value);
}
uint8_t McuINA260_ReadAlertLimitRegister(uint16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_ALERT_LIMIT_REGISTER, value);
}
uint8_t McuINA260_ReadManufacturereIDRegister(uint16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_MANUFACTURER_ID_REGISTER, value);
}
uint8_t McuINA260_ReadDieIDRegister(uint16_t *value) {
return McuINA260_ReadRegister(McuINA260_ADDR_DIE_ID_REGISTER, value);
}
/*!
* \brief Read the bus voltage measurement value from the device.
* \return Power value, as mV (micro-Volt).
*/
uint32_t McuINA260_ReadVoltage(void) {
uint8_t res;
uint16_t val;
res = McuINA260_ReadBusVoltageRegister(&val);
if (res==ERR_OK) {
return McuINA260_ConvertBusVoltageRegisterToMicroVoltage(val);
} else {
return 0; /* error case */
}
}
/*!
* \brief Read the power measurement value from the device.
* \return Power value, as mW (milli-Watt).
*/
uint32_t McuINA260_ReadPower(void) {
uint8_t res;
uint16_t val;
res = McuINA260_ReadPowerRegister(&val);
if (res==ERR_OK) {
return McuINA260_ConvertPowerRegisterToMilliWatt(val);
} else {
return 0; /* error case */
}
}
/*!
* \brief Read the current measurement value from the device.
* \return Current value, as uA (micro-Amps).
*/
int32_t McuINA260_ReadCurrent(void) {
uint8_t res;
int16_t val;
res = McuINA260_ReadCurrentRegister(&val);
if (res==ERR_OK) {
return McuINA260_ConvertCurrentRegisterToMicroAmps(val);
} else {
return 0; /* error case */
}
}
#if McuINA260_CONFIG_PARSE_COMMAND_ENABLED
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
uint8_t buf[32];
uint16_t value;
int16_t i16;
McuShell_SendStatusStr((unsigned char*)"McuINA260", (unsigned char*)"INA260 sensor status\r\n", io->stdOut);
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x");
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_CONFIG_I2C_ADDRESS);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
McuShell_SendStatusStr((unsigned char*)" I2C addr", buf, io->stdOut);
if (McuINA260_ReadConfigRegister(&value)==ERR_OK) {
buf[0] = '\0';
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_ADDR_CONFIGURATION_REGISTER);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"h: 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), value);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
} else {
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
}
McuShell_SendStatusStr((unsigned char*)" Config", buf, io->stdOut);
if (McuINA260_ReadCurrentRegister(&i16)==ERR_OK) {
int32_t uA = McuINA260_ConvertCurrentRegisterToMicroAmps(i16);
buf[0] = '\0';
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_ADDR_CURRENT_REGISTER);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"h: 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), i16);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", ");
McuUtility_strcatNum32s(buf, sizeof(buf), uA/1000);
McuUtility_chcat(buf, sizeof(buf), '.');
if (uA<0) { /* value can be negative */
uA = -uA; /* make it positive for the modulo operation below */
}
McuUtility_strcatNum32sFormatted(buf, sizeof(buf), uA%1000, '0', 3);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" mA\r\n");
} else {
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
}
McuShell_SendStatusStr((unsigned char*)" Current", buf, io->stdOut);
if (McuINA260_ReadBusVoltageRegister(&value)==ERR_OK) {
uint32_t uV = McuINA260_ConvertBusVoltageRegisterToMicroVoltage(value);
buf[0] = '\0';
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_ADDR_BUS_VOLTAGE_REGISTER);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"h: 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), value);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", ");
McuUtility_strcatNum32u(buf, sizeof(buf), uV/1000);
McuUtility_chcat(buf, sizeof(buf), '.');
McuUtility_strcatNum32sFormatted(buf, sizeof(buf), uV%1000, '0', 3);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" mV\r\n");
} else {
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
}
McuShell_SendStatusStr((unsigned char*)" Bus voltage", buf, io->stdOut);
if (McuINA260_ReadPowerRegister(&value)==ERR_OK) {
buf[0] = '\0';
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_ADDR_POWER_REGISTER);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"h: 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), value);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", ");
McuUtility_strcatNum32u(buf, sizeof(buf), McuINA260_ConvertPowerRegisterToMilliWatt(value));
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" mW\r\n");
} else {
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
}
McuShell_SendStatusStr((unsigned char*)" Power", buf, io->stdOut);
if (McuINA260_ReadAlertLimitRegister(&value)==ERR_OK) {
buf[0] = '\0';
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_ADDR_ALERT_LIMIT_REGISTER);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"h: 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), value);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
} else {
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
}
McuShell_SendStatusStr((unsigned char*)" Alert limit", buf, io->stdOut);
if (McuINA260_ReadManufacturereIDRegister(&value)==ERR_OK) {
buf[0] = '\0';
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_ADDR_MANUFACTURER_ID_REGISTER);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"h: 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), value);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
} else {
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
}
McuShell_SendStatusStr((unsigned char*)" Manufac. ID", buf, io->stdOut);
if (McuINA260_ReadDieIDRegister(&value)==ERR_OK) {
buf[0] = '\0';
McuUtility_strcatNum8Hex(buf, sizeof(buf), McuINA260_ADDR_DIE_ID_REGISTER);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"h: 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), value);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
} else {
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
}
McuShell_SendStatusStr((unsigned char*)" Die ID", buf, io->stdOut);
return ERR_OK;
}
static uint8_t PrintHelp(const McuShell_StdIOType *io) {
McuShell_SendHelpStr((unsigned char*)"INA260", (unsigned char*)"Group of INA260 commands\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)" reset", (unsigned char*)"Reset the device with the reset bit\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)" config <val>", (unsigned char*)"Write a value to the configuration register\r\n", io->stdOut);
return ERR_OK;
}
uint8_t McuINA260_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io) {
uint8_t res = ERR_OK;
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP) == 0
|| McuUtility_strcmp((char*)cmd, "INA260 help") == 0)
{
*handled = true;
return PrintHelp(io);
} else if ( (McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0)
|| (McuUtility_strcmp((char*)cmd, "INA260 status")==0)
)
{
*handled = true;
res = PrintStatus(io);
} else if (McuUtility_strcmp((char*)cmd, "INA260 reset")==0) {
*handled = true;
return McuINA260_WriteResetBit();
} else if (McuUtility_strncmp((char*)cmd, "INA260 config ", sizeof("INA260 config "-1))==0) {
const unsigned char *p;
int32_t val;
*handled = true;
p = cmd + sizeof("INA260 config "-1);
if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0) {
return McuINA260_WriteConfigRegister(val);
}
}
return res;
}
#endif /* McuINA260_CONFIG_PARSE_COMMAND_ENABLED */
void McuINA260_Deinit(void) {
/* nothing needed */
}
void McuINA260_Init(void) {
/* nothing needed */
}