本帖最后由 forgot 于 2022-11-17 10:57 编辑
#申请原创# 现在物联网越来越发达,很多嵌入式产品设计完成之后需要进行BUG修复升级或者个性化功能定制升级,今天主要说一说以STM32为代表的嵌入式产品可以远程升级的两种方式,标题说是两种常用的升级方式,其实无非也就是我本人用过的两种方式,在此做一个简单的分享,说得可能不好,但是希望能有帮助到第一次做远程升级功能的朋友们。 两种方式: 1、通过串口Ymodem协议进行升级, 2、通过网口TFTP方式进行升级
既然要升级,那程序必须是两部分构成: 1、Bootloader程序,实现程序的启动引导和升级固件接收的功能; 该程序应烧录于0x8000000地址,并且分配一定的code空间,如0x3000; 2、APP用户应用程序,实现用户功能程序的运行和接收升级命令的功能; 该程序应该烧录于Bootloader程序之后,如0x8003000;并且在Bootloader程序中需要指定该程序跳转的位置:#define ApplicationAddress 0x8003000 如图: 一、串口Ymodem协议进行升级方式: 1、首先设计Bootloader程序,在程序中奖基本的外设配置完成,如串口,因为需要用到串口进行Ymodem协议固件接收来升级,所以用到哪个串口升级就必须配置好哪个串口;然后需要进行ymodem.c程序的移植。这样就可以通过串口进行.BIN固件的接收升级(这里可以参考网上的官方IAP例程)。 void IAP_Init(void) { //结构体变量 USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; //开启总线时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //管脚配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_Init(GPIOA, &GPIO_InitStructure); //串口配置 USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure); USART_Cmd(USART2, ENABLE); } 在Bootloader程序启动后,应有判断是否需要进行固件升级,并且在后续需要通过跳转函数跳转到APP应用程序: void APP_RUN(void) { 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(); } 3、在APP应用程序中应该有判断是否需要升级的入口,如按键、远程命令等,通过软件复位等方式可以让程序回到Bootloader程序并开始接收固件包进行FLASH设定的位置进行烧写新固件。
二、网口TFTP方式进行升级方式: 跟串口升级原理类似,首先设计Bootloader程序,就是要配置好网卡驱动外设,开UDP套接字等操作,并且一直TFTP.c,这样就可以通过网络TFTP方式来实现.BIN固件的接收升级;然后通过跳转函数跳转到APP应用程序,具体不在重复描述;
/**tftp 初始化**/ void TFTP_init() { //初始化TFTP init_tftp(); open_tftp_socket(SOCK_TFTP); /*初始化套接字*/ g_tftp_rcv_buf = g_socket_rcv_buf;/*指向内存*/ }
因为以上两种方式升级固件都是以.bin的方式进行固件发送与升级,顺便说一下KEIL下.BIN文件的编译生成方法:
1、点击KEIL魔术棒"Options for Target" → 单击" Output " → 按下面截图所示配置,设置完成后 → 点击"Build"编译 → 生成axf输入文件
2、单击“User” → 按下面截图所示配置,配置完成后→ 点击"Build"编译 → 生成bin输出文件,实际是调用KEIL安装目录下的一个工具生成的.BIN。(具体的命令格式每人的项目工程目录不一样就说了,大家可以参照网上的命令解析)
最后提醒一点:在APP程序开头需要重新设置向量表的偏移位置:NVIC_SetVectorTable( NVIC_VectTab_FLASH,0x3000);
|