***************************************2017.6.6***************************************
最近在研究开发板远程升级的事情,稍微记录一下而已。功能大概是这样的:一台放在室外的板子,需
要通过服务器给开发板上的4G模块下发指令来进行远程升级。
看了网上好多资料,多数人的方法和串口IAP在线升级是一个套路。大致就是如下:上电,从boot区启动检测有没有新
的新用户程序,有就跳入处理,没有就跳到用户代码。具体的是,给开发板一个升级命令,下载升级包(注意校验),置更
新升级标志,将升级包写入到flash,清除更新升级标志,复位启动。我说的太简单,具体实现我还是有许多问题不知道怎
么实现,还需要在研究。
公司大牛前辈有给我指导,我也询问了一些问题。首先,他建议我先实现串口在线升级。他说的过程大致如下,先给一
个开发板一个升级指令,开发板收到命令之后,跳转到bootloader,置升级标志位,开始接收数据,校验正确写入RAM,一
包接收成功给外界一个回应,外界收到正确回应之后,继续发送下一包数据......收到全部数据之后,写入flash,清除升级标
志位,复位启动。下面我说一些我的疑问和需要解决的问题。
(串口在线升级可以参考STM32F10x_AN2557_FW_V3.3.0示例代码)
1.主要还是接收数据包的问题,怎么传输,校验用什么方法校验?
STM32F103串口升级用的是YModem这个文件传输协议,传输还是自拟协议好了,需要带ACK;校验的话我本来准备
用CRC16校验,前辈建议我用XOR校验。
2.怎么跳转到相应的地址以及bootloader的地址是什么?
#define jump(TargetAddr ) (*((void(*)())(TargetAddr))()
bootloader是哪个地址?
3.怎么擦除flash,写入flash?
4.RTC里面有个备份程序区,可以把更新升级标志位放在那里,不会因为断电重启而改变。
......姑且就这么多,一步一步解决吧。明天继续
***************************************2017.6.7***************************************
1./*软复位*/
NVIC_SystemReset(void);
2.stm32在线升级中的主要函数如下:
void Main_Menu(void)
{
uint8_t key = 0;
/* Get the number of block (4 or 2 pages) from where the user program will be loaded */
BlockNbr = (FlashDestination - 0x08000000) >> 12;
/* Compute the mask to test if the Flash memory, where the user program will be
loaded, is write protected */
#if defined (STM32F10X_MD) || defined (STM32F10X_MD_VL)
UserMemoryMask = ((uint32_t)~((1 << BlockNbr) - 1));
#else /* USE_STM3210E_EVAL */
if (BlockNbr < 62)
{
UserMemoryMask = ((uint32_t)~((1 << BlockNbr) - 1));
}
else
{
UserMemoryMask = ((uint32_t)0x80000000);
}
#endif /* (STM32F10X_MD) || (STM32F10X_MD_VL) */
/* Test if any page of Flash memory where program user will be loaded is write protected */
if ((FLASH_GetWriteProtectionOptionByte() & UserMemoryMask) != UserMemoryMask)
{
FlashProtection = 1;
}
else
{
FlashProtection = 0;
}
while (1)
{
SerialPutString("\r\n================== Main Menu ============================\r\n\n");
SerialPutString(" Download Image To the STM32F10x Internal Flash ------- 1\r\n\n");
SerialPutString(" Upload Image From the STM32F10x Internal Flash ------- 2\r\n\n");
SerialPutString(" Execute The New Program ------------------------------ 3\r\n\n");
if(FlashProtection != 0)
{
SerialPutString(" Disable the write protection ------------------------- 4\r\n\n");
}
SerialPutString("==========================================================\r\n\n");
key = GetKey();
if (key == 0x31)
{
/* Download user application in the Flash */
SerialDownload();
}
else if (key == 0x32)
{
/* Upload user application from the Flash */
SerialUpload();
}
else if (key == 0x33)
{
JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
/* Jump to user application */
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
}
else if ((key == 0x34) && (FlashProtection == 1))
{
/* Disable the write protection of desired pages */
FLASH_DisableWriteProtectionPages();
}
else
{
if (FlashProtection == 0)
{
SerialPutString("Invalid Number ! ==> The number should be either 1, 2 or 3\r");
}
else
{
SerialPutString("Invalid Number ! ==> The number should be either 1, 2, 3 or 4\r");
}
}
}
}
3.flash的地址(看datesheet)
program flash start_address:0x0000_0000 end_address:0x0007_FFFF
***************************************2017.6.8***************************************
1.前面的细节好像还没有解决,先实现通过串口向开发板传输bin文件,大小是80KB,怎么分包传输,怎么校验?
一包数据1.2KB,大概需要60包左右。我思考的是,70KB的文件怎么分包方便,怎么校验
校验部分:
uint8_t xor(char* source)
{
int j;
int slen=strlen(source);
uint8_t tmpstr = 0;
for(j=0;j<slen;j++)
{
tmpstr=tmpstr^source[j];
if(!tmpstr)
tmpstr=source[j];
}
source[j] = tmpstr;
return tmpstr;
}
上面参考的是网上的,下面是我自己调试可用的异或校验:
uint8_t xor(uint8_t* source, uint16_t length)
{
uint16_t j;
uint8_t tmpstr = 0;
for(j=0;j<length-2;j++)
{
tmpstr=tmpstr^source[j];
tmpstr=source[j];
}
return tmpstr;
// if(tmpstr == source[length-3])//去掉0D,0A的帧尾
// return true;
// else
// return false;
}
分包部分:最大预算80包,每包1260个字节,开通的全局buffer是boot_array[80][1300];
接下来是分包组包,写入flash。
***************************************2017.6.8***************************************
1.定义的buffer不能是boot_array[80][1300];,网上查了一下,好像是超过128KB的ram允许的范围了,改为boot_array[75][1300];
网上说的原因:由于Kinetis K系列芯片使用的是ARM Cortex M4内核,其使用哈弗架构,内部的SRAM被分成了两部分,通过不同的总线访问。也就是说,SRAM分成了两部分,虽然逻辑地址是连续的,但是这两部分SRAM不能当成一个连续空间来使用。因此,请避免将heap大小设置超过1/2 SRAM大小,否则在使用过程中会产生错误。
2.定义分包协议
包头:2个字节,包括总包数和现在第几包。
内容:1250个字节
校验:(XOR) 1个字节
帧尾:0x0D,0x0A
3.使用串口工具将bin文件发给板子,存在boot_arrat中,第1包就放在boot_array[0]中,第2包放在boot_array[1]中,第13包放在boot_array[12]中,类似存入buffer中。
*****问*****
怎么判定最后一包,且之前的每一包都正确收到???
————>每一包正确收到之后,会有反馈,收到反馈之后继续发送下一包。如果某一包不成功,那就重新发送这一包。等能够收到总包数和现在的包数一样时,不就证明是最后一包了吗,收到反馈之后,擦除flash,写入falsh。
4.研究怎么擦除flash,怎么写入flash
网上查资料和跑官网上给的flash例程。知道了怎么擦出一个大小是2KB的扇区,怎么检验是不是被擦除,怎么写入一个扇区。
知道了flash扇区的每一块的地址和总的地址范围。
***************************************2017.6.16***************************************
这么多天没写,第一个就是突然插入支持其他的项目,然后每次调试的时候,flash擦除,读写有问题,一直拖到现在。刚才把flash读写搞定,发现擦除,写入还是有一些讲究的,擦出多大,写入多少。。。