鉴于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] == '