固件 OTA 升级

更新时间:2021-09-17 09:15:35下载pdf

您可以通过涂鸦 IoT 平台,先将需要更新的固件文件上传至涂鸦,然后 Wi-Fi 模组通过串口协议对文件进行分包传输。最后,MCU 接收升级包并写入本地闪存,实现固件的升级。

OTA(Over-the-Air)即空中下载技术,通过网络远程为设备更新和升级软件程序。

SDK 开发

准备工作

  1. 涂鸦 IoT 平台 创建一个产品。
  2. 在产品的 硬件开发 开发阶段,在页面的底部,点击下载 MCU SDK产品串口通讯协议涂鸦串口调试助手功能点调试文件
  3. 移植涂鸦协议 SDK 的代码。详情请参考 HomeKit MCU SDK 移植
  4. 自行完成 BootLoader 开发。

协议说明

MCU 升级协议在涂鸦 Wi-Fi 模组串口协议中有相关命令字定义,具体协议格式参考 MCU 升级服务

  • Wi-Fi 模组发送完所有的升级包后,模组会重启。重新发送 01 命令字查询产品信息。
  • MCU 需要在一分钟内回复产品信息中的软件版本号,带上升级后的 MCU 版本号。版本号需要和在涂鸦 IoT 平台配置升级的版本号保持一致。

功能配置

了解协议的交互,有助于理解 SDK 的相关代码逻辑。本小节介绍 MCU SDK 相关功能配置。

  • 在 SDK 所在路径打开 protocol.h,将 MCU_VER 数值改为升级后的参数值。

    需要升级的固件中,老固件 MCU_VER 为当前固件,例如 1.0.0。升级后的固件中的 MCU_VER 要改为升级后的目标版本,例如 1.0.1(目标版本号)。

    /******************************************************************************
                            1:修改产品信息/
    ******************************************************************************/
    #define PRODUCT_KEY "xghwyjvd3ofo****"    // 开发平台创建产品后生成的 16 位字符产品唯一标识
    
    #define MCU_VER "1.0.0"                  // 用户的软件版本,用于 MCU 固件升级。MCU 升级版本需修改
    
    /******************************************************************************
    
  • 打开 protocol.h 中找到升级部分。

    /******************************************************************************
                            2: MCU 是否需要支持固件升级
    如需要支持MCU固件升级,请开启该宏。
    MCU 可调用 mcu_api.c 文件内的 mcu_firm_update_query() 函数获取当前 MCU 固件更新情况。
                            ********注意!!!**********
    当前接收缓冲区为关闭固件更新功能的大小,固件升级包可选择,默认为 256 字节大小。
    如需要开启该功能,串口接收缓冲区会变大。
    
    ******************************************************************************/
    //#define         SUPPORT_MCU_FIRM_UPDATE                 // 开启MCU固件升级功能(默认关闭)
    // 固件包大小选择
    #ifdef SUPPORT_MCU_FIRM_UPDATE
    #define PACKAGE_SIZE                   0        // 包大小为256字节
    //#define PACKAGE_SIZE                 1        // 包大小为512字节
    //#define PACKAGE_SIZE                 2       // 包大小为1024字节
    #endif
    /******************************************************************************
    
  • 打开宏定义 SUPPORT_MCU_FIRM_UPDATE

    /******************************************************************************
                            3:定义收发缓存:
                        如当前使用 MCU 的 RAM 不够,可修改为24
    ******************************************************************************/
    #ifndef SUPPORT_MCU_FIRM_UPDATE
    #define WIFI_UART_RECV_BUF_LMT          16              // 串口数据接收缓存区大小,如MCU的RAM不够,可缩小
    #define WIFI_DATA_PROCESS_LMT           24             // 串口数据处理缓存区大小,根据用户DP数据大小量定,必须大于24
    #else
    #define WIFI_UART_RECV_BUF_LMT          128           // 串口数据接收缓存区大小,如MCU的RAM不够,可缩小
    
    //请在此处选择合适的 MCU 升级缓存大小(根据上面固件包选择大小来选择开启多大的 MCU 升级缓存)
    #define WIFI_DATA_PROCESS_LMT           300             // 固件升级缓冲区,需大缓存,如单包大小选择256,则缓存必须大于260
    //#define WIFI_DATA_PROCESS_LMT           600          // 固件升级缓冲区,需大缓存,如单包大小选择512,则缓存必须大于520
    //#define WIFI_DATA_PROCESS_LMT           1200        // 固件升级缓冲区,需大缓存,如单包大小选择1024,则缓存必须大于1030
    
    #endif
    
    #define WIFIR_UART_SEND_BUF_LMT         48              //根据用户DP数据大小量定,必须大于48
    /******************************************************************************
    

    云端下发数据长度有 3 种,请根据 PACKAGE_SIZE 对应WIFI_DATA_PROCESS_LMT 的值。

    例如:

    #define PACKAGE_SIZE                 1
    

    对应:

    #define WIFI_DATA_PROCESS_LMT           600
    
  • 单备份 OTA:单备份 OTA 是指使用 Wi-Fi HomeKit 模组的固件备份分区作为 MCU 新固件的接收区。

    若 MCU 的 Flash 空间有限,不支持分成两个固件区,只够分出一个应用固件区,且您又希望可靠地使用 MCU OTA 升级功能,这时可以开启单备份 OTA 升级方案。启动 OTA 升级功能后:

    1. 模组先从云端拉取新的 MCU 固件包,接收完 MCU 新固件数据并校验成功后,存储在模组固件备份区。
    2. 然后模组通知 MCU 开始 OTA,并将固件分包发送给 MCU。
    3. MCU 的 BootLoader 开始引导一边擦除一边向用户固件区写入新的固件,直到接收完成。
    4. 重启模组后,完成 OTA 升级过程。
    /******************************************************************************/
    /*  MCU固件区类型  */
    #define MCU_FIRMWARE_BACKUP_AREA_TYPE   0       //MCU是双固件区(默认)
    //#define MCU_FIRMWARE_BACKUP_AREA_TYPE   1       //MCU是单固件区
    #endif
    /******************************************************************************
    

    如果在 OTA 升级过程中 MCU 断电,此时模组报告 OTA 升级失败。下次上电后,模组重启并下发 OTA 升级指令,通知 MCU 启动 OTA 升级流程,直到 OTA 升级成功。

相关命令字

#define         UPDATE_START_CMD                0x0a                            //升级开始
#define         UPDATE_TRANS_CMD                0x0b                            //升级传输

升级开始(0x0a)

#ifdef SUPPORT_MCU_FIRM_UPDATE
  case UPDATE_START_CMD:                                // 升级开始
	// 获取升级包大小全局变量
	firm_flag = PACKAGE_SIZE;
	if(firm_flag == 0) {
	  firm_size = 256;
	}else if(firm_flag == 1) {
	  firm_size = 512;
	}else if(firm_flag == 2) {
	  firm_size = 1024;
	}

	firm_length = wifi_data_process_buf[offset + DATA_START];
	firm_length <<= 8;
	firm_length |= wifi_data_process_buf[offset + DATA_START + 1];
	firm_length <<= 8;
	firm_length |= wifi_data_process_buf[offset + DATA_START + 2];
	firm_length <<= 8;
	firm_length |= wifi_data_process_buf[offset + DATA_START + 3];

	upgrade_package_choose(PACKAGE_SIZE);
	firm_update_flag = UPDATE_START_CMD;
	 break;

以上代码是处理接收函数。根据上文标志位的长度,选择数据包的规格,并回复云端。云端接收到数据包规格后下发数据。

升级传输(0x0b)

case UPDATE_TRANS_CMD:                                // 升级传输
	if(firm_update_flag == UPDATE_START_CMD)
	{
	  //停止一切数据上报
	  stop_update_flag = ENABLE;

	  total_len = wifi_data_process_buf[offset + LENGTH_HIGH] * 0x100;
	  total_len += wifi_data_process_buf[offset + LENGTH_LOW];

	  dp_len = wifi_data_process_buf[offset + DATA_START];
	  dp_len <<= 8;
	  dp_len |= wifi_data_process_buf[offset + DATA_START + 1];
	  dp_len <<= 8;
	  dp_len |= wifi_data_process_buf[offset + DATA_START + 2];
	  dp_len <<= 8;
	  dp_len |= wifi_data_process_buf[offset + DATA_START + 3];

	  firmware_addr = (unsigned char *)wifi_data_process_buf;
	  firmware_addr += (offset + DATA_START + 4);

	  if((total_len == 4) && (dp_len == firm_length))
	  {
	    // 最后一包
	    ret = mcu_firm_update_handle(firmware_addr,dp_len,0);

	    firm_update_flag = 0;
	  }
	  else if((total_len - 4) <= firm_size)
	  {
	    ret = mcu_firm_update_handle(firmware_addr,dp_len,total_len - 4);
	  }
	  else
	  {
	    firm_update_flag = 0;
	    ret = ERROR;
	  }

	  if(ret == SUCCESS)
	  {
	    wifi_uart_write_frame(UPDATE_TRANS_CMD,0);
	  }
	  // 恢复一切数据上报
	  stop_update_flag = DISABLE;
	}
	break;
#endif

升级回调函数

/*****************************************************************************
函数名称:mcu_firm_update_handle
功能描述:MCU进入固件升级模式
输入参数:value:固件缓冲区

	       position:数据包的位置
	       length:当前固件包长度(固件包长度为0时,表示固件包发送完成)

返回参数:无
使用说明:MCU 需要自行实现该功能
*****************************************************************************/
unsigned char mcu_firm_update_handle(const unsigned char value[],unsigned long position,unsigned short length)
{
  #error "请自行完成 MCU 固件升级代码,完成后请删除该行"
  if(length == 0)
  {
	// 固件数据发送完成

  }
  else
  {
	// 固件数据处理
  }

  return SUCCESS;
}
#endif

平台配置

您可以在涂鸦 IoT 平台,将需要更新的固件文件上传至涂鸦。具体操作步骤,请参考 固件升级 的自定义上传的固件章节。

功能调试

功能调试方法,请参考 使用模组调试助手

常见问题

如果升级包存在错误数据升级失败后,重新进行升级,Wi-Fi 会重复发送当前数据吗?

会。当前数据发送三次,三次之后判断升级失败。失败后,需要下次重新启动升级,Wi-Fi 将重新发送所有数据。

如何获取设备虚拟 ID?

您可以在 App 端产品页面的 编辑 > 设备信息 > 虚拟 ID,复制设备 ID。

固件 OTA 升级