本帖最后由 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永久免费吧。
|