1、BES的内核用的是RTX的内核,并且用了ARM推广的CMSIS_RTOS API接口;这样做的好处是可以方便内核的更换,方便移植上层代码。


2、程序是从RTX_CM_LIB.H里面的_main_init()开始的,里面包括了内核的初始化,堆栈的设置,线程任务main的创建,内核的开启。
此函数以绝对的物理内存地址定义在内存开始段中,上电直接运行。

3、然后,程序开启了第一个线程main的运行,在Main.cpp文件中。

4、需要提及的是CMSIS_RTOS API中,经常以这种风格来定义线程跟定时器,邮件通讯等的配置;

app_thread为线程loop函数,osThread其实是一个宏

其实现在就是取os_thread_def_app_thread的地址,而这个地址从何而来?
一般在线程创建的文件中,会看到如下图这样的定义:

osThreadDef其实也是一个宏

到了这里,我们知道了os_thread_def_app_thread的数据源了,是一个结构体变量初始化赋值,看其结构类型:

至此我们应该就能清楚明白了整个线程创建的定义了,通过osThreadDef设置线程名,优先级,堆栈大小,通过osThread获取配置的结构体变量的指针,作为形参传入osThreadCreate()函数中。

5、以上的案列,我们看到了最重要的一个线程的创建过程,这个线程就是app_thread线程,它在app_thread.c里面的app_os_init()函数里面创建,由main调用或者app_init()调用。这个线程将是以后应用模块修改跟添加的主要线程。
6、下面,我们看一下app_thread线程里面模块设计的实现。

我们可以看到在app_thread线程中,反复的在获取邮件信息app_mailbox_get(),并传入mod_handler[]里面

看其数据类型

是一个函数指针数组,再看其数组下标的定义。

我们再看一下,谁用到了mod_handler[]。

看下app_set_threadhandle原型

到此,我们看到了app_thread线程中,设置各模块,事件回调函数的API。
全局搜索下,谁调用了app_set_threadhandle?

7、继续研究app_thread线程中,模块的架构以及驱动层的调用。我们就从app_set_threadhandle的调用,进入到APP_MODUAL_BATTERY模块,分析具体的代码。

可以看到app_battery_open()调用了 app_set_threadhandle(APP_MODUAL_BATTERY, app_battery_handle_process);其中,app_battery_handle_process()就是app_thread线程回调的模块调用函数。
另外可以看一下文件目录结构:

后续自己的模块可以按照它SDK的风格,加入进来。
我们继续看代码,

app_battery_open()是由app_init()调用的,初始化battery模块。
其中,battery模块用到的全局变量为

数据结构为


从变量的初始化,我们可以看到客制化的设置,在tgt_hardware.h里面

其他客制化的设置,也可以一并在这个头文件里面看看。
在app_battery_handle_process()里面,我们可以看到

电池电量的获取以及更新,并通过BLE传给手机。

通过APP_BATTERY_STATUS_OVERVOLT看到app_battery_irqhandler()里面发起的事件

app_battery_measure.cb在app_battery_open()中有定义,


可以看到app_battery_event_process()发出的邮件信息。
回到app_battery_irqhandler(),



通过追踪,我们看到了定时器开启的app_battery_timehandler()回调。
至此,我们看到了battery模块电池电量的获取,中间层的流程,定时器,间隔固定时间通过驱动层获取当前电量的值,给到模块事件处理,再给到应用层。
关于定时器的配置和设置,上面有讲过CMSIS_RTOS的风格,这里就不追踪了。
8、我们看下battery模块,用到的ADC驱动层的代码应用。


通过这个入口所在的文件,看下驱动层所在的文件路径:

后续驱动的调用跟运用,可以看这个文件夹里面的文件。
回到代码:

可以看到,传入的回调函数指针,赋值给了 gpadc_event_cb[channel] ,另外,用到驱动的地方,要加互斥锁。

追踪gpadc_event_cb的调用,进入hal_gpadc_irq_handler()


通过上图,我们看到 gpadc_event_cb调用了app_battery_irqhandler,并传入了ADC扫描到的值。

以上,为ADC最底层接口。
我们再通过hal_gpadc_irq_handler(),追踪


以上,是ADC开启中断获取的流程 ,至此,驱动层开启ADC获取电量值的流程。
9、除app_thread主要线程外,我们可以看到还有BT跟audio一些线程,关于线程间的通信,以及BLE应用层处理的流程,今后再更新。

1万+

被折叠的 条评论
为什么被折叠?



