DA14531学习笔记-软件架构(1)

2024-03-10 22:30

本文主要是介绍DA14531学习笔记-软件架构(1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 环境描述
  • 软件架构
    • Main loop &System software
    • peripheral &radio drivers
    • Kernel 内核
      • 调度
      • 任务
      • 动态内存分配
      • 消息
      • 计时器

本文参考 UM-B-119_DA14585-DA14531_SW_Platform_Reference,由于本人水平有限,文中难免有遗漏或错误之处,还请谅解和指正。

环境描述

名称环境描述
操作系统Windows10专业工作站版 ,版本号1909
SoCDA14531
SDK6.0.12.1020.2
KeilμVision V5.15
参考文件UM-B-119_DA14585-DA14531_SW_Platform_Reference

软件架构

DA15431和其他的BLE协议栈的架构差不多,先看下BLE协议栈的架构,关于协议栈的内容另外的文章说明。
BLE协议栈
下图是DA14531/DA14585/586 SoC的软件架构
DA14531/585/586软件架构图
上图可以看出这些内容:

名称内容
ApplicationUser application
SDK application
ProfilesGATT Services
GATT Clients
prf_utils
HostGATT(通用属性配置文件)
ATT(属性协议)
ATTDB(属性协议数据库)
SMP(安全管理协议)
GAP(通用访问协议)
L2CAP(逻辑链路控制和适配协议)
S/W BLE ControlerLL Manger(链路层管理)
KernelRiviera Waves许可的小型高效实时内核
Main loop & System Software主循环函数和系统函数
Peripheral & radio Divers外设和Radio驱动

Main loop &System software

打开SDK文件的ble_examples中任意一个Keil工程

文件名函数名描述
sdk_archint main(void)主函数

  系统启动时,会进入到main函数初始化系统并进入主循环,检查BLE是否处于活动状态,如果是,则为内核调度程序提供CPU时间以处理所有未决消息和事件,接下来,查询用户应用程序是否要执行与消息无关的任务。如果内核和用户应用程序都无事可做,则迅速过渡到低功耗模式并等待中断再次开始。main loop不会随用户程序而更改。
  提供了一组回调,用于通知应用程序主循环的状态。对于这些回调,我们经常使用术语“异步执行”来将它们与内核调度程序中生成的其他事件和回调区分开来,这称为同步执行。应用程序可以使用回调的返回值或通过相应地设置睡眠设置来部分控制主循环。在这里重要的是要理解,当BLE处于活动状态时,将从主循环中调用内核调度程序。如果我们不将控制权授予主循环,或者BLE未激活,则内核消息的处理将延迟。

//main 函数代码
int main(void)
{sleep_mode_t sleep_mode;// initialize retention modeinit_retention_mode();//global initialisesystem_init();/************************************************************************************** Platform initialization*************************************************************************************/while(1){do {// schedule all pending events 安排所有未解决的事件schedule_while_ble_on();}while (app_asynch_proc() != GOTO_SLEEP);    //grant control to the application, try to go to power down//if the application returns GOTO_SLEEP//wait for interrupt and go to sleep if this is allowedif (((!BLE_APP_PRESENT) && (check_gtl_state())) || (BLE_APP_PRESENT)){//Disable the interruptsGLOBAL_INT_STOP();app_asynch_sleep_proc();// get the allowed sleep mode// time from rwip_power_down() to __WFI() must be kept as short as possible!!sleep_mode = rwip_power_down();if ((sleep_mode == mode_ext_sleep) || (sleep_mode == mode_ext_sleep_otp_copy)){//power down the radio and whatever is allowed 关闭radio和任何允许关闭的电源arch_goto_sleep(sleep_mode);// In extended sleep mode the watchdog timer is disabled// (power domain PD_SYS is automatically OFF). However, if the debugger// is attached the watchdog timer remains enabled and must be explicitly// disabled.//在扩展睡眠模式下,看门狗定时器被禁用(电源域PD_SYS自动关闭)。 但是,如果连接了调试器,则看门狗定时器将保持启用状态,并且必须显式禁用。if ((GetWord16(SYS_STAT_REG) & DBG_IS_UP) == DBG_IS_UP){wdg_freeze();    // Stop watchdog timer}//wait for an interrupt to resume operation 等待中断以恢复操作__WFI();if ((GetWord16(SYS_STAT_REG) & DBG_IS_UP) == DBG_IS_UP){wdg_resume();    // Resume watchdog timer 恢复看门狗定时器}//resume operation 恢复操作arch_resume_from_sleep();}else if (sleep_mode == mode_idle){if (((!BLE_APP_PRESENT) && check_gtl_state()) || (BLE_APP_PRESENT)){//wait for an interrupt to resume operation__WFI();}}// restore interruptsGLOBAL_INT_START();}wdg_reload(WATCHDOG_DEFAULT_PERIOD);}
}

未决消息和事件

do {// schedule all pending events 安排所有未解决的事件schedule_while_ble_on();}while (app_asynch_proc() != GOTO_SLEEP);    //grant control to the application, try to go to power down//if the application returns GOTO_SLEEP

  SoC在上电的时候调用 schedule_while_ble_on() 函数,这个函数的主要作用是检查BLE Clock是否使能,如果使能了,调用rwip_schedule() 来处理未解决的事件和消息,通过查找,并没有发现函数的原型,推测是rw内核系统封装的函数接口。
  等待中断,如果允许的话会进入睡眠模式,禁用系统全局中断,app_asynch_sleep_proc() 这个函数的作用是在睡眠检查开始之前更新应用程序的状态。后续的代码应该都是关于低功耗的一些操作,这里有关于看门狗的一些说明,在调试的时候,看门狗必须是保持开启状态,如果是进入了低功耗模式,那么看门狗会被关闭。具体可以看函数注释。

peripheral &radio drivers

  这部分其实都是SoC的一些外设和射频的一些驱动,比如SPI、I2C、USART等等。具体可以看SDK中的sdk_driver 里的函数。

Kernel 内核

  DA14531/585/586用的都是Riviera Waves许可的小型高效实时内核。提供以下几个功能。可以参考这篇文章:RW内核和消息处理机制或者是《RW-BT-KERNEL-SW-FS.pdf》这个指导文件。

  • 任务创建和状态转换
  • 任务之间的消息交换
  • 计时器管理
  • 动态内存分配
  • BLE事件调度和处理

调度

  内核的核心是运行在应用程序主循环中的调度程序。调度程序检查是否设置了事件,并调用相应的处理程序为未决事件提供服务。该事件可以是BLE或计时器事件,也可以是两个任务之间的消息。
  调度程序从BLE核心硬件获取任何时序信息。主循环代码可确保在BLE核心的硬件模块不处于睡眠模式时不执行内核调度程序。
  内核的实现位于ROM存储区中。因此,SDK发行版中不包含源代码文件。API类型的定义和API函数的原型可以在以下头文件中找到。关于内核的详细接口将在另外的文章详细介绍。

API说明
ke_task.h内核任务管理和创建
ke_msg.h消息处理
ke_mem.h动态内存分配
ke_timer.h计时器创建和删除API

任务

  BLE堆栈层/ GATT配置文件/主机应用程序等都被实例化为内核的任务,该任务通常在系统初始化时创建。单个BLE应用程序中支持的最大任务数为23
  每个任务都有唯一一个任务ID,任务结构体类型为struct ke_task_desc,这个结构体在ke_task.h

/// Task descriptor grouping all information required by the kernel for the scheduling.
struct ke_task_desc
{/// Pointer to the state handler table (one element for each state).//应用程序每个状态的消息处理程序const struct ke_state_handler* state_handler;/// Pointer to the default state handler (element parsed after the current state).//默认消息处理程序const struct ke_state_handler* default_handler;/// Pointer to the state table (one element for each instance).//当前任务状态ke_state_t* state;/// Maximum number of states in the task.//任务的最高有效状态uint16_t state_max;/// Maximum index of supported instances of the task.//任务实例的最大数量uint16_t idx_max;
};

ke_task.h头文件中声明了所有API函数以及内核任务创建和管理的类型。

类型名称描述
ke_msg_handler消息处理程序结构
ke_state_handler特定或默认状态的消息处理程序列表
ke_task_desc任务描述符
custom_msg_handler自定义消息处理程序
函数名功能
void ke_task_init(void)初始化内核任务模块
ke_task_create创建一个任务
ke_task_delete删除一个任务
ke_state_get检索任务的状态(获取任务的状态)
ke_state_set设置由其任务ID标识的任务的状态
ke_msg_discard通用消息处理程序,在不处理任务的情况下使用消息
ke_msg_save通用消息处理程序,在不处理任务的情况下使用消息。?待确认
ke_task_msg_flush此函数将刷新所有消息,这些消息当前在内核中针对特定任务的待处理状态。

动态内存分配

RW内核给应用程序提供了动态内存分配的API,定义了四个堆存储区。

堆存储区名称作用
KE_MEM_ENV用于环境变量的内存分配
KE_MEM_ATT_DB用于ATT协议数据库,即服务,特征,属性
KE_MEM_KE_MSG用于内核消息的内存分配
KE_MEM_NON_RETENTION通用堆内存。Note

堆内存的大小可以分为自动确定和用户确定,两者的分别位于以下文件。

种类文件位置
自动确定da1458x_scatter_config.h
用户确定da1458x_config_advanced.h

  这些堆中任何一个的动态内存分配都是通过调用该ke_malloc()函数来完成的。堆内存的大小和选择在函数的参数中传递。如果所选堆内存中的内存空间不足,则内核内存管理代码将尝试在另一个堆中分配请求的内存空间。如果内核的所有堆内存中的内存分配失败,则会发出系统软件重置信息。
  内核提供了两个API函数

函数名作用
ke_malloc()分配请求的内存空间
ke_msg_free()在请求的内存地址释放分配的内存空间

消息

内核提供了一种在任务之间交换消息的机制。 内核交换的消息具有特定的格式。 格式由ke_msg.h中定义的struct ke_msg类型确定。 ke_msg结构包括以下成员:

结构体成员说明
Id一个包含消息标识的16位无符号整数。 十个最低有效位形成一个序列号,该序列号在任务的消息中是唯一的。 六个最高有效位是任务的ID,以确保系统中消息标识的唯一性。 宏KE_BUILD_ID可用于构建符合此约定的消息ID。
dest_id消息的目标任务的任务ID
src_id消息源任务的任务ID
param_len参数中包含的消息数据的大小。
param消息数据的占位符。 结构成员的类型是32位无符号整数的一个位置表。 但是,分配的内存空间的大小由堆内存确定,堆内存由消息内存分配函数分配,并且等于param_len

消息传输分为三个步骤:
1、 消息发送者调用下面两个宏中的一个来进行消息内存的分配
   ① KE_MSG_ALLOCKE_MEM_KE_MSG 鼠标移到这里为消息分配堆内存中的空间。

/// Kernel memory heaps types.
enum
{/// Memory allocated for environment variablesKE_MEM_ENV,/// Memory allocated for Attribute databaseKE_MEM_ATT_DB,/// Memory allocated for kernel messagesKE_MEM_KE_MSG,/// Non Retention memory blockKE_MEM_NON_RETENTION,KE_MEM_BLOCK_MAX,
};

消息ID,源和目标任务ID以及消息数据的类型在函数的参数中传递。函数根据数据类型计算要分配的内存空间。返回指向已分配消息的数据开头的指针。详见下面代码块

/******************************************************************************************2. @brief Convenient wrapper to ke_msg_alloc()3.  4. This macro calls ke_msg_alloc() and cast the returned pointer to the5. appropriate structure. Can only be used if a parameter structure exists6. for this message (otherwise, use ke_msg_send_basic()).7.  8. @param[in] id        Message identifier9. @param[in] dest      Destination Identifier10. @param[in] src       Source Identifier11. @param[in] param_str parameter structure tag12.  13. @return Pointer to the parameter member of the ke_msg.*****************************************************************************************/
#define KE_MSG_ALLOC(id, dest, src, param_str) \(struct param_str*) ke_msg_alloc(id, dest, src, sizeof(struct param_str))

   ② KE_MSG_ALLOC_DYN :与KE_MSG_ALLOC类似,在KE_MSG_ALLOC的入口参数中加入了长度,这个长度是预数据类型大小相同的附加内存大小。详见下面代码块

/******************************************************************************************* @brief Convenient wrapper to ke_msg_alloc()** This macro calls ke_msg_alloc() and cast the returned pointer to the* appropriate structure with a variable length. Can only be used if a parameter structure exists* for this message (otherwise, use ke_msg_send_basic()).Can only be used if the data array is* located at the end of the structure.** @param[in] id        Message identifier* @param[in] dest      Destination Identifier* @param[in] src       Source Identifier* @param[in] param_str parameter structure tag* @param[in] length    length for the data** @return Pointer to the parameter member of the ke_msg.*****************************************************************************************/
#define KE_MSG_ALLOC_DYN(id, dest, src, param_str,length)  (struct param_str*)ke_msg_alloc(id, dest, src, \(sizeof(struct param_str) + length));

2、填写消息参数。 源任务的代码应填写消息的数据
3、将消息结构推送到内核中。

   调用函数 ke_msg_send() 将消息发送到目标任务。由KE_MSG_ALLOCKE_MSG_ALLOC_DYN返回的指针必须在函数的参数中传递。如果消息已分配但未发送,则必须调用ke_msg_free() 来释放已经分配的内存。
   通过在消息的任务描述符(ke_task_desc )中定义消息处理程序功能(结构体ke_msg_handler),可以实现发送到任务的消息的接收。 当目标任务使用消息时,状态处理程序应返回KE_MSG_CONSUMED,而将消息转发到另一个任务时,状态处理程序应返回KE_MSG_FREE。 函数 ke_msg_forward() 必须用于此操作。

计时器

   DA14531提供定时器服务的事件创建和删除。是以BLE硬件内核的BLE_GROSS_TIMER为基础的,BLE_GROSS_TIMER计时器的精度为10毫秒。 请求计时器事件的任务将收到有关计时器到期的消息的通知。 消息ID等于用于计时器创建的计时器ID。 因此,计时器ID必须是有效的消息ID。 还必须在任务处理程序列表中定义计时器处理程序功能。 内核计时器是一次性计时器。主要有以下两个API函数

API说明
app_timer_set()其具体实现函数是ke_time_set()函数,以10毫秒为单位,最大有效超时为4194300,相当于699分钟
ke_timer_delete()删除活动的内核计时器

这篇关于DA14531学习笔记-软件架构(1)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/795717

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件