GD32F103C8T6单片机与三网通Cat1模块开发板实现OTA远程升级BootLoader技术指南【特殊字符解析】
在物联网飞速发展的当下,设备的远程升级能力变得愈发关键。本文将以国产 GD32F103C8T6 单片机搭配三网通 4G Cat1 物联模块开发板为实验基础,为大家详细剖析如何从 0 开始编写 OTA 远程升级 BootLoader 程序。本教程分为上下两个篇章,此为上篇章内容。
教程简介 + 上篇章 BootLoader 程序功能总结
本教程旨在帮助开发者深入理解并掌握 OTA 远程升级技术在 GD32F103C8T6 单片机平台上的实现。通过一系列的步骤,从基础的理论讲解到实际代码编写与调试,逐步构建出一个完整的 OTA 远程升级 BootLoader 程序。
在上篇章中,我将专注于 BootLoader 程序本身的设计与实现。其功能涵盖了串口通信的配置与数据处理、模拟 IIC 接口操作、SPI 接口的运用、单片机内部 Flash 的操作、OTA 标志的判定与处理、分区跳转的实现、串口命令行交互以及 Xmdoem 协议的实现等多个方面,为实现 OTA 远程升级奠定坚实的基础。
为啥非要设计一个 BootLoader 程序
在很多应用场景中,设备部署后可能由于功能改进、漏洞修复等原因需要进行程序升级。如果没有 BootLoader 程序,就需要将设备返回工厂或者通过物理连接(如 JTAG)进行程序烧录,这在大规模部署且设备分布广泛的情况下,成本极高且效率低下。而 BootLoader 程序的存在,使得设备可以通过 OTA(Over – The – Air)方式,利用网络远程接收并更新程序,极大地提高了升级的便捷性和灵活性,降低了维护成本。
单片机内部 Flsah 分区 — 为啥 B 区在前
GD32F103C8T6 单片机的内部 Flash 需要合理分区以实现 BootLoader 与应用程序的协同工作。stm32都通用一套理论,通常将 Flash 分为 A 区和 B 区,这里将 B 区设置在前主要是基于程序执行顺序和安全性考虑。BootLoader 程序作为设备启动时首先执行的部分,放置在靠前的 B 区,能够保证在设备通电后迅速获得控制权,对系统进行初始化、检查 OTA 标志等操作,然后根据情况决定是否跳转至 A 区执行应用程序。同时,这样的分区方式也便于在 BootLoader 中对 A 区的应用程序进行擦除、写入等操作,保障整个 OTA 过程的顺利进行。
BootLoader 程序功能规划
- 通信功能:实现串口通信,用于接收上位机或物联网模块发送的 OTA 升级指令及程序数据。
- 存储操作功能:具备对内部 Flash、外部存储芯片(如通过 SPI 接口的 W25Q64)以及模拟 IIC 接口的 24C02 进行数据存取、擦除等操作的能力。
- OTA 流程控制功能:能够判定是否有 OTA 事件发生,依据 OTA_flag 做出决策。若有 OTA 需求,从外部存储读取新程序数据并写入内部 Flash 的应用程序区(A 区);若无 OTA 事件,则跳转至 A 区执行现有应用程序。
- 交互功能:构建串口交互式命令行,支持多种命令,如查询 OTA 版本号、启动 OTA 升级流程等,方便调试与管理。
- 数据校验功能:采用 Xmdoem 协议的 CRC 数据校验,确保接收数据的准确性。
构建第一个基础 Keil 工程
- 打开 Keil MDK 软件,创建新的工程,选择 GD32F103C8T6 芯片型号。
- 配置工程属性,如晶振频率等。
- 在工程中添加源文件和头文件路径,创建初始的 main.c 文件,编写简单的初始化代码,例如初始化系统时钟等,确保工程能够正常编译运行,为后续功能的添加搭建好基础框架。
第一步先调串口之 —— 处理接收数据方案设计
为了高效准确地处理串口接收的数据,我们采用串口空闲中断结合 DMA 的方案。当 DMA 接收到一帧数据后,触发串口空闲中断。在中断服务函数中,停止 DMA 传输,获取接收到的数据长度,然后对接收到的数据进行解析处理。这样的方案能够避免数据丢失,提高数据处理的实时性。例如,接收到的 OTA 升级指令可以通过特定的协议格式进行解析,提取出指令类型、数据长度等关键信息,以便后续执行相应的操作。
第一步先调串口之 ——usart.h 头文件编写
在 usart.h 头文件中,定义串口相关的寄存器地址、波特率设置宏、数据位、停止位、校验位等参数。同时,声明串口初始化函数、DMA 初始化函数、串口发送函数、串口接收函数以及串口空闲中断处理函数等。以下是一个简单的示例代码:
#ifndef __USART_H
#define __USART_H
#include "gd32f1x0.h"
// 定义串口相关寄存器地址
#define USARTx USART1
#define USARTx_CLK_ENABLE() rcu_periph_clock_enable(RCU_USART1)
#define USARTx_TX_PIN GPIO_PIN_9
#define USARTx_RX_PIN GPIO_PIN_10
#define USARTx_GPIO_PORT GPIOA
#define USARTx_GPIO_CLK_ENABLE() rcu_periph_clock_enable(RCU_GPIOA)
// 波特率设置宏
#define USART_BAUDRATE 115200
// 数据位、停止位、校验位等参数定义
#define USART_WORD_LENGTH USART_WL_8BIT
#define USART_STOP_BITS USART_STB_1BIT
#define USART_PARITY USART_PM_NONE
#define USART_HARDWARE_FLOW_CONTROL USART_RTS_CTS_DISABLE
// 函数声明
void usart_config(void);
void dma_config(void);
void usart_send_data(uint8_t data);
uint8_t usart_receive_data(void);
void USARTx_IRQHandler(void);
#endif /* __USART_H */
作者:G_托马斯回旋