zoukankan      html  css  js  c++  java
  • STM32 :IAP实验 & 写入内部Flash

    更新:__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成)0x8000004才是复位向量,所以需要在add+4 

    这两天再看IAP实验,觉得很实用,最近在做一个小项目,日后也肯定需要升级的。原子的程序是写在STM32的内部Flash,内部SRAM。还可以把程序写到外部Flash或者SD卡来更新。

    目前做了第一步:从串口更新,移植的正点的代码。先将IAP bootload写入ROM起始地址,这里我的ROM总共256k,我分了一半给bootload,一半给app。注意设置地址问题。

                           只更新了Flash app。用的流水灯实验。SD卡FAT目前先没用,空间节省不少啊,这个RAM,ROM占用很厉害啊。这个问题还需要去解决。

                           串口接收APP设置了10k容量。

                           流程:1,Jlink写bootload到ROM起始,与平时一样

                                   2,串口发送app.bin,串口接收

                                   3,将接收的app.bin写入flash的指定app位置

                                   4,使用bootload中的函数跳转到flash的指定app位置,执行app。

       

     1 #ifndef __IAP_H__
     2 #define __IAP_H__
     3 #include "sys.h"  
     4 //////////////////////////////////////////////////////////////////////////////////     
     5 //本程序只供学习使用,未经作者许可,不得用于其它任何用途
     6 //ALIENTEK战舰STM32开发板
     7 //IAP 代码       
     8 //正点原子@ALIENTEK
     9 //技术论坛:www.openedv.com
    10 //修改日期:2012/9/24
    11 //版本:V1.0
    12 //版权所有,盗版必究。
    13 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
    14 //All rights reserved                                      
    15 //////////////////////////////////////////////////////////////////////////////////    
    16 typedef  void (*iapfun)(void);                //定义一个函数类型的参数.
    17 
    18 #define FLASH_APP1_ADDR        0x08020000      //第一个应用程序起始地址(存放在FLASH)
    19                                             //保留0X08000000~0X0800FFFF的空间为IAP使用
    20 
    21 void iap_load_app(u32 appxaddr);            //执行flash里面的app程序
    22 void iap_load_appsram(u32 appxaddr);        //执行sram里面的app程序
    23 void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 applen);    //在指定地址开始,写入bin
    24 #endif
    iap.h
     1 #include "sys.h"
     2 #include "systick_config.h"
     3 //#include "stmflash.h"
     4 #include "iap.h"
     5 //////////////////////////////////////////////////////////////////////////////////     
     6 //本程序只供学习使用,未经作者许可,不得用于其它任何用途
     7 //ALIENTEK战舰STM32开发板
     8 //IAP 代码       
     9 //正点原子@ALIENTEK
    10 //技术论坛:www.openedv.com
    11 //修改日期:2012/9/24
    12 //版本:V1.0
    13 //版权所有,盗版必究。
    14 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
    15 //All rights reserved                                      
    16 //////////////////////////////////////////////////////////////////////////////////    
    17 
    18 iapfun jump2app; 
    19 u16 iapbuf[1024];   
    20 //appxaddr:应用程序的起始地址
    21 //appbuf:应用程序CODE.
    22 //appsize:应用程序大小(字节).
    23 void iap_write_appbin(u32 appxaddr,u8 *appbuf,u32 appsize)
    24 {
    25     u16 t;
    26     u16 i=0;
    27     u16 temp;
    28     u32 fwaddr=appxaddr;//当前写入的地址
    29     u8 *dfu=appbuf;
    30     for(t=0;t<appsize;t+=2)
    31     {                            
    32         temp=(u16)dfu[1]<<8;
    33         temp+=(u16)dfu[0];      
    34         dfu+=2;//偏移2个字节
    35         iapbuf[i++]=temp;        
    36         if(i==1024)
    37         {
    38             i=0;
    39             STMFLASH_Write(fwaddr,iapbuf,1024);    
    40             fwaddr+=2048;//偏移2048  16=2*8.所以要乘以2.
    41         }
    42     }
    43     if(i)STMFLASH_Write(fwaddr,iapbuf,i);//将最后的一些内容字节写进去.  
    44 }
    45 
    46 //跳转到应用程序段
    47 //appxaddr:用户代码起始地址.
    48 void iap_load_app(u32 appxaddr)
    49 {
    50     if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)    //检查栈顶地址是否合法.
    51     { 
    52         jump2app=(iapfun)*(vu32*)(appxaddr+4);        //用户代码区第二个字为程序开始地址(复位地址)        
    53         MSR_MSP(*(vu32*)appxaddr);                    //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
    54         jump2app();                                    //跳转到APP.
    55     }
    56 }         
    iap.c
      1 #include "stm32f10x.h"
      2 #include "stm32f10x_conf.h"
      3 #include "exti_interrupt.h"
      4 #include "usart_config.h" 
      5 #include "timer_config.h"  
      6 #include "key_config.h"       
      7 #include "sdspi_config.h"
      8 #include "Fatfs_config.h"
      9 #include "flashspi_config.h"
     10 #include "ff.h"
     11 #include "diskio.h"
     12 #include "iap.h"
     13 #include <stdio.h>
     14 #include <string.h>
     15 //#include "picture.h"
     16 
     17 //#define BmpHeadSize (54)
     18 FATFS fs;
     19 
     20 #ifdef __GNUC__
     21 /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     22  set to 'Yes') calls __io_putchar() */
     23 #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
     24 #else
     25   #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
     26 #endif /* __GNUC__ */
     27 
     28 static void Delay_ARMJISHU(__IO uint32_t nCount)
     29 {
     30   for (; nCount != 0; nCount--);
     31 }
     32 
     33 extern u8 USART_RX_BUF[];     //接收缓冲,最大USART_REC_LEN个字节.
     34 extern u16 USART_RX_CNT;
     35 //接收状态
     36 //bit15,    接收完成标志
     37 //bit14,    接收到0x0d
     38 //bit13~0,    接收到的有效字节数目
     39 extern u16 USART_RX_STA; 
     40 /**
     41   * @brief  Main program.
     42   * @param  None
     43   * @retval None
     44   */
     45 
     46 int main(void)
     47 {
     48          u8 len,t;
     49          u8 key;
     50          u16 oldcount=0;    //老的串口接收数据值
     51          u16 applenth=0;    //接收到的app代码长度
     52          u8 clearflag=0;
     53         
     54          /* 延时初始化 */
     55          delay_init();
     56 
     57          /* 串口设置 */
     58 //         Usart1_Config();
     59          Usart2_Config();
     60          USART_SendData(USART2,0x55);
     61          while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
     62          printf("english\r\n");
     63          printf("中文测试\r\n");
     64 
     65          /* 按键中断设置设置 */
     66          Key_Config();
     67 //         KEY_EXIT_Init();
     68 //         Key_NVIC_Config();     
     69 
     70    
     71 //         disk_initialize(0);
     72 //         printf("\n\r f_mount %d\r\n", f_mount(0, &fs));
     73 //         mf_scan_files("0:");
     74 
     75 //        printf("\r\n将要进入主程序while:\r\n\r\n");
     76          while(1)
     77          {     
     78 
     79                if(USART_RX_CNT)
     80             {
     81                 if(oldcount==USART_RX_CNT)//新周期内,没有收到任何数据,认为本次数据接收完成.
     82                 {
     83                     applenth=USART_RX_CNT;
     84                     oldcount=0;
     85                     USART_RX_CNT=0;
     86                     printf("用户程序接收完成!\r\n");
     87                     printf("代码长度:%dBytes\r\n",applenth);
     88                 }else oldcount=USART_RX_CNT;            
     89             }
     90 
     91             delay_ms(10);
     92 
     93             key=KEY_Scan();
     94             if(key==KEY1)
     95             {
     96                 printf("KEY1!!\r\n");
     97                 if(applenth)
     98                 {
     99                     printf("开始更新固件...\r\n");    
    100 //                    LCD_ShowString(60,210,200,16,16,"Copying APP2FLASH...");
    101                      if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
    102                     {     
    103                         iap_write_appbin(FLASH_APP1_ADDR,USART_RX_BUF,applenth);//更新FLASH代码   
    104                         delay_ms(100);
    105 //                        LCD_ShowString(60,210,200,16,16,"Copy APP Successed!!");
    106                         printf("固件更新完成!\r\n");    
    107                     }else 
    108                     {
    109 //                        LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!  ");       
    110                         printf("非FLASH应用程序!\r\n");
    111                     }
    112                  }
    113                 else 
    114                 {
    115                     printf("没有可以更新的固件!\r\n");
    116 //                    LCD_ShowString(60,210,200,16,16,"No APP!");    
    117                 }
    118                 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示                                     
    119             }
    120             
    121             if(key==KEY2)
    122             {
    123                 printf("KEY2!!\r\n");
    124                 if(applenth)
    125                 {                                                                     
    126                     printf("固件清除完成!\r\n");    
    127 //                    LCD_ShowString(60,210,200,16,16,"APP Erase Successed!");
    128                     applenth=0;
    129                 }else 
    130                 {
    131                     printf("没有可以清除的固件!\r\n");
    132 //                    LCD_ShowString(60,210,200,16,16,"No APP!");
    133                 }
    134                 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示                                     
    135             }
    136             if(key==KEY3)
    137             {
    138                 printf("开始执行FLASH用户代码!!\r\n");
    139                 if(((*(vu32*)(FLASH_APP1_ADDR+4))&0xFF000000)==0x08000000)//判断是否为0X08XXXXXX.
    140                 {     
    141                     iap_load_app(FLASH_APP1_ADDR);//执行FLASH APP代码
    142                 }else 
    143                 {
    144                     printf("非FLASH应用程序,无法执行!\r\n");
    145 //                    LCD_ShowString(60,210,200,16,16,"Illegal FLASH APP!");       
    146                 }                                     
    147                 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示      
    148             }
    149             if(key==KEY4)
    150             {
    151                 printf("开始执行SRAM用户代码!!\r\n");
    152                 if(((*(vu32*)(0X20001000+4))&0xFF000000)==0x20000000)//判断是否为0X20XXXXXX.
    153                 {     
    154                     iap_load_app(0X20001000);//SRAM地址
    155                 }else 
    156                 {
    157                     printf("非SRAM应用程序,无法执行!\r\n");
    158 //                    LCD_ShowString(60,210,200,16,16,"Illegal SRAM APP!");       
    159                 }                                     
    160                 clearflag=7;//标志更新了显示,并且设置7*300ms后清除显示     
    161             }                   
    162                  
    163           }          
    164 
    165 
    166          
    167 }
    168 
    169 /**
    170   * @brief  Retargets the C library printf function to the USART.
    171   * @param  None
    172   * @retval None
    173   */
    174 PUTCHAR_PROTOTYPE
    175 {
    176   /* Place your implementation of fputc here */
    177   /* e.g. write a character to the USART */
    178 //  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
    179 //  {}
    180 //
    181 //  USART_SendData(USART1, (uint8_t) ch);
    182 
    183   while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
    184   {}
    185 
    186   USART_SendData(USART2, (uint8_t) ch);
    187 
    188   /* Loop until the end of transmission */
    189 //  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
    190 //  {}
    191 
    192   return ch;
    193 }
    194 
    195 
    196 #ifdef  USE_FULL_ASSERT
    197 
    198 /**
    199   * @brief  Reports the name of the source file and the source line number
    200   *   where the assert_param error has occurred.
    201   * @param  file: pointer to the source file name
    202   * @param  line: assert_param error line source number
    203   * @retval None
    204   */
    205 void assert_failed(uint8_t* file, uint32_t line)
    206 { 
    207   /* User can add his own implementation to report the file name and line number,
    208      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    209 
    210   /* Infinite loop */
    211   while (1)
    212   {
    213   }
    214 }
    215 #endif
    216 
    217 /**
    218   * @}
    219   */
    220 
    221 
    222 /******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/
    main

    我们把程序自己写入片上flash,还需要一些函数

      1 #include "stm32f10x.h"
      2 #include "stm32f10x_gpio.h"
      3 #include "stm32f10x_rcc.h"
      4 #include "stm32f10x_rtc.h"
      5 #include "stmflash_config.h"
      6 #include "systick_config.h"
      7 
      8 //读取指定地址的半字(16位数据)
      9 //faddr:读地址(此地址必须为2的倍数!!)
     10 //返回值:对应数据.
     11 u16 STMFLASH_ReadHalfWord(u32 faddr)
     12 {
     13     return *(vu16*)faddr; 
     14 }
     15 
     16 #if STM32_FLASH_WREN    //如果使能了写   
     17 //不检查的写入
     18 //WriteAddr:起始地址
     19 //pBuffer:数据指针
     20 //NumToWrite:半字(16位)数   
     21 void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   
     22 {                       
     23     u16 i;
     24     for(i=0;i<NumToWrite;i++)
     25     {
     26         FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
     27         WriteAddr+=2;//地址增加2.
     28     }  
     29 }
     30 
     31 //从指定地址开始写入指定长度的数据
     32 //WriteAddr:起始地址(此地址必须为2的倍数!!)
     33 //pBuffer:数据指针
     34 //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
     35 #if STM32_FLASH_SIZE<256
     36 #define STM_SECTOR_SIZE 1024 //字节
     37 #else 
     38 #define STM_SECTOR_SIZE    2048
     39 #endif         
     40 u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
     41 void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)    
     42 {
     43     u32 secpos;       //扇区地址
     44     u16 secoff;       //扇区内偏移地址(16位字计算)
     45     u16 secremain; //扇区内剩余地址(16位字计算)       
     46      u16 i;    
     47     u32 offaddr;   //去掉0X08000000后的地址
     48     if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
     49     FLASH_Unlock();                        //解锁
     50     offaddr=WriteAddr-STM32_FLASH_BASE;        //实际偏移地址.
     51     secpos=offaddr/STM_SECTOR_SIZE;            //扇区地址  0~127 for STM32F103RBT6
     52     secoff=(offaddr%STM_SECTOR_SIZE)/2;        //在扇区内的偏移(2个字节为基本单位.)
     53     secremain=STM_SECTOR_SIZE/2-secoff;        //扇区剩余空间大小   
     54     if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围
     55     while(1) 
     56     {    
     57         STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
     58         for(i=0;i<secremain;i++)//校验数据
     59         {
     60             if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除        
     61         }
     62         if(i<secremain)//需要擦除
     63         {
     64             FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
     65             for(i=0;i<secremain;i++)//复制
     66             {
     67                 STMFLASH_BUF[i+secoff]=pBuffer[i];      
     68             }
     69             STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
     70         }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.                    
     71         if(NumToWrite==secremain)break;//写入结束了
     72         else//写入未结束
     73         {
     74             secpos++;                //扇区地址增1
     75             secoff=0;                //偏移位置为0      
     76                pBuffer+=secremain;      //指针偏移
     77             WriteAddr+=secremain;    //写地址偏移       
     78                NumToWrite-=secremain;    //字节(16位)数递减
     79             if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
     80             else secremain=NumToWrite;//下一个扇区可以写完了
     81         }     
     82     };    
     83     FLASH_Lock();//上锁
     84 }
     85 #endif
     86 
     87 
     88 //从指定地址开始读出指定长度的数据
     89 //ReadAddr:起始地址
     90 //pBuffer:数据指针
     91 //NumToWrite:半字(16位)数
     92 void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)       
     93 {
     94     u16 i;
     95     for(i=0;i<NumToRead;i++)
     96     {
     97         pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
     98         ReadAddr+=2;//偏移2个字节.    
     99     }
    100 }
    stmflash_config.c

    主要就是在iap里面用了void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)

    下一步计划:从SD卡更新

    通过SD卡更新app搞定,写了一个新函数在iap.c当中

     1 // 从SD卡更新bin到片内Flash
     2 // appxaddr:片内Flash的起始地址
     3 //     fxpath:bin在SD的路径
     4 u8 update_app(u32 appxaddr,u8 *fxpath)
     5 {
     6     u32 tempaddr=appxaddr;//当前写入的地址
     7     FIL * fftemp;
     8     u8 *tempbuf;
     9      u8 res;    
    10     u16 bread;
    11     u8 rval;
    12 
    13     fftemp=(FIL*)mymalloc(SRAMIN,sizeof(FIL));    //分配内存    
    14     if(fftemp==NULL)rval=1;
    15     tempbuf=mymalloc(SRAMIN,4096);    //分配4096个字节空间
    16     if(tempbuf==NULL)rval=1;
    17 
    18     res=f_open(fftemp,(const TCHAR*)fxpath,FA_READ); 
    19     while(res==FR_OK)//死循环执行
    20     {
    21          res=f_read(fftemp,tempbuf,4096,(UINT *)&bread);        //读取数据     
    22         if(res!=FR_OK)break;                     //执行错误
    23         iap_write_appbin(tempaddr,tempbuf, bread);
    24         tempaddr+=bread;                                   
    25         if(bread!=4096)break;                                //读完了.
    26      }     
    27     f_close(fftemp);
    28     
    29     return rval;    
    30 }
    update_app

    思路很简单,从SD文件系统读出文件,每次4k,写入片内flash

  • 相关阅读:
    error: device not found
    RK3288 查看时钟树
    GPS数据包格式解析
    Android 操作文件系统失败: Read-only file system
    Ubuntu 14.04 配置安卓5.1编译环境
    升级 php composer 版本
    清理 laravel blade 模板缓存
    Laravel collection 报错 join(): Invalid arguments passed
    Laravel firstOrNew 与 firstOrCreate 的区别
    执行 crontab 的计划任务
  • 原文地址:https://www.cnblogs.com/wwjdwy/p/3080292.html
Copyright © 2011-2022 走看看