文章目录

  • ❤2023重新理解记录
  • 其它文章链接,独家吐血整理
  • 实验现象
  • 主程序
  • IAP初始化程序
  • 代码讲解

文章目录

  • ❤2023重新理解记录
  • 其它文章链接,独家吐血整理
  • 实验现象
  • 主程序
  • IAP初始化程序
  • 代码讲解

❤2023重新理解记录


BOOT+APP=Flash,boot是通信使用,APP是功能代码,平时烧录的文件.hex时boot与app的结合体,一般刷boot要用专门的工具,boot的区域一般是固定的(也有说是出厂固化的),但是app代码区域是可以手动调整的,下载.hex文件就是下载更新了app文件

因为FLASH是放代码的,这个FLASH是单片机芯片内部的FLASH(不是外加的FLASH存储芯片),可以理解为,向量是地址,程序是函数,main函数的中断请求首先找到向量,再跳到中断函数,再跳回来main函数

上面函数与下面函数的区别可以理解为,上面是原有的程序,下面是通过IAP更新覆盖的程序,是新的程序(因为一个程序不允许两个main函数同时存在!,学过C语言也都知道这点),理论上可以有很多APP程序,都可以通过IAP覆盖原有的main程序实现升级或者更新!为什么要这样做呢?
1、正常我们用电脑keil或者IAR或者CUBE等编译器编译工程生成.hex文件烧录单片机,然后程序开始运行,这是最常用的方式,但是有时候客观原因不让我们带电脑下去,比如产品被盒子锁住打不开,比如产品在汽车上,全球几十万辆汽车乱跑,你去哪找?此时就是第二种方式了
2、这种采用串口IAP升级,更高级的叫做OTA=空中在线升级,将boot和app传进来,然后通过boot启动app程序就行了,如果实现存好不同的app,就可以实现手动升级程序,比如产品中的按键自己实现升级了,但是boot还是要通过ITAG传进来的,至于app那部分传进来可以被通过boot启动,我们平常的hex文件直接包括了boot和app,boot可以自己设计私有通信,比如串口输进来有没有一些匹配协议那是你自己设计的,正点的这款串口进来没有认证环节
3、如果这个串口换成了无线通信传输,不就相当于是,几万米外的你用电脑把编译好的app程序通过无线通信串口传到那边,然后接收到之后那边通过按键执行IAP升级app程序,这不就是OTA吗?


红色写错了,哈哈被我发现了

//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)  //检查栈顶地址是否合法.{ jump2app=(iapfun)*(vu32*)(appxaddr+4);     //用户代码区第二个字为程序开始地址(复位地址)        MSR_MSP(*(vu32*)appxaddr);                  //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)jump2app();                                 //跳转到APP.}
}
iapfun jump2app;
typedef  void (*iapfun)(void);               //定义一个函数类型的参数.
typedef __IO uint32_t  vu32;

这一块很不好理解,iapfun是指向iapfun()函数的指针类型,(iapfun)是iapfun()函数类型指针,(vu32)(appxaddr+4)是32位整型指针(appxaddr+4是地址,也就是它的内容)
jump2app=(iapfun)(vu32)(appxaddr+4);//连起来就是,将32位整型指针强制为函数型指针(存储地址)的appxaddr+4地址赋给了函数型指针jump2app,什么意思呢?就是相当于手动给这个函数定义地址了,一般我们定义一个函数都是让系统自动给它安排地址的,比如堆栈区地址,而这里我们通过这种方式手动把这个函数定义为我们想要的地址
jump2app();//这句话就是,开始从手动定义好的地址执行函数,也就是执行我们的app程序

其它文章链接,独家吐血整理

(实验3)单片机,STM32F4学习笔记,代码讲解【按键输入实验】【正点原子】【原创】
(实验4)单片机,STM32F4学习笔记,代码讲解【串口实验】【正点原子】【原创】
(实验5)单片机,STM32F4学习笔记,代码讲解【外部中断实验】【正点原子】【原创】
(实验6,实验7)单片机,STM32F4学习笔记,代码讲解【看门狗实验】【正点原子】【原创】
(实验8)单片机,STM32F4学习笔记,代码讲解【定时器实验】【正点原子】【原创】
(实验9)单片机,STM32F4学习笔记,代码讲解【PWM输出实验】【正点原子】【原创】
(实验10)单片机,STM32F4学习笔记,代码讲解【输入捕获实验】【正点原子】【原创】
(实验11)单片机,STM32F4学习笔记,代码讲解【电容触摸按键实验】【正点原子】【原创】
(实验12)单片机,STM32F4学习笔记,代码讲解【OLED显示实验】【正点原子】【原创】
(实验13)单片机,STM32F4学习笔记,代码讲解【TFTLCD彩屏显示实验】【正点原子】【原创】
(实验15)单片机,STM32F4学习笔记,代码讲解【RTC实时时钟实验】【正点原子】【原创】
(实验17)单片机,STM32F4学习笔记,代码讲解【待机唤醒实验】【正点原子】【原创】
(实验23)单片机,STM32F4学习笔记,代码讲解【DMA实验】【正点原子】【原创】
(实验25)单片机,STM32F4学习笔记,代码讲解【SPI实验】【正点原子】【原创】
(实验34)单片机,STM32F4学习笔记,代码讲解【FLASH模拟EEPROM实验】【正点原子】【原创】
(实验36)单片机,STM32F4学习笔记,代码讲解【外部SRAM实验】【正点原子】【原创】
(实验37)单片机,STM32F4学习笔记,代码讲解【内存管理实验】【正点原子】【原创】
(实验38)单片机,STM32F4学习笔记,代码讲解【SD卡实验】【正点原子】【原创】
(实验39)单片机,STM32F4学习笔记,代码讲解【FATFS实验】【正点原子】【原创】
(实验46)单片机,STM32F4学习笔记,代码讲解【FPU测试实验】【正点原子】【原创】
(实验47)单片机,STM32F4学习笔记,代码讲解【DSP-FFT测试实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验-RTC时钟实验】【正点原子】【原创】
(实验55)单片机,STM32F4学习笔记,代码讲解【网络通信实验】【正点原子】【原创】

实验现象

本实验开机的时候先显示提示信息,然后等待串口输入接收APP程序(无校验,一次性接收),在串口接收到APP程序之后,即可执行IAP。如果是SRAM APP,通过按下KEY0即可执行这个收到的SRAM APP程序。如果是FLASH APP,则需要先按下KEY_UP按键,将串口接收到的APP程序存放到STM32的FLASH,之后再按KEY1即可以执行这个FLASH APP程序。通过KEY2按键,可以手动清除串口接收到的APP程序。

主程序

int main(void)
{ u8 t;u8 key;u16 oldcount=0;  //老的串口接收数据值u16 applenth=0; //接收到的app代码长度u8 clearflag=0; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2delay_init(168);  //初始化延时函数uart_init(460800);        //初始化串口波特率为460800LED_Init();                    //初始化LED LCD_Init();                    //LCD初始化  KEY_Init();                   //按键初始化 POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");    LCD_ShowString(30,70,200,16,16,"IAP TEST");   LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,110,200,16,16,"2014/7/21");  LCD_ShowString(30,130,200,16,16,"KEY_UP:Copy APP2FLASH");LCD_ShowString(30,150,200,16,16,"KEY1:Erase SRAM APP");LCD_ShowString(30,170,200,16,16,"KEY0:Run SRAM APP");LCD_ShowString(30,190,200,16,16,"KEY2:Run FLASH APP");POINT_COLOR=BLUE;//显示提示信息POINT_COLOR=BLUE;//设置字体为蓝色      while(1){if(USART_RX_CNT){if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成.{applenth=USART_RX_CNT;oldcount=0;USART_RX_CNT=0;printf("用户程序接收完成!\r\n");printf("代码长度:%dBytes\r\n",applenth);}else oldcount=USART_RX_CNT;            }t++;delay_ms(10);if(t==30){LED0=!LED0;t=0;if(clearflag){clearflag--;if(clearflag==0)LCD_Fill(30,210,240,210+16,WHITE);//清除显示}}         key=KEY_Scan(0);if(key==WKUP_PRES)  //WK_UP按键按下{if(applenth){printf("开始更新固件...\r\n"); LCD_ShowString(30,210,200,16,16,"Copying APP2FLASH...");if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.{    iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码   LCD_ShowString(30,210,200,16,16,"Copy APP Successed!!");printf("固件更新完成!\r\n");   }else {LCD_ShowString(30,210,200,16,16,"Illegal FLASH APP!  ");      printf("非FLASH应用程序!\r\n");}}else {printf("没有可以更新的固件!\r\n");LCD_ShowString(30,210,200,16,16,"No APP!");}clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示                                  }if(key==KEY1_PRES)  //KEY1按下{if(applenth){                                                                   printf("固件清除完成!\r\n");    LCD_ShowString(30,210,200,16,16,"APP Erase Successed!");applenth=0;}else {printf("没有可以清除的固件!\r\n");LCD_ShowString(30,210,200,16,16,"No APP!");}clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示                                   }if(key==KEY2_PRES)  //KEY2按下{printf("开始执行FLASH用户代码!!\r\n");if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.{    iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码}else {printf("非FLASH应用程序,无法执行!\r\n");LCD_ShowString(30,210,200,16,16,"Illegal FLASH APP!");     }                                     clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示      }if(key==KEY0_PRES) //KEY0按下{printf("开始执行SRAM用户代码!!\r\n");if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x20000000)//判断是否为0X20XXXXXX.{  iap_load_app(0X20001000);//SRAM地址}else {printf("非SRAM应用程序,无法执行!\r\n");LCD_ShowString(30,210,200,16,16,"Illegal SRAM APP!");       }                                     clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示     }                 }
}

IAP初始化程序

iapfun jump2app;
u32 iapbuf[512];    //2K字节缓存
//appxaddr:应用程序的起始地址
//appbuf:应用程序CODE.
//appsize:应用程序大小(字节).
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
{u32 t;u16 i=0;u32 temp;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; STMFLASH_Write(fwaddr,iapbuf,512);fwaddr+=2048;//偏移2048  512*4=2048}} if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.
}//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(u32 appxaddr)
{if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)  //检查栈顶地址是否合法.{ jump2app=(iapfun)*(vu32*)(appxaddr+4);     //用户代码区第二个字为程序开始地址(复位地址)        MSR_MSP(*(vu32*)appxaddr);                  //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)jump2app();                                 //跳转到APP.}
}

代码讲解

//IAP=in application programming=在应用编程
//目的是通过预留的通信口对产品中的固件程序进行更新升级
//IAP=两个代码=BootLoader程序(只进行通信接收程序或数据)+APP程序(真正功能代码)
//两个代码都放在F4的FLASH里面,一般最低地址存放BootLoader代码(0x0800 0000)
//APP程序紧随其后,FLASH容量足够可以设计很多APP程序(Boot代码应该只有一个)
//本实验只设计一个APP程序,此外,APP程序既可以放在FLASH里面,也可以放在SRAM里面,
//本实验设计的APP代码一个放在FLASH里面,一个放在SRAM里面

//一般程序而言(不使用IAP功能),代码存放在FLASH(0x0800 0000是起始地址)里面,然后
//然后程序开始运行之后,从复位中断向量(0x0800 0004)里面取出复位中断地址,然后跳到
//复位中断程序地址入口,开始执行之后再跳到main函数入口,然后main里面一直死循环
//main函数里如果遇到中断,则去到这个中断向量,取出中断向量里面的中断函数地址
//然后跳到中断程序地址入口,执行完之后有回到main函数

//(加入IAP功能)先从复位中断向量=中断向量表起始地址跳到IAP程序main入口(中间废话省略)
//然后当IAP程序执行完之后,已经将APP代码写入FLASH里面了(在BootLoader代码之后)
//此时新程序的复位中断向量=中断向量表起始地址,再跳到新程序的main入口
//此时一直在main里面循环,如果在新程序main里遇到中断,则跳到IAP程序(之前的main程序)
//里面的中断向量,然后根据正个地址,跳到新程序里面的中断函数(有点绕,具体可看开发指南)

//具体配置操作步骤,可详看开发指南

//MDK默认生成的是hex文件,我们需要bin文件(二进制),所以我们需要用到MDK
//自带的格式转换工具,具体参考开发指南

//STM32的FLASH,探索者此款具有1024kb=1024字节,分为主储存器,系统存储器,OTP区域,选项字节
//其中主存储器中扇区0的地址==ox0800 0000,所以说,当boot0和boot1接地时
//系统默认从0800 0000字节开始读取FLASH,主存储器用来存放代码,和数据常数,分为12个扇区
//系统存储器,用来存放bootloader代码(出厂固化在里面的)
//OTP区域,一次性可编程区域,共628字节,分为512(存储用户数据)+16(用于锁定块)
//选项字节,只有16个字节,用于配置读保护,软件,硬件看门狗复位等···

//SRAM总共有128K字节空间(不包括CCM),这里面需要存boot代码和APP代码
//我们当然想boot代码越小越好,因为APP代码空间才会更大,但是此boot代码因为用到LCD程序
//和printf程序,所以就占用空间较大,不需要可删去,节省boot代码空间

//iap_load_app函数实现IAP代码跳到储存在FLASH里面的APP程序代码
//jump2app(); //跳转到APP.
//开发指南中说这个是虚拟函数,反正我没有看懂,也看不懂

//FLASH APP的起始地址必须是0x0801 0000
//SRAM的起始地址必须是0x2000 1000

(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验】【正点原子】【原创】相关推荐

  1. (实验38)单片机,STM32F4学习笔记,代码讲解【SD卡实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 SD卡驱动程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] ( ...

  2. (实验39)单片机,STM32F4学习笔记,代码讲解【FATFS实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 FATFS初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创 ...

  3. (实验55)单片机,STM32F4学习笔记,代码讲解【网络通信实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 LWIP初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] ...

  4. (实验37)单片机,STM32F4学习笔记,代码讲解【内存管理实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 内存池初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] ...

  5. (实验4)单片机,STM32F4学习笔记,代码讲解【串口实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 串口中断程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] (实 ...

  6. (实验6,实验7)单片机,STM32F4学习笔记,代码讲解【看门狗实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象(实验六) 主程序(实验六) 独立看门狗初始化程序(实验六) 代码讲解(实验六) 实验现象(实验七) 主程序(实验七) 窗口看门狗初始化程序(实验七) 代 ...

  7. (实验12)单片机,STM32F4学习笔记,代码讲解【OLED显示实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 OLED初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] ...

  8. (实验15)单片机,STM32F4学习笔记,代码讲解【RTC实时时钟实验】【正点原子】【原创】

    文章目录 其它文章链接,独家吐血整理 实验现象 主程序 RTC初始化程序 代码讲解 其它文章链接,独家吐血整理 (实验3)单片机,STM32F4学习笔记,代码讲解[按键输入实验][正点原子][原创] ...

  9. 坐标变换学习笔记—代码篇Matlab

    坐标变换学习笔记-代码篇Matlab 四元数 →\to→ 旋转矩阵 quat2dcm quat2rotm 四元数 →\to→ 欧拉角 quat2angle quat2eul 旋转矩阵 →\to→ 四元 ...

最新文章

  1. 台湾MCI报告:Security SaaS风潮渐起
  2. 谁说用 Git 一定要用命令行?试试 SourceTree 吧
  3. 1.html5究竟是什么
  4. Apache Maven 2 简介
  5. Android init.rc文件解析过程详解(三)
  6. Nginx安装成Windows服务
  7. 使用apache CXF和maven开发Web Service
  8. 我国最早超级计算机,全球十大超级计算机将在沪开通
  9. mysql8.0 线上线下数据库版本不一致导致的问题
  10. Kafka集群全部断开,然后重启时报“The broker is trying to join the wrong cluster. Configured zookeeper.connect……”问题
  11. liunx 命令 之 mkdir 与 touch
  12. “MapReduce: Simplified Data Processing on Large Clusters”
  13. 【Java必备技能二】防止表单重复提交方法
  14. java dateutils工具类_Java日期工具类DateUtils详解(转)
  15. 关于个人求职简历的一些见解
  16. 3、一层、二层、交换机原理、Cisco软件及命令
  17. SQL-根据生日计算年龄
  18. C# 自动转换为半角 (输入法半角/全角切换) 转载
  19. 测试既是一门科学,也是一门艺术
  20. Cobot与Jenkins集成

热门文章

  1. C盘扩容卷灰色无法点击
  2. iqooz1服务器无响应,iqooz1支持息屏显示吗,iqooz1可以息屏显示吗
  3. Matplotlib常用坐标图的绘制
  4. UML与软件工程专题集锦
  5. java基础—循环语句-while循环
  6. 2022年轩灵大前端知识体系王牌打造计划
  7. JS向上取整、向下取整、四舍五入、取绝对值、几次幂等方法
  8. 如何获取Java,JDK源码
  9. 网络性能测试工具简介
  10. 短信营销时短信发送失败的原因有哪些?