#define IAP_MAIN
#include "IAP.h"
uint32_t iapbuf[512];//缓存
pFunction JumpToApplication;
u8 USART3_RxData[USART3_Rx_LEN] __attribute__((at(SaveAddress)));//串口接收缓存
/***************************************************************************************
** 函数名称: iap_write_appbin
** 功能描述: 更新用户程序,写入FLASH
** 参 数: appxaddr:应用程序的起始地址
** appbuf:应用程序CODE
** appsize:应用程序大小(字节)
** 返 回 值: None
****************************************************************************************/
void iap_write_appbin(u32 appxaddr, u8 *appbuf, u32 appsize)
{
u32 t = 0;
u16 i = 0;
u32 temp = 0;
u32 fwaddr = appxaddr;//当前写入的地址
u8 *dfu = appbuf;
for(t=0; t<appsize; t+=4)
{
temp = (u32)dfu[3]<<24;
temp |= (u32)dfu[2]<<16;
temp |= (u32)dfu[1]<<8;
temp |= (u32)dfu[0];
dfu+=4;//偏移4个字节
iapbuf[i++] = temp;
if(i==512)
{
i = 0;
FLASH_WriteMoreData(fwaddr, iapbuf, 512);
fwaddr+=2048;//偏移2048 512*4=2045
}
}
if(i)
FLASH_WriteMoreData(fwaddr, iapbuf, i);//将最后的内容写入
}
/***************************************************************************************
** 函数名称: iap_load_app
** 功能描述: 跳转到应用程序段
** 参 数: appxaddr 用户代码起始地址
** 返 回 值: None
****************************************************************************************/
void iap_load_app(u32 appxaddr)
{
uint32_t jump2app;
__disable_irq();//关闭总中断
if (((*(__IO uint32_t*)appxaddr) & 0x2FFE0000 ) == 0x20000000)//检查栈顶地址是否合法
{
jump2app = *(__IO uint32_t*) (appxaddr + 4);//用户代码区第二个字节为程序开始地址(复位地址)
JumpToApplication = (pFunction) jump2app;
__set_MSP(*(__IO uint32_t*) appxaddr);//初始化用户程序的堆栈指针(用户代码区的第一个字用于存放栈顶指针)
JumpToApplication();//跳转到APP
}
}
/***************************************************************************************
** 函数名称: IAP_Usart_Init
** 功能描述: IAP串口初始化
** 参 数: BaudRate 波特率
** 返 回 值: None
****************************************************************************************/
void IAP_Usart_Init(uint32_t BaudRate)
{
LL_GPIO_InitTypeDef GPIO_InitStruct;
LL_USART_InitTypeDef USART_InitStruct;
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3);//串口时钟使能
//USART3引脚配置
GPIO_InitStruct.Pin = LL_GPIO_PIN_4 | LL_GPIO_PIN_5;//TX:PC4 RX:PC5
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;//复用模式
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;//高速
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;//推挽输出
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;//上拉
GPIO_InitStruct.Alternate = LL_GPIO_AF_7;//复用模式7
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);//初始化引脚配置
//USART3配置
USART_InitStruct.BaudRate = BaudRate;//波特率
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_9B;//9字节
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;//1位停止位
USART_InitStruct.Parity = LL_USART_PARITY_EVEN;//偶校验
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;//开启TX、RX
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;//禁用硬件流控制
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;//过采样16
LL_USART_Init(USART3, &USART_InitStruct);//初始化USART3配置
LL_USART_Enable(USART3);//使能USART3
while((!(LL_USART_IsActiveFlag_TEACK(USART3))) || (!(LL_USART_IsActiveFlag_REACK(USART3))));/* Polling USART initialisation */
LL_USART_EnableIT_RXNE(USART3); //使能接收中断
NVIC_SetPriority(USART3_IRQn, 0); //设置串口中断优先级
NVIC_EnableIRQ(USART3_IRQn); //使能串口中断
}
/***************************************************************************************
** 函数名称: IAPMain
** 功能描述: IAP引导程序
** 参 数: None
** 返 回 值: None
****************************************************************************************/
void IAPMain(void)
{
u32 oldcount=0;
u32 applenth=0;
IAP_Usart_Init(9600);//初始化IAP
while(1)
{
#if USE_DOG
LL_WWDG_SetCounter(WWDG, 0X7E);//喂狗
#endif
if(USART3_RX_DATA_BUF_CNT)
{
if(oldcount == USART3_RX_DATA_BUF_CNT)//新周期内没有数据认为接收完毕
{
applenth = USART3_RX_DATA_BUF_CNT;
oldcount = 0;
USART3_RX_DATA_BUF_CNT = 0;
if (((*(__IO uint32_t*)(SaveAddress + 0x00000004)) & 0xFF000000 ) == 0x08000000)//检查地址是否合法
iap_write_appbin(AppAddress1, USART3_RxData, applenth);//更新程序,串口接收数据写入APP地址
if (((*(__IO uint32_t*)(AppAddress1 + 0x00000004)) & 0xFF000000 ) == 0x08000000)//检查地址是否合法
iap_load_app(AppAddress1);//跳转到APP地址
}
else
oldcount = USART3_RX_DATA_BUF_CNT;
}
LL_mDelay(10);
}
}
//串口3中断函数
void USART3_IRQHandler(void)
{
if(LL_USART_IsActiveFlag_RXNE(USART3))//接受数据
{
u8 res = 0;
res = LL_USART_ReceiveData8(USART3);//读取接收寄存器,读数据会清中断
if(USART3_RX_DATA_BUF_CNT<USART3_Rx_LEN)
{
USART3_RxData[USART3_RX_DATA_BUF_CNT] = res;
USART3_RX_DATA_BUF_CNT++;
}
}
else
{
LL_USART_ClearFlag_ORE(USART3);//清除溢出标志
}
}