From 4b01c67d509fb505bb117fe4c7f0648cc909723d Mon Sep 17 00:00:00 2001 From: Skot Croshere Date: Thu, 19 Jan 2023 22:17:36 -0500 Subject: [PATCH] Fan speed seems to be working, Added some INA260 tests. doesn't seem like power is working yet --- main/CMakeLists.txt | 2 +- main/EMC2101.c | 37 ++++++--------- main/EMC2101.h | 55 +++++++++++++++++++++ main/INA260.c | 67 +++++++++++++++++++++++--- main/INA260.h | 105 +++++++++++++++++++++++++++++++++++++++++ main/i2c_simple_main.c | 12 ++++- 6 files changed, 246 insertions(+), 32 deletions(-) create mode 100644 main/INA260.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 558f425c..80efe477 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "EMC2101.c" "i2c_simple_main.c" "led_controller.c" "DS4432U.c" "EMC2101.c" +idf_component_register(SRCS "INA260.c" "EMC2101.c" "i2c_simple_main.c" "led_controller.c" "DS4432U.c" "EMC2101.c" "INA260.c" INCLUDE_DIRS ".") diff --git a/main/EMC2101.c b/main/EMC2101.c index 45bb8697..1b2dd11d 100644 --- a/main/EMC2101.c +++ b/main/EMC2101.c @@ -2,6 +2,8 @@ #include "esp_log.h" #include "driver/i2c.h" +#include "EMC2101.h" + #define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL /*!< GPIO number used for I2C master clock */ #define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA /*!< GPIO number used for I2C master data */ #define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */ @@ -10,24 +12,13 @@ #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ #define I2C_MASTER_TIMEOUT_MS 1000 -//EMC2101 -- Fan and temp sensor controller -//address: 0x4C -#define EMC2101_SENSOR_ADDR 0x4C //Slave address of the EMC2101 -#define EMC2101_PRODUCTID_REG 0xFD //should be 0x16 or 0x28 -#define EMC2101_CONFIG_REG 0x03 - -#define EMC2101_FANCONFIG_REG 0x4A -#define EMC2101_FANSETTING_REG 0x4C - -#define EMC2101_TACHREADING_REG 0x46 //2 bytes - static const char *TAG = "EMC2101.c"; /** * @brief Read a sequence of I2C bytes */ static esp_err_t register_read(uint8_t reg_addr, uint8_t *data, size_t len) { - return i2c_master_write_read_device(I2C_MASTER_NUM, EMC2101_SENSOR_ADDR, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS); + return i2c_master_write_read_device(I2C_MASTER_NUM, EMC2101_I2CADDR_DEFAULT, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS); } /** @@ -37,14 +28,15 @@ static esp_err_t register_write_byte(uint8_t reg_addr, uint8_t data) { int ret; uint8_t write_buf[2] = {reg_addr, data}; - ret = i2c_master_write_to_device(I2C_MASTER_NUM, EMC2101_SENSOR_ADDR, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS); + ret = i2c_master_write_to_device(I2C_MASTER_NUM, EMC2101_I2CADDR_DEFAULT, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS); return ret; } + //takes a fan speed percent void EMC2101_set_config(uint8_t reg) { - ESP_ERROR_CHECK(register_write_byte(EMC2101_CONFIG_REG, reg)); + ESP_ERROR_CHECK(register_write_byte(EMC2101_REG_CONFIG, reg)); } //takes a fan speed percent @@ -52,20 +44,21 @@ void EMC2101_set_fan_speed(float percent) { uint8_t speed; speed = (uint8_t)(63.0 * percent); - ESP_ERROR_CHECK(register_write_byte(EMC2101_FANSETTING_REG, speed)); + ESP_ERROR_CHECK(register_write_byte(EMC2101_REG_FAN_SETTING, speed)); } //RPM = 5400000/reading uint32_t EMC2101_get_fan_speed(void) { - uint8_t data[3]; + uint8_t tach_lsb, tach_msb; uint16_t reading; uint32_t RPM; - ESP_ERROR_CHECK(register_read(EMC2101_TACHREADING_REG, data, 2)); + ESP_ERROR_CHECK(register_read(EMC2101_TACH_LSB, &tach_lsb, 1)); + ESP_ERROR_CHECK(register_read(EMC2101_TACH_MSB, &tach_msb, 1)); - ESP_LOGI(TAG, "Raw Fan Speed = %02X %02X", data[0], data[1]); + //ESP_LOGI(TAG, "Raw Fan Speed = %02X %02X", tach_msb, tach_lsb); - reading = data[0] | (data[1] << 8); + reading = tach_lsb | (tach_msb << 8); RPM = 5400000/reading; ESP_LOGI(TAG, "Fan Speed = %d RPM", RPM); @@ -73,9 +66,9 @@ uint32_t EMC2101_get_fan_speed(void) { } void EMC2101_read(void) { - uint8_t data[3]; + uint8_t data; /* Read the EMC2101 WHO_AM_I register, on power up the register should have the value 0x16 or 0x28 */ - ESP_ERROR_CHECK(register_read(EMC2101_PRODUCTID_REG, data, 1)); - ESP_LOGI(TAG, "EMC2101 PRODUCT ID = 0x%02X", data[0]); + ESP_ERROR_CHECK(register_read(EMC2101_REG_CONFIG, &data, 1)); + ESP_LOGI(TAG, "EMC2101 Config register = 0x%02X", data); } \ No newline at end of file diff --git a/main/EMC2101.h b/main/EMC2101.h index 5ac11d7a..4aa11b74 100644 --- a/main/EMC2101.h +++ b/main/EMC2101.h @@ -1,6 +1,61 @@ #ifndef EMC2101_H_ #define EMC2101_H_ +#define EMC2101_I2CADDR_DEFAULT 0x4C ///< EMC2101 default i2c address +#define EMC2101_CHIP_ID 0x16 ///< EMC2101 default device id from part id +#define EMC2101_ALT_CHIP_ID 0x28 ///< EMC2101 alternate device id from part id +#define EMC2101_WHOAMI 0xFD ///< Chip ID register + +#define EMC2101_INTERNAL_TEMP 0x00 ///< The internal temperature register +#define EMC2101_EXTERNAL_TEMP_MSB 0x01 ///< high byte for the external temperature reading +#define EMC2101_EXTERNAL_TEMP_LSB 0x10 ///< low byte for the external temperature reading + +#define EMC2101_STATUS 0x02 ///< Status register +#define EMC2101_REG_CONFIG 0x03 ///< configuration register +#define EMC2101_REG_DATA_RATE 0x04 ///< Data rate config +#define EMC2101_TEMP_FORCE 0x0C ///< Temp force setting for LUT testing +#define EMC2101_TACH_LSB 0x46 ///< Tach RPM data low byte +#define EMC2101_TACH_MSB 0x47 ///< Tach RPM data high byte +#define EMC2101_TACH_LIMIT_LSB 0x48 ///< Tach low-speed setting low byte. INVERSE OF THE SPEED +#define EMC2101_TACH_LIMIT_MSB 0x49 ///< Tach low-speed setting high byte. INVERSE OF THE SPEED +#define EMC2101_FAN_CONFIG 0x4A ///< General fan config register +#define EMC2101_FAN_SPINUP 0x4B ///< Fan spinup behavior settings +#define EMC2101_REG_FAN_SETTING 0x4C ///< Fan speed for non-LUT settings, as a % PWM duty cycle +#define EMC2101_PWM_FREQ 0x4D ///< PWM frequency setting +#define EMC2101_PWM_DIV 0x4E ///< PWM frequency divisor +#define EMC2101_LUT_HYSTERESIS 0x4F ///< The hysteresis value for LUT lookups when temp is decreasing + +#define EMC2101_LUT_START 0x50 ///< The first temp threshold register + +#define EMC2101_TEMP_FILTER 0xBF ///< The external temperature sensor filtering behavior +#define EMC2101_REG_PARTID 0xFD ///< 0x16 +#define EMC2101_REG_MFGID 0xFE ///< 0xFF16 + +#define MAX_LUT_SPEED 0x3F ///< 6-bit value +#define MAX_LUT_TEMP 0x7F ///< 7-bit + +#define EMC2101_I2C_ADDR 0x4C ///< The default I2C address +#define EMC2101_FAN_RPM_NUMERATOR 5400000 ///< Conversion unit to convert LSBs to fan RPM +#define _TEMP_LSB 0.125 ///< single bit value for internal temperature readings + +/** + * @brief + * + * Allowed values for `setDataRate`. + */ +typedef enum { + EMC2101_RATE_1_16_HZ, ///< 1_16_HZ + EMC2101_RATE_1_8_HZ, ///< 1_8_HZ + EMC2101_RATE_1_4_HZ, ///< 1_4_HZ + EMC2101_RATE_1_2_HZ, ///< 1_2_HZ + EMC2101_RATE_1_HZ, ///< 1_HZ + EMC2101_RATE_2_HZ, ///< 2_HZ + EMC2101_RATE_4_HZ, ///< 4_HZ + EMC2101_RATE_8_HZ, ///< 8_HZ + EMC2101_RATE_16_HZ, ///< 16_HZ + EMC2101_RATE_32_HZ, ///< 32_HZ +} emc2101_rate_t; + void EMC2101_set_fan_speed(float); void EMC2101_read(void); uint32_t EMC2101_get_fan_speed(void); diff --git a/main/INA260.c b/main/INA260.c index d682ecf7..d5abd3bc 100644 --- a/main/INA260.c +++ b/main/INA260.c @@ -1,8 +1,61 @@ -//INA260 -- Power meter -//address: 0x40 -#define INA260_SENSOR_ADDR 0x40 //Slave address of the INA260 -#define INA260_MANFID_REG 0xFE //should be 0x5449 +#include +#include "esp_log.h" +#include "driver/i2c.h" - // /* Read the INA260 WHO_AM_I register, on power up the register should have the value 0x5449 */ - // ESP_ERROR_CHECK(register_read(INA260_SENSOR_ADDR, INA260_MANFID_REG, data, 2)); - // ESP_LOGI(TAG, "INA260 MANF ID = 0x%02X%02X", data[0], data[1]); \ No newline at end of file +#include "INA260.h" + +#define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL /*!< GPIO number used for I2C master clock */ +#define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA /*!< GPIO number used for I2C master data */ +#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */ +#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */ +#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define I2C_MASTER_TIMEOUT_MS 1000 + +static const char *TAG = "INA260.c"; + +/** + * @brief Read a sequence of I2C bytes + */ +static esp_err_t register_read(uint8_t reg_addr, uint8_t *data, size_t len) { + return i2c_master_write_read_device(I2C_MASTER_NUM, INA260_I2CADDR_DEFAULT, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS); +} + +/** + * @brief Write a byte to a I2C register + */ +static esp_err_t register_write_byte(uint8_t reg_addr, uint8_t data) { + int ret; + uint8_t write_buf[2] = {reg_addr, data}; + + ret = i2c_master_write_to_device(I2C_MASTER_NUM, INA260_I2CADDR_DEFAULT, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS); + + return ret; +} + +float INA260_read_current(void) { + uint8_t data[2]; + + ESP_ERROR_CHECK(register_read(INA260_REG_CURRENT, data, 2)); + //ESP_LOGI(TAG, "Raw Current = %02X %02X", data[1], data[0]); + + return (uint16_t)(data[0] | (data[1] << 8)) * 1.25; +} + +float INA260_read_voltage(void) { + uint8_t data[2]; + + ESP_ERROR_CHECK(register_read(INA260_REG_BUSVOLTAGE, data, 2)); + //ESP_LOGI(TAG, "Raw Voltage = %02X %02X", data[1], data[0]); + + return (uint16_t)(data[0] | (data[1] << 8)) * 1.25; +} + +float INA260_read_power(void) { + uint8_t data[2]; + + ESP_ERROR_CHECK(register_read(INA260_REG_POWER, data, 2)); + //ESP_LOGI(TAG, "Raw Power = %02X %02X", data[1], data[0]); + + return (uint16_t)(data[0] | (data[1] << 8)) * 10; +} \ No newline at end of file diff --git a/main/INA260.h b/main/INA260.h new file mode 100644 index 00000000..60ac2fcb --- /dev/null +++ b/main/INA260.h @@ -0,0 +1,105 @@ +#ifndef INA260_H_ +#define INA260_H_ + +#define INA260_I2CADDR_DEFAULT 0x40 ///< INA260 default i2c address +#define INA260_REG_CONFIG 0x00 ///< Configuration register +#define INA260_REG_CURRENT 0x01 ///< Current measurement register (signed) in mA +#define INA260_REG_BUSVOLTAGE 0x02 ///< Bus voltage measurement register in mV +#define INA260_REG_POWER 0x03 ///< Power calculation register in mW +#define INA260_REG_MASK_ENABLE 0x06 ///< Interrupt/Alert setting and checking register +#define INA260_REG_ALERT_LIMIT 0x07 ///< Alert limit value register +#define INA260_REG_MFG_UID 0xFE ///< Manufacturer ID Register +#define INA260_REG_DIE_UID 0xFF ///< Die ID and Revision Register + +/** + * @brief Mode options. + * + * Allowed values for setMode. + */ +typedef enum _mode { + INA260_MODE_SHUTDOWN = 0x00, /**< SHUTDOWN: Minimize quiescient current and + turn off current into the device inputs. Set + another mode to exit shutown mode **/ + INA260_MODE_TRIGGERED = 0x03, /**< TRIGGERED: Trigger a one-shot measurement + of current and bus voltage. Set the TRIGGERED + mode again to take a new measurement **/ + INA260_MODE_CONTINUOUS = 0x07, /**< CONTINUOUS: (Default) Continuously update + the current, bus voltage and power + registers with new measurements **/ +} INA260_MeasurementMode; + +/** + * @brief Conversion Time options. + * + * Allowed values for setCurrentConversionTime and setVoltageConversionTime. + */ +typedef enum _conversion_time { + INA260_TIME_140_us, ///< Measurement time: 140us + INA260_TIME_204_us, ///< Measurement time: 204us + INA260_TIME_332_us, ///< Measurement time: 332us + INA260_TIME_558_us, ///< Measurement time: 558us + INA260_TIME_1_1_ms, ///< Measurement time: 1.1ms (Default) + INA260_TIME_2_116_ms, ///< Measurement time: 2.116ms + INA260_TIME_4_156_ms, ///< Measurement time: 4.156ms + INA260_TIME_8_244_ms, ///< Measurement time: 8.224ms +} INA260_ConversionTime; + +/** + * @brief Averaging Count options. + * + * Allowed values forsetAveragingCount. + */ +typedef enum _count { + INA260_COUNT_1, ///< Window size: 1 sample (Default) + INA260_COUNT_4, ///< Window size: 4 samples + INA260_COUNT_16, ///< Window size: 16 samples + INA260_COUNT_64, ///< Window size: 64 samples + INA260_COUNT_128, ///< Window size: 128 samples + INA260_COUNT_256, ///< Window size: 256 samples + INA260_COUNT_512, ///< Window size: 512 samples + INA260_COUNT_1024, ///< Window size: 1024 samples +} INA260_AveragingCount; + +/** + * @brief Alert trigger options. + * + * Allowed values for setAlertType. + */ +typedef enum _alert_type { + INA260_ALERT_CONVERSION_READY = 0x1, ///< Trigger on conversion ready + INA260_ALERT_OVERPOWER = 0x2, ///< Trigger on power over limit + INA260_ALERT_UNDERVOLTAGE = 0x4, ///< Trigger on bus voltage under limit + INA260_ALERT_OVERVOLTAGE = 0x8, ///< Trigger on bus voltage over limit + INA260_ALERT_UNDERCURRENT = 0x10, ///< Trigger on current under limit + INA260_ALERT_OVERCURRENT = 0x20, ///< Trigger on current over limit + INA260_ALERT_NONE = 0x0, ///< Do not trigger alert pin (Default) +} INA260_AlertType; + +/** + * @brief Alert pin polarity options. + * + * Allowed values for setAlertPolarity. + */ +typedef enum _alert_polarity { + INA260_ALERT_POLARITY_NORMAL = 0x0, ///< Active high open-collector (Default) + INA260_ALERT_POLARITY_INVERTED = 0x1, ///< Active low open-collector +} INA260_AlertPolarity; + +/** + * @brief Alert pin latch options. + * + * Allowed values for setAlertLatch. + */ +typedef enum _alert_latch { + INA260_ALERT_LATCH_ENABLED = 0x1, /**< Alert will latch until Mask/Enable + register is read **/ + INA260_ALERT_LATCH_TRANSPARENT = 0x0, /**< Alert will reset when fault is + cleared **/ +} INA260_AlertLatch; + + +float INA260_read_current(void); +float INA260_read_voltage(void); +float INA260_read_power(void); + +#endif /* INA260_H_ */ \ No newline at end of file diff --git a/main/i2c_simple_main.c b/main/i2c_simple_main.c index ea46470a..80ab28a9 100755 --- a/main/i2c_simple_main.c +++ b/main/i2c_simple_main.c @@ -25,6 +25,7 @@ #include "led_controller.h" #include "DS4432U.h" #include "EMC2101.h" +#include "INA260.h" static const char *TAG = "i2c-test"; @@ -50,12 +51,19 @@ void app_main(void) { // DS4432U_set(reg_setting); ///eek! - EMC2101_read(); + + //Fan Tests EMC2101_set_config(0x04); //set the tach input + EMC2101_read(); EMC2101_set_fan_speed(0.5); - vTaskDelay(2000 / portTICK_RATE_MS); + vTaskDelay(1000 / portTICK_RATE_MS); EMC2101_get_fan_speed(); + //Current Sensor tests + ESP_LOGI(TAG, "Current: %.2fmA", INA260_read_current()); + ESP_LOGI(TAG, "Voltage: %.2fV", INA260_read_voltage()); + ESP_LOGI(TAG, "Power: %.2fW", INA260_read_power()); + ESP_ERROR_CHECK(i2c_master_delete()); ESP_LOGI(TAG, "I2C unitialized successfully"); }