From 2d15d447e02c17e8433955af919b9cbf08bdb86e Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Thu, 6 Jun 2024 12:14:15 +0200 Subject: [PATCH] refactor: split vcore out from ds4432 driver, to make it an abstraction of whatever hardware is regulating vcore (making room for TPS546) --- main/CMakeLists.txt | 1 + main/DS4432U.c | 92 +++++++++--------------------- main/DS4432U.h | 7 ++- main/EMC2101.c | 16 +++--- main/INA260.c | 8 +-- main/i2c_master.c | 4 +- main/i2c_master.h | 4 +- main/self_test/self_test.c | 3 +- main/system.c | 5 +- main/tasks/power_management_task.c | 1 - main/vcore.c | 62 ++++++++++++++++++++ main/vcore.h | 8 +++ 12 files changed, 121 insertions(+), 90 deletions(-) create mode 100644 main/vcore.c create mode 100644 main/vcore.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 4a2cf455..e7e8d284 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -11,6 +11,7 @@ SRCS "nvs_config.c" "oled.c" "system.c" + "vcore.c" "work_queue.c" "./tasks/stratum_task.c" "./tasks/create_jobs_task.c" diff --git a/main/DS4432U.c b/main/DS4432U.c index 4434dba4..f6f962e0 100644 --- a/main/DS4432U.c +++ b/main/DS4432U.c @@ -2,87 +2,47 @@ #include #include "esp_log.h" +#include "i2c_master.h" + #include "DS4432U.h" -// DS4432U+ -- Adjustable current DAC for use with the TPS40305 voltage regulator -// address: 0x90 +// DS4432U+ -- Adjustable current DAC #define DS4432U_SENSOR_ADDR 0x48 // Slave address of the DS4432U+ #define DS4432U_OUT0_REG 0xF8 // register for current output 0 #define DS4432U_OUT1_REG 0xF9 // register for current output 1 -// DS4432U Transfer function constants -#define VFB 0.6 -#define IFS 0.000098921 // (Vrfs / Rfs) x (127/16) -> Vrfs = 0.997, Rfs = 80000 -#define RA 4750.0 // R14 -#define RB 3320.0 // R15 -#define NOMINAL 1.451 // this is with the current DAC set to 0. Should be pretty close to (VFB*(RA+RB))/RB -#define MAXV 2.39 -#define MINV 0.046 - -static const char *TAG = "DS4432U.c"; +static const char *TAG = "DS4432U"; /** - * @brief voltage_to_reg takes a voltage and returns a register setting for the DS4432U to get that voltage on the TPS40305 - * careful with this one!! + * @brief Set the current DAC code for a specific DS4432U output. + * + * @param output The output channel (0 or 1). + * @param code The current code value to set. + * @return esp_err_t ESP_OK on success, or an error code on failure. */ -static uint8_t voltage_to_reg(float vout) -{ - float change; - uint8_t reg; +esp_err_t DS4432U_set_current_code(uint8_t output, uint8_t code) { + uint8_t reg = (output == 0) ? DS4432U_OUT0_REG : DS4432U_OUT1_REG; + return i2c_master_register_write_byte(DS4432U_SENSOR_ADDR, reg, code); +} - // make sure the requested voltage is in within range of MINV and MAXV - if (vout > MAXV || vout < MINV) - { - return 0; - } - - // this is the transfer function. comes from the DS4432U+ datasheet - change = fabs((((VFB / RB) - ((vout - VFB) / RA)) / IFS) * 127); - reg = (uint8_t)ceil(change); - - // Set the MSB high if the requested voltage is BELOW nominal - if (vout < NOMINAL) - { - reg |= 0x80; - } - - return reg; +/** + * @brief Get the current DAC code value for a specific DS4432U output. + * + * @param output The output channel (0 or 1). + * @param code Pointer to store the current code value. + * @return esp_err_t ESP_OK on success, or an error code on failure. + */ +esp_err_t DS4432U_get_current_code(uint8_t output, uint8_t *code) { + uint8_t reg = (output == 0) ? DS4432U_OUT0_REG : DS4432U_OUT1_REG; + return i2c_master_register_read(DS4432U_SENSOR_ADDR, reg, code, 1); } bool DS4432U_test(void) { - uint8_t data[3]; + uint8_t data; /* Read the DS4432U+ WHO_AM_I register, on power up the register should have the value 0x00 */ - esp_err_t register_result = register_read(DS4432U_SENSOR_ADDR, DS4432U_OUT0_REG, data, 1); - ESP_LOGI(TAG, "DS4432U+ OUT1 = 0x%02X", data[0]); + esp_err_t register_result = i2c_master_register_read(DS4432U_SENSOR_ADDR, DS4432U_OUT0_REG, &data, 1); + ESP_LOGI(TAG, "DS4432U+ OUT0 = 0x%02X", data); return register_result == ESP_OK; } - -void DS4432U_read(void) -{ - uint8_t data[3]; - - /* Read the DS4432U+ WHO_AM_I register, on power up the register should have the value 0x00 */ - ESP_ERROR_CHECK(register_read(DS4432U_SENSOR_ADDR, DS4432U_OUT0_REG, data, 1)); - ESP_LOGI(TAG, "DS4432U+ OUT1 = 0x%02X", data[0]); -} - -static void DS4432U_set(uint8_t val) -{ - ESP_LOGI(TAG, "Writing 0x%02X", val); - ESP_ERROR_CHECK(register_write_byte(DS4432U_SENSOR_ADDR, DS4432U_OUT0_REG, val)); -} - -bool DS4432U_set_vcore(float core_voltage) -{ - uint8_t reg_setting; - - reg_setting = voltage_to_reg(core_voltage); - - ESP_LOGI(TAG, "Set ASIC voltage = %.3fV [0x%02X]", core_voltage, reg_setting); - - DS4432U_set(reg_setting); /// eek! - - return true; -} diff --git a/main/DS4432U.h b/main/DS4432U.h index 5af9ec98..e0321622 100644 --- a/main/DS4432U.h +++ b/main/DS4432U.h @@ -1,10 +1,11 @@ #ifndef DS4432U_H_ #define DS4432U_H_ -#include "i2c_master.h" +#include +#include "esp_check.h" -void DS4432U_read(void); bool DS4432U_test(void); -bool DS4432U_set_vcore(float); +esp_err_t DS4432U_set_current_code(uint8_t output, uint8_t code); +esp_err_t DS4432U_get_current_code(uint8_t output, uint8_t *code); #endif /* DS4432U_H_ */ diff --git a/main/EMC2101.c b/main/EMC2101.c index dd6b0fd2..ed066e41 100644 --- a/main/EMC2101.c +++ b/main/EMC2101.c @@ -10,10 +10,10 @@ void EMC2101_init(bool invertPolarity) { // set the TACH input - ESP_ERROR_CHECK(register_write_byte(EMC2101_I2CADDR_DEFAULT, EMC2101_REG_CONFIG, 0x04)); + ESP_ERROR_CHECK(i2c_master_register_write_byte(EMC2101_I2CADDR_DEFAULT, EMC2101_REG_CONFIG, 0x04)); if (invertPolarity) { - ESP_ERROR_CHECK(register_write_byte(EMC2101_I2CADDR_DEFAULT, EMC2101_FAN_CONFIG, 0b00100011)); + ESP_ERROR_CHECK(i2c_master_register_write_byte(EMC2101_I2CADDR_DEFAULT, EMC2101_FAN_CONFIG, 0b00100011)); } } @@ -23,7 +23,7 @@ void EMC2101_set_fan_speed(float percent) uint8_t speed; speed = (uint8_t) (63.0 * percent); - ESP_ERROR_CHECK(register_write_byte(EMC2101_I2CADDR_DEFAULT, EMC2101_REG_FAN_SETTING, speed)); + ESP_ERROR_CHECK(i2c_master_register_write_byte(EMC2101_I2CADDR_DEFAULT, EMC2101_REG_FAN_SETTING, speed)); } // RPM = 5400000/reading @@ -33,8 +33,8 @@ uint16_t EMC2101_get_fan_speed(void) uint16_t reading; uint16_t RPM; - ESP_ERROR_CHECK(register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_TACH_LSB, &tach_lsb, 1)); - ESP_ERROR_CHECK(register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_TACH_MSB, &tach_msb, 1)); + ESP_ERROR_CHECK(i2c_master_register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_TACH_LSB, &tach_lsb, 1)); + ESP_ERROR_CHECK(i2c_master_register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_TACH_MSB, &tach_msb, 1)); // ESP_LOGI(TAG, "Raw Fan Speed = %02X %02X", tach_msb, tach_lsb); @@ -53,8 +53,8 @@ float EMC2101_get_external_temp(void) uint8_t temp_msb, temp_lsb; uint16_t reading; - ESP_ERROR_CHECK(register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_EXTERNAL_TEMP_MSB, &temp_msb, 1)); - ESP_ERROR_CHECK(register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_EXTERNAL_TEMP_LSB, &temp_lsb, 1)); + ESP_ERROR_CHECK(i2c_master_register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_EXTERNAL_TEMP_MSB, &temp_msb, 1)); + ESP_ERROR_CHECK(i2c_master_register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_EXTERNAL_TEMP_LSB, &temp_lsb, 1)); reading = temp_lsb | (temp_msb << 8); reading >>= 5; @@ -65,6 +65,6 @@ float EMC2101_get_external_temp(void) uint8_t EMC2101_get_internal_temp(void) { uint8_t temp; - ESP_ERROR_CHECK(register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_INTERNAL_TEMP, &temp, 1)); + ESP_ERROR_CHECK(i2c_master_register_read(EMC2101_I2CADDR_DEFAULT, EMC2101_INTERNAL_TEMP, &temp, 1)); return temp; } diff --git a/main/INA260.c b/main/INA260.c index 844708f0..d65727e9 100644 --- a/main/INA260.c +++ b/main/INA260.c @@ -8,14 +8,14 @@ bool INA260_installed(void) { uint8_t data[2]; - return register_read(INA260_I2CADDR_DEFAULT, INA260_REG_BUSVOLTAGE, data, 2) == ESP_OK; + return i2c_master_register_read(INA260_I2CADDR_DEFAULT, INA260_REG_BUSVOLTAGE, data, 2) == ESP_OK; } float INA260_read_current(void) { uint8_t data[2]; - ESP_ERROR_CHECK(register_read(INA260_I2CADDR_DEFAULT, INA260_REG_CURRENT, data, 2)); + ESP_ERROR_CHECK(i2c_master_register_read(INA260_I2CADDR_DEFAULT, INA260_REG_CURRENT, data, 2)); // ESP_LOGI(TAG, "Raw Current = %02X %02X", data[1], data[0]); return (uint16_t)(data[1] | (data[0] << 8)) * 1.25; @@ -25,7 +25,7 @@ float INA260_read_voltage(void) { uint8_t data[2]; - ESP_ERROR_CHECK(register_read(INA260_I2CADDR_DEFAULT, INA260_REG_BUSVOLTAGE, data, 2)); + ESP_ERROR_CHECK(i2c_master_register_read(INA260_I2CADDR_DEFAULT, INA260_REG_BUSVOLTAGE, data, 2)); // ESP_LOGI(TAG, "Raw Voltage = %02X %02X", data[1], data[0]); return (uint16_t)(data[1] | (data[0] << 8)) * 1.25; @@ -35,7 +35,7 @@ float INA260_read_power(void) { uint8_t data[2]; - ESP_ERROR_CHECK(register_read(INA260_I2CADDR_DEFAULT, INA260_REG_POWER, data, 2)); + ESP_ERROR_CHECK(i2c_master_register_read(INA260_I2CADDR_DEFAULT, INA260_REG_POWER, data, 2)); // ESP_LOGI(TAG, "Raw Power = %02X %02X", data[1], data[0]); return (data[1] | (data[0] << 8)) * 10; diff --git a/main/i2c_master.c b/main/i2c_master.c index 98727b8b..5b632dce 100644 --- a/main/i2c_master.c +++ b/main/i2c_master.c @@ -38,7 +38,7 @@ esp_err_t i2c_master_delete(void) /** * @brief Read a sequence of I2C bytes */ -esp_err_t register_read(uint8_t device_address, uint8_t reg_addr, uint8_t * data, size_t len) +esp_err_t i2c_master_register_read(uint8_t device_address, uint8_t reg_addr, uint8_t * data, size_t len) { return i2c_master_write_read_device(I2C_MASTER_NUM, device_address, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); @@ -47,7 +47,7 @@ esp_err_t register_read(uint8_t device_address, uint8_t reg_addr, uint8_t * data /** * @brief Write a byte to a I2C register */ -esp_err_t register_write_byte(uint8_t device_address, uint8_t reg_addr, uint8_t data) +esp_err_t i2c_master_register_write_byte(uint8_t device_address, uint8_t reg_addr, uint8_t data) { int ret; uint8_t write_buf[2] = {reg_addr, data}; diff --git a/main/i2c_master.h b/main/i2c_master.h index 5320c74c..604c4512 100644 --- a/main/i2c_master.h +++ b/main/i2c_master.h @@ -8,7 +8,7 @@ esp_err_t i2c_master_init(void); esp_err_t i2c_master_delete(void); -esp_err_t register_read(uint8_t device_address, uint8_t reg_addr, uint8_t * data, size_t len); -esp_err_t register_write_byte(uint8_t device_address, uint8_t reg_addr, uint8_t data); +esp_err_t i2c_master_register_read(uint8_t device_address, uint8_t reg_addr, uint8_t * data, size_t len); +esp_err_t i2c_master_register_write_byte(uint8_t device_address, uint8_t reg_addr, uint8_t data); #endif /* I2C_MASTER_H_ */ diff --git a/main/self_test/self_test.c b/main/self_test/self_test.c index 8f176852..f2f183b3 100644 --- a/main/self_test/self_test.c +++ b/main/self_test/self_test.c @@ -8,6 +8,7 @@ #include "nvs_config.h" #include "nvs_flash.h" #include "oled.h" +#include "vcore.h" #include "utils.h" static const char * TAG = "self_test"; @@ -67,7 +68,7 @@ void self_test(void * pvParameters) ESP_LOGI(TAG, "I2C initialized successfully"); ADC_init(); - DS4432U_set_vcore(nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE) / 1000.0); + VCORE_set_voltage(nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE) / 1000.0, *GLOBAL_STATE); EMC2101_init(nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1)); EMC2101_set_fan_speed(1); diff --git a/main/system.c b/main/system.c index bd6a5e82..00a99ff5 100644 --- a/main/system.c +++ b/main/system.c @@ -3,7 +3,6 @@ #include "esp_log.h" #include "i2c_master.h" -#include "DS4432U.h" #include "EMC2101.h" #include "INA260.h" #include "adc.h" @@ -12,6 +11,7 @@ #include "led_controller.h" #include "nvs_config.h" #include "oled.h" +#include "vcore.h" #include "driver/gpio.h" #include "esp_app_desc.h" @@ -84,8 +84,7 @@ static void _init_system(GlobalState * global_state, SystemModule * module) ADC_init(); - // DS4432U tests - DS4432U_set_vcore(nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE) / 1000.0); + VCORE_set_voltage(nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE) / 1000.0, *global_state); EMC2101_init(nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1)); diff --git a/main/tasks/power_management_task.c b/main/tasks/power_management_task.c index f997e5b6..f84c8a5d 100644 --- a/main/tasks/power_management_task.c +++ b/main/tasks/power_management_task.c @@ -1,4 +1,3 @@ -#include "DS4432U.h" #include "EMC2101.h" #include "INA260.h" #include "bm1397.h" diff --git a/main/vcore.c b/main/vcore.c new file mode 100644 index 00000000..9a92f15c --- /dev/null +++ b/main/vcore.c @@ -0,0 +1,62 @@ +#include +#include +#include "esp_log.h" + +#include "vcore.h" +#include "DS4432U.h" + +// DS4432U Transfer function constants for Bitaxe board +#define BITAXE_VFB 0.6 +#define BITAXE_IFS 0.000098921 // (Vrfs / Rfs) x (127/16) -> Vrfs = 0.997, Rfs = 80000 +#define BITAXE_RA 4750.0 // R14 +#define BITAXE_RB 3320.0 // R15 +#define BITAXE_VNOM 1.451 // this is with the current DAC set to 0. Should be pretty close to (VFB*(RA+RB))/RB +#define BITAXE_VMAX 2.39 +#define BITAXE_VMIN 0.046 + +static const char *TAG = "vcore.c"; + +/** + * @brief ds4432_tps40305_bitaxe_voltage_to_reg takes a voltage and returns a register setting for the DS4432U to get that voltage on the TPS40305 + * careful with this one!! + */ +static uint8_t ds4432_tps40305_bitaxe_voltage_to_reg(float vout) +{ + float change; + uint8_t reg; + + // make sure the requested voltage is in within range of BITAXE_VMIN and BITAXE_VMAX + if (vout > BITAXE_VMAX || vout < BITAXE_VMIN) + { + return 0; + } + + // this is the transfer function. comes from the DS4432U+ datasheet + change = fabs((((BITAXE_VFB / BITAXE_RB) - ((vout - BITAXE_VFB) / BITAXE_RA)) / BITAXE_IFS) * 127); + reg = (uint8_t)ceil(change); + + // Set the MSB high if the requested voltage is BELOW nominal + if (vout < BITAXE_VNOM) + { + reg |= 0x80; + } + + return reg; +} + +bool VCORE_set_voltage(float core_voltage, GlobalState global_state) +{ + uint8_t reg_setting; + + if ((global_state.device_model == DEVICE_MAX) || + (global_state.device_model == DEVICE_ULTRA) || + (global_state.device_model == DEVICE_SUPRA)) { + reg_setting = ds4432_tps40305_bitaxe_voltage_to_reg(core_voltage); + ESP_LOGI(TAG, "Set ASIC voltage = %.3fV [0x%02X]", core_voltage, reg_setting); + DS4432U_set_current_code(0, reg_setting); /// eek! + } + // can make other fancy 'else if' based on other device_model or specific version that have different HW to set VCore value + // for example DEVICE_HEX will have a different way to set VCore using TPS546... + + return true; +} diff --git a/main/vcore.h b/main/vcore.h new file mode 100644 index 00000000..db517e7d --- /dev/null +++ b/main/vcore.h @@ -0,0 +1,8 @@ +#ifndef VCORE_H_ +#define VCORE_H_ + +#include "global_state.h" + +bool VCORE_set_voltage(float core_voltage, GlobalState global_state); + +#endif /* VCORE_H_ */