stm32f103 firmware upload via esp32

this was my hardware setup manually controlling the boot pin.
what my condition was I am initialized the bootloader receiving the ack 0x79 for that and also erasing the flash correctly i checked it with the cube programmer , but the write operation is not done. every time i checked with the cube programmer nothing is written in new. this was my current condition
this was my code written in arduino framework is attached below,
#include <WiFi.h>
#include <WebServer.h>
#include <LittleFS.h>
#define WIFI_SSID "Hotspot"
#define WIFI_PASSWORD "12341234"
#define UART_PORT Serial2
#define STM32_BAUDRATE 115200
#define STM32_RX 16
#define STM32_TX 17
#define STM32_ACK 0x79
#define STM32_NACK 0x1F
#define STM32_INIT 0x7F
WebServer server(80);
uint8_t packet[300];
uint32_t currentAddress = 0x08000000;
const char* serverIndex = R"rawliteral(
<!DOCTYPE HTML><html>
<head><title>STM32 FOTA</title><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body><h2>STM32 Firmware Upload</h2>
<form method='POST' action='/update' enctype='multipart/form-data' id='upload_form'>
<input type='file' name='update' accept='.bin'><input type='submit' value='Upload'></form>
<div id='prg'>Progress: 0%</div>
<script>
document.getElementById('upload_form').onsubmit = function(e) {
e.preventDefault();
var form = document.getElementById('upload_form');
var data = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/update', true);
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;
document.getElementById('prg').innerHTML = 'Progress: ' + Math.round(percentComplete) + '%';
}
};
xhr.onload = function() {
alert(xhr.status === 200 ? 'Upload successful' : 'Upload failed');
};
xhr.send(data);
};
</script></body></html>
)rawliteral";
void setup() {
Serial.begin(115200);
UART_PORT.begin(STM32_BAUDRATE, SERIAL_8E1, STM32_RX, STM32_TX);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(300);
Serial.print(".");
}
Serial.println("\nConnected! IP: " + WiFi.localIP().toString());
LittleFS.begin();
server.on("/", HTTP_GET, []() {
server.send(200, "text/html", serverIndex);
});
server.on("/update", HTTP_POST, []() {
server.send(200, "text/plain", "Upload Complete");
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.println("[BOOT] Initializing bootloader...");
currentAddress = 0x08000000;
if (!stm32InitBootloader()) {
Serial.println("[BOOT] Failed to sync with STM32 bootloader");
return;
}
Send_CMD_Erase_Flash();
} else if (upload.status == UPLOAD_FILE_WRITE) {
Serial.printf("[UPLOAD] Chunk received: %d bytes\n", upload.currentSize);
SendBinaryToSTM32(upload.buf, upload.currentSize, currentAddress);
currentAddress += upload.currentSize;
} else if (upload.status == UPLOAD_FILE_END) {
Serial.println("[UPLOAD] Complete. Jumping to application.");
Send_CMD_Jump_To_Application();
}
});
server.begin();
}
void loop() {
server.handleClient();
}
bool waitForAck(uint32_t timeout = 1000) {
unsigned long start = millis();
while (millis() - start < timeout) {
if (UART_PORT.available()) {
uint8_t b = UART_PORT.read();
if (b == STM32_ACK) {
Serial.println("[ACK] Received");
return true;
} else if (b == STM32_NACK) {
Serial.println("[NACK] Received");
return false;
} else {
Serial.printf("[UART] Unknown byte: 0x%02X\n", b);
}
}
}
Serial.println("[TIMEOUT] No ACK/NACK received");
return false;
}
bool stm32InitBootloader() {
UART_PORT.write(STM32_INIT);
UART_PORT.flush();
return waitForAck();
}
void Send_CMD_Erase_Flash() {
Serial.println("[CMD] Sending Erase Flash");
packet[0] = 0x43;
packet[1] = ~packet[0];
UART_PORT.write(packet, 2);
UART_PORT.flush();
if (!waitForAck()) return;
packet[0] = 0xFF;
packet[1] = 0x00;
UART_PORT.write(packet, 2);
UART_PORT.flush();
waitForAck();
}
void Send_CMD_Jump_To_Application() {
Serial.println("[CMD] Jump to application");
packet[0] = 0x21;
packet[1] = ~packet[0];
UART_PORT.write(packet, 2);
UART_PORT.flush();
waitForAck();
}
void SendBinaryToSTM32(uint8_t* data, size_t len, uint32_t address) {
if (!data || len == 0 || len > 256) return;
Serial.printf("[WRITE] Sending %d bytes to 0x%08X\n", len, address);
packet[0] = 0x31;
packet[1] = ~packet[0];
UART_PORT.write(packet, 2);
UART_PORT.flush();
if (!waitForAck()) return;
// Address
uint8_t addr[5];
addr[0] = (address >> 24) & 0xFF;
addr[1] = (address >> 16) & 0xFF;
addr[2] = (address >> 8) & 0xFF;
addr[3] = address & 0xFF;
addr[4] = addr[0] ^ addr[1] ^ addr[2] ^ addr[3];
UART_PORT.write(addr, 5);
UART_PORT.flush();
if (!waitForAck()) return;
uint8_t lenByte = len - 1;
uint8_t checksum = lenByte;
UART_PORT.write(lenByte);
Serial.print("[DATA] ");
for (size_t i = 0; i < len; i++) {
UART_PORT.write(data[i]);
Serial.printf("%02X ", data[i]);
checksum ^= data[i];
}
UART_PORT.write(checksum);
UART_PORT.flush();
Serial.printf("\n[CHK] %02X\n", checksum);
waitForAck();
}
