Dialog SDK中app_easy_timer的大坑

        我们的电子表产品有一个墨水屏,整个系统使用Dialog14585芯片来驱动,每秒都会尝试刷新屏幕。墨水屏有一个特点是,就算是断电了,屏幕还是能正常显示出内容的。中间有几次发现,屏幕彻底不动了,看起来是程序死机了,但是蓝牙仍然正常工作,说明没有死机。

        开始找问题。我设计的应用架构,是通过一个全局的timer来驱动各种测温湿度、刷新屏幕、存储数据和更新广播内容等逻辑的,这个timer必须要在进入sleep的时候仍然有效,但是14585芯片上只提供了2个Timer,一般用于PWM之类的,但是这两个Timer跑起来功耗很大(相对的)。这里的话,使用了内核的timer,叫做ke_timer。sdk的描述是 “This module implements the functions used for managing kernel timers.”,这个timer的特点是跟随内核一起跑的,休眠的时候也能生效。关键是,功耗相对于芯片上的两个Timer模块几乎不计。然后,细心体贴的Dialog提供了一个app_easy_timer的文件,让这个timer的使用变得极为方便。

        然后,这个timer有几个特别重要的地方需要注意,不然就是一个超级大坑。

        一个是这个timer是随着BT内核一起启动的,BT的初始化没有完成之前,使用这个timer无效。具体的在应用上需要注意的就是,不可以在 app_on_init 的时候调用,必须在app_on_db_init_complete 之后。

        另一个问题是,内核提供的这个Timer可以计时的长度是有上限的,源文件中给出的描述是Max timer delay 41943sec (4194300 * 10ms),大约11.6小时。大多数时候不需要这么长时间的delay,但是难保有失心疯的...

        然后,真正的深坑来了,这是个很容易忽略难以察觉的Bug。就是这个timer的资源是很有限的!

        app_easy_timer文件中,开启timer的函数就叫app_easy_timer,这个函数有个返回值,指向timer的id,如果资源不够,就会返回EASY_TIMER_INVALID_TIMER,timer的开启失败!

         仔细去探究什么情况下会开启失败,可以发现,app_easy_timer中定义了一个APP_TIMER_MAX_NUM  (APP_TIMER_API_LAST_MES - APP_TIMER_API_MES0 + 1),然后进入到app.h中,找到了如下的定义:

    APP_TIMER_API_MES0,
    APP_TIMER_API_MES1=APP_TIMER_API_MES0+1,
    APP_TIMER_API_MES2=APP_TIMER_API_MES0+2,
    APP_TIMER_API_MES3=APP_TIMER_API_MES0+3,
    APP_TIMER_API_MES4=APP_TIMER_API_MES0+4,
    APP_TIMER_API_MES5=APP_TIMER_API_MES0+5,
    APP_TIMER_API_MES6=APP_TIMER_API_MES0+6,
    APP_TIMER_API_MES7=APP_TIMER_API_MES0+7,
    APP_TIMER_API_MES8=APP_TIMER_API_MES0+8,
    APP_TIMER_API_MES9=APP_TIMER_API_MES0+9,
    APP_TIMER_API_LAST_MES=APP_TIMER_API_MES9,

     可见,使用内核的timer,同时开启的timer数量上限是10个,超过10个的调用都会失效。当然实际上不是app_easy_timer这个文件写的有bug,而是ke_timer只分配了这么多可用的,这种先天上的问题无法解决,只能尽量减少使用,多注意一下自己开启的timer是否超过了上限。

你可能感兴趣的:(#,BLE,物联网)