tag 标签: iap

相关博文
  • 热度 22
    2015-12-5 16:24
    3078 次阅读|
    8 个评论
    写在最前:转载请注明出处,谢谢,如果我的博客给您帮助,请您点个赞。 关于Bootloader的解释有很多,我就不多说了,想详细了解的 摸我之前写的 http://note.youdao.com/share/?id=42ae06075e076bde55ce80c02e28370c&type=note 在这里我上传的东西有以下几个 1,简单的Bootloader 2,App1 (左边等亮) 3,App2(右边等亮) 4, 5, 写在之后!由于文件过大,上传不了,我就在下面贴些简单的源码,大家自己去写。 Tip: a,你其实可以不用下载APP1和APP2的,在你自己的程序上修改就好了 b,我在keil5中写的程序,在其他的keil程序可能需要重新配置,如果不知道怎么配置参考我下面的注释 ok,进入正题。 功能:User在Bootloader(以下简称Boot)里面,写入APP1与APP2的版本好,哪个版本号大就执行哪一个。比较简单,大神们莫笑。大家也可以在基础上进行二次开发。 首先,自己做一个协议 #define VER_DEVICE_ID_SAVEADD 0x0800FFF0 //存放写数据的地址 //存放版本号 #define DEBUG 1 //1为测试 #define APP1DATAH 0xff //0x1E //没用到的 #define APP1DATAL 0xff //0x93//没用到的 #define APP2DATAH 0xff//没用到的 #define APP2DATAL 0xff//没用到的 #define APP1version 0x18 //哪一个数值大执行哪一个 #define APP2version 0x17 //哪一个数值大执行哪一个 unsigned char FLASH__WRITE_BUF ={0xBD,0x01,0x00,0x00,0x01,APP1DATAH,APP1DATAL,0xFF,APP1version,APP2DATAH,APP2DATAL,0xFF,APP2version,0xFF,0x55,0xDD} ; //自己做的协议 tip: a,这是一个工程的一部分,有些大家不需要用到的尽可以忽略。 Bootloader的思路如下: 上电,将 FLASH__WRITE_BUF[]数组写入特定的地址,检测APP1与APP2哪个版本新一点(大一点) 抛出标志位, 在while(1)里面对标志位进行相应的判断与执行。 重点函数: 1, /****************************** *功能:跳转到对应位置 *参数:u32 appxaddr APP1的初始地址或APP2的初始地址 ******************************/ void iap_load_app(u32 appxaddr) { if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)// jump2app=(iapfun)*(vu32*)(appxaddr+4);// MSR_MSP(*(vu32*)appxaddr);// jump2app();// } } 2, /****************************** *功能:写入数值到对应地址 *参数:写入的地址,数组名,写入个数(不是数值) ******************************/ void Write_FlashBuf(INT32U addr,INT8U *p,INT16U n) { INT32U r1; INT8U index=0; INT8U len; if((n%4)==0)n=n/4; else n=(n/4)+1; FLASH_Unlock(); FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); //FLASH_ErasePage(addr); while(n--) { r1=*(p++); r1|=*(p++)<<8; r1|=*(p++)<<16; r1|=*(p++)<<24; FLASH_ProgramWord(addr, r1); //写入一个字 addr+=4; } FLASH_Lock(); } 关于Bootloader的小贴士 a,Bootloader里面请不要做中断 b, Bootloader的大小尽可能小。 c,偏移量是0x200的整数倍 d,在项目配置哪里,IAP要改成EARSE FULL C 然后再把IAP APP1 APP2再下载一遍 f,关于移植keil5到keil4程序的简单解决方法 keil4的配置 keil5的配置 少了 STM32F10X_MD, 附件:由于APP文件过大,也简单,我就在这里贴一些简单的源码 APP1: APP1的配置 //实现功能:右边灯亮,间隔闪烁 ........ ........ ........ int main(void) { VTOR = FLASH_BASE | 0x1000; //这个是重点 RCC_Configuration(); //printf("程序1\r\n"); LED_Init(); delay_init(72); for(;;) { unsigned char index; KEY1=1; delay_ms(200); KEY1=0; delay_ms(200); } } APP2: //实现功能:左边灯亮,间隔闪烁 keil配置如上图再做对应修改! ........ ........ ........ int main(void) { VTOR = FLASH_BASE | 0x8800; //这个是重点 RCC_Configuration(); LED_Init(); delay_init(72); for(;;) { KEY1=1; delay_ms(500); KEY1=0; delay_ms(500); } }
  • 热度 17
    2015-2-22 22:38
    1883 次阅读|
    0 个评论
    接 现场升级方案:采用U盘方式进行IAP功能的实现(一) 下面分别概括一下实现IAP命令的函数,IAP功能命令有准备编程扇区,复制RAM到FLASH,擦除扇区,扇区查空,读器件ID,读BOOT代码版本,比较等指令。程序要进行IAP升级,必须要先选择扇区擦除扇区之后才能写进Flash。先需要定义系统时钟,参数和一些变量。 #define IAP_FCCLK 48000 uint32_t paramin ; uint32_t paramout ; unsigned long command ; unsigned long result ; typedef void (*IAP) (unsigned int , unsigned int ); 写数据之前,必须要选择需要写入的扇区,选择扇区部分代码: uint32_t SelSector(uint8_t sec1,uint8_t sec2) { paramin = IAP_SELECTOR; paramin = sec1; paramin = sec2; (*(void(*)())IAP_LOCATION)(paramin,paramout); return(paramout ); Blog: 更多技术文章请关注: 百家号: https://author.baidu.com/home?context=%7B%22app_id%22%3A%221646108714303504%22%7D&wfr=bjh 头条号: https://www.toutiao.com/c/user/8115738721/#mid=1646025109246987 CSDN : https://blog.csdn.net/u012246376
  • 热度 19
    2015-2-22 21:22
    3158 次阅读|
    0 个评论
    闲来无事,总结一下前段时间做过的U盘升级项目。一个新手的成长之路在于善于总结,生活也是一样扯远了,我准备了两个软件环境,一个带操作系统(UCOS)的,另一个裸机版的。随后我会附上两个程序代码。U盘升级可以分为两部分代码:U盘读取 bin文件和IAP功能两部分。大概说一下实现过程,具体IAP网上都玩坏了。 硬件环境:NXP 1788 软件环境:KEIL 运行升级程序。其实可以更具体,比如说设置升级标志或者按键。 拿到一个程序先从main开始,直接贴代码,说一大堆废话有什么用。 int main() { int32_t rc; uint32_t numBlks, blkSize; uint8_t inquiryResult ; SystemInit(); /*目标板初始化 */ UART_Init(57600); /*串口调试初始化 */ Host_Init(); /* USB初始化*/ rc = Host_EnumDev(); /*USB设备枚举 */ if (rc == OK) { /* Initialize the mass storage and scsi interfaces */ rc = MS_Init( &blkSize, &numBlks, inquiryResult ); if (rc == OK) { rc = FAT_Init(); /*文件系统初始化*/ if (rc == OK) { Bin_Read(); /*读取bin文件调用IAP */ } else { return (0); } } else { return (0); } } else { return (0); } while(1); } 下面分模块说一下,前面的硬件初始化函数很简单,USB设备枚举和FAT文件系统NXP官网上都有,只需改硬件接口,Host_Init函数如下: void Host_Init (void) { uint32_t HostBaseAddr; PCONP |= 0x80000000; OTGClkCtrl = 0x00000019; /* Enable USB host clock */ OTGClkSt & 0x00000019) != 0x19); StCtrl = 0x1;/* 01: U1 = host (OTG), U2 = host */ P0_29 &= ~(0x07UL << 0); P0_30 &= ~(0x07UL << 0); P1_28 &= ~(0x07UL << 0); P1_29 &= ~(0x07UL << 0); P0_29 |= 0x01UL << 0; /* P0.29 -- USB1 D+ */ P0_30 |= 0x01UL << 0; /* P0.30 -- USB1 D- */ P1_28 |= 0x01UL << 0; /* P1.28 -- USB_SCL1 */ P1_29 |= 0x01UL << 0; // P1.29 -- USB_SDA1 PRINT_Log("Initializing Host Stack\n"); /* Set up host base address and TD and ED descriptors */ HostBaseAddr = HOST_BASE_ADDR; Hcca = (volatile HCCA *)(HostBaseAddr+0x000); TDHead = (volatile HCTD *)(HostBaseAddr+0x100); TDTail = (volatile HCTD *)(HostBaseAddr+0x110); EDCtrl = (volatile HCED *)(HostBaseAddr+0x120); EDBulkIn = (volatile HCED *)(HostBaseAddr+0x130); EDBulkOut = (volatile HCED *)(HostBaseAddr+0x140); TDBuffer = (volatile uint8_t *)(HostBaseAddr+0x150); FATBuffer = (volatile uint8_t *)(HostBaseAddr+0x1D0); UserBuffer = (volatile uint8_t *)(HostBaseAddr+0x1000); /* Initialize all the TDs, EDs and HCCA to 0 */ Host_EDInit(EDCtrl); Host_EDInit(EDBulkIn); Host_EDInit(EDBulkOut); Host_TDInit(TDHead); Host_TDInit(TDTail); Host_HCCAInit(Hcca); Host_DelayMS(50); /* Wait 50 ms before apply reset */ Control = 0; /* HARDWARE RESET */ ControlHeadED = 0; /* Initialize Control list head to Zero */ BulkHeadED = 0; /* Initialize Bulk list head to Zero */ /* SOFTWARE RESET */ CommandStatus = OR_CMD_STATUS_HCR; FmInterval = DEFAULT_FMINTERVAL; /* Write Fm Interval and Largest Data Packet Counter */ /* Put HC in operational state */ Control & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER; RhStatus = OR_RH_STATUS_LPSC; /* Set Global Power */ HCCA = (uint32_t)Hcca; InterruptStatus; /* Clear Interrrupt Status */ InterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC | OR_INTR_ENABLE_UE; /* Enable the USB Interrupt */ NVIC_EnableIRQ(USB_IRQn); /* enable USB interrupt */ NVIC_SetPriority (USB_IRQn, 0);/* highest priority */ PRINT_Log("Host Initialized\n"); } 这段主要是USB引脚配置和USB主机初始化。Bin_Read()函数如下: void Bin_Read (void) { int32_t fdr; uint32_t bytes_read,writelen; uint32_t dstaddr; SelSector(APP_START_SECTOR,APP_END_SECTOR);//选择扇区 EraseSector(APP_START_SECTOR,APP_END_SECTOR); /*擦除扇区 */ BlankCHK(APP_START_SECTOR,APP_END_SECTOR); /*查空扇区 */ SelSector(APP_START_SECTOR,APP_END_SECTOR); PRINT_Log("\r\nstart file operations...\r\n"); fdr = FILE_Open(FILENAME_R, RDONLY); 0) { PRINT_Log("Reading from %s...\n", FILENAME_R); for(writelen=0;writelen<(APP_END_ADDR-APP_START_ADDR)/1024;writelen++) { bytes_read = FILE_Read(fdr, UserBuffer, MAX_BUFFER_SIZE); /*读出文件 */ dstaddr = (uint32_t)(APP_START_ADDR + (writelen)*1024);//dst address. SelSector(APP_START_SECTOR,APP_END_SECTOR); RamToFlash(dstaddr,(uint32_t)UserBuffer, 1024); Compare(dstaddr, (uint32_t)UserBuffer, 1024); } // printf("%x",writelen); PRINT_Log("\r\n write file successful\r\n"); VTOR = APP_START_ADDR; /*重新映射向量表 */ ExceuteApplication();/*执行用户程序*/ FILE_Close(fdr);/*关闭文件系统*/ } else { PRINT_Log("\r\n write file failed\r\n"); } } void Bin_Read (void) { int32_t fdr; uint32_t bytes_read,writelen; uint32_t dstaddr; SelSector(APP_START_SECTOR,APP_END_SECTOR); EraseSector(APP_START_SECTOR,APP_END_SECTOR); /* ²Á³ýÉÈÇø */ BlankCHK(APP_START_SECTOR,APP_END_SECTOR); /* ²é¿ÕÉÈÇø */ SelSector(APP_START_SECTOR,APP_END_SECTOR); PRINT_Log("\r\nstart file operations...\r\n"); fdr = FILE_Open(FILENAME_R, RDONLY); 0) { PRINT_Log("Reading from %s...\n", FILENAME_R); for(writelen=0;writelen<(APP_END_ADDR-APP_START_ADDR)/1024;writelen++) { bytes_read = FILE_Read(fdr, UserBuffer, MAX_BUFFER_SIZE); /* ¶Á³öÎļþ */ dstaddr = (uint32_t)(APP_START_ADDR + (writelen)*1024);//dst address. SelSector(APP_START_SECTOR,APP_END_SECTOR); RamToFlash(dstaddr,(uint32_t)UserBuffer, 1024); Compare(dstaddr, (uint32_t)UserBuffer, 1024); } // printf("%x",writelen); PRINT_Log("\r\n write file successful\r\n"); VTOR = APP_START_ADDR; /* ÖØÐÂÓ³ÉäÏòÁ¿±í */ ExceuteApplication(); FILE_Close(fdr); } else { 上面的代码可以分为两部分:1.从U盘读取bin文件2.IAP功能。先说IAP部分,IAP实现方法有UART,GPRS,USB等方式。要进行IAP设计,先划分FLASH扇区。LPC1788的FLASH划分如下: 将flash划分为两个区,bootloader和APP区,bootloader存放升级引导程序,即我们的USB_HOST_IAP代码,根据具体的Code大小确定bootloader的扇区,APP就是用户程序即需要升级的程序代码。APP需要配置后面再说。这是我的扇区划分: #define IAP_START_ADDR 0x00000000 // IAP开始地址 #define IAP_LOCATION 0x1FFF1FF1 /*IAP升级的入口地址 */ /* The area will be erase and program */ #define APP_START_ADDR0x00A000 //用户程序起始地址 #define APP_END_ADDR 0x78000 //LPC1788 512K Flash //#define APP_SIZE 0x10000 /* * Define the flash sectors used by the application */ #define APP_START_SECTOR10 #define APP_END_SECTOR 29 // LPC1788 512K Flash扇区 接下面 现场升级方案:采用U盘方式进行IAP功能的实现(二) Blog: 更多技术文章请关注: 百家号: https://author.baidu.com/home?context=%7B%22app_id%22%3A%221646108714303504%22%7D&wfr=bjh 头条号: https://www.toutiao.com/c/user/8115738721/#mid=1646025109246987 CSDN : https://blog.csdn.net/u012246376
  • 热度 20
    2013-4-19 22:58
    3741 次阅读|
    3 个评论
    第五十三章 串口IAP实验       IAP,即在应用编程。很多单片机都支持这个功能,STM32也不例外。在之前的FLASH模拟EEPROM实验里面,我们学习了STM32的FLASH自编程,本章我们将结合FLASH自编程的知识,通过STM32的串口实现一个简单的IAP功能本章分为如下几个部: 53.1 IAP简介 53.2 硬件设计 53.3 软件设计 53.4 下载验证 53.1 IAP简介    IAP(In Application Programming)即在应用编程,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。 通常实现IAP功能时,即用户程序运行中作自身的更新操作,需要在设计固件程序时编写两个项目代码,第一个项目程序不执行正常的功能操作,而只是通过某种通信方式(如USB、USART)接收程序或数据,执行对第二部分代码的更新;第二个项目代码才是真正的功能代码。这两部分项目代码都同时烧录在User Flash中,当芯片上电后,首先是第一个项目代码开始运行,它作如下操作:    1)检查是否需要对第二部分代码进行更新    2)如果不需要更新则转到4)    3)执行更新操作    4)跳转到第二部分代码执行    第一部分代码必须通过其它手段,如JTAG或ISP烧入;第二部分代码可以使用第一部分代码IAP功能烧入,也可以和第一部分代码一起烧入,以后需要程序更新是再通过第一部分IAP代码更新。   我们将第一个项目代码称之为Bootloader程序,第二个项目代码称之为APP程序,他们存放在STM32 FLASH的不同地址范围,一般从最低地址区开始存放Bootloader,紧跟其后的就是APP程序(注意,如果FLASH容量足够,是可以设计很多APP程序的,本章我们只讨论一个APP程序的情况)。这样我们就是要实现2个程序:Bootloader和APP。  STM32的APP程序不仅可以放到FLASH里面运行,也可以放到SRAM里面运行,本章,我们将制作两个APP,一个用于FLASH运行,一个用于SRAM运行。 我们先来看看STM32正常的程序运行流程,如图53.1.1所示:   图53.1.1 STM32正常运行流程图        STM32的内部闪存(FLASH)地址起始于0x08000000,一般情况下,程序文件就从此地址开始写入。此外STM32是基于Cortex-M3内核的微控制器,其内部通过一张“中断向量表”来响应中断,程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,而这张“中断向量表”的起始地址是0x08000004,当中断来临,STM32的内部硬件机制亦会自动将PC指针定位到“中断向量表”处,并根据中断源取出对应的中断向量执行中断服务程序。        在图53.1.1中,STM32在复位后,先从0X08000004地址取出复位中断向量的地址,并跳转到复位中断服务程序,如图标号①所示;在复位中断服务程序执行完之后,会跳转到我们的main函数,如图标号②所示;而我们的main函数一般都是一个死循环,在main函数执行过程中,如果收到中断请求(发生重中断),此时STM32强制将PC指针指回中断向量表处,如图标号③所示;然后,根据中断源进入相应的中断服务程序,如图标号④所示;在执行完中断服务程序以后,程序再次返回main函数执行,如图标号⑤所示。        当加入IAP程序之后,程序运行流程如图53.1.2所示:   图53.1.2 加入IAP之后程序运行流程图        在图53.1.2所示流程中,STM32复位后,还是从0X08000004地址取出复位中断向量的地址,并跳转到复位中断服务程序,在运行完复位中断服务程序之后跳转到IAP的main函数,如图标号①所示,此部分同图53.1.1一样;在执行完IAP以后(即将新的APP代码写入STM32的FLASH,灰底部分。新程序的复位中断向量起始地址为0X08000004+N+M),跳转至新写入程序的复位向量表,取出新程序的复位中断向量的地址,并跳转执行新程序的复位中断服务程序,随后跳转至新程序的main函数,如图标号②和③所示,同样main函数为一个死循环,并且注意到此时STM32的FLASH,在不同位置上,共有两个中断向量表。        在main函数执行过程中,如果CPU得到一个中断请求,PC指针仍强制跳转到地址0X08000004中断向量表处,而不是新程序的中断向量表,如图标号④所示;程序再根据我们设置的中断向量表偏移量,跳转到对应中断源新的中断服务程序中,如图标号⑤所示;在执行完中断服务程序后,程序返回main函数继续运行,如图标号⑥所示。        通过以上两个过程的分析,我们知道IAP程序必须满足两个要求: 1)  新程序必须在IAP程序之后的某个偏移量为x的地址开始; 2)  必须将新程序的中断向量表相应的移动,移动的偏移量为x; 本章,我们有2个APP程序,一个为FLASH的APP,另外一个位SRAM的APP,图53.1.2虽然是针对FLASH APP来说的,但是在SRAM里面运行的过程和FLASH基本一致,只是需要设置向量表的地址为SRAM的地址。 1.APP 程序起始地址设置方法 随便打开一个之前的实例工程,点击Options for TargetàTarget选项卡,如图53.1.3所示:   图53.1.3 FLASH APP Target选项卡设置        默认的条件下,图中IROM1的起始地址(Start)一般为0X08000000,大小(Size)为0X80000,即从0X08000000开始的512K空间为我们的程序存储区。而图中,我们设置起始地址(Start)为0X08005000,即偏移量为0X5000(20K字节),因而,留给APP用的FLASH空间(Size)只有0X80000-0X5000=0X7B000(480K字节)大小了。设置好Start和Szie,就完成APP程序的起始地址设置。        这里的20K字节,需要大家根据Bootloader程序大小进行选择,比如我们本章的Bootloader程序为18K左右,理论上我们只需要确保APP起始地址在Bootloader之后,并且偏移量为0X200的倍数即可(相关知识,请参考:http://www.openedv.com/posts/list/392.htm)。这里我们选择20K(0X5000)字节,留了一些余量,方便Bootloader以后的升级修改。        这是针对FLASH APP的起始地址设置,如果是SRAM APP,那么起始地址设置如图53.1.4所示:   图53.1.4 SRAM APP Target选项卡设置        这里我们将IROM1的起始地址(Start)定义为:0X20001000,大小为0XA000(40K字节),即从地址0X20000000偏移0X1000开始,存放APP代码。因为整个STM32F103ZET6的SRAM大小为64K字节,所以IRAM1(SRAM)的起始地址变为0X2000B000,大小只有0X5000(20K字节)。这样,整个STM32F103ZET6的SRAM分配情况为:最开始的4K给Bootloader程序使用,随后的40K存放APP程序,最后20K,用作APP程序的内存。这个分配关系大家可以根据自己的实际情况修改,不一定和我们这里的设置一模一样,不过也需要注意,保证偏移量为0X200的倍数(我们这里为0X1000)。        2. 中断向量表的偏移量设置方法        此步,我们通过修改sys.c里面的MYRCC_DeInit函数实现,该函数代码如下: void MYRCC_DeInit(void) {           //省略部分代码        //配置向量表                         #ifdef  VECT_TAB_RAM        MY_NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);   #else          MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH,0); #endif }        该函数我们只需要修改最后两行代码,默认的情况下VECT_TAB_RAM是没有定义的,所以执行:MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH,0);这是正常情况的向量表偏移量(为0),本章,我们修改这句代码为:MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH,0X5000);偏移量为0X5000。其中NVIC_VectTab_RAM和NVIC_VectTab_FLASH是在stm32f10x_nvic.h里面定义的两个宏定义,代表RAM和FLASH的起始地址。        以上是FLASH APP的情况,当使用SRAM APP的时候,我们需要定义VECT_TAB_RAM,点击Options for TargetàC/C++选项卡,在Preprocessor Symblols栏定义:VECT_TAB_RAM,如图54.1.5所示:   图53.1.5 SRAM APP C/C++选项卡设置        通过这个设置,我们定义VECT_TAB_RAM,故在执行MYRCC_DeInit函数的时候,会执行MY_NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 这里的0X0是默认的设置,本章我们修改此句代码为:MY_NVIC_SetVectorTable(NVIC_VectTab_SRAM,0X1000);即设置偏移量为0X1000。        这样,我们就完成了中断向量表偏移量的设置。 通过以上两个步骤的设置,我们就可以生成APP程序了,只要APP程序的FLASH和SRAM大小不超过我们的设置即可。不过MDK默认生成的文件是.hex文件,并不方便我们用作IAP更新,我们希望生成的文件是.bin文件,这样可以方便进行IAP升级(至于为什么,请大家自行百度HEX和BIN文件的区别!)。这里我们通过MDK自带的格式转换工具fromelf.exe,来实现.axf文件到.bin文件的转换。该工具在MDK的安装目录\ARM\BIN40文件夹里面。 fromelf.exe转换工具的语法格式为:fromelf input_file。其中options有很多选项可以设置,详细使用请参考光盘《mdk如何生成bin文件.pdf》. 本章,我们通过在MDK点击Options for TargetàUser选项卡,在Run User Programs After Build/Rebuild 栏,勾选Run#1和DOS16,并写入:D:\Keil3.80a\ARM\BIN40\fromelf.exe  --bin -o  ..\OBJ\TEST.bin ..\OBJ\TEST.axf ,如图53.1.6所示:          通过这一步设置,我们就可以在MDK编译成功之后,调用fromelf.exe(注意,我的MDK是安装在D:\Keil3.80A文件夹下,如果你是安装在其他目录,请根据你自己的目录修改fromelf.exe的路径),根据当前工程的TEST.axf,生成一个TEST.bin的文件。并存放在axf文件相同的目录下,即工程的OBJ文件夹里面。在得到.bin文件之后,我们只需要将这个bin文件传送给单片机,即可执行IAP升级。        最后再来看看APP程序的生成步骤: 1) 设置APP 程序的起始地址和存储空间大小 对于在FLASH里面运行的APP程序,我们只需要设置APP程序的起始地址,和存储空间大小即可。而对于在SRAM里面运行的APP程序,我们还需要设置SRAM的起始地址和大小。无论哪种APP程序,都需要确保APP程序的大小和所占SRAM大小不超过我们的设置范围。 2) 设置中断向量表偏移量 此步,通过在MYRCC_DeInit函数里面调用MY_NVIC_SetVectorTable函数,实现对中断向量表偏移量的设置。这个偏移量的大小,其实就等于程序起始地址相对于0X08000000或者0X20000000的偏移。对于SRAM APP程序,我们还需要在C/C++选项卡定义VECT_TAB_RAM,以申明中断向量表是在SRAM里面。 3) 设置编译后运行fromelf.exe ,生成.bin 文件. 通过在User选项卡,设置编译后调用fromelf.exe,根据.axf文件生成.bin文件,用于IAP更新。 以上3个步骤,我们就可以得到一个.bin的APP程序,通过Bootlader程序即可实现更新。 53.2 硬件设计 本章实验(Bootloader部分)功能简介:开机的时候先显示提示信息,然后等待串口输入接收APP程序(无校验,一次性接收),在串口接收到APP程序之后,即可执行IAP。如果是SRAM APP,通过按下KEY0即可执行这个收到的SRAM APP程序。如果是FLASH APP,则需要先按下WK_UP按键,将串口接收到的APP程序存放到STM32的FLASH,之后再按KEY2既可以执行这个FLASH APP程序。通过KEY1按键,可以手动清除串口接收到的APP程序。DS0用于指示程序运行状态。 本实验用到的资源如下: 1)  指示灯DS0 2)  四个按键(KEY0/KEY1/KEY2/WK_UP) 3)  串口 4)  TFTLCD模块 这些用到的硬件,我们在之前都已经介绍过,这里就不再介绍了。 53.3 软件设计 本章,我们总共需要3个程序:1,Bootloader;2,FLASH APP;3)SRAM APP;其中,我们选择之前做过的RTC实验(在第二十章介绍)来做为FLASH APP程序(起始地址为0X08005000),选择触摸屏实验(在第三十一章介绍)来做SRAM APP程序(起始地址为0X20001000)。Bootloader则是通过TFTLCD显示实验(在第十八章介绍)修改得来。本章,关于SRAM APP和FLASH APP的生成比较简单,我们就不细说,请大家结合光盘源码,以及53.1节的介绍,自行理解。本章软件设计仅针对Bootloader程序。 复制第十八章的工程(即实验13),作为本章的工程模版(命名为:IAP Bootloader V1.0),并复制第三十九章实验(FLASH模拟EEPROM实验)的STMFLASH文件夹到本工程的HARDWARE文件夹下,打开本实验工程,并将STMFLASH文件夹内的stmflash.c加入到HARDWARE组下,同时将STMFLASH加入头文件包含路径。 在HARDWARE文件夹所在的文件夹下新建一个IAP的文件夹,并在该文件夹下新建iap.c和iap.h两个文件。然后在工程里面新建一个IAP的组,将iap.c加入到该组下面。最后,将IAP文件夹加入头文件包含路径。 打开iap.c,输入如下代码: //省略代码.         该文件总共只有2个函数,其中,iap_write_appbin函数用于将存放在串口接收buf里面的APP程序写入到FLASH。iap_load_app函数,则用于跳转到APP程序运行,其参数appxaddr为APP程序的起始地址,程序先判断栈顶地址是否合法,在得到合法的栈顶地址后,通过MSR_MSP函数(该函数在sys.c文件)设置栈顶地址,最后通过一个虚拟的函数(jump2app)跳转到APP程序执行代码,实现IAPàAPP的跳转。        保存iap.c,打开iap.h输入如下代码: #ifndef __IAP_H__ #define __IAP_H__ #include "sys.h"    typedef  void (*iapfun)(void);     //定义一个函数类型的参数.   #define FLASH_APP1_ADDR            0x08005000         //第一个应用程序起始地址(存放在FLASH) //保留0X08000000~0X08004FFF的空间为Bootloader使用      void iap_load_app(u32 appxaddr);                                                 //跳转到APP程序执行 void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 applen);   //在指定地址开始,写入bin #endif        这部分代码比较简单,保存iap.h。本章,我们是通过串口接收APP程序的,我们将usart.c和usart.h做了稍微修改,在usart.h中,我们定义USART_REC_LEN为55K字节,也就是串口最大一次可以接收55K字节的数据,这也是本Bootloader程序所能接收的最大APP程序大小。然后新增一个USART_RX_CNT的变量,用于记录接收到的文件大小,而USART_RX_STA不再使用。在usart.c里面,我们修改USART1_IRQHandler部分代码如下: //串口1中断服务程序 //注意,读取USARTx-SR能避免莫名其妙的错误        u8 USART_RX_BUF __attribute__ ((at(0X20001000))); //接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.    //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0,     接收到的有效字节数目 u16 USART_RX_STA=0;              //接收状态标记       u16 USART_RX_CNT=0;                   //接收的字节数       void USART1_IRQHandler(void) {        u8 res;     #ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.        OSIntEnter();    #endif        if(USART1-SR(15))//接收到数据        {                   res=USART1-DR;               if(USART_RX_CNT               {                      USART_RX_BUF =res;                      USART_RX_CNT++;                                                                                                   }        } #ifdef OS_CRITICAL_METHOD       //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.        OSIntExit();                                                                                 #endif }        这里,我们指定USART_RX_BUF的地址是从0X20001000开始,该地址也就是SRAM APP程序的起始地址!然后在USART1_IRQHandler函数里面,将串口发送过来的数据,全部接收到USART_RX_BUF,并通过USART_RX_CNT计数。代码比较简单,我们就不多说了。 改完usart.c和usart.h之后,我们在test.c修改main函数如下: int main(void) {  //篇幅所限,省略代码            }        该段代码,实现了串口数据处理,以及IAP更新和跳转等各项操作。Bootloader程序就设计完成了,但是一般要求bootloader程序越小越好(给APP省空间嘛),所以,本章我们把一些不需要用到的.c文件全部去掉,最后得到工程截图如图53.3.1所示:   图53.3.1 Bootloader 工程截图        从上图可以看出,虽然去掉了一些不用的.c文件,但是Bootloader大小还是有18K左右,比较大,主要原因是液晶驱动和printf占用了比较多的flash,如果大家想进一步删减,可以去掉LCD显示和printf等,不过我们在本章为了演示效果,所以保留了这些代码。       至此,本实验的软件设计部分结束。        FLASH APP和SRAM APP两部分代码,根据53.1节的介绍,大家自行修改都比较简单,我们这里就不介绍了,不过要提醒大家:FLASH APP的起始地址必须是0X08005000,而SRAM APP的起始地址必须是0X20001000。 53.4 下载验证 在代码编译成功之后,我们下载代码到ALIENTEK战舰STM32开发板上,得到,如图53.4.1所示:   图53.4.1 IAP程序界面 此时,我们可以通过串口,发送FLASH APP或者SRAM APP到战舰STM32开发板,如图53.4.2所示:   图53.4.2 串口发送APP程序界面        先用串口调试助手的打开文件按钮(如图标号1所示),找到APP程序生成的.bin文件,然后设置波特率为256000(为了提高速度,Bootloader程序将波特率被设置为256000了),最后点击发送文件(图中标号3所示),将.bin文件发送给战舰STM32开发板。        在收到APP程序之后,我们就可以通过KEY0/KEY2运行这个APP程序了(如果是FLASH APP,则先需要通过WK_UP将其存入对应FLASH区域)。   )                            
  • 热度 19
    2012-10-16 20:37
    2321 次阅读|
    1 个评论
    在对片面FLASH编程时,查看芯片数据手册上面说只需配置FMA、FMD、FMC三个寄存器就行了,可是忽略了很重要的一点,这一点在AN01237 笔记上面说明了,就是一定要配置FLASH操作的时钟频率USECRL以确保正确的时序。   AN01237相关文档及详细说明请看: http://www.cnblogs.com/tdyizhen1314/archive/2012/10/16/2726734.html   另外一定要慎重对片内FLASH使用ReadOnly模式,否则很有可能使你的芯片无法擦除或再编程,致使芯片无法再工作。  
相关资源