本文使用单片机型号:STM32F104xx
IAP(In Application Programming) 是用户自己的程序在运行过程中对 User Flash 的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。为了实现 IAP 功能,系统将分为 bootloader 和 app 两部分。bootloader 部分实现 app 升级功能和跳转,app 部分实现系统核心功能并能触发升级。
如:EEPROM 指定地址为1000 的位置数据是否为
0x1B
;
另外,在运行APP 代码过程中,输入指定指令,可跳转到步骤4(IAP 代码)
.hex
文件转.bin
在Keil 中下图位置添加代码fromelf.exe --bin -o "[email protected]" "#L"
,编译后,可在.hex
同文件夹下生成.bin
文件;
【点击跳转百度百科】YModem 是⼀种⽂件传输的协议,由XModem协议演变⽽来的,每包数据可以达到1024字节,是⼀个⾮常⾼效的⽂件传输协议。
使用Ymodem协议可以保证我们的传输数据安全,避免因为丢包等原因导致错误的bin(用户程序)烧录到FLASH,导致单片机运行异常跑飞等等
NVIC_SetVectorTable(NVIC_VectTab_FLASH,(0x08003000));
除了3.1 步骤的操作外,在APP 中也需要添加一个跳转到IAP 到接口,以实现在APP 代码运行中进入IAP 代码升级APP 代码的功能;
if(strcmp("UPLOAD FIRMWARE",ptr)==0){Get_TO_BootLoader();return;}
#define UPLOAD_FLAG_ADDR 1000
void Get_TO_BootLoader(void)
{
IIC_24C256_Write_Byte(0XA0,UPLOAD_FLAG_ADDR,4,0X1B); // 在板载EEPROM 指定位置中改变标志数据,使得单片机重启后进入IAP 代码
printf("0x%X\r\n",IIC_24C256_Read_Byte(0XA0,UPLOAD_FLAG_ADDR,4));
printf("MCU Into Upload firmware Pass\r\n@_@");
soft_reset(); // 单片机重启
}
void soft_reset(void)
{
//关闭所有中断
__set_FAULTMASK(1);
//单片机复位
NVIC_SystemReset();
}
int main(void)
{
int i;
IAP_Init(); // <--- 进入
IIC_Init();
...
}
void IAP_Init(void)
{
USART_InitTypeDef USART_InitStructure;
/* USART resources configuration (Clock, GPIO pins and USART registers) ----*/
/* USART configured as follow:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
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;
STM_EVAL_COMInit(COM1, &USART_InitStructure); // <--- 进入STM_EVAL_COMInit 的函数本体
}
void STM_EVAL_COMInit(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIO clock */
RCC_APB2PeriphClockCmd(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM] | RCC_APB2Periph_AFIO, ENABLE); // <--- 选择COM_TX_PORT_CLK进入其定义
/* Enable UART clock */
if (COM == COM1)
{
RCC_APB1PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
}
else
{
RCC_APB2PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
}
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COM];
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(COM_TX_PORT[COM], &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COM];
GPIO_Init(COM_RX_PORT[COM], &GPIO_InitStructure);
/* USART configuration */
USART_Init(COM_USART[COM], USART_InitStruct);
/* Enable USART */
USART_Cmd(COM_USART[COM], ENABLE);
}
USART_TypeDef* COM_USART[COMn] = {EVAL_COM1, EVAL_COM2}; // <--- 选择EVAL_COM1进入其定义
GPIO_TypeDef* COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT, EVAL_COM2_TX_GPIO_PORT};
GPIO_TypeDef* COM_RX_PORT[COMn] = {EVAL_COM1_RX_GPIO_PORT, EVAL_COM2_RX_GPIO_PORT};
const uint32_t COM_USART_CLK[COMn] = {EVAL_COM1_CLK, EVAL_COM2_CLK};
const uint32_t COM_TX_PORT_CLK[COMn] = {EVAL_COM1_TX_GPIO_CLK, EVAL_COM2_TX_GPIO_CLK};
const uint32_t COM_RX_PORT_CLK[COMn] = {EVAL_COM1_RX_GPIO_CLK, EVAL_COM2_RX_GPIO_CLK};
const uint16_t COM_TX_PIN[COMn] = {EVAL_COM1_TX_PIN, EVAL_COM2_TX_PIN};
const uint16_t COM_RX_PIN[COMn] = {EVAL_COM1_RX_PIN, EVAL_COM2_RX_PIN};
// 修改对应的串口和Pin 引脚
#define EVAL_COM1 USART2 // 如改为串口4,就把该项改为USART4,以下项同理
#define EVAL_COM1_CLK RCC_APB1Periph_USART2
#define EVAL_COM1_TX_PIN GPIO_Pin_2
#define EVAL_COM1_TX_GPIO_PORT GPIOA
#define EVAL_COM1_TX_GPIO_CLK RCC_APB2Periph_GPIOA
#define EVAL_COM1_RX_PIN GPIO_Pin_3
#define EVAL_COM1_RX_GPIO_PORT GPIOA
#define EVAL_COM1_RX_GPIO_CLK RCC_APB2Periph_GPIOA
#define EVAL_COM1_IRQn USART2_IRQn