/*************************************************************
Function : IAP_Init
Description: IAP初始化函数,初始化串口1
Input : none
return : none
*************************************************************/
void IAP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(COM1_RCC, ENABLE);//使能 USART1 时钟
RCC_APB2PeriphClockCmd(COM1_GPIO_RCC, ENABLE);//使能串口2引脚时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//配置 USART1 的Tx 引脚类型为推挽式的
GPIO_InitStructure.GPIO_Pin = COM1_TX_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(COM1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//配置 USART1 的Rx 为输入悬空
GPIO_InitStructure.GPIO_Pin = COM1_RX_PIN;
GPIO_Init(COM1_GPIO_PORT, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;//设置波特率为115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位为8位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//设置停止位为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;//发送与接收
USART_ITConfig(COM1, USART_IT_RXNE, ENABLE);//接收中断使能
USART_Init(COM1,&USART_InitStructure);//串口2相关寄存器的配置
USART_Cmd(COM1,ENABLE); //使能串口2
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//通道设置为串口2中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//中断占优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//打开中断
NVIC_Init(&NVIC_InitStructure);
}
/*************************************************************
Function : IAP_SerialSendByte
Description: 串口发送字节
Input : c-要发送的字节
return : none
*************************************************************/
static void IAP_SerialSendByte(u8 c)
{
USART_SendData(COM1, c);
while (USART_GetFlagStatus(COM1, USART_FLAG_TXE) == RESET) {}
}
/*************************************************************
Function : IAP_SerialSendStr
Description: 串口发送字符串
Input : none
return : none
*************************************************************/
void IAP_SerialSendStr(u8 *s)
{
while(*s != '\0')
{
IAP_SerialSendByte(*s);
s++;
}
}
#define MAXBUFFER 512 //缓冲大小
u8 UsartBuffer[MAXBUFFER]; //数据缓冲区
u16 UsartWptr = 0;
u16 UsartRptr = 0;
/*************************************************************
Function : IAP_BufferWrite
Description: 写缓冲区
Input : none
return : none
*************************************************************/
void IAP_BufferWrite(void)
{
if(UsartWptr == (UsartRptr - 1))//缓冲区存满了
{
return;//返回
}
UsartBuffer[UsartWptr] = USART_ReceiveData(COM1);//存取串口数据
UsartWptr++;//缓冲写位置值自增
UsartWptr = UsartWptr%MAXBUFFER;//保证写位置值不溢出
}
/*************************************************************
Function : IAP_BufferRead
Description: 读缓冲区
Input : none
return : none
*************************************************************/
static u8 IAP_BufferRead(u8 *data)
{
if(UsartRptr == UsartWptr)//无数据可读
{
return 0;
}
*data = UsartBuffer[UsartRptr];//读取缓冲区数据
UsartRptr++;//读位置值自增
UsartRptr = UsartRptr % MAXBUFFER;//保证读位置值不溢出
return 1;
}
/*************************************************************
Function : IAP_ShowMenu
Description: 显示菜单界面
Input : none
return : none
*************************************************************/
void IAP_ShowMenu(void)
{
IAP_SerialSendStr("\r\n+================(C) COPYRIGHT 2014 Ziye334 ================+");
IAP_SerialSendStr("\r\n| In-Application Programing Application (Version 1.0) |");
IAP_SerialSendStr("\r\n+----command----+-----------------function------------------+");
IAP_SerialSendStr("\r\n| 1: FWUPDATA | Update the firmware to flash |");
IAP_SerialSendStr("\r\n| 2: FWERASE | Erase the current firmware |");
IAP_SerialSendStr("\r\n| 3: BOOT | Excute the current firmware |");
IAP_SerialSendStr("\r\n| 4:REBOOT | Reboot |");
IAP_SerialSendStr("\r\n| ?: HELP | Display this help |");
IAP_SerialSendStr("\r\n+===========================================================+");
IAP_SerialSendStr("\r\n\r\n");
IAP_SerialSendStr("STM32-IAP>>");
}
extern u8 rcvTimeout; //接收超时标志
/*************************************************************
Function : IAP_UpdataProgram
Description: 更新程序
Input : none
return : none
*************************************************************/
static void IAP_UpdataProgram(void)
{
u8 blockNum = 0; //块,一块4页,对于STM32F10X_HD来说,1页2Kbytes
u8 n = 0;
u8 data = 0;
u8 datalow = 0;
u8 datahigh = 0;
u32 UserMemoryMask = 0;
rcvTimeout = 0; //清除接收超时标志位
blockNum = (IAP_ADDR - FLASH_BASE_ADDR) >> 12; //计算flash块
UserMemoryMask = ((u32)(~((1 << blockNum) - 1)));//计算掩码
//查看块所在区域是否写保护
if((FLASH_GetWriteProtectionOptionByte() & UserMemoryMask) != UserMemoryMask)
{
FLASH_EraseOptionBytes (); //关闭写保护
}
while(1)
{
switch(n)
{
case 0:
if(IAP_BufferRead(&data)) //接收地字节数据
{
datalow = data;
n = 1;
}
else
{
break;
}
case 1:
if(IAP_BufferRead(&data)) //接收高字节数据
{
datahigh = data;
n = 0;
IAP_FlashProgramdata(((u16)(datalow)) | ((u16)(datahigh << 8)));
}
if(rcvTimeout)//接收超时,错误或者接收结束
{
datahigh = 0xff;
n = 0;
IAP_FlashProgramdata(((u16)(datalow)) | ((u16)(datahigh << 8)));
}
default:
break;
}
if(rcvTimeout)//接收超时
{
break;
}
}
}
/*************************************************************
Function : IAP_FlashProgramdata
Description: 烧写数据
Input : data-要烧写的数据
return : none
*************************************************************/
static void IAP_FlashProgramdata(u16 data)
{
static u32 flashwptr = IAP_ADDR;
FLASH_Unlock();//flash上锁
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清除flash相关标志位
FLASH_ProgramHalfWord(flashwptr, data); //烧写半字数据
if(flashwptr == IAP_ADDR)//开始烧写
{
IAP_SerialSendStr("\r\nUpdating firmware to 0x8005000 ");
}
IAP_SerialSendStr(".");//显示烧写进程
flashwptr = flashwptr + 2;//移动烧写地址
FLASH_Lock();//flash解锁
}
/*************************************************************
Function : IAP_FlashEease
Description: 擦除Flash
Input : none
return : none
*************************************************************/
static void IAP_FlashEease(void)
{
u16 eraseCounter = 0;
u16 nbrOfPage = 0;
nbrOfPage = (FLASH_BASE_ADDR + FLASH_SIZE - IAP_ADDR)/PAGE_SIZE;//计算page数
FLASH_Unlock(); //解除flash擦写锁定
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清除flash相关标志位
for(eraseCounter = 0; eraseCounter < nbrOfPage; eraseCounter++)//开始擦除
{
IAP_SerialSendStr(".");//显示进度
FLASH_ErasePage(IAP_ADDR + (eraseCounter * PAGE_SIZE));//擦除
}
FLASH_Lock();//flash擦写锁定
}
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
u32 JumpAddress; //跳转地址
/*************************************************************
Function : IAP_JumpToApplication
Description: 跳转到升级程序处
Input : none
return : none
*************************************************************/
void IAP_JumpToApplication(void)
{
if(((*(__IO u32 *)IAP_ADDR) & 0x2FFE0000) == 0x20000000)//有升级代码,IAP_ADDR地址处理应指向主堆栈区,即0x20000000
{
JumpAddress = *(__IO u32 *)(IAP_ADDR + 4);//获取复位地址
Jump_To_Application = (pFunction)JumpAddress;//函数指针指向复位地址
__set_MSP(*(__IO u32*)IAP_ADDR);//设置主堆栈指针MSP指向升级机制IAP_ADDR
Jump_To_Application();//跳转到升级代码处
}
}
/*************************************************************
Function : ShwHelpInfo
Description: 显示帮助信息
Input : none
return : none
*************************************************************/
static void ShwHelpInfo(void)
{
IAP_SerialSendStr("\r\nEnter '1' to updtate you apllication code!");
IAP_SerialSendStr("\r\nRnter '2' to erase the current application code!");
IAP_SerialSendStr("\r\nEnter '3' to go to excute the current application code!");
IAP_SerialSendStr("\r\nEnter '4' to restart the system!");
IAP_SerialSendStr("\r\nEnter '?' to show the help infomation!\r\n");
}
/*************************************************************
Function : IAP_GetKey
Description: 获取键入值
Input : none
return : 返回键值
*************************************************************/
static u8 IAP_GetKey(void)
{
u8 data;
while(!IAP_BufferRead(&data)){}//从缓冲区中获取键值
return data;
}
/*************************************************************
Function : IAP_WiatForChoose
Description: 功能选择
Input : none
return : none
*************************************************************/
void IAP_WiatForChoose(void)
{
u8 c = 0;
while (1)
{
c = IAP_GetKey();//获取键值
IAP_SerialSendByte(c);//串口返回键值
switch(c)
{
case '1': //FWUPDATA固件升级
if((IAP_GetKey() == '\r'))//检测回车键
{
IAP_SerialSendStr("\r\nErasing...");
IAP_FlashEease();//擦除Flash
IAP_SerialSendStr("\r\nErase done!\r\n");
IAP_SerialSendStr("Please send firmware file!\r\n");
IAP_UpdataProgram();//烧写升级代码
IAP_SerialSendStr("\r\nFirmware update done!\r\n");
IAP_SerialSendStr("Booting...\r\n");
Delay_ms(500);
NVIC_SystemReset();//重启
}
break;
case '2'://FWERASE固件擦除
if((IAP_GetKey() == '\r'))//检测回车键
{
IAP_SerialSendStr("\r\nErasing...");
IAP_FlashEease();//擦除Flash
IAP_SerialSendStr("\r\nErase done!\r\n");
return;//退出循环
}
break;
case '3'://BOOT执行升级程序
if((IAP_GetKey() == '\r'))
{
IAP_SerialSendStr("\r\nBotting...\r\n");
if(((*(__IO u32 *)IAP_ADDR) & 0x2FFE0000) != 0x20000000)
{
IAP_SerialSendStr("No user program! Please download a firmware!\r\n");
}
Delay_ms(500);
NVIC_SystemReset();
return;//退出循环
}
break;
case '4'://REBOOT系统重启
if((IAP_GetKey() == '\r'))//检测回车键
{
IAP_SerialSendStr("\r\nRebooting...\r\n");
return;//退出循环
}
break;
case '?'://HELP帮助
if((IAP_GetKey() == '\r'))
{
ShwHelpInfo();//显示帮助信息
return;//退出循环
}
break;
default:
IAP_SerialSendStr("\r\nInvalid Number! The number should be either 1、2、3、4or5\r\n");
return;//退出循环
}
}
}
#ifndef __IAP_H__
#define __IAP_H__
#include "stm32f10x.h"
#define FLASH_BASE_ADDR 0x8000000 //Flash基地址
#define IAP_ADDR 0x8005000 //升级代码地址
#if defined (STM32F10X_MD) || defined (STM32F10X_MD_VL)
#define PAGE_SIZE (0x400) // 1 Kbyte
#define FLASH_SIZE (0x20000) // 128 KBytes
#elif defined STM32F10X_CL
#define PAGE_SIZE (0x800) // 2 Kbytes
#define FLASH_SIZE (0x40000) // 256 KBytes
#elif defined STM32F10X_HD || defined (STM32F10X_HD_VL)
#define PAGE_SIZE (0x800) // 2 Kbytes
#define FLASH_SIZE (0x80000) // 512 KBytes
#elif defined STM32F10X_XL
#define PAGE_SIZE (0x800) // 2 Kbytes
#define FLASH_SIZE (0x100000) // 1 MByte
#else
#error "Please select first the STM32 device to be used (in stm32f10x.h)"
#endif
void IAP_Init(void);
void IAP_SerialSendStr(u8 *s);
void IAP_ShowMenu(void);
void IAP_WiatForChoose(void);
void IAP_BufferWrite(void);
void IAP_JumpToApplication(void);
#endif
/*************************************************************
Function : TIM2_IRQHandler
Description: 定时器2中断服务程序
Input : none
return : none
*************************************************************/
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
SoftTimer_TimerExecute();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
/*************************************************************
Function : USART1_IRQHandler
Description: 串口1中断服务程序
Input : none
return : none
*************************************************************/
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//检测接收中断标志位
{
SoftTimer_TimerStart(0, 100, RcvTimeoutSet, (void*)0, TIMER_ONESHOT);//开启软定时器1
IAP_BufferWrite();//存放接收到的数据
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除标志位
}
}
u8 rcvTimeout = 0; //接收超时标志
/*************************************************************
Function : RcvTimeoutSet
Description: 串口接收数据超时
Input : parameter-参数
return : none
*************************************************************/
void RcvTimeoutSet(void *parameter)
{
rcvTimeout = 1; //设置接收超时标志
}
/*************************************************************
Function : KeyInit
Description: 初始化按键
Input : none
return : none
*************************************************************/
void KeyInit (void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA , &GPIO_InitStructure);
}
/*************************************************************
Function : GetKey
Description: 获取按键状态
Input : none
return : none
*************************************************************/
u8 GetKey (void)
{
return (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8));
}
/*************************************************************
Function : main
Description: main入口
Input : none
return : none
*************************************************************/
int main(void)
{
BSP_Init();//板子初始化
KeyInit();//初始化按键
if(!GetKey ())//按键按下,进入升级界面
{
set: IAP_Init();//初始化串口
SoftTimer_Init();//初始化软定时器
shw: IAP_ShowMenu();//显示功能菜单
IAP_WiatForChoose(); //等待选择界面
goto shw;//重新显示界面
}
else
{
IAP_JumpToApplication();//跳转到升级出代码执行
goto set;//没有升级程序或者升级程序错误才会执行到这句,然后天转到升级界面
}
}
上一篇:STM32升级文件的制作
下一篇:STM32 多路软定时器
推荐阅读最新更新时间:2024-03-16 15:14