gpio: update config to use only one gpio for ATX PSU
All checks were successful
Build ESP32 BMC Firmware / build (push) Successful in 59s

This commit is contained in:
2026-03-12 15:28:20 +01:00
parent c6f4d26c58
commit ccf4569969
6 changed files with 25 additions and 143 deletions

View File

@@ -37,15 +37,7 @@ A Baseboard Management Controller (BMC) firmware for ESP32-S3 that provides remo
#### BMC GPIOs #### BMC GPIOs
| GPIO | Name | Description | | GPIO | Name | Description |
|------|------|-------------| |------|------|-------------|
| 4 | POWER_ON | Power control output | | 37 | POWER | ATX power supply "PS_ON#" signal |
| 5 | POWER_OFF | Power control output |
| 6 | RESET | Reset control (active-low) |
| 7 | STATUS_LED | Status LED |
| 15 | PWR_GOOD | Power good input |
| 16 | TEMP_ALERT | Temperature alert input |
| 17 | FAN_CTRL | Fan control PWM |
| 18-25 | USER_1-8 | User configurable GPIOs |
| 35-38 | USER_5-8 | Input-only GPIOs |
## Building ## Building

View File

@@ -47,7 +47,7 @@
// ============================================================================ // ============================================================================
// Number of user-configurable GPIOs // Number of user-configurable GPIOs
#define BMC_GPIO_COUNT 16 #define BMC_GPIO_COUNT 1
// GPIO pin definitions with names and default modes // GPIO pin definitions with names and default modes
typedef struct { typedef struct {
@@ -60,54 +60,18 @@ typedef struct {
} bmc_gpio_def_t; } bmc_gpio_def_t;
// Predefined GPIO assignments // Predefined GPIO assignments
#define BMC_GPIO_POWER_ON GPIO_NUM_4 #define BMC_GPIO_POWER GPIO_NUM_37
#define BMC_GPIO_POWER_OFF GPIO_NUM_5
#define BMC_GPIO_RESET GPIO_NUM_6
#define BMC_GPIO_STATUS_LED GPIO_NUM_7
#define BMC_GPIO_PWR_GOOD GPIO_NUM_15
#define BMC_GPIO_TEMP_ALERT GPIO_NUM_16
#define BMC_GPIO_FAN_CTRL GPIO_NUM_17
#define BMC_GPIO_USER_1 GPIO_NUM_18
#define BMC_GPIO_USER_2 GPIO_NUM_21
#define BMC_GPIO_USER_3 GPIO_NUM_35
#define BMC_GPIO_USER_4 GPIO_NUM_36
#define BMC_GPIO_USER_5 GPIO_NUM_37
#define BMC_GPIO_USER_6 GPIO_NUM_38
#define BMC_GPIO_USER_7 GPIO_NUM_47
#define BMC_GPIO_USER_8 GPIO_NUM_48
// Default GPIO configuration table // Default GPIO configuration table
static const bmc_gpio_def_t bmc_gpio_defaults[BMC_GPIO_COUNT] = { static const bmc_gpio_def_t bmc_gpio_defaults[BMC_GPIO_COUNT] = {
// Power control outputs // Power control outputs
{ BMC_GPIO_POWER_ON, "POWER_ON", GPIO_MODE_OUTPUT, 0, false, false}, {BMC_GPIO_POWER, "POWER", GPIO_MODE_OUTPUT, 1 /* AC power ON */, true, false},
{ BMC_GPIO_POWER_OFF, "POWER_OFF", GPIO_MODE_OUTPUT, 0, false, false},
{ BMC_GPIO_RESET, "RESET", GPIO_MODE_OUTPUT, 0, true, false}, // Active-low reset
{BMC_GPIO_STATUS_LED, "STATUS_LED", GPIO_MODE_OUTPUT, 0, false, false},
// Status inputs
{ BMC_GPIO_PWR_GOOD, "PWR_GOOD", GPIO_MODE_INPUT, 0, false, false},
{BMC_GPIO_TEMP_ALERT, "TEMP_ALERT", GPIO_MODE_INPUT, 0, true, false}, // Active-low alert
// PWM output
{ BMC_GPIO_FAN_CTRL, "FAN_CTRL", GPIO_MODE_OUTPUT, 0, false, false},
// User-configurable GPIOs
{ BMC_GPIO_USER_1, "USER_1", GPIO_MODE_INPUT, 0, false, false},
{ BMC_GPIO_USER_2, "USER_2", GPIO_MODE_INPUT, 0, false, false},
{ BMC_GPIO_USER_3, "USER_3", GPIO_MODE_INPUT, 0, false, false},
{ BMC_GPIO_USER_4, "USER_4", GPIO_MODE_INPUT, 0, false, false},
{ BMC_GPIO_USER_5, "USER_5", GPIO_MODE_INPUT, 0, false, true}, // Input-only on ESP32-S3
{ BMC_GPIO_USER_6, "USER_6", GPIO_MODE_INPUT, 0, false, true}, // Input-only on ESP32-S3
{ BMC_GPIO_USER_7, "USER_7", GPIO_MODE_INPUT, 0, false, true}, // Input-only on ESP32-S3
{ BMC_GPIO_USER_8, "USER_8", GPIO_MODE_INPUT, 0, false, true}, // Input-only on ESP32-S3
}; };
// ============================================================================ // ============================================================================
// Power Control Timing // Power Control Timing
// ============================================================================ // ============================================================================
#define BMC_POWER_ON_PULSE_MS 100 #define BMC_RESET_PULSE_MS 200
#define BMC_POWER_OFF_PULSE_MS 5000
#define BMC_RESET_PULSE_MS 100
#define BMC_POWER_GOOD_DELAY_MS 2000 #define BMC_POWER_GOOD_DELAY_MS 2000
// ============================================================================ // ============================================================================

View File

@@ -218,61 +218,29 @@ esp_err_t gpio_toggle(gpio_num_t pin) {
esp_err_t gpio_power_on(void) { esp_err_t gpio_power_on(void) {
ESP_LOGI(TAG, "Power ON sequence initiated"); ESP_LOGI(TAG, "Power ON sequence initiated");
gpio_write(BMC_GPIO_POWER, 1);
// Pulse the POWER_ON signal
gpio_write(BMC_GPIO_POWER_ON, 1);
vTaskDelay(pdMS_TO_TICKS(BMC_POWER_ON_PULSE_MS));
gpio_write(BMC_GPIO_POWER_ON, 0);
// Wait for power good signal
vTaskDelay(pdMS_TO_TICKS(BMC_POWER_GOOD_DELAY_MS));
if (gpio_is_power_good()) {
ESP_LOGI(TAG, "Power ON successful - power good detected");
gpio_set_status_led(true);
return ESP_OK; return ESP_OK;
} else {
ESP_LOGW(TAG, "Power ON completed - no power good signal");
return ESP_OK; // Still return OK, just no confirmation
}
} }
esp_err_t gpio_power_off(void) { esp_err_t gpio_power_off(void) {
ESP_LOGI(TAG, "Power OFF sequence initiated"); ESP_LOGI(TAG, "Power OFF sequence initiated");
gpio_write(BMC_GPIO_POWER, 0);
// Pulse the POWER_OFF signal
gpio_write(BMC_GPIO_POWER_OFF, 1);
vTaskDelay(pdMS_TO_TICKS(BMC_POWER_OFF_PULSE_MS));
gpio_write(BMC_GPIO_POWER_OFF, 0);
gpio_set_status_led(false);
ESP_LOGI(TAG, "Power OFF completed");
return ESP_OK; return ESP_OK;
} }
esp_err_t gpio_reset(void) { esp_err_t gpio_reset(void) {
ESP_LOGI(TAG, "Reset sequence initiated"); ESP_LOGI(TAG, "Reset sequence initiated");
// Pulse the RESET signal (active-low) // Pulse the POWER signal
gpio_write(BMC_GPIO_RESET, 0); // Assert reset (active-low) gpio_write(BMC_GPIO_POWER, 0);
vTaskDelay(pdMS_TO_TICKS(BMC_RESET_PULSE_MS)); vTaskDelay(pdMS_TO_TICKS(BMC_RESET_PULSE_MS));
gpio_write(BMC_GPIO_RESET, 1); // De-assert reset gpio_write(BMC_GPIO_POWER, 1);
ESP_LOGI(TAG, "Reset completed"); ESP_LOGI(TAG, "Reset completed");
return ESP_OK; return ESP_OK;
} }
bool gpio_is_power_good(void) { bool gpio_power_status(void) {
int idx = gpio_find_index(BMC_GPIO_PWR_GOOD); int level = gpio_get_level(BMC_GPIO_POWER);
if (idx < 0) {
return false;
}
int level = gpio_get_level(BMC_GPIO_PWR_GOOD);
return (level == 1); return (level == 1);
} }
esp_err_t gpio_set_status_led(bool on) {
return gpio_write(BMC_GPIO_STATUS_LED, on ? 1 : 0);
}

View File

@@ -131,18 +131,10 @@ esp_err_t gpio_power_off(void);
esp_err_t gpio_reset(void); esp_err_t gpio_reset(void);
/** /**
* @brief Check if power is good * @brief Check if power is on or off
* *
* @return true if power good signal is high, false otherwise * @return true if power signal is high, false otherwise
*/ */
bool gpio_is_power_good(void); bool gpio_power_status(void);
/**
* @brief Set status LED state
*
* @param on true to turn on, false to turn off
* @return ESP_OK on success, error code otherwise
*/
esp_err_t gpio_set_status_led(bool on);
#endif // GPIO_CONTROLLER_H #endif // GPIO_CONTROLLER_H

View File

@@ -17,12 +17,10 @@ static void eth_event_callback(eth_event_type_t event) {
switch (event) { switch (event) {
case ETH_EVENT_CONNECTED: case ETH_EVENT_CONNECTED:
ESP_LOGI(TAG, "Ethernet connected"); ESP_LOGI(TAG, "Ethernet connected");
gpio_set_status_led(true);
break; break;
case ETH_EVENT_DISCONNECTED: case ETH_EVENT_DISCONNECTED:
ESP_LOGW(TAG, "Ethernet disconnected"); ESP_LOGW(TAG, "Ethernet disconnected");
gpio_set_status_led(false);
break; break;
case ETH_EVENT_GOT_IP: { case ETH_EVENT_GOT_IP: {
@@ -51,9 +49,6 @@ void app_main(void) {
// Continue anyway - some GPIOs might still work // Continue anyway - some GPIOs might still work
} }
// Set status LED to indicate initialization
gpio_set_status_led(false);
// Initialize UART handler // Initialize UART handler
ESP_LOGI(TAG, "Initializing UART handler..."); ESP_LOGI(TAG, "Initializing UART handler...");
ret = uart_handler_init(); ret = uart_handler_init();
@@ -119,20 +114,5 @@ void app_main(void) {
ESP_LOGI(TAG, "Web interface: http://%s/", ip); ESP_LOGI(TAG, "Web interface: http://%s/", ip);
ESP_LOGI(TAG, "========================================"); ESP_LOGI(TAG, "========================================");
// Main loop - monitor system health return;
while (1) {
// Update status LED based on connection state
if (ethernet_is_connected()) {
gpio_set_status_led(true);
} else {
// Blink LED if not connected
gpio_set_status_led(false);
vTaskDelay(pdMS_TO_TICKS(500));
gpio_set_status_led(true);
vTaskDelay(pdMS_TO_TICKS(500));
gpio_set_status_led(false);
}
vTaskDelay(pdMS_TO_TICKS(5000));
}
} }

View File

@@ -258,24 +258,7 @@ static esp_err_t api_gpio_config_handler(httpd_req_t *req) {
static esp_err_t api_power_status_handler(httpd_req_t *req) { static esp_err_t api_power_status_handler(httpd_req_t *req) {
cJSON *status = cJSON_CreateObject(); cJSON *status = cJSON_CreateObject();
cJSON_AddBoolToObject(status, "power_good", gpio_is_power_good()); cJSON_AddStringToObject(status, "power_status", gpio_power_status() ? "on" : "off");
// Get power control GPIO states
int power_on_idx = gpio_find_index(BMC_GPIO_POWER_ON);
int power_off_idx = gpio_find_index(BMC_GPIO_POWER_OFF);
if (power_on_idx >= 0) {
bmc_gpio_state_t state;
gpio_get_state(BMC_GPIO_POWER_ON, &state);
cJSON_AddNumberToObject(status, "power_on_state", state.value);
}
if (power_off_idx >= 0) {
bmc_gpio_state_t state;
gpio_get_state(BMC_GPIO_POWER_OFF, &state);
cJSON_AddNumberToObject(status, "power_off_state", state.value);
}
return send_json_success(req, status); return send_json_success(req, status);
} }
@@ -287,7 +270,7 @@ static esp_err_t api_power_on_handler(httpd_req_t *req) {
cJSON *response = cJSON_CreateObject(); cJSON *response = cJSON_CreateObject();
cJSON_AddStringToObject(response, "message", "Power on sequence initiated"); cJSON_AddStringToObject(response, "message", "Power on sequence initiated");
cJSON_AddBoolToObject(response, "power_good", gpio_is_power_good()); cJSON_AddStringToObject(response, "power_status", "on");
return send_json_success(req, response); return send_json_success(req, response);
} }
@@ -300,6 +283,7 @@ static esp_err_t api_power_off_handler(httpd_req_t *req) {
cJSON *response = cJSON_CreateObject(); cJSON *response = cJSON_CreateObject();
cJSON_AddStringToObject(response, "message", "Power off sequence initiated"); cJSON_AddStringToObject(response, "message", "Power off sequence initiated");
cJSON_AddStringToObject(response, "power_status", "off");
return send_json_success(req, response); return send_json_success(req, response);
} }
@@ -312,6 +296,7 @@ static esp_err_t api_power_reset_handler(httpd_req_t *req) {
cJSON *response = cJSON_CreateObject(); cJSON *response = cJSON_CreateObject();
cJSON_AddStringToObject(response, "message", "Reset sequence initiated"); cJSON_AddStringToObject(response, "message", "Reset sequence initiated");
cJSON_AddStringToObject(response, "power_status", "on");
return send_json_success(req, response); return send_json_success(req, response);
} }
@@ -484,7 +469,7 @@ static esp_err_t api_system_status_handler(httpd_req_t *req) {
// Power status // Power status
cJSON *power = cJSON_CreateObject(); cJSON *power = cJSON_CreateObject();
cJSON_AddBoolToObject(power, "power_good", gpio_is_power_good()); cJSON_AddBoolToObject(power, "power_status", gpio_power_status());
cJSON_AddItemToObject(status, "power", power); cJSON_AddItemToObject(status, "power", power);
// Network status // Network status
@@ -918,8 +903,9 @@ esp_err_t web_server_ws_broadcast(const uint8_t *data, size_t len) {
// Get client list - httpd has its own internal locking // Get client list - httpd has its own internal locking
esp_err_t ret = httpd_get_client_list(server, &clients, client_fds); esp_err_t ret = httpd_get_client_list(server, &clients, client_fds);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGW(TAG, "Failed to get client list: %s", esp_err_to_name(ret)); // This can happen when there are no clients or server is busy - not a critical error
return ret; ESP_LOGD(TAG, "Could not get client list: %s (may be no clients connected)", esp_err_to_name(ret));
return ESP_OK; // Return OK since this is not a critical error
} }
// Count and send to all WebSocket clients // Count and send to all WebSocket clients