device tree 预研
linux kernel 引入 dts 的背景
http://www.wowotech.net/linux_kenrel/why-dt.html
什么是 device tree
device tree 是一种描述硬件资源的数据结构。device tree 可以描述的信息包括 cpu 的数量和类别、内存基地址和大小、clock 控制器和 clock 使用情况、外设基地址以及配置信息、中断控制器和中断使用情况。
设备树解决了什么问题
本质上,device tree 改变了原来用 hardcode 方式将 HW 配置信息嵌入到内核代码(驱动程序)的方法,改用 bootloader 传递一个 DB 的形式。对于基于 ARM CPU 的嵌入式系统,我们习惯于针对每一个 platform 进行内核的编译,但是随着 ARM 在消费电子上的广泛应用,我们期望 ARM 能够像 x86 那样用一个 kernel image 来支持多个 platform。
其实,就是将驱动程序中硬编码的定义改为由设备树来描述,优化了驱动程序,同时,让 kernel image 相对独立,同一份 image 可在不同的 soc 上运行。
总之,设备树是为 kernel 服务的,让内核与设备尽可能的保持独立。
Linux 与 Zephyr 的 dts
linux
以下是 at5050_codec.c
// 通过 platform 驱动框架,将驱动注册到系统中去.
// 驱动程序解析 dts, 避免硬编码到该文件中
static struct platform_driver at5k_codec_driver = {.driver = {.name = "at5050-codec",.owner = THIS_MODULE,.of_match_table = of_match_ptr(of_at5k_codec_match),},.probe = at5k_codec_probe,.remove = at5k_codec_remove,
};module_platform_driver(at5k_codec_driver);
linux 中的驱动程序会通过 一套设备树接口获取设备树节点,通过这些节点的描述实现驱动程序,注意,这里驱动程序是强依赖设备树的,驱动程序不可能做到通用(不同的 soc 之间,寄存器操作存在差异),通用的是驱动框架,如上述 platform 框架,或者字符设备、块设备、mtd 设备框架等等。
驱动程序需要有一套 设备树解析接口 。注册到系统中之后,应用程序就能够使用设备了。
zephyr
以下是 gpio_stm32.c :
// 操作 pin 设备的虚函数表,注册到系统中去(这里是真正意义上的驱动代码,通常是直接操作寄存器或者调用 hal 层提供的接口)
static const struct gpio_driver_api gpio_stm32_driver = {.pin_configure = gpio_stm32_config,.port_get_raw = gpio_stm32_port_get_raw,.port_set_masked_raw = gpio_stm32_port_set_masked_raw,.port_set_bits_raw = gpio_stm32_port_set_bits_raw,.port_clear_bits_raw = gpio_stm32_port_clear_bits_raw,.port_toggle_bits = gpio_stm32_port_toggle_bits,.pin_interrupt_configure = gpio_stm32_pin_interrupt_configure,.manage_callback = gpio_stm32_manage_callback,
};// 注册 pin 设备,系统初始化期间会处理好
DEVICE_DT_DEFINE(__node, \gpio_stm32_init, \PM_DEVICE_DT_GET(__node), \&gpio_stm32_data_## __suffix, \&gpio_stm32_cfg_## __suffix, \PRE_KERNEL_1, \CONFIG_GPIO_INIT_PRIORITY, \&gpio_stm32_driver)#define GPIO_DEVICE_INIT_STM32(__suffix, __SUFFIX) \GPIO_DEVICE_INIT(DT_NODELABEL(gpio##__suffix), \__suffix, \DT_REG_ADDR(DT_NODELABEL(gpio##__suffix)), \STM32_PORT##__SUFFIX, \DT_CLOCKS_CELL(DT_NODELABEL(gpio##__suffix), bits),\DT_CLOCKS_CELL(DT_NODELABEL(gpio##__suffix), bus))// 根据 dts 文件中对于 gpio 的描述,注册该 pin 设备到系统中
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay)
GPIO_DEVICE_INIT_STM32(a, A);
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(gpioa), okay) */
以下是应用代码 main.c:
// led0 这个名字在设备树文件中定义
#define LED_BLUE DT_ALIAS(led0)
#define LED_RED DT_ALIAS(led1)// 根据设备树中的描述,得到操作该 pin 设备的句柄
static const struct gpio_dt_spec led_blue = GPIO_DT_SPEC_GET(LED_BLUE, gpios);
static const struct gpio_dt_spec led_red = GPIO_DT_SPEC_GET(LED_RED, gpios);int main(void)
{printk("hello zephyr.\n");// 通过统一设备树接口,操作 pin 设备,而不是直接操作 hal 层方法if (!gpio_is_ready_dt(&led_blue) && !gpio_is_ready_dt(&led_red)) {return 0;}if (gpio_pin_configure_dt(&led_blue, GPIO_OUTPUT_ACTIVE) < 0 || gpio_pin_configure_dt(&led_red, GPIO_OUTPUT_ACTIVE) < 0) {return 0;}sdram_test();while (1) {if (gpio_pin_toggle_dt(&led_blue) < 0 || gpio_pin_toggle_dt(&led_red)) {return 0;}k_msleep(SLEEP_TIME_MS);}return 0;
}
// 可以看出,应用程序在使用 pin 设备时,使用的是一套带有 dt 字符的抽象接口,这里让应用程序感受到了设备树的存在
- zephyr 支持两种设备驱动的注册,一种是使用设备树相关宏
DEVICE_DT_DEFINE,另外一种是不使用设备树相关宏DEVICE_DEFINE - 如果使用设备树,应用程序中操作设备时,需要
依赖设备树,具体操作如下:ADC_DT_SPEC_GET使用该宏,获取adc设备,需要知道该设备在设备树中的命名static inline int adc_read_dt(const struct adc_dt_spec *spec,const struct adc_sequence *sequence),读取struct adc_dt_spec设备static inline int adc_channel_setup_dt(const struct adc_dt_spec *spec)配置 adc 设备- 这里略微不合理,我们希望应用程序不要考虑那么多,不要知道设备树的存在。
- 如果不使用设备树,而是使用
DEVICE_DEFINE注册设备,那么应用程序对设备的操作如下static inline const struct device * device_get_binding(const char * name),返回一个device对象,如果该设备是个 adc 设备,使用如下接口操作设备static inline int adc_read(const struct device * dev, const struct adc_sequence * sequence),读取 adc 设备,会调用到驱动层实现的虚函数表static inline int adc_channel_setup(const struct device * dev, const struct adc_channel_cfg * channel_cfg),配置 adc 设备- 这里应用程序通过
binding接口得到了设备句柄
抛开 linux 历史原因,直接从内核源码来看,目前 dts 目前为什么是 linux 的标配?
- linux kernel 已经依赖 dts,如 kernel 内部稳定的驱动框架(platform、spi、i2c 等等)。
- 从驱动框架来看,dts 是必须的,从使用驱动框架的人(linux 驱动开发人员)来看,dts 也是必须的。Linux 驱动开发人员需要使用 dts 中描述的信息来写驱动。
为什么各大主流 rtos 不引入 dts ?
- 首先 rtos 面向的是小型嵌入式设备,业务逻辑没那么复杂
- 其次,如果引入 dts,那么 dtb 文件如何放入 mcu / mpu 里面?需要额外引入其他依赖。设备开机重启后,需要保证 dtb 文件依然存在,需要预留持久化存储空间。
- 这可能也是 zephyr 为什么改变 dts 常规使用方法(编译 dts 成为 dtb,再使用一些工具把 dtb 放到持久化存储的地方),而是改为编译时解析,不用再考虑 dtb 文件放哪里了,系统启动流程不用那么复杂了,甚至系统都没起来(堆都没初始化)都能先初始化设备了。
综上,dts 对于 rtos 来说,意义不大,甚至会引入副作用。
dts 文件如何使用 dtc 工具编译成 dtb
先使用 c / cpp 预处理器展开头文件
cpp -nostdinc -I /home/null/zephyrproject/zephyr/dts/arm/ -I /home/null/zephyrproject/zephyr/dts/common -undef -x assembler-with-cpp stm32h750_art_pi.dts stm32h750_art_pi.dts.preprocessed
然后使用 dtc 工具
dtc -I dts -O dtb -o example.dtb example.dts
如果 dts 文件中使用了 include 关键字,则需要通过 c/cpp 预处理器来展开头文件,dtc 工具是不负责展开头文件的,只是编译,否则会报错。
相关文章:
device tree 预研
linux kernel 引入 dts 的背景 http://www.wowotech.net/linux_kenrel/why-dt.html 什么是 device tree device tree 是一种描述硬件资源的数据结构。device tree 可以描述的信息包括 cpu 的数量和类别、内存基地址和大小、clock 控制器和 clock 使用情况、外设基地址以及…...
英伟达股价分析:英伟达股价能否上涨到150美元,接下来该如何操作?
来源:猛兽财经 作者:猛兽财经 猛兽财经核心观点: (1)华尔街投行Oppenheimer已将英伟达的目标价上调到了150美元。 (2)产品方面的最新进展和合作伙伴关系进一步提升了英伟达的市场地位。 &…...
Rust 快速入门(一)
Rust安装信息解释 cargo:Rust的编译管理器、包管理器、通用工具。可以用Cargo启动新的项目,构建和运行程序,并管理代码所依赖的所有外部库。 Rustc:Rust的编译器。通常Cargo会替我们调用此编译器。 Rustdoc:是Rust的…...
java 程序在服务器出现时区错误问题(使用Date,LocalDateTime,ZonedDateTime都不正确)
排查 查询系统时区信息 timedatectl status打印java的时区信息 import java.util.TimeZone;public class CheckTimeZone {public static void main(String[] args) {TimeZone defaultTimeZone TimeZone.getDefault();System.out.println("Default TimeZone ID: "…...
Kotlin 语言的协程是什么?
目录 1. 什么是协程 2. 协程的基本概念 3. 如何使用协程 3.1. 引入依赖 3.2. 启动协程 3.3. 使用挂起函数 4. 结构化并发 5. 处理异常 6. 总结 Kotlin 的协程是一种轻量级的线程,可以用于简化异步编程。它允许你以顺序的方式编写异步代码,从而提…...
uniapp 游戏 - 使用 uniapp 实现的扫雷游戏
0. 思路 1. 效果图 2. 游戏规则 扫雷的规则很简单。盘面上有许多方格,方格中随机分布着一些雷。你的目标是避开雷,打开其他所有格子。一个非雷格中的数字表示其相邻 8 格子中的雷数,你可以利用这个信息推导出安全格和雷的位置。你可以用右键在你认为是雷的地方插旗(称为标…...
LeetCode组合总和
题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被…...
MATLAB - 机械臂手眼标定(眼在手内) - 估计安装在机器人上的移动相机的姿态
系列文章目录 前言 本示例展示了如何为装有手眼构型摄像头的机械臂或机械手执行和验证手眼校准。 一、概述 执行手眼校准有助于操作配备末端执行器(简称 “手”)的机械臂,该末端执行器依赖于摄像头提供的视觉数据。一旦完成了眼在手外的校准&…...
【Unity】TextMeshPro 3.0.9无法显示emoji表情问题
需要下载TextMeshPro 3.2.x-pre.xxx版本,重新生成Sprite Asset文件解决 注意:若Package Manager没有搜到pre版本,那么可以去github下载到本地,再解压后,将文件夹移动到工程Packages文件夹下,然后打开Packa…...
金九银十软件测试面试题(800道)
今年你的目标是拿下大厂offer?还是多少万年薪?其实这些都离不开日积月累的过程。 为此我特意整理出一份(超详细笔记/面试题)它几乎涵盖了所有的测试开发技术栈,非常珍贵,人手一份 肝完进大厂 妥妥的&#…...
中国剩余定理 C++
题目 解题思路 原链接:https://www.acwing.com/solution/content/3539/ 大致步骤: 将第2,3,4…n个方程不断与第一个方程合并,得到方程a1k1a2k2m2-m1;用扩展欧几里得算法解出a1k1a2k2gcd(a1, a2)的结果,再将结果扩大(m2-m1)/d倍即…...
动态规划lc
先找到规律,然后找边界情况;部分特殊情况分类讨论 *递归 70.爬楼梯 简单 提示 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:…...
介绍xshell的使用技巧
使用技巧目录 1. 开启左键选中即复制,右键点击即粘贴2. 开启撰写功能3. 开启日志记录功能 1. 开启左键选中即复制,右键点击即粘贴 参考:https://blog.csdn.net/chirrupy_hamal/article/details/108619262 2. 开启撰写功能 使用场景&#x…...
揭秘语音识别巨头1:国内外顶尖技术服务商全解析01(万字长文)
一、学习导航 解密语音识别巨头:国内顶尖技术服务商全解析00:学习地图 解密语音识别巨头:国内顶尖技术服务商全解析01:微软语音,商业No.1 解密语音识别巨头:国内顶尖技术服务商全解析02:百度…...
JAVA使用SM2算法生成密钥对加密解密加签验签
简介 SM2是非对称加密算法,一提非对称加密算法,第一想到的是RSA,没错,这个就是替代RSA的。它是基于椭圆曲线密码的公钥密码算法标准,其秘钥长度256bit,包含数字签名、密钥交换和公钥加密,用于替…...
uniapp(vue)打包web项目页面刷新后报404解决方案
一、问题概述 uniapp是一款优秀的跨平台开发框架,它可以帮助开发者快速构建出适用于多端的应用程序。然而,在项目打包后,有可能发现页面在刷新时会出现404错误。这无疑给用户体验带来了极大的困扰,下面我们就来分析一下这个问题。…...
ansible学习之ansible-vault
相关文档参考:http://www.ansible.com.cn/docs/playbooks_vault.html#what-can-be-encrypted-with-vault ansible-vault 功能介绍 Ansible-Vault是一个用于加密和管理Ansible playbook中敏感数据的工具。通过创建、编辑、加密、解密、查看和重置密码,可以安全地存储…...
封装el-upload组件,用于上传图片和视频的组件
使用环境 vue3element plus 需要根据后端返回结构修改的函数:onPreview onRemove onSuccess 组件使用 基本使用 源代码: <script setup> import AutoUploadFile from /components/auto-upload-file/index.vue function change(urls){console.log…...
6.将扩散模型与其他生成模型的关联(2)
1.归一化流与扩散模型 自一化流(Normalizing Flow)是生成模型,通过将易于处理的分布进行变换以队对高维数据进行建模。归一化流可以将简单的概率分布转化为极其复杂的分布,并用于强化学习、变分推理等领域。 现有的归一化流是基于变量替换公式构…...
【C++】基于红黑树封装set和map
🚀个人主页:小羊 🚀所属专栏:C 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 前言一、更高维度的泛型二、模版参数三、比较逻辑的重写四、迭代器4.1 const迭代器4.2 重载4.3 - -重载 五、完整代…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
