BES SDK 软件架构开发简介

Hello ,大家好!上次写了基于恒玄模块的 单线串口通讯模块,本文在这里对恒玄蓝牙SDK 做简单的介绍。

一 .软件系统构架

1.BES采用的是RXT RTOS(嵌入式实时操作系统),并且用了ARM的CMSIS_RTOS API接口

2. 我们知道程序运行开始的地方是RTX_CM_LIB.H里面的_main_init(),主要是进行内核初始化、堆栈的设置、main线程的创建和开启内核等。

3.第一个线程os_thread_def_main就是main,接着看,在main.cpp文件中。

然后再是 debug 端口的初始化 (一把我们用 debug=1)默认开启UART0  RX的 打印输出。

在 uart 初始化完成后 会打印输出 当前软件、芯片、flash分区大小等一些信息  hal_trace.c 中:

打印输出大致如下 :

[18:35:14.391]CHIP=best1305
[18:35:14.391]KERNEL=RTX5
[18:35:14.391]CRASH_DUMP_SIZE=0
[18:35:14.391]AUD_SEC_SIZE=0x10000
[18:35:14.391]USER_SEC_SIZE=0x1000
[18:35:14.391]FACT_SEC_SIZE=0x1000
[18:35:14.391]NV_REC_DEV_VER=2
[18:35:14.391]FLASH_BASE=0x38000000
[18:35:14.391]FLASH_SIZE=0x400000
[18:35:14.391]OTA_CODE_OFFSET=0x28000
[18:35:14.391]CRC32_OF_IMAGE=0x00000000
[18:35:14.391]BUILD_DATE=Mar 10 2021 18:21:32
[18:35:14.391]REV_INFO=:best2500i_JBL_T230
[18:35:14.391]
[18:35:14.391]
[18:35:14.391]------
[18:35:14.391]METAL_ID: 0
[18:35:14.391]------

随后 软件运行会判断当前flash实际大小与软件定义是否匹配,如果软件定义的flash size 超过芯片自带flash大小,就会打印输出

“Wrong FLASH_SIZE defined in target.mk!”

“FLASH_SIZE is defined as 0x20000 while the actual chip flash size is 0x40000” 随后死机。

如果flash无异常 后续就会启动  硬件IO 配置和模拟输入输出IO 配置

随后 跑入app_init

最后 如果初始化完成 就在一直死循环执行 线程任务

 

如果app_init里面初始化提前结束并且返回 非0  则直接关机

 

4. BES 的线程/任务消息 /定时器创建和使用。

首先说个概念理解 :1.线程是基于RTOS的一个任务调度处理 (模拟多核 占用时间片的)

                                  2.每个线程都是独立并且不会被同一时间执行的 

                                  3.一个线程里面可以包含多个 消息模块处理.

A.线程

第一个线程os_thread_def_main就是main,接着看,在main.cpp文件中:

app_os_init()里有线程创建,这是CMSIS的风格,开发过STM32应该比较熟悉,用来定义线程、定时器和邮箱通讯等;
app_thread_tid = osThreadCreate(osThread(app_thread), NULL);

app_thread为线程loop函数,OSThread其实是一个宏,就是取地址而已
#define osThread(name) &os_thread_def_##name

所以OSThreadDef是设置线程名、优先级以及堆栈大小,通过osThread获取配置的结构体变量的指针,然后作为参数传入OSThreadCreate()。

一般在文件开头会看到这样的定义:osThreadDef其实也是一个宏
osThreadDef(app_thread, osPriorityHigh, 1, 1024, “app_thread”);

PS:早期的线程定义是这样的:

/* thread */
static osThreadId uartrxtx_tid; 
uint32_t os_thread_def_stack_uartrxtx [UART_STACK_SIZE/ sizeof(uint32_t)];
osThreadDef_t os_thread_def_app_uartrxtx = {(app_uartrxtx),(osPriorityHigh),(UART_STACK_SIZE),(os_thread_def_stack_uartrxtx)};

这里就是给一个结构体变量初始化赋值,然后把os_thread_def_app_thread的地址传给os_thread()。结构体类型是:

/  ==== Thread Management Functions ====

/// Create a Thread Definition with function, priority, and stack requirements.
/// \param         name          name of the thread function.
/// \param         priority      initial priority of the thread function.
/// \param         instances     number of possible thread instances.
/// \param         stacksz       stack size (in bytes) requirements for the thread function.
/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the
///       macro body is implementation specific in every CMSIS-RTOS.

#define osThreadDef(name, priority, instances, stacksz, task_name) \
uint64_t os_thread_def_stack_##name [(8*((stacksz+7)/8)) / sizeof(uint64_t)]; \
const osThreadDef_t os_thread_def_##name = \
{ (name), \
  { task_name, osThreadDetached, NULL, 0U, os_thread_def_stack_##name, 8*((stacksz+7)/8), (priority), 1U, 0U } }
下面是关于线程的创建:

我们再看下线程的执行:

下面我们看一下app_thread线程里面的具体做了什么:
if (mod_handler[msg_p->mod_id])
int ret = mod_handler[msg_p->mod_id] (&(msg_p->msg_body));

我们可以看到在app_thread线程中,通过app_mailbox_get()反复的在获取邮箱信息,并传入mod_handler[]里面。
static APP_MOD_HANDLER_T mod_handler[APP_MODUAL_NUM];
在这里插入图片描述
看其数据类型是一个函数指针数组,再看其数组下标的定义:

关于线程的创建使用实际代码连接如下 (包含新旧版本):

https://share.weiyun.com/GUat9L7n

 

B:消息任务:

消息任务是基于 线程下一级的处理 

目前通用的都是基于 app_thread  线程的消息任务处理 ,当然也可以在其余线程中增加任务处理 。

由上面线程讲解我们知道各个模块会注册自己的回调函数,然后app_thread()会根据get的消息回调模块对应的API进行处理。

所以任务在注册之前需要在app_os_init 之后 然后再去注册消息执行函数。

 

消息处理函数通用接口:

返回值为  int 类型数据  携带 APP_MESSAGE_BOY *的 结构体参数指针。

这里以我写的NTC 消息处理做讲解:

C 定时器:

定时器分为软件定时器和硬件定时器,本质上都是时间到了后执行中断处理。

区别是硬件定时器以 硬件时钟为基准 所以相对来说会更准确 测量精度更小,且硬件定时器是一次性的 。

定时器 可以重载 但不能在中断里面使用

C1:硬件定时器

头文件: #include "hwtimer_list.h"

static HWTIMER_ID app_box_det_debounce_tid = NULL;  //硬件定时器ID 定义  一般定义为全部变量

app_box_det_debounce_tid = hwtimer_alloc(app_box_det_debounce_timehanlder, NULL); //关联定时器中断执行函数。app_box_det_debounce_timehanlder会携带 void*类型参数。

hwtimer_start(app_box_det_debounce_tid,MS_TO_TICKS(200));// 启动定时器  需要注意后面不能直接填写时间,需要转为时钟

hwtimer_stop(app_box_det_debounce_tid); // 定时器可以被提前停止,移除队列 改定时器就当此就不再执行。

 

C2: 软件定时器:

头文件:

#include "cmsis_os.h"
#include "hal_timer.h"

typedef enum {
  osTimerOnce               = 0,          ///< One-shot timer.
  osTimerPeriodic           = 1           ///< Repeating timer.
} osTimerType_t;

static osTimerId app_battery_timer = NULL; //软件定时器ID  
static void app_battery_timer_handler(void const *param); //定时器 中断执行函数 ,可以携带 void* 类型参数
osTimerDef (APP_BATTERY, app_battery_timer_handler); //软件定时器 需要用宏关联定时器 和 执行函数

app_battery_timer = osTimerCreate (osTimer(APP_BATTERY), osTimerPeriodic, NULL); //软件定时器创建 APP_BATTERY为定时器寻址ID 

第二个参数 是 定时器是否为周期性的,如果是一次性的 那么以后时间到了 执行完后就不会再被执行 ,但是ID 还是在  可以再次start.

 osTimerStop(app_battery_timer); //停止该软件定时器
 osTimerStart(app_battery_timer,5000); // 重新开启软件定时器 ,并在5S后执行 定时器中断。

 

这一篇的系统架构 暂时说到这里  后续 子模块详细分析  请大家继续订阅 查看 ,谢谢!

QQ:1902026113

 

 

### 配置 VS Code 开发环境以支持BESSDK 为了在 Visual Studio Code (VS Code) 中高效地开发基于 SDK 的项目,需要完成一系列配置工作。以下是详细的说明: #### 1. 安装必要的扩展 安装以下扩展来增强 VS Code 对 C/C++ 和嵌入式开发的支持: - **C/C++ Extension Pack**: 提供 IntelliSense 支持以及代码导航功能。 - **Platform IO**: 虽然 PlatformIO 主要用于 Arduino 类型的开发,但它也可以通过自定义设置适配其他平台。 - **CMake Tools**: 如果您的项目依赖于 CMake 构建系统,则此插件非常有用。 这些工具可以通过 VS Code 市场place直接获取并安装[^4]。 #### 2. 设置编译器路径 确保已正确安装交叉编译工具链,并将其添加到系统的 PATH 环境变量中。例如,在 Linux 或 macOS 下可以运行如下命令验证 GCC 工具链是否存在: ```bash arm-none-eabi-gcc --version ``` 如果未找到,请先按照官方文档中的指导下载适合目标硬件架构的 GNU ARM Embedded Toolchain[^1]。 #### 3. 创建 launch.json 文件 为了让调试更加便捷,需手动编辑 `.vscode/launch.json` 来指定 GDB 调试器的位置以及其他选项。下面是一个基本模板: ```json { "version": "0.2.0", "configurations": [ { "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/build/firmware.elf", // 替换为您实际生成的目标文件名 "miDebuggerPath": "/path/to/arm-none-eabi-gdb", // 修改为GDB的实际位置 "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": true, "MIMode": "gdb" } ] } ``` 注意替换 `${workspaceFolder}` 及 `/path/to/arm-none-eabi-gdb` 成具体目录名称[^2]。 #### 4. 自定义 tasks.json 同样位于 `.vscode/tasks.json` 内部的任务描述允许我们轻松调用不同的构建脚本。这里给出一个例子: ```json { "tasks": [ { "label": "Build Normal Firmware", "type": "shell", "command": "./build.sh normal", "group": "build" }, { "label": "Build Test Firmware", "type": "shell", "command": "./build.sh test", "problemMatcher": [] } ], "version": "2.0.0" } ``` 这样就可以利用快捷键触发对应的操作了。 #### 5. 初始化 c_cpp_properties.json 最后一步是调整 `c_cpp_properties.json` ,让 IDE 明白头文件所在之处以便提供更好的补全建议等功能。假设源码根目录结构清晰合理的话,可尝试如下设定: ```json { "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "/absolute/path/to/toolchain/include" // 添加所有可能涉及的标准库或者第三方库包含路径 ], "defines": ["DEBUG","_GNU_SOURCE"], "compilerPath": "/usr/bin/gcc", // 更改为正确的GCC版本号 "intelliSenseMode": "gcc-x64", "browse": { "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" } } ], "version": 4 } ``` 以上步骤完成后应该能够顺利加载整个工程并在其中自由操作了[^3]。 ---
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值