Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5567824
  • 博文数量: 1310
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 15646
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1310)

文章存档

2020年(92)

2019年(193)

2018年(81)

2017年(80)

2016年(70)

2015年(52)

2014年(41)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: 其他平台

2019-12-11 20:07:44

M451系列中. IAP允许ROM中存在几个程序, 可以相互调用. 
步骤一 . 首先开启 IAP.
    需要启用CONFIG0的CBS位,
        设置为 10b为 APROM启动并使能 IAP
        设置为 00b为 APROM启动并使能 IAP
    启用方式: 代码: 

点击(此处)折叠或打开

  1. /*
  2. 确保 IAP function is enabled. 我们需要使用 IAP APROM 功能
  3. */
  4. static int set_iap_aprom_boot(void)
  5. {
  6.     uint32_t au32Config[2];
  7.     
  8.     //read current boot mode
  9.     FMC_ReadConfig(au32Config, 2);
  10.     { //我们需要的是 10b(IAP APROM) b00是 IAP LDROM
  11.         if((au32Config[0] & 0xc0) != 0x80) //如果不是 10b(IAP APROM)
  12.         {
  13.             FMC_EnableConfigUpdate(); /* Enable user configuration update */
  14.             /* Set CBS to b
或者直接使用Keil的工具, 或者官方的ICP工具. 


步骤二:
    编辑各个共存的应用, 主要是进行flash布局, 然后编译应用到指定的flash地址上.

保存编译后, 可以看到 objects/ **.sct 链接脚本的内容和上图的设置是一样的.
点击download即可把应用烧录到flash的start地址上.

步骤三:  调用flash的某个应用上.

点击(此处)折叠或打开

  1. void reset_firmware_valid(uint32_t flash_addr)
  2. {
  3.     /* Mask all interrupt before changing VECMAP to avoid wrong interrupt handler fetched */
  4.     __set_PRIMASK(1);
  5.     FMC_SetVectorPageAddr(flash_addr);
  6.     __set_PRIMASK(0);
  7.         
  8.     NVIC_SystemReset();
  9.     while (1);
  10. }
这种方式的好处是: 如果在一块板子上有很多种功能, 那么使用此方式, 可以随时切换功能.
缺点是: 要预先进行flash布局, 而且某个功能应用是和flash地址紧密耦合的.
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
展开一下, 如果用于升级的时候, 要怎么办呢?
想法:
1. 使能IAP, APROM引导 bootloader应用.
2. 读取flash的自定义配置区, 查看是否需要更新APROM, (即备份区的内容是否已经更新到APP的flash地址上), 如果有更新, 则把备份区内容写到APP的flash地址上.
3. 调用 App的flash地址.
参考范例. USBHUB_VBATOUT.rar
目前的问题是: 在Ymodem升级之后, 发现主控板不能主动刷新枚举USB VCP设备. 可以通过重新硬复位M451或者重新拔插板子所在的USB连接线, 或者重启主控板才能重新识别到VCOM设备.
可参考的建议: 试过 都没有什么用处啊, 所以最终的方案可以是<在线升级, 成功后. 主控板重启>, 后面看看主控板端是否有方法进行设备重新枚举.
1.  https://blog.csdn.net/zhanglifu3601881/article/details/90645559
2.

注意的是:
1. 首先确认flash的布局

点击(此处)折叠或打开

  1. /*
  2. Flash 布局: 128KB.
  3. * 引导区 bootload : 16K 0x00000 -> 0x04000 size: 4000
  4. * 自定义 custom: 2K 0x04000 -> 0x04800 size: 800
  5. * 应用区 app: 55K 0x04800 -> 0x13800 size: DC00
  6. * 升级区 update: 55K 0x12400 -> 0x20000 size: DC00
  7. */
  8. #define NDADDR_BOOTLOAD 0x00000 //FMC_APROM_BASE
  9. #define NDADDR_FACTORY 0x04000
  10. #define NDADDR_APP 0x04800
  11. #define NDADDR_BAK 0x12400
  12. #define FW_MAX_SIZE             0xDC00 //55KB

那么 bootloader的内容.

点击(此处)折叠或打开

  1. void SYS_Init(void)
  2. {
  3. ////先启用内部晶振, 等待期稳定起来.
  4.     CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
  5.     /* Enable Internal RC 22.1184MHz clock */
  6.     /* Waiting for Internal RC clock ready */
  7.     CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
  8.     /* Switch HCLK clock source to Internal RC and set HCLK divider to 1 */
  9.     CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1));

  10. ////启用外部晶振, 等待期稳定起来.
  11.     /* Enable external XTAL 12MHz clock */
  12.     CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);
  13.     /* Waiting for external XTAL clock ready */
  14.     CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);

  15.     /* Set core clock */
  16.     CLK_SetCoreClock(72000000);
  17.     /* Set Flash Access Delay */
  18.     FMC->FTCTL |= FMC_FTCTL_FOM_Msk;
  19. }
  20. uint32_t FLASH_Erase_FW_Page(uint32_t addr, uint32_t page_cnt)
  21. {
  22.     uint32_t iResult = 0;

  23.     uint32_t EraseCounter = 0x0;
  24.     for (EraseCounter = 0; (EraseCounter < page_cnt); EraseCounter++)
  25.     {
  26.         iResult = FMC_Erase(addr + (FMC_FLASH_PAGE_SIZE * EraseCounter));
  27.         if (iResult != 0)
  28.             return 0;
  29.     }
  30.     return EraseCounter;
  31. }

  32. uint32_t FLASH_ProgramWord(uint32_t oft, uint32_t data)
  33. {
  34.     FMC_Write(oft, data);
  35.     if (FMC_Read(oft) != data)
  36.         return 0;

  37.     return 1;
  38. }

  39. uint32_t FLASH_PageCopy(uint32_t addr_src, uint32_t addr_dst)
  40. {
  41.     uint32_t data, idx, verify;
  42.     for (idx = 0; idx < FMC_FLASH_PAGE_SIZE; idx+=4) {
  43.         data = FMC_Read(addr_src+idx);
  44.         FMC_Write(addr_dst+idx, data);
  45.         
  46.         verify = FMC_Read(addr_dst+idx);
  47.         if (verify != data) {
  48.             return 0;
  49.         }
  50.     }
  51.     return 1;
  52. }

  53. void update_fw_data(uint32_t page_cnt)
  54. {
  55.     uint32_t src_addr = NDADDR_BAK;
  56.     uint32_t dst_addr = NDADDR_APP;
  57.     uint32_t idx = 0;
  58.     
  59.     FLASH_Erase_FW_Page(dst_addr, page_cnt);
  60.     for (idx = 0; idx < page_cnt; idx++) {
  61.         FLASH_PageCopy(src_addr+FMC_FLASH_PAGE_SIZE*idx, dst_addr+FMC_FLASH_PAGE_SIZE*idx);
  62.     }
  63. }

  64. void update_fw_config_area(void)
  65. {
  66.     uint8_t cfg[FMC_FLASH_PAGE_SIZE];
  67.     uint32_t data, idx;
  68.     uint32_t *pData;
  69.     for (idx = 0; idx < FMC_FLASH_PAGE_SIZE; idx+=4) {
  70.         data = FMC_Read(NDADDR_FACTORY+idx);
  71.         pData = (uint32_t *)(&cfg[idx]);
  72.         *pData = data;
  73.     }
  74.     FLASH_Erase_FW_Page(NDADDR_FACTORY, 1);
  75.     
  76.     *(uint32_t *)(cfg) = 0x0ul;
  77.     *(uint32_t *)(cfg+4) = 0x0ul;
  78.     for (idx = 0; idx < FMC_FLASH_PAGE_SIZE; idx+=4) {
  79.         pData = (uint32_t *)(&cfg[idx]);
  80.         data = *pData;
  81.         FLASH_ProgramWord(NDADDR_FACTORY+idx, data);
  82.     }
  83. }
  84. int32_t main(void)
  85. {
  86.     /* Unlock protected registers */
  87.     SYS_UnlockReg();
  88.     SYS_Init();
  89.     /* Enable FMC ISP function */
  90.     FMC_Open();
  91.         
  92.     FMC_ENABLE_AP_UPDATE();
  93.        
  94.     fw_update_info_t info = {0};
  95.     info.fw_addr = FMC_Read(NDADDR_FACTORY);
  96.     info.page_cnt = FMC_Read(NDADDR_FACTORY + 4);
  97.     if ((info.fw_addr == NDADDR_BAK) && (info.page_cnt > 0x0ul))
  98.     {
  99.         update_fw_data(info.page_cnt);
  100.         update_fw_config_area();
  101.     }
  102.     
  103.     FMC_DISABLE_AP_UPDATE();
  104.     
  105.     /* Mask all interrupt before changing VECMAP to avoid wrong interrupt handler fetched */
  106.     __set_PRIMASK(1);
  107.     /* Change VECMAP for booting to APROM */
  108.     FMC_SetVectorPageAddr(NDADDR_APP);
  109.     /* Lock protected Register */
  110.     SYS_LockReg();

  111.     /* Software reset to boot to APROM */
  112.     NVIC_SystemReset();
  113.     while (1);
  114. }
配置内容


说明: 1. 确认为 IAP APROM启动.  因为重新不久后再用Keil debug 调试时可能当前的中断向量时不再0 , 所以设置硬复位调试才能走到 main 函数. 另外可以适当调整 栈大小. 而且因为是bootloader, 所有设置此工程的编译对应位置为0x00;

2. 编译应用程序.

3.
   然后在线升级BIN固件文件, (注意固件文件是按照步骤2, 即上图设置的地址编译的固件文件 BIN)



阅读(234) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~