本帖最后由 Simon21ic 于 2015-8-23 12:20 编辑
然并卵系列之一是动态加载,cortexM上,实现对应用程序的动态加载,应用程序开发的时候,可以选择cortexM0,而不用选择特定的芯片。
对了,然并卵系列,只讲一些可以玩玩,但是没太大用处的技术。
能够实现这个后,可以继续开大脑洞,系统的各个模块都适用动态加载的方式。
系统只需要具备VSF的核心构架,多任务和事件驱动,通用接口的处理器驱动,bootloader。
然后,系统以外的flash的第一块用于配置flash中的哪些位置有需要载入的模块。
系统启动后,就一一载入各个模块。模块间使用接口来通信。
这么实现的模块化,就不仅仅是C代码的一个模块,模块已经被当作一个独立工程编译了。
想到之前IAR发律师函,为啥不把模块分好,每个模块小于32K,IAR不就是免费的了?
上一个简单的模块代码吧。
- struct vsfapp_t
- {
- struct vsf_module_t module;
- struct led_ifs_t ifs;
- };
- static vsf_err_t led_init(struct led_t *led)
- {
- struct led_hw_t const *hwled = led->hw;
-
- led->on = false;
- core_interfaces.gpio.init(hwled->lport);
- core_interfaces.gpio.clear(hwled->lport, 1 << hwled->lpin);
- core_interfaces.gpio.config_pin(hwled->lport, hwled->lpin,
- core_interfaces.gpio.constants.OUTPP);
- core_interfaces.gpio.init(hwled->hport);
- core_interfaces.gpio.clear(hwled->hport, 1 << hwled->hpin);
- core_interfaces.gpio.config_pin(hwled->hport, hwled->hpin,
- core_interfaces.gpio.constants.OUTPP);
- return VSFERR_NONE;
- }
- static vsf_err_t led_on(struct led_t *led)
- {
- return core_interfaces.gpio.set(led->hw->hport, 1 << led->hw->hpin);
- }
- static vsf_err_t led_off(struct led_t *led)
- {
- return core_interfaces.gpio.clear(led->hw->hport, 1 << led->hw->hpin);
- }
- static bool led_is_on(struct led_t *led)
- {
- return led->on;
- }
- vsf_err_t __iar_program_start(struct app_hwcfg_t const *hwcfg)
- {
- struct vsfapp_t *app;
-
- // check board and api version
- if (strcmp(hwcfg->board, APP_BOARD_NAME) ||
- (vsf_api_ver != VSF_API_VERSION))
- {
- return VSFERR_NOT_SUPPORT;
- }
-
- app = vsf_bufmgr_malloc(sizeof(struct vsfapp_t));
- if (NULL == app)
- {
- return VSFERR_NOT_ENOUGH_RESOURCES;
- }
-
- memset(app, 0, sizeof(*app));
-
- app->ifs.init = led_init;
- app->ifs.on = led_on;
- app->ifs.off = led_off;
- app->ifs.is_on = led_is_on;
- app->module.ifs = &app->ifs;
- app->module.name = "led";
- return vsf_module_load(&app->module);
- }
这里,程序入口不是main,而是__iar_program_start,编译器不会加入C的一些初始化代码,也不会加入芯片的中断向量。当然,ropi是必须的。
__iar_program_start传入一个硬件配置文件,程序先检测硬件配置文件是否是自己可以运行的板子,并且检查系统API版本是否和自己用的一致。
之后就动态分配自己需要的内存,并且初始化,注册自己的模块(模块中,有接口的指针)。
其他模块或者应用可以查找这个模块,得到接口,然后调用模块中的功能。其他模块如果需要led模块,但是led模块还没有注册的话,可以使用模块的回调接口:
- // get led_module
- led_mod = vsf_module_get("led");
- if (NULL == led_mod)
- {
- app->app_mod.name = "app";
- app->app_mod.callback.on_load = app_on_load;
- return VSFERR_NONE;
- }
- app_on_load(&app->app_mod, led_mod);
- return VSFERR_NONE;
- }
这里,没有得到led模块,就注册app模块,设置on_load接口,之后系统载入模块的时候,都会调用on_load。这样也就用简单的方式,解决模块依赖性问题。
另外,这里,模块调用的系统函数,一直想不到好的方法解决,就只是把接口放在中断向量后,0x200的位置,希望大部分cortexM这里都可以用吧。
和动态加载一样,由于CortexM并不具备MMU,这种设计方式,并没有什么用。
可能如果程序规模大于32K,可以用这种方式分割成各个小模块,让IAR永久免费吧。
|