diff --git a/main/TPS546.c b/main/TPS546.c index e139ec23d..d5cdc6fc3 100644 --- a/main/TPS546.c +++ b/main/TPS546.c @@ -3,13 +3,14 @@ #include #include #include +#include #include "pmbus_commands.h" #include "TPS546.h" #define I2C_MASTER_SCL_IO 48 /*!< GPIO number used for I2C master clock */ #define I2C_MASTER_SDA_IO 47 /*!< GPIO number used for I2C master data */ -#define I2C_MASTER_NUM \ +#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 */ @@ -28,6 +29,10 @@ static const char *TAG = "TPS546.c"; +static uint8_t DEVICE_ID[] = {0x54, 0x49, 0x54, 0x6B, 0x24, 0x41}; +static uint8_t MFR_ID[] = {'B', 'A', 'X'}; +static uint8_t MFR_MODEL[] = {'H', 'E', 'X'}; +static uint8_t MFR_REVISION[] = {0x00, 0x00, 0x01}; /** * @brief SMBus read byte @@ -47,7 +52,7 @@ static esp_err_t smb_read_byte(uint8_t command, uint8_t *data) ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, SMBUS_DEFAULT_TIMEOUT)); i2c_cmd_link_delete(cmd); - // TODO get an actual error status + // return get an actual error status return err; } @@ -67,7 +72,7 @@ static esp_err_t smb_write_byte(uint8_t command, uint8_t data) ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, SMBUS_DEFAULT_TIMEOUT)); i2c_cmd_link_delete(cmd); - // TODO get an actual error status + // TODO return an actual error status return err; } @@ -92,7 +97,7 @@ static esp_err_t smb_read_word(uint8_t command, uint16_t *result) i2c_cmd_link_delete(cmd); *result = (data[1] << 8) + data[0]; - // TODO get an actual error status + // TODO return an actual error status return err; } @@ -113,14 +118,14 @@ static esp_err_t smb_write_word(uint8_t command, uint16_t data) ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, SMBUS_DEFAULT_TIMEOUT)); i2c_cmd_link_delete(cmd); - // TODO get an actual error status + // TODO return an actual error status return err; } /** * @brief SMBus read block */ -static esp_err_t smb_read_block(uint8_t command, uint8_t * data, uint8_t len) +static esp_err_t smb_read_block(uint8_t command, uint8_t *data, uint8_t len) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); i2c_master_start(cmd); @@ -143,10 +148,31 @@ static esp_err_t smb_read_block(uint8_t command, uint8_t * data, uint8_t len) ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, SMBUS_DEFAULT_TIMEOUT)); i2c_cmd_link_delete(cmd); - // TODO get an actual error status + // TODO return an actual error status return 0; } +/** + * @brief SMBus write block + */ +static esp_err_t smb_write_block(uint8_t command, uint8_t *data, uint8_t len) +{ + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, TPS546_I2CADDR << 1 | WRITE_BIT, ACK_CHECK); + i2c_master_write_byte(cmd, command, ACK_CHECK); + i2c_master_write_byte(cmd, len, ACK_CHECK); + for (size_t i = 0; i < len; ++i) + { + i2c_master_write_byte(cmd, data[i], ACK_CHECK); + } + i2c_master_stop(cmd); + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, SMBUS_DEFAULT_TIMEOUT)); + i2c_cmd_link_delete(cmd); + + // TODO return an actual error status + return 0; +} /** * @brief Convert an SLINEAR11 value into an int @@ -192,9 +218,6 @@ static uint16_t int_2_slinear11(int value) ESP_LOGI(TAG, "mantissa: %f, exponent: %d", mantissa, exponent); result = (mantissa * 1024); -// ESP_LOGI(TAG, "result: %04x", result); - // TPS546.c: Writing new frequency: 550 - // TPS546.c: result: 0.537109, exponent: 10 // First 5 bits is exponent in twos-complement // check the first bit of the exponent to see if its negative @@ -213,8 +236,6 @@ static uint16_t int_2_slinear11(int value) // mantissa = (value & 0x07FF); // } - // TPS546.c: Read Freq: 1234 - // TPS546.c: result: 2256.000000 // calculate result (mantissa * 2^exponent) // result = mantissa * powf(2.0, exponent); @@ -273,24 +294,41 @@ static uint16_t int_2_ulinear16(int value) /*--- Public TPS546 functions ---*/ // Set up the TPS546 regulator and turn it on -void TPS546_init(void) +int TPS546_init(void) { uint8_t data[6]; uint8_t u8_value; uint16_t u16_value; - int i_value; - int millivolts; - int vmax; - float f_value; int iout; + uint8_t mfr_revision[3]; + int temp; + ESP_LOGI(TAG, "Initializing the core voltage regulator"); + /* Establish communication with regulator */ smb_read_block(PMBUS_IC_DEVICE_ID, data, 6); ESP_LOGI(TAG, "Device ID: %02x %02x %02x %02x %02x %02x", data[0], data[1], data[2], data[3], data[4], data[5]); + if (memcmp(data, DEVICE_ID, 6) != 0) + { + ESP_LOGI(TAG, "ERROR- cannot find TPS546 regulator"); + return -1; + } - smb_read_byte(PMBUS_REVISION, &u8_value); - ESP_LOGI(TAG, "PMBus revision: %02x", u8_value); + /* Make sure power is turned off until commanded */ + ESP_LOGI(TAG, "Setting power config"); + u8_value = ON_OFF_CONFIG_CMD | ON_OFF_CONFIG_PU | ON_OFF_CONFIG_CP | + ON_OFF_CONFIG_POLARITY | ON_OFF_CONFIG_DELAY; + smb_write_byte(PMBUS_ON_OFF_CONFIG, u8_value); + + /* Read version number and see if it matches */ + TPS546_read_mfr_info(mfr_revision); + if (memcmp(mfr_revision, MFR_REVISION, 3) != 0) { + // If it doesn't match, then set the version and write all the registers + ESP_LOGI(TAG, "Config version mismatch, writing new config values"); + //TPS546_write_entire_config(); + // TODO write new config version here + } /* Show temperature */ ESP_LOGI(TAG, "--------------------------------"); @@ -303,16 +341,6 @@ void TPS546_init(void) /* Show voltage settings */ TPS546_show_voltage_settings(); - /* Test changing value */ -// u16_value = int_2_ulinear16(1300); -// smb_write_word(PMBUS_VOUT_MAX, u16_value); -// ESP_LOGI(TAG, "Vout Max changed to 1300"); - -// smb_read_word(PMBUS_VOUT_MAX, &u16_value); -// ESP_LOGI(TAG, "VOUT_MAX: %04x", u16_value); -// vmax = ulinear16_2_int(u16_value); -// ESP_LOGI(TAG, "Vout Max set to: %d mV", vmax); - ESP_LOGI(TAG, "-----------CURRENT---------------------"); /* Get output current (SLINEAR11) */ smb_read_word(PMBUS_READ_IOUT, &u16_value); @@ -326,6 +354,102 @@ void TPS546_init(void) // millivolts = ulinear16_2_int(u16_value); // ESP_LOGI(TAG, "Vout measured: %d mV", millivolts); + ESP_LOGI(TAG, "-----------TIMING---------------------"); + smb_read_word(PMBUS_TON_DELAY, &u16_value); + temp = slinear11_2_int(u16_value); + ESP_LOGI(TAG, "TON_DELAY: %d", temp); + smb_read_word(PMBUS_TON_RISE, &u16_value); + temp = slinear11_2_int(u16_value); + ESP_LOGI(TAG, "TON_RISE: %d", temp); + smb_read_word(PMBUS_TON_MAX_FAULT_LIMIT, &u16_value); + temp = slinear11_2_int(u16_value); + ESP_LOGI(TAG, "TON_MAX_FAULT_LIMIT: %d", temp); + smb_read_byte(PMBUS_TON_MAX_FAULT_RESPONSE, &u8_value); + ESP_LOGI(TAG, "TON_MAX_FAULT_RESPONSE: %02x", u8_value); + smb_read_word(PMBUS_TOFF_DELAY, &u16_value); + temp = slinear11_2_int(u16_value); + ESP_LOGI(TAG, "TOFF_DELAY: %d", temp); + smb_read_word(PMBUS_TOFF_FALL, &u16_value); + temp = slinear11_2_int(u16_value); + ESP_LOGI(TAG, "TOFF_FALL: %d", temp); + ESP_LOGI(TAG, "--------------------------------------"); + + + return 0; +} + +/* Read the manufacturer model and revision */ +void TPS546_read_mfr_info(uint8_t *read_mfr_revision) +{ + uint8_t read_mfr_id[4]; + uint8_t read_mfr_model[4]; + + ESP_LOGI(TAG, "Reading MFR info"); + smb_read_block(PMBUS_MFR_ID, read_mfr_id, 3); + read_mfr_id[3] = 0x00; + smb_read_block(PMBUS_MFR_MODEL, read_mfr_model, 3); + read_mfr_model[3] = 0x00; + smb_read_block(PMBUS_MFR_REVISION, read_mfr_revision, 3); + + ESP_LOGI(TAG, "MFR_ID: %s", read_mfr_id); + ESP_LOGI(TAG, "MFR_MODEL: %s", read_mfr_model); + ESP_LOGI(TAG, "MFR_REVISION: %d%d%d ", read_mfr_revision[0], + read_mfr_revision[1], read_mfr_revision[2]); +} + +/* Write the manufacturer ID and revision to NVM */ +void TPS546_set_mfr_info(void) +{ + ESP_LOGI(TAG, "Setting MFR info"); + smb_write_block(PMBUS_MFR_ID, MFR_ID, 3); + smb_write_block(PMBUS_MFR_MODEL, MFR_MODEL, 3); + smb_write_block(PMBUS_MFR_REVISION, MFR_REVISION, 3); +} + +/* Set all the relevant config registers for normal operation */ +void TPS546_write_entire_config(void) +{ + /* Switch frequency */ + smb_write_word(PMBUS_FREQUENCY_SWITCH, int_2_slinear11(TPS546_INIT_FREQUENCY)); + + /* vin voltage */ + smb_write_word(PMBUS_VIN_ON, int_2_slinear11(TPS546_INIT_VIN_ON)); + smb_write_word(PMBUS_VIN_OFF, int_2_slinear11(TPS546_INIT_VIN_OFF)); + smb_write_word(PMBUS_VIN_UV_WARN_LIMIT, int_2_slinear11(TPS546_INIT_VIN_UV_WARN_LIMIT)); + smb_write_word(PMBUS_VIN_OV_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_VIN_OV_FAULT_LIMIT)); + smb_write_byte(PMBUS_VIN_OV_FAULT_RESPONSE, TPS546_INIT_VIN_OV_FAULT_RESPONSE); + + /* vout voltage */ + smb_write_word(PMBUS_VOUT_SCALE_LOOP, TPS546_INIT_SCALE_LOOP); /* no conversion necessary */ + smb_write_word(PMBUS_VOUT_MAX, int_2_slinear11(TPS546_INIT_VOUT_MAX)); + smb_write_word(PMBUS_VOUT_OV_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_VOUT_OV_FAULT_LIMIT)); + smb_write_word(PMBUS_VOUT_OV_WARN_LIMIT, int_2_slinear11(TPS546_INIT_VOUT_OV_WARN_LIMIT)); + //TODO enable this someplace smb_write_word(PMBUS_VOUT_COMMAND, int_2_slinear11(TPS546_INIT_VOUT_COMMAND)); + smb_write_word(PMBUS_VOUT_UV_WARN_LIMIT, int_2_slinear11(TPS546_INIT_VOUT_UV_WARN_LIMIT)); + smb_write_word(PMBUS_VOUT_UV_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_VOUT_UV_FAULT_LIMIT)); + smb_write_word(PMBUS_VOUT_MIN, int_2_slinear11(TPS546_INIT_VOUT_MIN)); + + /* iout current */ + smb_write_word(PMBUS_IOUT_OC_WARN_LIMIT, int_2_slinear11(TPS546_INIT_IOUT_OC_WARN_LIMIT)); + smb_write_word(PMBUS_IOUT_OC_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_IOUT_OC_FAULT_LIMIT)); + smb_write_byte(PMBUS_IOUT_OC_FAULT_RESPONSE, TPS546_INIT_IOUT_OC_FAULT_RESPONSE); + + /* temperature */ + smb_write_word(PMBUS_OT_WARN_LIMIT, int_2_slinear11(TPS546_INIT_OT_WARN_LIMIT)); + smb_write_word(PMBUS_OT_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_OT_FAULT_LIMIT)); + smb_write_byte(PMBUS_OT_FAULT_RESPONSE, TPS546_INIT_OT_FAULT_RESPONSE); + + /* timing */ + smb_write_word(PMBUS_TON_DELAY, int_2_slinear11(TPS546_INIT_TON_DELAY)); + smb_write_word(PMBUS_TON_RISE, int_2_slinear11(TPS546_INIT_TON_RISE)); + smb_write_word(PMBUS_TON_MAX_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_TON_MAX_FAULT_LIMIT)); + smb_write_byte(PMBUS_TON_MAX_FAULT_RESPONSE, TPS546_INIT_TON_MAX_FAULT_RESPONSE); + smb_write_word(PMBUS_TOFF_DELAY, int_2_slinear11(TPS546_INIT_TOFF_DELAY)); + smb_write_word(PMBUS_TOFF_FALL, int_2_slinear11(TPS546_INIT_TOFF_FALL)); + + /* store configuration in NVM */ + smb_write_byte(PMBUS_STORE_USER_ALL, 0xFF); + } int TPS546_get_frequency(void) @@ -383,7 +507,6 @@ void TPS546_show_voltage_settings(void) { uint16_t u16_value; int i_value; - float f_value; int millivolts; ESP_LOGI(TAG, "-----------VOLTAGE---------------------"); diff --git a/main/TPS546.h b/main/TPS546.h index daf905222..bd7aa2ad7 100644 --- a/main/TPS546.h +++ b/main/TPS546.h @@ -5,54 +5,63 @@ #define TPS546_MANUFACTURER_ID 0xFE //< Manufacturer ID #define TPS546_REVISION 0xFF //< Chip revision -struct tps546_settings_t -{ - int switch_frequency; +/*-------------------------*/ +/* These are the inital values for the voltage regulator configuration */ +/* when the config revision stored in the TPS546 doesn't match, these values are used */ - /* vin voltage */ - int vin_on; /* voltage level to start power conversion */ - int vin_off; /* voltage level to stop power conversion */ - int vin_uv_warn_limit; - int vin_ov_fault_limit; - int vin_ov_fault_response; + +#define TPS546_INIT_FREQUENCY 650 /* KHz */ + +/* vin voltage */ +#define TPS546_INIT_VIN_ON 11900 /* mV */ +#define TPS546_INIT_VIN_OFF 11000 /* mV */ +#define TPS546_INIT_VIN_UV_WARN_LIMIT 11000 /* mV */ +#define TPS546_INIT_VIN_OV_FAULT_LIMIT 14000 /* mV */ +#define TPS546_INIT_VIN_OV_FAULT_RESPONSE 0xB7 /* retry 6 times */ /* vout voltage */ - int vout_transition_rate; - int vout_scale_loop; - int vout_trim; - int vout_max; - int vout_ov_fault_limit; - int vout_ov_warn_limit; - int vout_margin_high; - int vout_command; - int vout_margin_low; - int vout_uv_warn_limit; - int vout_uv_fault_limit; - int vout_min; +#define TPS546_INIT_SCALE_LOOP 0xC808 /* 0.125 */ +#define TPS546_INIT_VOUT_MAX 4500 /* mV */ +#define TPS546_INIT_VOUT_OV_FAULT_LIMIT 4500 /* mV */ +#define TPS546_INIT_VOUT_OV_WARN_LIMIT 4400 /* mV */ +#define TPS546_INIT_VOUT_COMMAND 3600 /* mV */ +#define TPS546_INIT_VOUT_UV_WARN_LIMIT 3100 /* mV */ +#define TPS546_INIT_VOUT_UV_FAULT_LIMIT 3000 /* mV */ +#define TPS546_INIT_VOUT_MIN 3000 /* mv */ /* iout current */ - int iout_oc_warn_limit; - int iout_oc_fault_limit; - int iout_oc_fault_response; - int iout_cal_gain; - int iout_cal_offset; +#define TPS546_INIT_IOUT_OC_WARN_LIMIT 25000 /* mA */ +#define TPS546_INIT_IOUT_OC_FAULT_LIMIT 30000 /* mA */ +#define TPS546_INIT_IOUT_OC_FAULT_RESPONSE 0xC0 /* shut down, no retries */ /* temperature */ - int ot_warn_limit; - int ot_fault_limit; - int ot_fault_response; +#define TPS546_INIT_OT_WARN_LIMIT 70 /* degrees C */ +#define TPS546_INIT_OT_FAULT_LIMIT 80 /* degrees C */ +#define TPS546_INIT_OT_FAULT_RESPONSE 0xFF /* wait for cooling, and retry */ /* timing */ - int ton_delay; - int ton_rise; - int ton_max_fault_limit; - int ton_max_fault_response; - int toff_delay; - int toff_fall; +#define TPS546_INIT_TON_DELAY 0 +#define TPS546_INIT_TON_RISE 3 +#define TPS546_INIT_TON_MAX_FAULT_LIMIT 0 +#define TPS546_INIT_TON_MAX_FAULT_RESPONSE 0x3B +#define TPS546_INIT_TOFF_DELAY 0 +#define TPS546_INIT_TOFF_FALL 0 + +/*-------------------------*/ + +/* PMBUS_ON_OFF_CONFIG initialization values */ +#define ON_OFF_CONFIG_PU 0x10 // turn on PU bit +#define ON_OFF_CONFIG_CMD 0x08 // turn on CMD bit +#define ON_OFF_CONFIG_CP 0x00 // turn off CP bit +#define ON_OFF_CONFIG_POLARITY 0x00 // turn off POLARITY bit +#define ON_OFF_CONFIG_DELAY 0x00 // turn off DELAY bit -}; -void TPS546_init(void); +/* public functions */ +int TPS546_init(void); +void TPS546_read_mfr_info(uint8_t *); +void TPS546_set_mfr_info(void); +void TPS546_write_entire_config(void); int TPS546_get_frequency(void); void TPS546_set_frequency(int); int TPS546_get_temperature(void);