串口 IAP

串口 IAP_第1张图片
串口 IAP_第2张图片
APP程序的生成步骤:
①设置APP程序的起始地址和存储空间大小
② 设置中断向量表偏移量
设置SCB->VTOR的值即可。
③ 设置MDK编译后运行fromelf.exe,生成.bin文件.
通过在MDK User选项卡,设置编译后调用fromelf.exe,根据.axf文件生
成.bin文件,用于IAP更新。
bootloader作用:
1.通过某种串口下载.bin文件 2.写入flash的某个区域
3.跳转执行

查看 SYSTEM–usart.c

u8 USART_RX_BUF[USART_REC_LEN] __attribute__ ((at(0X20001000)));//接收缓冲,最大USART_REC_LEN个字节,起始地址为0X20001000.
查看定义(usart.h)得到buf的宽度
#define USART_REC_LEN 120*1024 //定义最大接收字节数 120K(1024BYTE(字节)=1KB)

查看 IAP–iap.c–iap.h

#define FLASH_APP1_ADDR     0x08010000      //第一个应用程序起始地址(存放在FLASH),保留0X08000000~0X0800FFFF的空间为Bootloader使用(共64KB)
void iap_load_app(u32 appxaddr); //跳转到APP程序执行
void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 applen); //在指定地址开始,写入bin

这里写图片描述
Bootloader使用的存储空间大小可以根据程序运行后的大小来定。

iap.c里面的iap_write_appbin

iapfun jump2app; 
u32 iapbuf[512];    //2K字节缓存,4x512=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;t4)
    {                          
        temp=(u32)dfu[3]<<24;   
        temp|=(u32)dfu[2]<<16;    
        temp|=(u32)dfu[1]<<8;
        temp|=(u32)dfu[0];    
        dfu+=4;//偏移4个字节 u8转换为u32
        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);//将最后的一些内容字节写进去.  
}

iap.c iap_load_ap

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

main.c

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后清除显示   
        }                  

    }  
}

APP程序的生成
①设置APP程序的起始地址和存储空间大小
串口 IAP_第3张图片

②中断向量表的偏移量设置方法
APP存放在FLASH中的设置方法
SCB->VTOR = FLASH_BASE | 0x10000;

APP存放在SRAM中的设置方法
SCB->VTOR = SRAM_BASE | 0x1000;
串口 IAP_第4张图片
③设置MDK编译后运行fromelf.exe,生成.bin文件
B:\MDK5\ARM\ARMCC\bin\fromelf.exe –bin -o ..\OBJ\RTC.bin ..\OBJ\RTC.axf
B:\MDK5\ARM\ARMCC\bin\fromelf.exe,keil的具体地址根据安装路径。
其他的修改可以在output查看,比如这个程序里就是RTC。

串口 IAP_第5张图片

打开
C:\Users\84329\Desktop\实验15 RTC实时时钟实验_FLASH APP版本\OBJ 可以查找有bin文件

程序下载 先将bootloard下载至开发板
打开串口调试助手 波特率 设为460800 打开文件RTC.bin 发送文件

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

你可能感兴趣的:(串口 IAP)