必威体育Betway必威体育官网
当前位置:首页 > IT技术

STM32通过USB实现Bootloader/IAP功能

时间:2019-07-16 04:12:12来源:IT技术作者:seo实验室小编阅读:66次「手机版」
 

iap

原文地址:http://www.embed-net.com/thread-268-1-1.html

前沿:

最近在做STM32的USB Bootlader/IAP功能,也就是通过USB实现固件升级,本文介绍下实现的基本思路,希望对实现IAP的同学一个参考,改方法已经在产品中得到实际应用并验证是比较合理,稳定可靠的。

程序空间划分:

在单片机的程序Flash中分两个区,分别存储bootloader代码APP代码,Bootloader放到代码起始地址,也就是0x08000000,App放到0x8020000地址,中间预留了很多的地址空间,主要是为了用来存储一些需要掉电保存的数据,比如我在0x0800C000地址就存放了App程序运行后写入该地址的标志数据。

启动流程:

上电后自然是运行Bootloader程序,Bootloader运行后,做的第一件事情如下所示

[C]纯文本查看复制代码

?

01

02

03

if((*((uint32_t *)EXE_FLAG_ADDR))==0x12345678){

JumpToApplication(APP_START_ADDR);

}

也就是判断App运行标志是否有效,这个标志是存放到EXE_FLAG_ADDR地址的,若有效就直接跳转到App程序运行,这个时间很短,所以用户看不到有Bootloader执行的效果,感觉就是直接运行的App程序,进入App程序后,App程序第一件事情如下

[C]纯文本查看复制代码

?

01

02

03

04

05

06

07

if((*((uint32_t *)EXE_FLAG_ADDR))==0xFFFFFFFF){

uint32_t ExeFlag = 0x12345678;

__set_PRIMASK(1);//禁止全局中断

FLASH_Unlock();

ProgrAMDatatoFlash(EXE_FLAG_ADDR,(uint8_t*)(&ExeFlag),4);

FLASH_Lock();

}

也就是判断App标志是否有效,若有效则直接执行后面的程序,若无效则需要在EXE_FLAG_ADDR地址写入执行标志。

Bootloader程序判断App标志若无效,那么Bootloader就不会直接跳转到App,因为这个时候是需要进行升级App的操作,所以程序就进入Bootloader的正常工作流程,也就是等待升级App的各种命令,比如擦出固件,烧写固件,校验固件等。当固件成功写入并校验通过之后,PC端就可以发送一个程序跳转命令跳转到App执行。

PC端操作流程:

PC端和单片机是通过USB进行数据交换的,当然用其他方式也可以,基本流程都是差不多的。

Pc程序首先当然是扫描设备,打开设备,然后调用获取固件信息的函数,调用该函数后可以得知当前固件的名称,版本号,固件类型(Bootloader还是App),若发现当前固件不是Bootloader,那么就得通过USB给固件发送一个程序跳转命令,也就是跳转到Bootloader代码执行,当然App在跳转到Bootloader的时候必须把EXE_FLAG_ADDR地址的标志数据擦出掉,这样Bootloader才能进入正常的升级流程。

控制固件程序进入Bootloader之后,PC端程序将打开App固件程序文件,然后根据文件大小,发送擦出App代码存储区域Flash的数据,然后再分包将固件发送给单片机,单片机端Bootlader程序接收到数据后将数据写入App的Flash区域,数据写完之后再进行校验,我是通过计算CRC16的方式进行校验的,校验通过之后就可以发送跳转命令控制程序跳转到App运行了,到此升级流程完毕。

PC端程序代码:

[C]纯文本查看复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

// USB2XXXTest.cpp : defines the entry point for the console application.

//

#include "stdafx.h"

#include <stdlib.h>

#include "../../USB2XXX/source/bootloader.h"

int _tmain(int argc, _TCHAR* argv[])

{

int PackSize = 1024*10;

int TimeOut = 0;

int ApplicationAddress = 0x08020000;

int BootAddress = 0x08000000;

FW_INFO FwInfo;

bool state;

int ret;

//扫描查找设备

ret = BT_ScanDevice(true);

if(ret <= 0){

printf("No device connected!\n");

return 0;

}

//打开设备

state = BT_OpenDevice(0);

if(!state){

printf("Open device ERROR!\n");

return 0;

}

//获取固件信息

BT_GetFirmwareInfo(0,&FwInfo);

printf("Firmware Name:%s\n",FwInfo.FirmwareName);

printf("Firmware Functions:%08X\n",FwInfo.Functions);

//判断当前固件是否为Bootloader固件

while(!(FwInfo.Functions&FUNCTION_BOOTLOADER)){

//控制程序跳转到Bootloader

state = BT_ExcuteFirmware(0,BootAddress);

printf("BT_ExcuteFirmware state = %d\n",state);

BT_CloseDevice(0);

do{

Sleep(100);

ret = BT_ScanDevice(true);//扫描查找设备

if((ret <= 0)&&(TimeOut > 50)){

printf("No device connected!\n");

return 0;

}else if(ret > 0){

break;

}

TimeOut++;

}while(ret<=0);

TimeOut = 0;

do{

Sleep(100);

state = BT_OpenDevice(0);//打开设备

if((!state)&&(TimeOut > 50)){

printf("Open device error!\n");

return 0;

}else if(state){

break;

}

TimeOut++;

}while(!state);

//获取固件信息

BT_GetFirmwareInfo(0,&FwInfo);

printf("Firmware Name:%s\n",FwInfo.FirmwareName);

printf("Firmware Functions:%08X\n",FwInfo.Functions);

}

//打开固件文件

FILE *pFile=fopen("Project.bin","rb"); //获取文件的指针

fseek(pFile,0,SEEK_END); //把指针移动到文件的结尾 ,获取文件长度

int FileLen=ftell(pFile); //获取文件长度

static char *pBuf = (char *)malloc(FileLen); //定义文件指针

if(pBuf == NULL){

printf("malloc error\n");

return 0;

}

rewind(pFile); //把指针移动到文件开头 因为我们一开始把指针移动到结尾,如果不移动回来 会出错

fread(pBuf,1,FileLen,pFile); //读文件

fclose(pFile); // 关闭文件

//擦除之前的固件

state = BT_erasesectors(0,ApplicationAddress,ApplicationAddress+FileLen);

if(!state){

printf("BT_EraseSectors error!\n");

return 0;

}else{

printf("BT_EraseSectors success\n");

}

//循环写入固件数据到芯片Flash

int PackIndex = 0;

for(PackIndex=0;PackIndex<FileLen/PackSize;PackIndex++){

state = BT_WriteData(0,ApplicationAddress+PackIndex*PackSize,(unsigned char *)(&pBuf[PackIndex*PackSize]),PackSize,0);

if(!state){

printf("BT_WriteData Error\n");

return 0;

}

}

if(FileLen%PackSize){

state = BT_WriteData(0,ApplicationAddress+PackIndex*PackSize,(unsigned char *)(&pBuf[PackIndex*PackSize]),FileLen%PackSize,0);

if(!state){

printf("BT_WriteData Error\n");

return 0;

}

}

printf("BT_WriteData Success\n");

//循环校验数据是否写成功

for(PackIndex=0;PackIndex<FileLen/PackSize;PackIndex++){

state = BT_VerifyData(0,ApplicationAddress+PackIndex*PackSize,(unsigned char *)(&pBuf[PackIndex*PackSize]),PackSize);

if(!state){

printf("BT_VerifyData Error\n");

return 0;

}

}

if(FileLen%PackSize){

state = BT_VerifyData(0,ApplicationAddress+PackIndex*PackSize,(unsigned char *)(&pBuf[PackIndex*PackSize]),FileLen%PackSize);

if(!state){

printf("BT_VerifyData Error\n");

return 0;

}

}

printf("BT_VerifyData Success\n");

//执行固件

state = BT_ExcuteFirmware(0,ApplicationAddress);

printf("BT_ExcuteFirmware state = %d\n",state);

//关闭设备

BT_CloseDevice(0);

return 0;

}

PC端程序运行效果如下所示:

后记:

我是用STM32F4+USB3300高速USB实现IAP功能的,12K的App代码几乎瞬间下载完毕,整个程序测试了很多次,没一次出问题...

相关阅读

增量式 PID 算法的 STM32 实现

虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态。特地分享一些自己如何实现的过程。首先说说增量式P

STM32开发 -- GPS模块开发详解

本文为VIP专属文章,单击开通VIP

【常用模块】OLED显示模块(原理讲解、STM32实例操作)

OLED的基础介绍 OLED的定义和优势 OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electrolum

STM32的IWDG(独立看门狗)详细用法

文章出处:https://www.cnblogs.com/Liu-Jing/p/7243029.html章参考资料:《STM32F4XX 中文参考手册》IWDG 章节。1、IWDG简介:STM32

分享到:

栏目导航

推荐阅读

热门阅读