Static Module Demo
介绍
本项目在MCU(STM32)平台实现类似于Linux内核模块的动态加载功能,但不是将模块加载到内存(SRAM)而是加载到Flash。
所以叫做静态加载,而被加载的模块就叫静态模块。
软件架构
本演示项目有两个工程,分别是APP工程和Module工程。前者是常规应用工程,是芯片的入口;Module工程类似于静态库,不能单独运行而依赖于APP,但它编译生成的目标文件内所有符号均已链接。两个工程各自单独编译,烧录时也可以分开单独烧录。
软件架构说明
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时获取模块的函数向量表并告知APP的函数向量表给模块;此时APP和Module都获取得到对方的函数向量表,两者也就连接起来了。
Module的主要接口
Module由于不是程序主体而只是功能的扩展,所以不能执行带有死循环的函数,也就不能执行Module里的main函数。(本项目的Module工程里没有main函数实现。)
Reset_Handler:位于中断向量表内,依然是Module的入口,但供APP调用;
init:位于函数向量表内,用于执行整体(全局变量、外设等)的初始化;
schedule: 位于函数向量表内,相当于不带死循环的main函数。
Module的Reset_Handler
常规的应用中,芯片复位时其程序入口为Reset_Handler。Reset_Handler要负责初始化C语言运行时环境(主要是DATA段及BSS段内变量的初始化)并调用main函数。
由于Module的Reset_Handler并不是芯片的入口而由APP调用,其实现就是整个架构的关键。本项目Module的Reset_Handler的实现如下:
void Reset_Handler(const APP_Vector_t *app, Module_Vector_t *module)
{
_initialize_data(& _sidata, & _sdata, & _edata);
_initialize_bss(& _sbss, & _ebss);
Module_SetAppVector(app);
Module_GetModuleVector(module);
}
其主要工作有两个:初始化DATA段、BSS段及跟APP交换函数向量表。函数向量表一但确定,跨区域的函数调用就畅通无阻了。
Module的中断处理函数的进入
为了在Module内灵活使用(APP未占用的)外设资源,需要处理Module的中断服务。而Module的中断向量表并不是芯片的入口而由APP调用,那么就需要从APP的中断向量表跳转到Module的中断向量表。
在APP的中断向量表内,未使用的中断服务其实都是Default_Handler的别名(并且都是弱(weak)符号)。而APP未使用的中断有可能会被Module使用;所以只要修改APP的Default_Handler,使其跳转到Module那边就行了。本项目的APP的Default_Handler实现如下:
void __attribute__ ((weak)) Default_Handler(void)
{
typedef void (* IrqHandler_t)(void);
extern unsigned int _eflash; // 来自链接脚本,指向Flash末尾
uint32_t isrNum;
IrqHandler_t *moduleIsrVector;
IrqHandler_t handler;
if(Main_IsModuleLoaded())
{
moduleIsrVector = (IrqHandler_t *) & _eflash;
isrNum = __get_IPSR();
handler = moduleIsrVector[isrNum];
handler();
}
else
{
__DEBUG_BKPT();
while(1);
}
}
其中_eflash定义于链接脚本,其值指向APP的Flash空间的末尾即Module的Flash的起始亦即Module的中断向量表。
Default_Handler的主要工作为:当Module已经载入时,获取当前的中断号并直接跳转到Module的中断服务函数;当Module未载入时,则进行常规处理,进入死循环。
使用说明
本项目基于STM32CubeIDE实现,硬件平台为NUCLEO-F446RE,即MCU为STM32F446RE。在IDE内很容易就可以切换到其他硬件平台。
APP和Module工程都包含一个跟git代码仓库挂钩的版本头文件version.h,这个文件是在编译时自动通过python脚本(version.py)生成的。所以要保证电脑内安装有python解释器才能通过编译。(PS:Linux和Windows 10已内置python)。
参与贡献
Fork 本仓库
新建 Feat_xxx 分支
提交代码
新建 Pull Request
特技
使用 Readme_XXX.md 来支持不同的语言,例如 Readme_en.md, Readme_zh.md
你可以 https://gitee.com/explore 这个地址来了解 Gitee 上的优秀开源项目
GVP 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 https://gitee.com/gitee-stars/