完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
鉴于flymcu下载时有点慢,flash_loader.exe容易卡死的原因,所以决定自己写个串口编程和控制台程序。然后写成bat文件,再整合到Visual studio的外部工具里,实现一键下载。 STM32_ISP的协议文档可以在st的官网上找到。 先说下控制台的大致思路: 程序的目标:把*.bin文件通过指定串口发送到stm32,stm32把收到的*.bin文件数据存到指定的flash地址。 控制台这边要给的指令是:例如:COM4 256000 0X08000000 M:codedebugtext.bin 1.电脑的串口编号: COM4 2.要使用的串口波特率: 256000 3.编程地址: 0X08000000 4.*.bin文件路径: M:codedebugtext.bin 所有的指令可以通过int main(int argc, char** argv),的**argv指针获得。 例如:把上面的指令通过CMD输入后 程序: int main(int argc, char** argv) { for (int i = 0; i < argc; i++) { printf("argv[%d]:%sn", i, argv); } } 运行结果: argv[0]:M:stm32_isp_programerstm32_isp_programmerDebugstm32_isp_programmer.exe argv[1]:COM6 argv[2]:256000 argv[3]:0X08000000 argv[4]:M:codedebugtext.bin 但是获得只是文本类型(char *)。 windows 要打开串口的话用需要用WCHAR* 类型。 所以要做一定的类型转换。 字符串转WCHAR: #include wchar_t wstr[20]; swprintf(wstr, 20, L"%S", str); LPCWSTR wstr_p= wstr; 字符串转10进制 字符串转16进制 #include long baudrate = strtol(setBuadrate_p, &endptr, 10); long writeAddress = strtol(writeAddress_p, &endptr, 16); 然后是打开串口: SerialPort.hSerial = CreateFile(filename, //lpFileName GENERIC_READ | GENERIC_WRITE,//dwDesiredAccess 0, //dwShareMode NULL,//lpSecurityAttributes OPEN_EXISTING,//dwCreationDisposition FILE_ATTRIBUTE_NORMAL, NULL);//hTemplateFile 串口配制: SerialPort.NewDCBParams.BaudRate = baudrate; SerialPort.NewDCBParams.ByteSize = 8; SerialPort.NewDCBParams.StopBits = ONESTOPBIT; SerialPort.NewDCBParams.Parity = EVENPARITY; if (!SetCommState(SerialPort.hSerial, &SerialPort.NewDCBParams)) { printf("nSetCommState error!n"); fflush(stdout); return(1); } COMMTIMEOUTS timeouts = { 0 }; timeouts.ReadIntervalTimeout = 1000; timeouts.ReadTotalTimeoutConstant = 1000; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (!SetCommTimeouts(SerialPort.hSerial, &timeouts)) { printf("nSetCommTimeouts error!n"); fflush(stdout); return(1); } 串口读写: DWORD serial_write(unsigned char* buffer, DWORD len) { DWORD lengthwrote; if (!WriteFile(SerialPort.hSerial, buffer, len, &lengthwrote, NULL)) { if (GetLastError() == ERROR_IO_PENDING) { printf("Error:%d Serial write fail, exiting lengthwrote:%dn", GetLastError(), lengthwrote); } printf("Error:%d Serial write fail, exiting lengthwrote:%dn", GetLastError(), lengthwrote); exit(1); } return(lengthwrote); } DWORD serial_read(unsigned char* buffer, size_t len) //windows version { DWORD bytesread; if (!ReadFile(SerialPort.hSerial, buffer, len, &bytesread, NULL)) { printf("Error: Serial read fail, exitingn"); exit(1); } return(bytesread); } 如果有加了RTS#控制的话,还可以用RTS来控制单片机复位: void hardwareReset() { UINT8 restTime = 5; while (restTime--) { if (!EscapeCommFunction(SerialPort.hSerial, SETRTS)) { printf("nEscapeCommFunction error in serial_config, SETRTSn"); fflush(stdout); exit(1); } Sleep(100); if (!EscapeCommFunction(SerialPort.hSerial, CLRRTS)) { printf("nEscapeCommFunction error in serial_config, SETRTSn"); fflush(stdout); exit(1); } Sleep(100); printf("%dn", restTime); } } 后面是STM32 ISP协议部分: 主要用到这几个: void autoBaudrateStart(void);//自动识别波特率 void clear_writeprotect(void);//清除写保护 void get_version(void);//获取bootloader版本号,不同版本支持的指令不一样 void get_id(void);//获取芯片ID void globalerase_flash(void);//全片清除flash void program_memory(void);//flash编程 然后是通信格式: 基本是: 1字节命令+1字节命令反码 N字节内容+1字节所有内容字节的^(异或运算) 通信流程:发送指令,等待ACK或者NACK,发送内容,等待ACK或者NACK 主程序: #include #include #include #include "Serial.h" #include "action.h" #include /* COM3 115200 0X08000000 D:SDALJGG.BIN */ int main(int argc, char** argv) { SYSTEMTIME bootTime; SYSTEMTIME exitTime; char* selectPort_p; char* setBuadrate_p; char* writeAddress_p; char* loadFile; GetSystemTime(&bootTime); for (int i = 0; i < argc; i++) { printf("argv[%d]:%sn", i, argv); } selectPort_p = argv[1]; setBuadrate_p = argv[2]; writeAddress_p = argv[3]; loadFile = argv[4]; printf("selectPort:%sn", selectPort_p); printf("setBuadrate_p:%sn", setBuadrate_p); printf("writeAddress_p:%sn", writeAddress_p); printf("loadFile:%sn", loadFile); char *endptr; long baudrate = strtol(setBuadrate_p, &endptr, 10); long writeAddress = strtol(writeAddress_p, &endptr, 16); hostHandle.baudrate = baudrate; hostHandle.loadFile = loadFile; hostHandle.serialDev = selectPort_p; hostHandle.writeAddress = writeAddress; serial_init(selectPort_p, baudrate); autoBaudrateStart(); get_version(); get_id(); clear_writeprotect(); globalerase_flash(); program_memory(); printf("Isp complete and reseting...n"); hardwareReset(); GetSystemTime(&exitTime); size_t timeUse = (exitTime.wMinute * 60 + exitTime.wSecond) * 1000 + exitTime.wMilliseconds; timeUse = timeUse - ((bootTime.wMinute * 60 + bootTime.wSecond) * 1000 + bootTime.wMilliseconds); printf("Total time use: %d.%d secondsn", timeUse/1000, timeUse%1000); } 串口配置: #pragma once #include char serial_init(char * serialPortName, UINT32 baudrate); DWORD serial_write(unsigned char* buffer, DWORD len); DWORD serial_read(unsigned char* buffer, size_t len); void Serial_putc(unsigned char c); unsigned char Serial_getc(void); void hardwareReset(); typedef struct { int open; int status; HANDLE hSerial; DCB OldDCBParams; DCB NewDCBParams; }SerialPort_s; extern SerialPort_s SerialPort; #include #include #include #include "Serial.h" SerialPort_s SerialPort; void hardwareReset() { UINT8 restTime = 5; while (restTime--) { if (!EscapeCommFunction(SerialPort.hSerial, SETRTS)) { printf("nEscapeCommFunction error in serial_config, SETRTSn"); fflush(stdout); exit(1); } Sleep(100); if (!EscapeCommFunction(SerialPort.hSerial, CLRRTS)) { printf("nEscapeCommFunction error in serial_config, SETRTSn"); fflush(stdout); exit(1); } Sleep(100); printf("%dn", restTime); } } char serial_init(char *serialPortName, UINT32 baudrate) { wchar_t portName[20]; swprintf(portName, 20, L"%S", serialPortName); LPCWSTR filename = portName; SerialPort.hSerial = CreateFile(filename, //lpFileName GENERIC_READ | GENERIC_WRITE,//dwDesiredAccess 0, //dwShareMode NULL,//lpSecurityAttributes OPEN_EXISTING,//dwCreationDisposition FILE_ATTRIBUTE_NORMAL, NULL);//hTemplateFile if (SerialPort.hSerial == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_FILE_NOT_FOUND) { printf("ERROR_FILE_NOT_FOUND: Serial port: %ws not found on your computer.n", filename); fflush(stdout); return(1); } else if (GetLastError() == ERROR_ACCESS_DENIED) { printf("ERROR_ACCESS_DENIED: Serisl port: %ws Access denied!n", filename); fflush(stdout); return(1); } else if (GetLastError() == ERROR_INVALID_NAME) { printf("ERROR_INVALID_NAME Error: Serisl port: %ws !n", filename); fflush(stdout); return(1); } else { printf("Error: Serial operat failure. Error Code:%ldn", GetLastError()); fflush(stdout); return(1); } } printf("Serial port: %s open success!n", serialPortName); //success! switch (baudrate) { case 2400: SerialPort.NewDCBParams.BaudRate = CBR_2400; break; case 4800: SerialPort.NewDCBParams.BaudRate = CBR_4800; break; case 9600: SerialPort.NewDCBParams.BaudRate = CBR_9600; break; case 19200: SerialPort.NewDCBParams.BaudRate = CBR_19200; break; case 38400: SerialPort.NewDCBParams.BaudRate = CBR_38400; break; case 57600: SerialPort.NewDCBParams.BaudRate = CBR_57600; break; case 115200: SerialPort.NewDCBParams.BaudRate = CBR_115200; break; case 256000: SerialPort.NewDCBParams.BaudRate = CBR_256000; break; default: SerialPort.NewDCBParams.BaudRate = baudrate; printf("baudrate:%d may not support.n", baudrate); fflush(stdout); break; } SerialPort.NewDCBParams.ByteSize = 8; SerialPort.NewDCBParams.StopBits = ONESTOPBIT; SerialPort.NewDCBParams.Parity = EVENPARITY; if (!SetCommState(SerialPort.hSerial, &SerialPort.NewDCBParams)) { printf("nSetCommState error!n"); fflush(stdout); return(1); } COMMTIMEOUTS timeouts = { 0 }; timeouts.ReadIntervalTimeout = 1000; timeouts.ReadTotalTimeoutConstant = 1000; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (!SetCommTimeouts(SerialPort.hSerial, &timeouts)) { printf("nSetCommTimeouts error!n"); fflush(stdout); return(1); } printf("Serial port: %sn", serialPortName); printf("Buadrate: %dn", baudrate); printf("Data bits: 8n"); printf("Parity: Evenn"); printf("Stop bits: 1n"); printf("Flow control: nonen"); printf("Serial init complete!n"); printf("nnnTrying to rest and connet target, please push and hold ""boot0"" button!n"); printf("Using RTS LOW to reset taeget...n"); hardwareReset(); PurgeComm(SerialPort.hSerial, (PURGE_RXCLEAR)); return 0; } DWORD serial_write(unsigned char* buffer, DWORD len) { DWORD lengthwrote; if (!WriteFile(SerialPort.hSerial, buffer, len, &lengthwrote, NULL)) { if (GetLastError() == ERROR_IO_PENDING) { printf("Error:%d Serial write fail, exiting lengthwrote:%dn", GetLastError(), lengthwrote); } printf("Error:%d Serial write fail, exiting lengthwrote:%dn", GetLastError(), lengthwrote); exit(1); } return(lengthwrote); } DWORD serial_read(unsigned char* buffer, size_t len) //windows version { DWORD bytesread; if (!ReadFile(SerialPort.hSerial, buffer, len, &bytesread, NULL)) { printf("Error: Serial read fail, exitingn"); exit(1); } return(bytesread); } void Serial_putc(unsigned char c) { if (serial_write(&c, 1) != (size_t)1) { perror("Error:Serial write one byte fail, exitingn"); exit(1); } } unsigned char Serial_getc(void) { unsigned char byte; int bytesread; int trycount; bytesread = 0; trycount = 0; while (bytesread == 0 && trycount < 10) { bytesread = serial_read(&byte, 1); trycount++; if (trycount > 1) { printf("Waiting data from serial port: %i rx:%xn", trycount, bytesread); fflush(stdout); } } if (bytesread != 1) { perror("Error: serial port no reponse, exitingn"); exit(1); } return(byte); } 通信协议: #pragma once // * Usart config*/ // * 1bit start // * 0x7F data bits // * even parity bit // * one stop bit // */ #define STM32_ISP_CMD_AUTOBUADRATE 0x7f #define STM32_ISP_ACK 0x79 #define STM32_ISP_NACK 0x1f #define STM32_ISP_CMD_GET 0x00 #define STM32_ISP_CMD_GETVERSION 0x01 #define STM32_ISP_CMD_GETID 0x02 #define STM32_ISP_CMD_READMEMORY 0x11 #define STM32_ISP_CMD_GO 0x21 #define STM32_ISP_CMD_WRITEMEMORY 0x31 #define STM32_ISP_CMD_ERASE 0x43 #define STM32_ISP_CMD_EXTENDEDERASE 0x44 #define STM32_ISP_CMD_WRITEPROTECT 0x63 #define STM32_ISP_CMD_WRITEUNPROTECT 0x73 #define STM32_ISP_CMD_READOUTPROTECT 0x82 #define STM32_ISP_CMD_READOUTUNPROTECT 0x92 #define STM32_ISP_CMD_GETVERSIONBYTESTOREAD 3 #define STM32_ISP_CMD_GETVERSION_VERSIONBYTE 0 #define STM32_ISP_CMD_GETVERSION_RDPROTDISABLEDQTYBYTE 1 #define STM32_ISP_CMD_GETVERSION_RDPROTENABLEDQTYBYTE 2 #define STM32_CMD_ERASEGLOBALPAGEQTYFIELD 0xff #define READPACKETMAXDATA 0x80 #define WRITEPACKETMAXDATA 0x80 #define READPACKETREADCALLSMAX 20 #define STM32FLASHSTART 0x08000000 #define COMMANDWAIT 10 #define COMMANDRETRYCOUNT 4 #define SENDPACKETWAIT 0 #define PACKETREADWAIT 0 #define AUTOBAUDRETRYCOUNT 4 #define AUTOBAUDRETRYWAIT 1000 协议驱动: #pragma once #include #define MAXPACKLEN 250 typedef struct { char* serialDev; DWORD32 baudrate; DWORD32 writeAddress; char* loadFile; }hostHandle_s; typedef struct{ unsigned char storage[MAXPACKLEN]; int length; }Packet; extern hostHandle_s hostHandle; void waitms(int mstowait); void packet_append(Packet* packet, unsigned char c); void packet_append16(Packet* packet, unsigned short int c); void packet_checksumappend(Packet* packet); void packet_appendcommandandcheck(Packet* packet, unsigned char command); void packet_zero(Packet* packet); void packet_send(Packet* packet); int packet_sendandgetack(Packet* packet, int trycount); void autoBaudrateStart(void); void clear_writeprotect(void); void get_version(void); void get_id(void); void globalerase_flash(void); void program_memory(void); #include #include #include "Serial.h" #include "action.h" #include "STM32_ISP_CommandDefs.h" hostHandle_s hostHandle; void waitms(int mstowait) { Sleep(mstowait); //windows Sleep() takes ms. return; } void packet_append(Packet* packet, unsigned char c) { if (packet->length >= MAXPACKLEN - 1) { printf("packet too long in packet_append, exiting!"); exit(1); } packet->storage[packet->length] = c; packet->length++; return; } void packet_append16(Packet* packet, unsigned short int c) { if (packet->length >= MAXPACKLEN - 1) { printf("packet too long in packet_append, exiting!"); exit(1); } packet->storage[packet->length] = c >> 8; packet->storage[packet->length + 1] = (unsigned char)c; packet->length++; return; } void packet_checksumappend(Packet* packet) { int i; unsigned char checksum = 0; for (i = 0; i < packet->length; i++) checksum = checksum ^ packet->storage; packet_append(packet, checksum); return; } void packet_appendcommandandcheck(Packet* packet, unsigned char command) { packet_append(packet, command); packet_append(packet, ~command); //checksum for commands is the inverted command. return; } void packet_zero(Packet* packet) { packet->length = 0; return; } void packet_send(Packet* packet) { int lengthleft; int bytesactuallyread; unsigned char* packptr; packptr = packet->storage; lengthleft = packet->length; while (1) { bytesactuallyread = serial_write(packptr, lengthleft); lengthleft -= bytesactuallyread; packptr += (size_t)bytesactuallyread; if (lengthleft == 0) break; } waitms(SENDPACKETWAIT); return; } int packet_sendandgetack(Packet* packet, int trycount) { int packsendtrycount = 0; while (1) { packet_send(packet); if (Serial_getc() == STM32_ISP_ACK) break; if (++packsendtrycount >= trycount) return(1); } return(0);//success if we got ACK } void autoBaudrateStart(void) { UINT16 trycount = 0; char autobaudestablished = 0; printf("Auto Baudrate Start ...n"); fflush(stdout); while (1) { trycount++; Serial_putc(STM32_ISP_CMD_AUTOBUADRATE); unsigned char readByte; readByte = Serial_getc(); if (readByte == STM32_ISP_ACK) { autobaudestablished = 1; break; printf("nReceived ACK.n"); } else if (readByte == STM32_ISP_NACK) { printf("nReceived NACK.n"); autobaudestablished = 1; break; } if (trycount > 15) break; printf("."); fflush(stdout); } if (autobaudestablished) { printf("Done!n"); ///*printf("Serial port: %sn", hostopts.serialdevname); //printf("Buadrate: %dn", hostopts.baudrate);*/ printf("Data bits: 8n"); printf("Parity: Even"); printf("Stop bits: 1n"); printf("Flow control: nonen"); fflush(stdout); } else { perror("no respone!n"); exit(0); } } void clear_writeprotect(void) { Packet packet; packet_zero(&packet); packet_appendcommandandcheck(&packet, STM32_ISP_CMD_WRITEUNPROTECT); if (packet_sendandgetack(&packet, COMMANDRETRYCOUNT)) { printf("tried sending write unprotect command %i times w/o ack, exitingn", COMMANDRETRYCOUNT); fflush(stdout); exit(1); } printf("got first ACK from writeunprotect.. goodn"); fflush(stdout); packet_zero(&packet); if (packet_sendandgetack(&packet, 1)) { printf("didn't get second ack from writeunprotect, exitingn"); fflush(stdout); exit(1); } printf("got second ACK from writeunprotect, assumed successfuln"); fflush(stdout); return; } void get_version(void) { Packet outpacket, inpacket; int packsendtrycount = 0; int bytestoreadfromtarget; int bytesactuallyread = 0; unsigned char* packptr; packet_zero(&outpacket); packet_zero(&inpacket); packet_appendcommandandcheck(&outpacket, STM32_ISP_CMD_GETVERSION); if (packet_sendandgetack(&outpacket, COMMANDRETRYCOUNT)) { printf("tried getversion command %i times w/o ack, exitingn", packsendtrycount); exit(1); } bytestoreadfromtarget = STM32_ISP_CMD_GETVERSIONBYTESTOREAD; packptr = inpacket.storage; while (1) { bytesactuallyread = serial_read(packptr, bytestoreadfromtarget); inpacket.length += bytesactuallyread; packptr += (size_t)bytesactuallyread; bytestoreadfromtarget -= bytesactuallyread; if (bytestoreadfromtarget == 0) break; } printf("... got %i data bytes from get_version, waiting for an ACKn", inpacket.length); if (Serial_getc() == STM32_ISP_ACK) printf("got ACK after data in get_version, goodn"); else { printf("didn't get ACK after data in get_version, exitingn"); exit(1); } printf("byte %.2i : bootloader version = %.2xn", STM32_ISP_CMD_GETVERSION_VERSIONBYTE, inpacket.storage[STM32_ISP_CMD_GETVERSION_VERSIONBYTE]); printf("byte %.2i : bootloader version = %.2xn", STM32_ISP_CMD_GETVERSION_RDPROTDISABLEDQTYBYTE, inpacket.storage[STM32_ISP_CMD_GETVERSION_RDPROTDISABLEDQTYBYTE]); printf("byte %.2i : bootloader version = %.2xn", STM32_ISP_CMD_GETVERSION_RDPROTENABLEDQTYBYTE, inpacket.storage[STM32_ISP_CMD_GETVERSION_RDPROTENABLEDQTYBYTE]); fflush(stdout); } void get_id(void) { Packet outpacket, inpacket; int packsendtrycount = 0; int bytestoreadfromtarget; int bytesactuallyread = 0; unsigned char* packptr; int i; packet_zero(&outpacket); packet_zero(&inpacket); packet_appendcommandandcheck(&outpacket, STM32_ISP_CMD_GETID); if (packet_sendandgetack(&outpacket, COMMANDRETRYCOUNT)) { printf("tried getid command %i times w/o ack, exitingn", packsendtrycount); exit(1); } //now get the number of bytes the target says it's going to send us. bytestoreadfromtarget = (int)Serial_getc() + 1; packptr = inpacket.storage; while (1) { bytesactuallyread = serial_read(packptr, bytestoreadfromtarget); inpacket.length += bytesactuallyread; packptr += (size_t)bytesactuallyread; bytestoreadfromtarget -= bytesactuallyread; if (bytestoreadfromtarget == 0) break; } printf("... got %i data bytes from get_command, waiting for an ACKn", inpacket.length); if (Serial_getc() == STM32_ISP_ACK) printf("got ACK after data in get_id, goodn"); else { printf("didn't get ACK after data in get_id, exitingn"); exit(1); } printf("got PID: n"); for (i = 0; i < inpacket.length; i++) printf("%.2x ", inpacket.storage); printf("n"); fflush(stdout); return; } void globalerase_flash(void) { Packet packet; printf("nStarting global flash erase...n"); fflush(stdout); packet_zero(&packet); packet_appendcommandandcheck(&packet, STM32_ISP_CMD_ERASE); if (packet_sendandgetack(&packet, COMMANDRETRYCOUNT)) { printf("tried sending erase command %i times w/o ack, exitingn", COMMANDRETRYCOUNT); fflush(stdout); exit(1); } packet_zero(&packet); packet_append(&packet, STM32_CMD_ERASEGLOBALPAGEQTYFIELD); packet_append(&packet, (unsigned char)~STM32_CMD_ERASEGLOBALPAGEQTYFIELD); if (packet_sendandgetack(&packet, 1)) { printf("didn't get second ack from globalerase, exitingn"); fflush(stdout); exit(1); } printf("Done!n"); fflush(stdout); return; } void program_memory(void) { Packet datapacket; //for data Packet outpacket; //for command unsigned int address; char hitEOFinloadfile = 0; int packsendtrycount; DWORD bytestosendthispacket; int bytessenttotal = 0; FILE* fp; if ((fp = fopen(hostHandle.loadFile, "rb")) == NULL) { printf("nerror on open %s!", hostHandle.loadFile); exit(0); } //printf("nfseek error:%dn", GetLastError()); if (fseek(fp, 0L, SEEK_END)) { printf("nfseek error:%dn", GetLastError()); exit(0); } long fsize = ftell(fp); fclose(fp); address = hostHandle.writeAddress; //starting address printf("Starting program memory...n"); fflush(stdout); if (hostHandle.loadFile[0] == ' |