refactor: split vcore out from ds4432 driver, to make it an abstraction of whatever hardware is regulating vcore (making room for TPS546)

This commit is contained in:
Georges Palauqui 2024-06-06 12:14:15 +02:00
parent c9865a5e0a
commit 2d15d447e0
No known key found for this signature in database
GPG Key ID: 1E45F544CE4D04A5
12 changed files with 121 additions and 90 deletions

View File

@ -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"

View File

@ -2,87 +2,47 @@
#include <math.h>
#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;
}

View File

@ -1,10 +1,11 @@
#ifndef DS4432U_H_
#define DS4432U_H_
#include "i2c_master.h"
#include <stdbool.h>
#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_ */

View File

@ -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;
}

View File

@ -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;

View File

@ -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, &reg_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};

View File

@ -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_ */

View File

@ -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);

View File

@ -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));

View File

@ -1,4 +1,3 @@
#include "DS4432U.h"
#include "EMC2101.h"
#include "INA260.h"
#include "bm1397.h"

62
main/vcore.c Normal file
View File

@ -0,0 +1,62 @@
#include <stdio.h>
#include <math.h>
#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;
}

8
main/vcore.h Normal file
View File

@ -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_ */