stm32 IAP

硬件平台 : STM32f407ZGT6 , 1024K flash, 128K ram

# stm32 IAP

# mtdparts
 No.     name                     range                   size
 1    bootloader         0x08000000 ~ 0x08010000         0x10000 (64K)
 2    application        0x08010000 ~ 0x08100000         0xF0000 (960K)


# bootloader

```
typedef  void (* start_kernel_t)(void);

#define REG32_READ(addr)    (*(volatile u32 *)((u32)(addr)))

start_kernel_t start_kernel;

//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr) 
{
    MSR MSP, r0             //set Main Stack value
    BX r14
}


void load_kernel(u32 addr)
{
    if((REG32_READ(addr) & 0x2FFE0000) == 0x20000000)    //检查栈顶地址是否合法.
    { 
        start_kernel = (start_kernel_t)(REG32_READ(addr + 4));        //用户代码区第二个字为程序开始地址(复位地址)    
        
        MSR_MSP(REG32_READ(addr));                    //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
        
        /*
        * now, start the application we have
        */
        start_kernel();                                //
    }
}


#ifdef USE_CLI
static void do_load (u32 addr)
{
    printf("addr : %08x \r\n", addr);
    
    load_kernel(addr);
}


REGISTER_CMD(
    load,
    2,
    ARG_TYPE_U32,
    do_load,
    " load the kernel"
);

#endif

```

# application

```
LR_IROM1 0x08010000 0x000F0000  {    ; load region size_region
  ER_IROM1 0x08010000 0x000F0000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  CMDREG +0
  {
    .ANY(cmd)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

```

keil设置

misc controls :
--keep=strcmd_*


R/O Base : 0x08010000
R/W Base : 0x20000000


IROM1 : 0x08010000 , 0xF0000

After Build/Rebuild :           // not neccessary
D:\ProgramFiles\Keil5\ARM\ARMCC\bin\fromelf.exe --bin -o Objects\EVA.bin Objects\EVA.axf

 


then 


void main()
{
    ...
    SCB->VTOR = FLASH_BASE | 0x10000;
    ...
    
    while(1)
    {
        ...
    }
}

# 总结

以上可以实现IAP,但是关于bootloader和application的堆栈没有搞清楚

下面来总结

# bootloader

keil:  Program Size: Code=8216 RO-data=960 RW-data=72 ZI-data=3880  

在map文件里面:

```
    Total RO  Size (Code + RO Data)                 9176 (   8.96kB)
    Total RW  Size (RW Data + ZI Data)              3952 (   3.86kB)
    Total ROM Size (Code + RO Data + RW Data)       9248 (   9.03kB)
```

flash base  = 0x08000000
sram base   = 0x20000000

其中 : ROM = Code + RO Data + RW Data = 9284
RAM是多少呢?
        RAM = RW-data + ZI-data = 3880 + 72   = 3952(0xF70)
        
其中ROM存在 flash里面,即基地址0x08000000, 大小0x100000 (1024K)
    RAM存在 SRAM里面, 其基地址0x20000000, 大小 0x20000 (128K)    

STACK size = 0x400 , 在startup_stm32f40_41xxx.s文件开头指定, 而arm一般栈向下增长,即SP(MSP) =     0xF70
这点可以在keil进debug模式看到MSP的值MSP = 0x20000F70,与上面分析一致。

对于application,由于这里选用与bootloader一样的程序,其map

```
    Total RO  Size (Code + RO Data)                 9248 (   9.03kB)
    Total RW  Size (RW Data + ZI Data)              3952 (   3.86kB)
    Total ROM Size (Code + RO Data + RW Data)       9324 (   9.11kB)
```

SRAM = RW Data + ZI-data = 76 + 3876 = 3952(F70)

也即,启动application后,原来bootloader的栈会完全被application覆盖;这个并没有问题。


#优化栈(重新分配)

 No.     name                     stack                   size
 1    bootloader         0x20000000 ~ 0x20008000         0x8000 (32K)
 2    application        0x20008000 ~ 0x20020000         0x18000 (96K)

栈的地址和大小分配,需要在keil里面设置,有必要时需要在xxx.sct  (即分散存储脚本)
这样的化,将bootloader和application的栈区分开。

# bootloader sct

```
LR_IROM1 0x08000000 0x00100000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  CMDREG +0
  {
    .ANY(cmd)
  }
  RW_IRAM1 0x20000000 0x00008000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
```

# application sct

```
LR_IROM1 0x08010000 0x000F0000  {    ; load region size_region
  ER_IROM1 0x08010000 0x000F0000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  CMDREG +0
  {
    .ANY(cmd)
  }
  RW_IRAM1 0x20008000 0x00018000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
```

ymodem升级

stm32 IAP_第1张图片

其中一个串口作为调试,用来启动ymodem传输,另一个ymodem使用的串口

调试串口里面输入req命令启动ymodem传输

stm32 IAP_第2张图片

ymodem端串口接收到C后会发送数据

最后在调试串口执行load 0x08010000,启动app

stm32 IAP_第3张图片

 

可以看到新程序启动

 

 

你可能感兴趣的:(STM32)