完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
说明:
1.本例程参考正点原子的IAP的代码。 2.本例程基于STM32F103C8T6单片机编写。 3.本例程使用USART1进行程序下载,波特率115200。 4.串口输出”Bootloder“字样后,请在3s内通过串口将APP的.bin文件传入单片机,之后会自动烧写并启动APP。若3s内未传入.bin文件或传入的文件有误,则会自动原来的启动APP。.bin文件最大只能15KByte。 5.STM32F103C8T6拥有128KByte的flash和20KByte的sram。本程序将0x0800 0000 - 0x0800 FFFF作为Bootloder空间,将0x0801 0000 - 0x0801 FFFF作为APP空间。 6.APP程序需要将flash中的向量表偏移0x10000。 工程源码下载(fci5), 工程使用 Keil uVision5 创建 ,密码 fci5 。 XCOM V2.6下载(48cm),密码 48cm 。 程序源码: main.c #include "delay.h" #include "usart.h" #include "flash.h" #include "iap.h" /*********************************************** * 支持最大15KByte的APP * * * * 0x0800 0000 - 0x0800 FFFF 为Bootloder空间 * * 0x0801 0000 - 0x0801 FFFF 为APP空间 * * * ***********************************************/ int main () { u8 flag_update = 0; //升级完成后置1 u16 t = 0; u16 oldcount = 0; u16 applen = 0; //初始化 delay_init(); USART1_Init(115200); delay_ms(20); printf("Bootloderrn"); while(1) { if(USART1_RX_CNT) //如果接收到了数据 { if(oldcount == USART1_RX_CNT) //如果新周期内没收到数据,则认为接收完成 { applen = USART1_RX_CNT; oldcount = 0; USART1_RX_CNT = 0; if(((*(vu32*)(0x20001000+4)) & 0xFF000000) == 0x08000000) //判断是否为0x08XXXXXX,(是否为APP数据) { printf("APP len : %drn",applen); //开始升级APP printf("Updating...rn"); iap_write_appbin(FLASH_APP1_ADDR,USART1_RX_BUF,applen); //写入flash flag_update = 1; printf("Updae success !!!rn"); } else printf("APP data error!!!rn"); } else oldcount = USART1_RX_CNT; //更新接收到的字节数 } if(flag_update || (t == 300 & USART1_RX_CNT == 0)) //如果升级APP完成或3s内没收到正确的APP数据,则启动APP { printf("APP Startrnrn"); iap_load_app(FLASH_APP1_ADDR); } t++; delay_ms(10); } } delay.h #ifndef _DELAY_H #define _DELAY_H #include "stm32f10x.h" void delay_init(void); void delay_ms(u16 nms); void delay_us(u32 nus); #endif delay.c #include "delay.h" static u8 fac_us = 0; //us延时倍乘数 static u16 fac_ms = 0; //ms延时倍乘数 void delay_init(void) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCL/8 fac_us = SystemCoreClock/8000000; //为系统时钟的1/8 fac_ms = (u16)fac_us * 1000; } void delay_us(u32 nus) { u32 temp; SysTick->LOAD = nus * fac_us;//时间加数 SysTick->VAL = 0x00;//清空计数器 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//开始倒数 do { temp = SysTick->CTRL; }while((temp & 0x01) &&! (temp & (1<<16))); //等待时间到达 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭计数器、 SysTick->VAL = 0x00;//清空计数器 } void delay_ms(u16 nms) { u32 temp; SysTick->LOAD = (u32)nms * fac_ms;//时间加载(SysTick->LOAD为24bit) SysTick->VAL = 0x00;//清空计数器 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数 do { temp = SysTick->CTRL; }while((temp & 0x01) &&! (temp & (1<<16))); //等待时间到达 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭计数器 SysTick->VAL = 0x00;//清空计数器 } usart.h #ifndef __USART_H #define __USART_H #include "stdio.h" #include "stm32f10x.h" #include "stdarg.h" #define PRINTF_USARTx USART1 //USARTx 映射到 printf #define EN_USART1_RX 1 //1使能接收,0失能接收。 #define USART1_REC_LEN 15*1024 //最大接收15KByte extern u8 USART1_RX_BUF[USART1_REC_LEN]; //USART1 储存接收到的数据 extern u16 USART1_RX_STA; //USART1 接收状态即接收到的有效数据个数 extern u16 USART1_RX_CNT; void USART1_Init(unsigned int BaudRate); //USART1用户初始化函数 void printf1(u8 *data,...); int fputc(int ch, FILE *f); void _sys_exit(int x); static char *itoa(int value,char *string,int radix); #endif usart.c #include "usart.h" /*******************************************************************************************************************************************/ /* USART1 */ /*******************************************************************************************************************************************/ void USART1_Init(unsigned int BaudRate) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 /*初始化USART1的Tx、Rx引脚*/ //PA9 复用推挽输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStruct); //PA10浮空输入 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,&GPIO_InitStruct); // PA9outAF_PP(); //PA9 复用推挽输出 // PA10inFLOATING();//PA10浮空输入 USART_InitStructure.USART_BaudRate = BaudRate; //波特率 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_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启接收中断 USART_Cmd(USART1, ENABLE); //中断设置 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //中断分组1:1位抢占优先级,3位响应优先级 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); } /***************************************************** 如果开启了接收 *****************************************************/ #if EN_USART1_RX //如果开启了USART1接收 u8 USART1_RX_BUF[USART1_REC_LEN] __attribute__ ((at(0x20001000))); //接收缓冲,最大USART1_REC_LEN个字节。 设定起始地址为0x20001000 u16 USART1_RX_STA = 0; //接收状态标记 u16 USART1_RX_CNT = 0; //接收的字节数 void USART1_IRQHandler(void) { u8 res; if(USART1->SR & (1<<5)) { res = USART1->DR; if(USART1_RX_CNT USART1_RX_BUF[USART1_RX_CNT] = res; USART1_RX_CNT++; } } } #endif /*******************************************************************************************************************************************/ /* 以下代码实现printf输出(无需MircoLIB) */ /*******************************************************************************************************************************************/ /***************************************************** *function: 写字符文件函数 *param1: 输出的字符 *param2: 文件指针 *return: 输出字符的ASCII码 ******************************************************/ int fputc(int ch, FILE *f) { while((USART1->SR & 0x40) == 0); USART1->DR = (u8) ch; return ch; } /********** 禁用半主机模式 **********/ #pragma import(__use_no_semihosting) struct __FILE { int handle; }; FILE __stdout; void _sys_exit(int x) { x=x; } /*******************************************************************************************************************************************/ /* itoa */ /*******************************************************************************************************************************************/ static char *itoa(int value,char *string,int radix) { int i,d; int flag = 0; char *ptr = string; if(radix != 10) { *ptr = 0; return string; } if(!value) { *ptr++ = 0x30; *ptr = 0; return string; } if(value < 0) { *ptr++ = '-'; value *= -1; } for(i=10000;i>0;i /= 10) { d = value / i; if(d || flag) { *ptr++ = (char)(d + 0x30); value -= (d * i); flag = 1; } } *ptr = 0; return string; } /*******************************************************************************************************************************************/ /* 用户自定义的USART1输出函数 printf1 */ /*******************************************************************************************************************************************/ void printf1(u8 *data,...) { const char *s; int d; char buf[16]; va_list ap; va_start(ap,data); while( *data != 0) { if( *data == 0x5C ) // '' { switch ( *++data ) { case 'r': USART_SendData(USART1,0x0D); data++; break; case 'n': USART_SendData(USART1,0x0A); data++; break; default: data++; break; } } else if( *data == '%' ) { switch ( *++data ) { case 's': //字符串 s = va_arg(ap,const char *); for(;*s;s++) { USART_SendData(USART1,*s); while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET ); } data++; break; case 'd': d = va_arg(ap,int); itoa(d,buf,10); for(s = buf;*s;s++) { USART_SendData(USART1,*s); while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET ); } data++; break; default: data++; break; } } else USART_SendData(USART1,*data++); while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); } } flash.h #ifndef _FLASH_H #define _FLASH_H #include "stm32f10x.h" /*********************** 移植 *************************/ #define FLASH_SIZE 128 //FLASH容量(KByte) #define FLSAH_EN_WRITE 1 //1使能写入,0失能写入 /******************************************************/ #define FLSAH_BASH 0x08000000 //判断页大小 #if FLASH_SIZE < 256 #define SECTOR_SIZE 1024 #else #define SECTOR_SIZE 2048 #endif //提供给用户的函数 void FLASH_Write(u32 Addr,u16 *pBuff,u16 len); u16 FLASH_ReadHalfWord(u32 faddr); //读取一个半字(16位) void FLASH_Read(u32 Addr,u16 *pBuff,u16 len); //读出一段数据(16位) void FLASH_Writ_NoCheck(u32 Addr,u16 *pBuff,u16 len); //不检查的写入 #endif falsh.c #include "flash.h" u16 FLASH_BUF[SECTOR_SIZE/2]; //1KByte //提供给用户的函数 void FLASH_Write(u32 Addr,u16 *pBuff,u16 len) { u32 Sector_Number; //第几扇区 u32 Sector_Relative; //扇区内偏移地址(按16位计算) u32 Sector_Remain; //扇区内剩余地址(按16位计算) u32 OffAddr; //减去0x08000000后的地址 u16 i; //判断地址合理性 if(Addr FLASH_Unlock(); OffAddr = Addr - FLASH_BASE; Sector_Number = OffAddr/SECTOR_SIZE; Sector_Relative = (OffAddr%SECTOR_SIZE)/2; Sector_Remain = SECTOR_SIZE/2-Sector_Relative; //如果一页能够写完 if(len <= Sector_Remain) Sector_Remain = len; //写入 while(1) { //整页读出 FLASH_Read(Sector_Number*SECTOR_SIZE+FLASH_BASE,FLASH_BUF,SECTOR_SIZE/2); for(i=0;i if(FLASH_BUF[Sector_Relative+i] != 0xFFFF) break; //需要擦除 } if(i FLASH_ErasePage(Sector_Number*SECTOR_SIZE+FLASH_BASE); //替换数据 for(i=0;i FLASH_BUF[Sector_Relative+i] = pBuff; } //写入FLASH FLASH_Writ_NoCheck(Sector_Number*SECTOR_SIZE+FLASH_BASE,FLASH_BUF,SECTOR_SIZE/2); } else { FLASH_Writ_NoCheck(Addr,pBuff,Sector_Remain); } if(len == Sector_Remain) break; //写入结束 else { Sector_Number++; //页+1 Sector_Relative = 0; //页内偏移0 pBuff += Sector_Remain; //更新传入的数组指针 Addr += Sector_Remain*2; //写地址偏移 len -= Sector_Remain; //更新写长度 if(len>(SECTOR_SIZE/2)) Sector_Remain = SECTOR_SIZE/2; else Sector_Remain = len; } } FLASH_Lock(); } //读取一个半字(16位) u16 FLASH_ReadHalfWord(u32 faddr) { return *(vu16*)faddr; } //读出一段数据(16位) void FLASH_Read(u32 Addr,u16 *pBuff,u16 len) { u16 i; for(i=0;i pBuff = FLASH_ReadHalfWord(Addr); Addr += 2; } } #if FLSAH_EN_WRITE //如果使能了写 //不检查的写入 void FLASH_Writ_NoCheck(u32 Addr,u16 *pBuff,u16 len) { u16 i; for(i=0;i FLASH_ProgramHalfWord(Addr,pBuff); Addr += 2; } } #endif iap.h #ifndef _IAP_H #define _IAP_H #include "sys.h" #include "delay.h" #include "usart.h" #include "flash.h" #define FLASH_APP1_ADDR 0x08010000 //第一个应用程序起始地址 typedef void (*iapfun) (void); //定义一个函数类型的参数(?) void iap_load_app(u32 addr); //执行flash里的app程序 void iap_load_appsram(u32 addr); //执行sram里的app程序 void iap_write_appbin(u32 addr,u8 *buf,u32 len); //将程序写入到指定flash地址 #endif iap.c #include "iap.h" /******************************************************* 0x0800 0000 - 0x0800 FFFF 为Bootloder空间 0x0801 0000 - 0x0801 FFFF 为APP空间 *******************************************************/ iapfun jump2app; //(?) u16 iapbuf[1024]; //按2KByte合并接收到的数据,然后写入flash //将程序写入到指定flash地址 void iap_write_appbin(u32 addr,u8 *buf,u32 len) { u16 t; u16 i = 0; u16 temp; u32 fwaddr = addr; u8 *dfu = buf; for(t=0;t //将8位数据合并为16位数据 temp = (u16)dfu[1]<<8; temp += (u16)dfu[0]; dfu += 2; iapbuf[i++] = temp; //将合并完成的16位数据储存在数组中 if(i == 1024) //合并的数据填满iapbuf缓冲区后,开始写入falsh { i=0; FLASH_Write(fwaddr,iapbuf,1024); fwaddr += 2048; } } if(i)FLASH_Write(fwaddr,iapbuf,i); //将最后一些内容写入flash } //执行flash里的app程序 void iap_load_app(u32 addr) { if(((*(vu32*)addr) & 0x2FFE0000) == 0x20000000) //检查栈顶地址是否合法(?) { jump2app = (iapfun)*(vu32*)(addr + 4); //用户代码区第二个字为程序开始地址(复位地址) MSR_MSP(*(vu32*)addr); //初始化app栈顶指针(用户区的第一个字用于存放栈顶地址) jump2app(); //跳转到APP } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1658 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1568 浏览 1 评论
996 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
695 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1616 浏览 2 评论
1876浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
660浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
528浏览 3评论
546浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
517浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-28 18:04 , Processed in 0.749636 second(s), Total 45, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号