Improve status messages on self-test finish. (#1086)

* Improve status messages on self-test finish.

This doesn't change the logic, but does change the messaging to the user, mainly on a failed self-test which was started by pressing the BOOT button on start-up.

Also moved display logic into self-test for clarity.

Fixes #1076

* Missed some renamed variable

* Improve wording

* Wait on boot button is only for failed factory self-test

* Add logging line

* Call nvs_commit before esp_restart

* More logging

* Test boot button after factory self-test check
This commit is contained in:
mutatrum
2025-06-27 17:58:14 +02:00
committed by GitHub
parent c9cca926d5
commit 6711078839
7 changed files with 99 additions and 72 deletions

View File

@@ -47,5 +47,5 @@ DS4432U,data,u16,0
INA260,data,u16,0 INA260,data,u16,0
# TPS546 (0,1) # TPS546 (0,1)
TPS546,data,u16,1 TPS546,data,u16,1
# Self Test Power Consumption Target (> 0) # Self-test Power Consumption Target (> 0)
power_cons_tgt,data,u16,12 power_cons_tgt,data,u16,12

View File

@@ -17,4 +17,4 @@ You can flash [factory images](https://github.com/bitaxeorg/ESP-Miner/releases)
- Keep waiting until the console on ESP Tool says "Leaving..." - Keep waiting until the console on ESP Tool says "Leaving..."
- If you are _sure_ you have seen ESP Tool say "Leaving..." then you're bitaxe might restart. - If you are _sure_ you have seen ESP Tool say "Leaving..." then you're bitaxe might restart.
- If you bitaxe hasn't restarted, you can press the RESET button on the bitaxe - If you bitaxe hasn't restarted, you can press the RESET button on the bitaxe
- The self test should run. this can take a second. You'll need to press the RESET button on the bitaxe once the self test has passed. - The self-test should run. this can take a second. You'll need to press the RESET button on the bitaxe once the self-test has passed.

View File

@@ -75,10 +75,11 @@ typedef struct
typedef struct typedef struct
{ {
bool active; bool is_active;
bool is_finished;
char *message; char *message;
bool result; char *result;
bool finished; char *finished;
} SelfTestModule; } SelfTestModule;
typedef struct typedef struct

View File

@@ -166,3 +166,20 @@ void nvs_config_set_u64(const char * key, const uint64_t value)
} }
nvs_close(handle); nvs_close(handle);
} }
void nvs_config_commit()
{
nvs_handle handle;
esp_err_t err;
err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Could not open nvs");
return;
}
err = nvs_commit(handle);
if (err != ESP_OK) {
ESP_LOGW(TAG, "Could not commit nvs");
}
nvs_close(handle);
}

View File

@@ -65,5 +65,6 @@ int32_t nvs_config_get_i32(const char * key, const int32_t default_value);
void nvs_config_set_i32(const char * key, const int32_t value); void nvs_config_set_i32(const char * key, const int32_t value);
uint64_t nvs_config_get_u64(const char * key, const uint64_t default_value); uint64_t nvs_config_get_u64(const char * key, const uint64_t default_value);
void nvs_config_set_u64(const char * key, const uint64_t value); void nvs_config_set_u64(const char * key, const uint64_t value);
void nvs_config_commit(void);
#endif // MAIN_NVS_CONFIG_H #endif // MAIN_NVS_CONFIG_H

View File

@@ -96,7 +96,7 @@ static lv_obj_t * create_scr_self_test() {
lv_obj_t * scr = create_flex_screen(4); lv_obj_t * scr = create_flex_screen(4);
lv_obj_t *label1 = lv_label_create(scr); lv_obj_t *label1 = lv_label_create(scr);
lv_label_set_text(label1, "BITAXE SELF TEST"); lv_label_set_text(label1, "BITAXE SELF-TEST");
self_test_message_label = lv_label_create(scr); self_test_message_label = lv_label_create(scr);
self_test_result_label = lv_label_create(scr); self_test_result_label = lv_label_create(scr);
@@ -318,23 +318,17 @@ static void screen_update_cb(lv_timer_t * timer)
} }
} }
if (GLOBAL_STATE->SELF_TEST_MODULE.active) { if (GLOBAL_STATE->SELF_TEST_MODULE.is_active) {
screen_show(SCR_SELF_TEST); screen_show(SCR_SELF_TEST);
SelfTestModule * self_test = &GLOBAL_STATE->SELF_TEST_MODULE; SelfTestModule * self_test = &GLOBAL_STATE->SELF_TEST_MODULE;
lv_label_set_text(self_test_message_label, self_test->message); lv_label_set_text(self_test_message_label, self_test->message);
if (self_test->finished && !self_test_finished) { if (self_test->is_finished && !self_test_finished) {
self_test_finished = true; self_test_finished = true;
lv_label_set_text(self_test_result_label, self_test->result);
if (self_test->result) { lv_label_set_text(self_test_finished_label, self_test->finished);
lv_label_set_text(self_test_result_label, "TESTS PASS!");
lv_label_set_text(self_test_finished_label, "Press RESET button to start Bitaxe.");
} else {
lv_label_set_text(self_test_result_label, "TESTS FAIL!");
lv_label_set_text(self_test_finished_label, "Hold BOOT button for 2 seconds to cancel self test, or press RESET to run again.");
}
} }
return; return;

View File

@@ -35,9 +35,6 @@
#define GPIO_ASIC_ENABLE CONFIG_GPIO_ASIC_ENABLE #define GPIO_ASIC_ENABLE CONFIG_GPIO_ASIC_ENABLE
#define TESTS_FAILED 0
#define TESTS_PASSED 1
/////Test Constants///// /////Test Constants/////
//Test Fan Speed //Test Fan Speed
#define FAN_SPEED_TARGET_MIN 1000 //RPM #define FAN_SPEED_TARGET_MIN 1000 //RPM
@@ -51,30 +48,28 @@
static const char * TAG = "self_test"; static const char * TAG = "self_test";
SemaphoreHandle_t BootSemaphore; static SemaphoreHandle_t longPressSemaphore;
static bool isFactoryTest = false;
//local function prototypes //local function prototypes
static void tests_done(GlobalState * GLOBAL_STATE, bool test_result); static void tests_done(GlobalState * GLOBAL_STATE, bool test_result);
static bool should_test(GlobalState * GLOBAL_STATE) { static bool should_test() {
// Optionally hold the boot button uint64_t is_factory_flash = nvs_config_get_u64(NVS_CONFIG_BEST_DIFF, 0) < 1;
if (gpio_get_level(CONFIG_GPIO_BUTTON_BOOT) == 0) { // LOW when pressed uint16_t is_self_test_flag_set = nvs_config_get_u16(NVS_CONFIG_SELF_TEST, 0);
if (is_factory_flash && is_self_test_flag_set) {
isFactoryTest = true;
return true; return true;
} }
bool is_max = GLOBAL_STATE->DEVICE_CONFIG.family.asic.id == BM1397; // Optionally start self-test when boot button is pressed
uint64_t best_diff = nvs_config_get_u64(NVS_CONFIG_BEST_DIFF, 0); return gpio_get_level(CONFIG_GPIO_BUTTON_BOOT) == 0; // LOW when pressed
uint16_t should_self_test = nvs_config_get_u16(NVS_CONFIG_SELF_TEST, 0);
if (should_self_test == 1 && !is_max && best_diff < 1) {
return true;
}
return false;
} }
static void reset_self_test() { static void reset_self_test() {
ESP_LOGI(TAG, "Long press detected..."); ESP_LOGI(TAG, "Long press detected...");
// Give the semaphore back // Give the semaphore back
xSemaphoreGive(BootSemaphore); xSemaphoreGive(longPressSemaphore);
} }
static void display_msg(char * msg, GlobalState * GLOBAL_STATE) static void display_msg(char * msg, GlobalState * GLOBAL_STATE)
@@ -201,7 +196,7 @@ esp_err_t test_voltage_regulator(GlobalState * GLOBAL_STATE) {
if (init_voltage_regulator(GLOBAL_STATE) != ESP_OK) { if (init_voltage_regulator(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "VCORE init failed!"); ESP_LOGE(TAG, "VCORE init failed!");
display_msg("VCORE:FAIL", GLOBAL_STATE); display_msg("VCORE:FAIL", GLOBAL_STATE);
//tests_done(GLOBAL_STATE, TESTS_FAILED); //tests_done(GLOBAL_STATE, false);
return ESP_FAIL; return ESP_FAIL;
} }
@@ -210,7 +205,7 @@ esp_err_t test_voltage_regulator(GlobalState * GLOBAL_STATE) {
if (DS4432U_test() != ESP_OK) { if (DS4432U_test() != ESP_OK) {
ESP_LOGE(TAG, "DS4432 test failed!"); ESP_LOGE(TAG, "DS4432 test failed!");
display_msg("DS4432U:FAIL", GLOBAL_STATE); display_msg("DS4432U:FAIL", GLOBAL_STATE);
//tests_done(GLOBAL_STATE, TESTS_FAILED); //tests_done(GLOBAL_STATE, false);
return ESP_FAIL; return ESP_FAIL;
} }
} }
@@ -263,19 +258,23 @@ bool self_test(void * pvParameters)
{ {
GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters; GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters;
// Should we run the self test? // Should we run the self-test?
if (!should_test(GLOBAL_STATE)) return false; if (!should_test()) return false;
ESP_LOGI(TAG, "Running Self Tests"); if (isFactoryTest) {
ESP_LOGI(TAG, "Running factory self-test");
} else {
ESP_LOGI(TAG, "Running manual self-test");
}
GLOBAL_STATE->SELF_TEST_MODULE.active = true; GLOBAL_STATE->SELF_TEST_MODULE.is_active = true;
// Create a binary semaphore // Create a binary semaphore
BootSemaphore = xSemaphoreCreateBinary(); longPressSemaphore = xSemaphoreCreateBinary();
gpio_install_isr_service(0); gpio_install_isr_service(0);
if (BootSemaphore == NULL) { if (longPressSemaphore == NULL) {
ESP_LOGE(TAG, "Failed to create semaphore"); ESP_LOGE(TAG, "Failed to create semaphore");
return true; return true;
} }
@@ -283,48 +282,48 @@ bool self_test(void * pvParameters)
//Run PSRAM test //Run PSRAM test
if(test_psram(GLOBAL_STATE) != ESP_OK) { if(test_psram(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "NO PSRAM on device!"); ESP_LOGE(TAG, "NO PSRAM on device!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//Run display tests //Run display tests
if (test_display(GLOBAL_STATE) != ESP_OK) { if (test_display(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "Display test failed!"); ESP_LOGE(TAG, "Display test failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//Run input tests //Run input tests
if (test_input(GLOBAL_STATE) != ESP_OK) { if (test_input(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "Input test failed!"); ESP_LOGE(TAG, "Input test failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//Run screen tests //Run screen tests
if (test_screen(GLOBAL_STATE) != ESP_OK) { if (test_screen(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "Screen test failed!"); ESP_LOGE(TAG, "Screen test failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//Init peripherals EMC2101 and INA260 (if present) //Init peripherals EMC2101 and INA260 (if present)
if (test_init_peripherals(GLOBAL_STATE) != ESP_OK) { if (test_init_peripherals(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "Peripherals init failed!"); ESP_LOGE(TAG, "Peripherals init failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//Voltage Regulator Testing //Voltage Regulator Testing
if (test_voltage_regulator(GLOBAL_STATE) != ESP_OK) { if (test_voltage_regulator(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "Voltage Regulator test failed!"); ESP_LOGE(TAG, "Voltage Regulator test failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
if (asic_reset() != ESP_OK) { if (asic_reset() != ESP_OK) {
ESP_LOGE(TAG, "ASIC reset failed!"); ESP_LOGE(TAG, "ASIC reset failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//test for number of ASICs //test for number of ASICs
if (SERIAL_init() != ESP_OK) { if (SERIAL_init() != ESP_OK) {
ESP_LOGE(TAG, "SERIAL init failed!"); ESP_LOGE(TAG, "SERIAL init failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY); GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
@@ -335,11 +334,11 @@ bool self_test(void * pvParameters)
ESP_LOGI(TAG, "%u chips detected, %u expected", chips_detected, chips_expected); ESP_LOGI(TAG, "%u chips detected, %u expected", chips_detected, chips_expected);
if (chips_detected != chips_expected) { if (chips_detected != chips_expected) {
ESP_LOGE(TAG, "SELF TEST FAIL, %d of %d CHIPS DETECTED", chips_detected, chips_expected); ESP_LOGE(TAG, "SELF-TEST FAIL, %d of %d CHIPS DETECTED", chips_detected, chips_expected);
char error_buf[20]; char error_buf[20];
snprintf(error_buf, 20, "ASIC:FAIL %d CHIPS", chips_detected); snprintf(error_buf, 20, "ASIC:FAIL %d CHIPS", chips_detected);
display_msg(error_buf, GLOBAL_STATE); display_msg(error_buf, GLOBAL_STATE);
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//test for voltage regulator faults //test for voltage regulator faults
@@ -348,7 +347,7 @@ bool self_test(void * pvParameters)
char error_buf[20]; char error_buf[20];
snprintf(error_buf, 20, "VCORE:PWR FAULT"); snprintf(error_buf, 20, "VCORE:PWR FAULT");
display_msg(error_buf, GLOBAL_STATE); display_msg(error_buf, GLOBAL_STATE);
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
//setup and test hashrate //setup and test hashrate
@@ -357,7 +356,7 @@ bool self_test(void * pvParameters)
if (SERIAL_set_baud(baud) != ESP_OK) { if (SERIAL_set_baud(baud) != ESP_OK) {
ESP_LOGE(TAG, "SERIAL set baud failed!"); ESP_LOGE(TAG, "SERIAL set baud failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs = malloc(sizeof(bm_job *) * 128); GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs = malloc(sizeof(bm_job *) * 128);
@@ -446,14 +445,14 @@ bool self_test(void * pvParameters)
if (hash_rate < expected_hashrate_mhs) { if (hash_rate < expected_hashrate_mhs) {
display_msg("HASHRATE:FAIL", GLOBAL_STATE); display_msg("HASHRATE:FAIL", GLOBAL_STATE);
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
free(GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs); free(GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs);
free(GLOBAL_STATE->valid_jobs); free(GLOBAL_STATE->valid_jobs);
if (test_core_voltage(GLOBAL_STATE) != ESP_OK) { if (test_core_voltage(GLOBAL_STATE) != ESP_OK) {
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
// TODO: Maybe make a test equivalent for test values // TODO: Maybe make a test equivalent for test values
@@ -461,46 +460,61 @@ bool self_test(void * pvParameters)
if (test_INA260_power_consumption(GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target, POWER_CONSUMPTION_MARGIN) != ESP_OK) { if (test_INA260_power_consumption(GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target, POWER_CONSUMPTION_MARGIN) != ESP_OK) {
ESP_LOGE(TAG, "INA260 Power Draw Failed, target %.2f", (float)GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target); ESP_LOGE(TAG, "INA260 Power Draw Failed, target %.2f", (float)GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target);
display_msg("POWER:FAIL", GLOBAL_STATE); display_msg("POWER:FAIL", GLOBAL_STATE);
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
} }
if (GLOBAL_STATE->DEVICE_CONFIG.TPS546) { if (GLOBAL_STATE->DEVICE_CONFIG.TPS546) {
if (test_TPS546_power_consumption(GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target, POWER_CONSUMPTION_MARGIN) != ESP_OK) { if (test_TPS546_power_consumption(GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target, POWER_CONSUMPTION_MARGIN) != ESP_OK) {
ESP_LOGE(TAG, "TPS546 Power Draw Failed, target %.2f", (float)GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target); ESP_LOGE(TAG, "TPS546 Power Draw Failed, target %.2f", (float)GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target);
display_msg("POWER:FAIL", GLOBAL_STATE); display_msg("POWER:FAIL", GLOBAL_STATE);
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
} }
if (test_fan_sense(GLOBAL_STATE) != ESP_OK) { if (test_fan_sense(GLOBAL_STATE) != ESP_OK) {
ESP_LOGE(TAG, "Fan test failed!"); ESP_LOGE(TAG, "Fan test failed!");
tests_done(GLOBAL_STATE, TESTS_FAILED); tests_done(GLOBAL_STATE, false);
} }
tests_done(GLOBAL_STATE, TESTS_PASSED); tests_done(GLOBAL_STATE, true);
return true; return true;
} }
static void tests_done(GlobalState * GLOBAL_STATE, bool test_result) static void tests_done(GlobalState * GLOBAL_STATE, bool isTestPassed)
{ {
GLOBAL_STATE->SELF_TEST_MODULE.result = test_result;
GLOBAL_STATE->SELF_TEST_MODULE.finished = true;
VCORE_set_voltage(0.0f, GLOBAL_STATE); VCORE_set_voltage(0.0f, GLOBAL_STATE);
if (test_result == TESTS_FAILED) { if (isTestPassed) {
ESP_LOGI(TAG, "SELF TESTS FAIL -- Press RESET to continue"); if (isFactoryTest) {
while (1) { ESP_LOGI(TAG, "Self-test flag cleared");
// Wait here forever until reset_self_test() gives the BootSemaphore nvs_config_set_u16(NVS_CONFIG_SELF_TEST, 0);
if (xSemaphoreTake(BootSemaphore, portMAX_DELAY) == pdTRUE) {
nvs_config_set_u16(NVS_CONFIG_SELF_TEST, 0);
//wait 100ms for nvs write to finish?
vTaskDelay(100 / portTICK_PERIOD_MS);
esp_restart();
}
} }
ESP_LOGI(TAG, "SELF-TEST PASS! -- Press RESET button to restart.");
GLOBAL_STATE->SELF_TEST_MODULE.result = "SELF-TEST PASS!";
GLOBAL_STATE->SELF_TEST_MODULE.finished = "Press RESET button to restart.";
} else { } else {
nvs_config_set_u16(NVS_CONFIG_SELF_TEST, 0); // isTestFailed
ESP_LOGI(TAG, "Self Tests Passed!!!"); GLOBAL_STATE->SELF_TEST_MODULE.result = "SELF-TEST FAIL!";
if (isFactoryTest) {
ESP_LOGI(TAG, "SELF-TEST FAIL! -- Hold BOOT button for 2 seconds to cancel self-test, or press RESET to run self-test again.");
GLOBAL_STATE->SELF_TEST_MODULE.finished = "Hold BOOT button for 2 seconds to cancel self-test, or press RESET to run self-test again.";
GLOBAL_STATE->SELF_TEST_MODULE.is_finished = true;
while (1) {
// Wait here forever until reset_self_test() gives the longPressSemaphore
if (xSemaphoreTake(longPressSemaphore, portMAX_DELAY) == pdTRUE) {
ESP_LOGI(TAG, "Self-test flag cleared");
nvs_config_set_u16(NVS_CONFIG_SELF_TEST, 0);
// flush all pending NVS writes
nvs_config_commit();
esp_restart();
}
}
} else {
ESP_LOGI(TAG, "SELF-TEST FAIL -- Press RESET button to restart.");
GLOBAL_STATE->SELF_TEST_MODULE.finished = "Press RESET button to restart.";
}
} }
GLOBAL_STATE->SELF_TEST_MODULE.is_finished = true;
} }