- #include "vsf.h"
- #include "app_hw_cfg.h"
- struct vsfapp_t
- {
- struct app_hwcfg_t hwcfg;
-
- uint8_t bufmgr_buffer[64 * 1024];
- } static app =
- {
- {
- {
- {
- 2, // uint8_t port;
- 13, // uint8_t pin;
- }, // struct usb_pullup;
- }, // struct usbd;
- {
- {3, 4, 3, 6},
- {4, 1, 4, 0},
- {3, 5, 3, 3},
- {3, 9, 3, 10},
- {4, 15, 3, 8},
- {4, 13, 4, 14},
- {4, 11, 4, 12},
- {4, 9, 4, 10},
- {4, 7, 4, 8},
- {3, 0, 3, 1},
- {3, 14, 3, 15},
- {6, 13, 6, 14},
- {4, 6, 4, 2},
- {4, 4, 4, 5},
- {3, 13, 4, 3},
- {3, 11, 3, 12},
- {6, 4, 6, 5},
- {6, 2, 6, 3},
- {6, 0, 6, 1},
- {5, 14, 5, 15},
- {5, 12, 6, 13},
- {5, 4, 5, 5},
- {5, 2, 5, 3},
- {5, 0, 5, 1},
- }, // struct led_t led[24];
- }, // struct app_hwcfg_t hwcfg;
- };
- // tickclk interrupt, simply call vsftimer_callback_int
- static void app_tickclk_callback_int(void *param)
- {
- vsftimer_callback_int();
- }
- int main(void)
- {
- int (*app_main)(const struct vsf_t *vsf, struct app_hwcfg_t *hwcfg) = NULL;
-
- vsf_leave_critical();
-
- // system initialize
- vsf_bufmgr_init(app.bufmgr_buffer, sizeof(app.bufmgr_buffer));
- core_interfaces.core.init(NULL);
- core_interfaces.tickclk.init();
- core_interfaces.tickclk.start();
- vsftimer_init();
- core_interfaces.tickclk.set_callback(app_tickclk_callback_int, NULL);
-
- // load and call application
- // TODO: try to load app_main address
- app_main = (int (*)(const struct vsf_t *vsf, struct app_hwcfg_t *hwcfg))0x08008000;
- if (app_main != NULL)
- {
- app_main(&vsf, &app.hwcfg);
- }
-
- while (1)
- {
- vsfsm_poll();
-
- vsf_enter_critical();
- if (!vsfsm_get_event_pending())
- {
- // sleep, will also enable interrupt
- core_interfaces.core.sleep(SLEEP_WFI);
- }
- else
- {
- vsf_leave_critical();
- }
- }
- }
应用层序只是做了系统初始化,包括系统初始化,定时器管理初始化,内存管理初始化后,就可以调用应用程序了,这里假定应用程序位于0x08008000的位置。当然,应用程序可以是多个,也可以不在内部flash里(这个就需要先把应用程序复制到内存中)。应用程序的第一个32位数据,是放应用程序用,main函数的偏移。应用中的main函数,参数为vsf和硬件配置。vsf提供了可以使用的系统的所有接口,包括访问硬件的接口,简单的定义如下:
- const struct vsf_t vsf =
- {
- &core_interfaces,
-
- {
- vsfsm_init,
- vsfsm_pt_init,
- vsfsm_post_evt,
- vsfsm_post_evt_pending,
- vsfsm_enter_critical_internal,
- vsfsm_leave_critical_internal,
- vsfsm_sem_init_internal,
- vsfsm_sem_post_internal,
- vsfsm_sem_pend_internal,
- vsfsm_crit_init_internal,
- vsfsm_crit_enter_internal,
- vsfsm_crit_leave_internal,
- vsftimer_register,
- vsftimer_unregister,
- }, // struct vsf_framework_t framework;
-
- {
- {
- vsf_fifo_init,
- vsf_fifo_push8,
- vsf_fifo_pop8,
- vsf_fifo_push,
- vsf_fifo_pop,
- vsf_fifo_get_data_length,
- vsf_fifo_get_avail_length,
- }, // struct fifo
- {
- vsf_bufmgr_malloc,
- vsf_bufmgr_malloc_aligned,
- vsf_bufmgr_free,
- }, // struct bufmgr;
- }, // struct buffer;
- };
当然,这个还只是测试的代码,很多协议栈的接口还都没放进去。
应用部分:
应用程序,只需要知道芯片是什么类型的,用来指定编译用的指令集。比如,本例程中芯片使用stm32,所以应用程序的工程可以选择CortexM3的芯片。当然,如果选择CortexM0,那就各种CortexM的处理器都可以兼容。简单的说就是硬件可以使用stm32f1,也可以用新塘的M0,或者atmel的M4,应用程序的二进制文件都不用修改。上代码吧:
- #include "vsf.h"
- #include "app_hw_cfg.h"
- #define LED_EVT_CARRY (VSFSM_EVT_USER_LOCAL + 0)
- struct vsfapp_t
- {
- struct
- {
- struct vsf_t const *vsf;
- } sys;
-
- struct vsfsm_t sm;
- struct vsftimer_timer_t timer;
-
- // Application
- uint8_t led_num;
- struct app_led_t
- {
- struct led_t const *hw;
- bool on;
-
- struct vsfsm_pt_t pt;
- struct vsfsm_t *sm_carry;
-
- struct vsfsm_t sm;
- struct vsfapp_t *app;
- } led[24];
- };
- static vsf_err_t app_led_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt)
- {
- struct app_led_t *led = (struct app_led_t *)pt->user_data;
- struct vsfapp_t *app = led->app;
- struct interfaces_info_t const *ifs = app->sys.vsf->ifs;
- struct vsf_framework_t const *framework = &app->sys.vsf->framework;
-
- vsfsm_pt_begin(pt);
-
- while (1)
- {
- vsfsm_pt_wfe(pt, LED_EVT_CARRY);
-
- if (led->on)
- {
- ifs->gpio.clear(led->hw->hport, 1 << led->hw->hpin);
- if (led->sm_carry != NULL)
- {
- framework->post_evt(led->sm_carry, LED_EVT_CARRY);
- }
- }
- else
- {
- ifs->gpio.set(led->hw->hport, 1 << led->hw->hpin);
- }
- led->on = !led->on;
- }
-
- vsfsm_pt_end(pt);
- return VSFERR_NONE;
- }
- static struct vsfsm_state_t *
- app_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
- {
- struct vsfapp_t *app = (struct vsfapp_t *)sm->user_data;
- struct interfaces_info_t const *ifs = app->sys.vsf->ifs;
- struct vsf_framework_t const *framework = &app->sys.vsf->framework;
- struct app_led_t *led;
- struct led_t const *hwled;
- uint8_t i;
-
- switch (evt)
- {
- case VSFSM_EVT_INIT:
- // Application
- for (i = 0; i < app->led_num; i++)
- {
- led = &app->led[i];
- hwled = led->hw;
-
- led->on = false;
- led->pt.thread = app_led_thread;
- led->pt.user_data = led;
- led->sm_carry = (i < (app->led_num - 1)) ? &app->led[i + 1].sm : NULL;
- led->app = app;
-
- ifs->gpio.init(hwled->lport);
- ifs->gpio.clear(hwled->lport, 1 << hwled->lpin);
- ifs->gpio.config_pin(hwled->lport, hwled->lpin, ifs->gpio.constants.OUTPP);
- ifs->gpio.init(hwled->hport);
- ifs->gpio.clear(hwled->hport, 1 << hwled->hpin);
- ifs->gpio.config_pin(hwled->hport, hwled->hpin, ifs->gpio.constants.OUTPP);
-
- framework->pt_init(&led->sm, &led->pt);
- }
-
- app->timer.interval = 1;
- app->timer.evt = LED_EVT_CARRY;
- app->timer.sm = sm;
- framework->timer_register(&app->timer);
- break;
- case LED_EVT_CARRY:
- framework->post_evt(&app->led[0].sm, LED_EVT_CARRY);
- break;
- }
- return NULL;
- }
- vsf_err_t __iar_program_start(struct vsf_t const *vsf, struct app_hwcfg_t const *hwcfg)
- {
- int i;
- struct vsfapp_t *app = vsf->buffer.bufmgr.malloc(sizeof(struct vsfapp_t));
-
- if (NULL == app)
- {
- return VSFERR_NOT_ENOUGH_RESOURCES;
- }
-
- memset(app, 0, sizeof(*app));
- app->sys.vsf = vsf;
- app->led_num = dimof(hwcfg->led);
- for (i = 0; i < app->led_num; i++)
- {
- app->led[i].hw = &hwcfg->led[i];
- }
-
- app->sm.init_state.evt_handler = app_evt_handler;
- app->sm.user_data = app;
- vsf->framework.sm_init(&app->sm);
- return VSFERR_NONE;
- }
应用程序里,定义了struct vsfapp_t结构,但是并没有使用静态分配的内存,所以应用程序编译后,只占用flash,不占用ram。运行应用程序的main后,调用vsf提供的内存管理接口,分配app的内存,并设置给相应的结构。应用中,并没有实现main函数,而是实现了__iar_program_start,这个是iar的程序入口,如果实现这个的话,IAR就不会自己添加调用main的代码(因为main是在系统里调用的,不需要程序自己调用),这里可以认为__iar_program_start就是应用的main函数。应用中的其他部分,都只是访问指向app内存的指针,来访问内存资源。当然,还有一个,就是编译后的镜像的第一个32为,需要是main函数的指针,IAR下可以这么实现,在startup.s文件中:
- SECTION .entry:CODE:ROOT(4)
- EXTERN __iar_program_start
- DATA
- DCD __iar_program_start
- END
并且,在linker文件中,把这个放在地址0。