使用的芯片为GD32F303VC
什么是IAP呢?有个博主写的很清楚;就是远程升级;
【单片机开发】单片机的烧录方式详解(ICP、IAP、ISP)_isp烧录-CSDN博客
我们需要写一个boot 和APP
通过 boot对APP的程序进行更新;操作;而不是像单个调试板子那样使用ISP 和 ICP进行烧录;升级过程:上位机和板子进行can通讯;上位机将APP的BIN文件给板子;Boot 进行 0x0801 0000处 的擦除和写入;进而完成APP的更新过程;
也可以看我上篇文章 如何进行在 0x0801 0000处进行擦除和写入的;
GD32F303----内部Flash读写-CSDN博客
IAP(In-Application Programming):在应用编程
还需要了解一些关于Flash的内内容;
在手册里面对应的就是:
GD32F303VCT6-MCU选择器-兆易创新 GigaDevice | 官方网站
前段时间 需要给电池系统升级 ,插上can线,还需要给电池断电,在开启的3s中进行上电;感觉很是麻烦;
实验过程
BOOT:
上电,LED1和LED2 同时闪烁200ms的间隔亮灭; 4s之内没有接收到更新固件的指定(can没有收到数据),那么如果进入can的函数,会更新这个全局变量 g_T_bootIdle ,即进入APP;
#include "gd32f30x.h"
#include "systick.h"
#include "Global.h"
#include "gpio.h"
#include "timer.h"
//#include "can.h"
#include "cancomm.h"
#include <stdbool.h>
#include <stdio.h>#define DEV_VER 0x0200CBL_CMD_LIST CMD_List;
u32 g_T_bootIdle = 0;//boot idle timeout.void GlobeInit(void);
void Init_CMD_List(void);/****************************************************************************** 函数名称: main** 功能描述: ** 调用条件限定: None* * 输入参数: ** 返回结果: None** 附属影响: None* * 其他: 主函数* *****************************************************************************/
int main(void)
{uint32_t u32T_Led = 0;//led flash timeout.uint8_t FlagLedToggle = 0;//flag of led toggle// VECT_TAB_OFFSET-------0x10000 //Bootloader时需将system_stm32f10x.c文件更改此处为0x1000//nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x00000);GlobeInit();while(1){ fnCan1DealProc();//receive data process.if(Timer_GetMsDif(g_T_bootIdle, Timer_GetMs()) >= 4000)//{if((*((uint32_t *)APP_START_ADDRESS)!=0xFFFFFFFF)) //跳转地址可能是0x08010000(64KB) #define APP_START_ADDRESS ((uint32_t)0x08010000) {//Disable the TIM Countertimer_disable(TIMER2);CAN_BOOT_JumpToApplication(APP_START_ADDRESS); } else {g_T_bootIdle = Timer_GetMs();}}if(Timer_GetMsDif(u32T_Led, Timer_GetMs()) >= 200)//{u32T_Led = Timer_GetMs();if(FlagLedToggle == 0) {FlagLedToggle = 1;LED2 = 1;//灭LED1 = 1;//灭} else {FlagLedToggle = 0;LED2 = 0;//亮LED1 = 0;//亮}}}
}/****************************************************************************** 函数名称: GlobeInit** 功能描述: ** 调用条件限定: None* * 输入参数: ** 返回结果: None** 附属影响: None* * 其他: 系统总初始化* *****************************************************************************/
void GlobeInit(void)
{ SystemInit(); systick_config();TIMR2_Init(500,71); //72M/72=1000Khz的计数频率,计数到500为500us Can_Init();GPIOInit();Init_CMD_List();
}/****************************************************************************** 函数名称: TIM3_IRQHandler** 功能描述: ** 调用条件限定: None* * 输入参数: ** 返回结果: None** 附属影响: None* * 其他: 定时器2中断服务程序* *****************************************************************************/
void TIMER2_IRQHandler(void) //TIM2中断
{if(timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP) != RESET) //检查TIM2更新中断发生与否{ g_u32HalfMsCnt++;//0.5毫秒奇数器timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP); //清除TIMx更新中断标志 }
}void Init_CMD_List(void)
{CMD_List.OnlineCheck = 0x01;CMD_List.EraseFlash = 0x03;CMD_List.SetBaudRate = 0x04;CMD_List.BlockWriteInfo = 0x05;CMD_List.WriteBlockFlash = 0x06;CMD_List.BlockReadInfo = 0x07;CMD_List.ReadBlockFlash = 0x08;CMD_List.ExcuteApp = 0x09;CMD_List.CmdFaild = 0x00;CMD_List.CmdSuccess = 0x0A;
}
/*** @brief 控制程序跳转到指定位置开始执行 。* @param Addr 程序执行地址。* @retval 程序跳转状态。*/
void CAN_BOOT_JumpToApplication(__IO u32 Addr)
{pFunction Jump_To_Application;__IO u32 JumpAddress; /* Test if user code is programmed starting from address "ApplicationAddress" */if (((*(__IO u32*)Addr) & 0x2FFE0000 ) == 0x20000000){ /* Jump to user application */JumpAddress = *(__IO u32*) (Addr + 4);Jump_To_Application = (pFunction) JumpAddress;//__set_PRIMASK(1);//关闭所有中断//CAN_ITConfig(CAN1,CAN_IT_FMP0, DISABLE);/* Initialize user application's Stack Pointer */__set_MSP(*(__IO u32*)Addr);Jump_To_Application();}
}
注意这里;
APP:
GPIO_LedWork(); LED1和LED2 1s进行反转一次;8s之后再次进入boot,因此 NVIC_SystemReset();相当于掉电 在上电的过程。
#include "gd32f30x.h"
#include "systick.h"void GlobeInit(void);/****************************************************************************** 函数名称: main** 功能描述: ** 调用条件限定: None* * 输入参数: ** 返回结果: None** 附属影响: None* * 其他: 主函数* *****************************************************************************/
int main(void)
{
// VECT_TAB_OFFSET-------0x10000 //Bootloader时需将system_stm32f10x.c文件更改此处为0x1000//nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x10000);GlobeInit();while(1){//GPIO_InputDetect();fnCan1DealProc();fnSampProc();//电压电流采样
// fnCheckProc();fnBmsCtrlProc();//BMS控制
// fnDataSave();//LEDDealCtrl();GPIO_LedWork();static uint32_t s_u32Time = 0;if(Timer_Get5msDif(s_u32Time, Timer_Get5ms()) >= 1600) // 5*1600 = 8000ms 8s后进入boot,{s_u32Time = Timer_Get5ms();__set_FAULTMASK(1);NVIC_SystemReset();}}
}
void GPIO_LedWork(void)
{ static uint8_t s_u8LedVal = 0;static uint32_t s_u32Time = 0;if(Timer_Get5msDif(s_u32Time, Timer_Get5ms()) >= 200) // 5*200 = 1000ms 5ms增加一次 ,增加200次,{s_u32Time = Timer_Get5ms();s_u8LedVal ^= 1; // turnGPIO_LED1_WORK(s_u8LedVal); // on 1s,off 1s GPIO_LED2_WORK(s_u8LedVal); // on 1s,off 1s}
}
通过上位机和板子的can通信,可以发送一帧 让板子复位的命令; 进入BOOT 就是升级了 擦除APP的页地址;在写入;