OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3703|回复: 4

分享一种裸机平台下独立模块的加载实现方法

[复制链接]

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2020-12-30 16:23:56 | 显示全部楼层 |阅读模式
本帖最后由 ufbycd 于 2020-12-30 16:56 编辑

灵感来源于一个帖子 。
需求是一个固件分成两个部分,这里分别叫APP和Module,APP可以单独独立运行,Module可以随时加入或修改,Module不能单独运行而是APP的功能扩展; APP和Module分开单独编译,单独烧录。
看上去有点像Linux内核和RT-Thread的动态模块,但动态模块有点复杂,模块加载时需要在目标平台上做链接操作,不容易实现。
后面再细想,这个需求其实不是动态模块,因为模块不一定要加载到内存,而可以保留在固定的Flash区域。所以我把它叫做静态模块,后来在空余时间把这个灵感实现了。

软件架构说明
  • APP和Module的Flash和SRAM空间各自分开并且固定排布,Module空间位于APP空间之后并紧密相连;
  • APP和Mouule都有常规的中断向量表,并且都位于各自FLASH的起始地址;
  • APP的中断向量表是芯片的入口,而Module的中断向量表由APP调用;
  • APP和Module都各自维护一张公开的函数向量表:APP_Vector_t、Module_Vector_t;跨区域的函数调用即是通过函数向量表内的函数指针实现;
  • Module的Reset_Handler由于不是芯片的入口,所以可以修改其原型;APP在调用Module的Reset_Handler时获取Module的函数向量表并告知APP的函数向量表;此时APP和Module都获取得到对方的函数向量表,两者也就连接起来了。

有兴趣的同学可以参见项目源码:https://gitee.com/ufbycd/static_module
里面有更详细的说明。

欢迎提交 Pull Request,共同改进。

目前整体架构已验证通过,运行时串口调试信息输出如下:
  1. MStdio Init
  2. NRST Pin Reset!
  3. APP:
  4. Version: bc74f2c-202012301355
  5. Build  : 2020-12-30 13:55:46
  6. Config : Debug

  7. shell>Static module loaded.
  8. Module:
  9. Version: bc74f2c-202012301358
  10. Build  : 2020-12-30 13:58:05
  11. Config : Debug
复制代码





正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
 楼主| 发表于 2021-1-1 13:04:50 | 显示全部楼层
本帖最后由 ufbycd 于 2021-1-1 16:08 编辑

更新:添加Module的中断服务处理

Module的中断处理函数的进入
    为了在Module内灵活使用(APP未占用的)外设资源,需要处理Module的中断服务。而Module的中断向量表并不是芯片的入口而由APP调用,那么就需要从APP的中断向量表跳转到Module的中断向量表。
在APP的中断向量表内,未使用的中断服务其实都是Default_Handler的别名(并且都是弱(weak)符号)。而APP未使用的中断有可能会被Module使用;所以只要修改APP的Default_Handler,使其跳转到Module那边就行了。本项目的APP的Default_Handler实现如下:
  1. void __attribute__ ((weak)) Default_Handler(void)
  2. {
  3.     typedef void (* IrqHandler_t)(void);
  4.     extern unsigned int _eflash;     // 来自链接脚本,指向Flash末尾
  5.     uint32_t isrNum;
  6.     IrqHandler_t *moduleIsrVector;
  7.     IrqHandler_t handler;

  8.     if(Main_IsModuleLoaded())
  9.     {
  10.         moduleIsrVector = (IrqHandler_t *) & _eflash;
  11.         isrNum = __get_IPSR();
  12.         handler = moduleIsrVector[isrNum];
  13.         handler();
  14.     }
  15.     else
  16.     {
  17.         __DEBUG_BKPT();
  18.         while(1);
  19.     }
  20. }
复制代码
  • 其中_eflash定义于链接脚本,其值指向APP的Flash空间的末尾即Module的Flash的起始亦即Module的中断向量表。
  • Default_Handler的主要工作为:当Module已经载入时,获取当前的中断号并直接跳转到Module的中断服务函数;当Module未载入时,则进行常规处理,进入死循环。
目前测试了在Module使用硬件定时器6,中断频率为10Hz、每计时2秒打印一条信息,运行时的调试串口输出如下:
  1. MStdio Init
  2. Software Reset
  3. APP:
  4. Version: 5d31203-202101011115
  5. Build  : 2021-01-01 11:15:34
  6. Config : Debug

  7. shell>Static module loading...
  8. Module:
  9. Version: 5d31203-202101011106
  10. Build  : 2021-01-01 11:06:11
  11. Config : Debug
  12. .data test: 123
  13. Module: Stimer Tick: 20
  14. Module: Stimer Tick: 40
  15. Module: Stimer Tick: 60
复制代码




回复 支持 反对

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
 楼主| 发表于 2021-1-3 19:41:11 | 显示全部楼层
APP和Module可以同时调试,调试方法参见这个帖子
回复 支持 反对

使用道具 举报

56

主题

343

帖子

0

精华

高级会员

Rank: 4

积分
977
金钱
977
注册时间
2016-3-8
在线时间
267 小时
发表于 2021-1-5 22:47:56 | 显示全部楼层
好想法,之前也设想过,是不是可以把功能做成一个个小模块,需要什么烧什么。更新只要用bootloader烧小模块程序和新的APP程序就行。已经做好的模块程序可以不用动。。不然一点小改动都要更新整个程序费时。
回复 支持 反对

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
 楼主| 发表于 2021-1-6 19:16:03 | 显示全部楼层
pdwdzz 发表于 2021-1-5 22:47
好想法,之前也设想过,是不是可以把功能做成一个个小模块,需要什么烧什么。更新只要用bootloader烧小模块 ...

是的,不同的模块就是不同的工程,单独编译、单独烧录。好处有多个:
  • 有利于减小IAP更新的固件大小;
  • 有利于多人项目的分工;
  • 也可以实现闭源项目的二次开发:APP为闭源,在Module上做二次开发。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-3-1 04:55

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表