- 博客(545)
- 资源 (1)
- 收藏
- 关注
原创 u-boot完全分析与移植-U-Boot的功能
"U-Boot" 是 "Universal Bootloader" 的简称,是一个广泛使用的开源引导程序,主要用于嵌入式系统。U-Boot 的主要功能是在设备启动时初始化硬件、加载操作系统内核并将控制权移交给内核。它支持多种处理器架构和硬件平台,因此在嵌入式设备、单板计算机、路由器等多种设备中得到了广泛应用。U-Boot 允许用户通过命令行界面执行各种任务,如修改引导参数、调试硬件问题、从网络或存储设备加载操作系统镜像等。这种灵活性使得 U-Boot 成为嵌入式开发中的一个重要工具。
2024-08-21 21:43:44
365
原创 韦东山嵌入式linux系列-mmap
ARM 架构支持一级页表映射,也就是说 MMU 根据 CPU 发来的虚拟地址可以找到第 1 个页表,从第 1 个页表里就可以知道这个虚拟地址对应的物理地址。一级页表里地址映射的最小单位是 1M。ARM 架构还支持二级页表映射,也就是说 MMU 根据 CPU 发来的虚拟地址先找到第 1 个页表,从第 1 个页表里就可以知道第 2 级页表在哪里;再取出第 2级页表,从第 2 个页表里才能确定这个虚拟地址对应的物理地址。二级页表地址映射的最小单位有 4K、 1K, Linux 使用 4K。
2024-08-06 21:18:29
949
原创 韦东山嵌入式linux系列-驱动程序基石
值得注意的是,上面 2个红线部分都属于 APP1 的“上下文”,或者这样说:红线所涉及的代码,都是 APP1调用的。但是按键的中断服务程序,不属于 APP1的“上下文”,这是突如其来的,当中断发生时, APP1正在休眠呢。当 APP1 再次运行时,就会继续执行 drv_read 中剩下的代码,把数据复制回用户空间,返回用户空间。在中断的处理过程中,也就是 gpio_key_irq 的执行过程中,它不能休眠:“中断”怎么能休眠?在 APP1的“上下文”,也就是在 APP1的执行过程中,它是可以休眠的。
2024-07-31 22:24:58
645
原创 韦东山嵌入式linux系列-Linux 系统对中断的处理
以前用 work 来线程化地处理中断,一个 worker 线程只能由一个 CPU 执行,多个中断的 work 都由同一个 worker 线程来处理,在单 CPU 系统中也只能忍着了。而这些线程,之间是互相独立的,“同时运行”,也就是说:每一个线程,都有自己的栈。在中断的处理过程中,该 CPU 是不能进行进程调度的,所以中断的处理要越快越好,尽早让其他中断能被处理──进程调度靠定时器中断来实现。可以,但是开销太大:读按键的程序,要把按键通知播放音乐的程序,进程间通信的效率没那么高。
2024-07-27 17:37:59
775
原创 韦东山嵌入式linux系列-异常与中断的概念及处理流程
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。后面的 3 种方式,都需要“小孩来中断妈妈”:中断她的睡眠、中断她的工作。
2024-07-27 11:56:07
821
原创 韦东山嵌入式linux系列-GPIO 和 Pinctrl 子系统的使用
前面的学习,我们使用直接操作寄存器的方法编写驱动。这只是为了让大家掌握驱动程序的本质,在实际开发过程中我们可不这样做,太低效了!如果驱动开发都是这样去查找寄存器,那我们就变成“寄存器工程师”了,即使是做单片机的都不执着于裸写寄存器了。Linux 下针对引脚有 2 个重要的子系统: GPIO、 Pinctrl。
2024-07-26 17:45:50
714
原创 韦东山嵌入式linux系列-具体单板的按键驱动程序(查询方式)
button_operations 结 构 体 中 有 init 函 数 指 针 , 它 指 向board_stm32mp157_button_init 函数,在里面将会初始化 LED 引脚:使能、设置为 GPIO 模式、设置为输出引脚。该寄存器共32位,涉及16个GPIO,每个GPIO对应 2 位。button_operations 结 构 体 中 还 有 有 read 函 数 指 针 , 它 指 向board_stm32mp157_button_read 函数,在里面将会读取并返回按键引脚的电平。
2024-07-24 22:27:20
1168
1
原创 韦东山嵌入式linux系列-gpio_drv_template
合并 LED 、 BUTTON 框 架 驱 动 程 序 :01_led_drv_template 、01_button_drv_template,合并为:gpio_drv_template
2024-07-23 21:39:34
307
原创 韦东山嵌入式linux系列-查询方式的按键驱动程序_编写框架
这样的结构易于扩展,对于不同的单板,只需要替换 board_xxx.c 提供自己的 button_operations 结构体即可。register_button_operations 函 数代码如下,它还根据底层提供button_operations 调用 device_create,这是创建设备节点。上层是 button_drv.c,它的核心是 file_operations 结构体,首先看看入口函数,代码如下。按键被按下后,上图中左边的 GPIO 电平为低,右边的 GPIO 电平为高。
2024-07-22 22:30:17
956
原创 韦东山嵌入式linux系列-APP 怎么读取按键值
在做单片机开发时,要读取GPIO按键,通常是执行一个循环,不断地检测GPIO引脚电平有没有发生变化。。这 4 种方法并不仅仅用于 GPIO 按键,在所有的APP 调用驱动程序过程中,都是使用这些方法。通过这 4 种方式的学习,可以掌握如下知识:① 驱动的基本技能:中断、休眠、唤醒、 poll 等机制。这些基本技能是驱动开发的基础,其他大型驱动复杂的地方是它的框架及设计思想,但是基本技术就这些。② APP 开发的基本技能:阻塞 、非阻塞、休眠、 poll、异步通知。
2024-07-21 19:09:38
750
原创 韦东山嵌入式linux系列-LED 模板驱动程序的改造:设备树-具体单板stm32mp157的驱动程序
韦东山嵌入式linux系列-LED 模板驱动程序的改造:设备树-具体单板stm32mp157的驱动程序
2024-07-21 10:13:46
355
原创 韦东山嵌入式linux系列-LED 模板驱动程序的改造:设备树
① dts 在PC机上被编译为 dtb 文件;② u-boot 把dtb文件传给内核;③ 内核解析dtb文件,把每一个节点都转换为 device_node 结构体;④ 对于某些 device_node 结构体,会被转换为 platform_device 结构体。
2024-07-20 12:11:57
817
原创 韦东山嵌入式linux系列-驱动进化之路:设备树的引入及简明教程
在内核中,使用同一个芯片的板子,它们所用的外设资源不一样,比如A板用 GPIO A, B 板用 GPIO B。而 GPIO 的驱动程序既支持 GPIO A 也支持GPIO B,你需要指定使用哪一个引脚,怎么指定?比如 LED 驱动,在内核的驱动程序里去操作寄存器,但是操作哪一个引脚?请想想,要操作硬件就需要去操作复杂的寄存器,如果设备树可以操作寄存器,那么它就是“驱动”,它就一样很复杂。设备树并不是重新发明出来的,在 Linux 内核中其他平台如 PowerPC,早就使用设备树来描述硬件了。
2024-07-18 22:30:00
923
原创 韦东山嵌入式linux系列-LED 模板驱动程序的改造:总线设备驱动模型
p_led_opr这个指针是由底层芯片相关的(chip_demo_gpio.c)代码提供的,其中chip_demo_gpio.c这里面有led_operations结构体,结构体中有init/ctl函数。应用程序调用open/write等函数最简单的方法时驱动层也提供对应的drv_open/drv_write,应用程序调用read/write,驱动层也提供对应的drv_open/drv_write等等,需要写出驱动层的函数。platform_driver有name,和platform_device匹配;
2024-07-17 22:43:45
1001
原创 韦东山嵌入式linux系列-驱动进化之路:总线设备驱动模型-课后作业
③ 进入 platform_device_register/platform_driver_register 内部,分析 dev 和 drv 的匹配过程。有一个platform device,里面有resource,resource指向一个数组,里面定义了设备的资源,平台设备指定资源。(1)搜索 platform_device_register,随便找一个文件,找有全局变量的。(4)继续搜索它的platform_driver,按名称搜索(orion_nand)(2)点进去,在这个文件中可以看到注册。
2024-07-16 23:07:14
214
原创 韦东山嵌入式linux系列-驱动进化之路:总线设备驱动模型
应用程序调用open等函数最简单的方法是驱动层也提供对应的drv_open,应用程序调用read,驱动层也提供对应的drv_read等等。需要写出驱动层的函数,为了便于管理,将这些函数放到file_operations结构体中,即第一步定义对应的file_operations结构体,并实现对应的open等程序(第一步);实现完成之后,将file_operations结构体通过register_chrdev注册到内核(第二步);然后通过入口函数调用注册函数(chrdev),安装驱动程序的时候,内核会调用入口函
2024-07-13 19:58:18
931
原创 韦东山嵌入式linux系列-驱动设计的思想(面向对象/分层/分离)
比如 board_A.c 使用芯片 chipY,那就可以写出: chipY_gpio.c,它实现芯片 Y 的 GPIO 操作,适用于芯片 Y 的所有 GPIO 引脚。以面向对象的思想,在 board_A_led.c 中实现 led_resouce 结构体,它定义“资源”──要用哪一个引脚。在 chipY_gpio.c 中仍是实现 led_operations 结构体,它要写得更完善,支持所有 GPIO。a) 有方向寄存器 DIR、数据寄存器DR等,基础地址是addr_base_addr_gpio1。
2024-07-13 17:32:01
1036
原创 韦东山嵌入式linux系列-具体单板的 LED 驱动程序
1怎么写 LED 驱动程序?详细步骤如下:① 看原理图确定引脚,确定引脚输出什么电平才能点亮/熄灭 LED② 看主芯片手册,确定寄存器操作方法:哪些寄存器?哪些位?地址是?③ 编写驱动:先写框架,再写硬件操作的代码注意:在芯片手册中确定的寄存器地址被称为物理地址,在 Linux 内核中无法直接使用。
2024-07-13 12:48:50
809
原创 韦东山嵌入式linux系列-LED 驱动程序框架
③ 实现对应的 drv_open/drv_read/drv_write 等函数,填入 file_operations 结构体;④ 把 file_operations 结构体告诉内核:通过 register_chrdev 函数;⑤ 谁来注册驱动程序?需要一个入口函数:安装驱动程序时,就会去调用这个入口函数;⑥ 有入口函数就应该有出口函数:卸载驱动程序是,出口函数调用unregister_chrdev;
2024-07-11 22:08:12
677
原创 韦东山嵌入式linux系列-LED驱动程序
之前学习STM32F103C8T6的时候,学习过对应GPIO的输出:操作STM32的GPIO需要3个步骤:这里再看看STM32MP157的GPIO引脚使用。
2024-07-08 22:22:06
914
原创 韦东山嵌入式linux系列-第一个实验
笔者使用的是韦东山STM32MP157 Pro的板子,环境搭建部分按照说明文档配置完成。配置桥接网卡实现板子、windows、ubuntu的通信,也在开发板挂载 Ubuntu 的NFS目录 ,这里就不再赘述了。板子: 192.168.5.9在板子上执行。
2024-07-07 16:18:19
671
原创 《linux系统内核设计与实现》-内核空间和用户空间的概念以及内核空间和用户空间的数据拷贝
整个系统中有各种资源,比如计算资源、内存资源和外设资源,而linux是多用户、多进程系统,所以,这些资源必须在受限的、被管理的状态下使用,要不然就陷入了混乱。(3)从软件设计思想来看,解除了核心代码和业务逻辑代码的耦合内核代码偏重于系统管理;对于x86体系的cpu,用户空间代码运行在Ring3模式,内核空间代码运行Ring o模式;对于arm体系的cpu,用户空间代码运行在usr模式,内核空间代码运行在svc模式;read.c:把内核空间的数据拷贝到内核空间。write.c:将用户数据拷贝到内核空间。
2024-07-07 08:53:25
451
原创 《linux系统内核设计与实现》-实现最简单的字符设备驱动
驱动也需要,但是驱动不能链接和使用应用层的任何lib库,驱动需要引用内核的头文件和函数。所以,编译的时候需要指定内核源码的地址。为了开发方便,也可以安装内核开发包,之后引用这个内核开发包的目录也可以。驱动代码如下 helloDev.c,这是一个最小、最简单的驱动,去掉了其他的不相干代码,尽量让大家能了解驱动本身。linux应用层程序在编译的时候,需要链接c运行时库和glibc库。有了驱动文件之后,还需要一个Makefile才能把驱动编译出来。编译出来的驱动文件,名称为:helloDev.ko。
2024-07-07 08:34:24
433
原创 《linux系统内核设计与实现》第三章-进程管理
在Linux系统中,这通常是调用fork()系统的结果,该系统调用通过复制一个现有进程来创建一个全新的进程。进程描述符中包含的数据能完整地描述一个正在执行的程序:它打开的文件,进程的地址空间,挂起的信号,进程的状态,还有其他更多信息。在传统的Unix系统中,一个进程只包含一个线程,但现在的系统中,包含多个线程的多线程程序司空见惯。通常,创建新的进程都是为了立即执行新的、不同的程序,而接着调用exec()这组函数就可以创建新的地址空间,并把新的程序载入其中。实际上,进程就是正在执行的程序代码的实时结果。
2024-04-22 11:15:33
759
原创 《linux系统内核设计与实现》第二章-从内核触发
登录Linux 内核官方网站http://www.kernel.org,可以随时获取当前版本的Linux源代码,可以是完整的压缩形式(使用tar命令创建的一个压缩文件),也可以是增量补丁形式。配置选项CONFIG_IKCONFIG_PROC把完整的压缩过的内核配置文件存放在/proc/config.g下,这样当你编译一个新内核的时候就可以方便地克隆当前的配置。尽管这些缺省值有点随意性(在i386上,据说那就是Linus的配置),但是,如果你从未配置过内核,那它们会提供一个良好的开端。
2024-04-14 18:04:25
1005
3
原创 《linux系统内核设计与实现》第一章-linux内核简介
内核有时候被称作是管理者或者是操作系统核心。通常一个内核由负责响应中断的中断服务程序,负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间的内存管理程序和网络、进程间通信等系统服务程序共同组成。对于提供保护机制的现代系统来说,内核独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限。这种系统态和被保护起来的内存空间,统称为内核空间。相对的,应用程序在用户空间执行。
2024-04-14 10:48:07
886
原创 CMU15/445 2023 Spring-project1 LRU-K 替换策略
在通读完15/445这块的说明之后,发现和LRU还是有些差别的。官方文档中对LRU-K的解释是:LRU-K算法根据所谓的“后向k距离”来确定替换哪个缓存帧。。如果某个缓存帧的历史访问次数少于k次,。换句话说,它会替换最近访问时间最早的缓存帧,从而使得系统更可能淘汰不常用的数据,而保留最常用的数据。解释一下:之前学习的LRU算法是替换/最近最少使用的数据,在具体实现上采用的是哈希+双向链表的形式,将最近使用的数据放在双向链表表头,最少使用的放在尾部。这里的LRU-K算法是以当前节点位基准,往前计数到。
2024-04-06 11:06:29
927
转载 C++14 新特性总结
C++14中增加了deprecated标记,修饰类、变、函数等,当程序中使用到了被其修饰的代码时,编译时被产生警告,用户提示开发者该标记修饰的内容将来可能会被丢弃,尽量不要使用。(5)返回类型推导可以用在递归函数中,但是递归调用必须以至少一个返回语句作为先导,以便编译器推导出返回类型。(1)C++11中constexpr函数可以使用递归,在C++14中可以使用局部变量和循环。(4)返回类型推导可以用在前向声明中,但是在使用它们之前,翻译单元中必须能够得到函数定义。
2024-04-01 21:49:03
438
转载 C++11新特性智能指针
在实际的 C++ 开发中,我们经常会遇到诸如程序运行中突然崩溃、程序运行所用内存越来越多最终不得不重启等问题,这些问题往往都是内存资源管理不当造成的。针对以上这些情况,很多程序员认为 C++ 语言应该提供更友好的内存管理机制,这样就可以将精力集中于开发项目的各个功能上。事实上,显示内存管理的替代方案很早就有了,早在 1959 年前后,就有人提出了“垃圾自动回收”机制。所谓垃圾,指的是那些不再使用或者没有任何指针指向的内存空间,而“回收”则指的是将这些“垃圾”收集起来以便再次利用。
2024-04-01 20:46:56
100
转载 cmake学习
set_target_properties重新定义了库的输出名称,如果不使用set_target_properties也可以,那么库的名称就是add_library里定义的名称。具体可以参考官方文档。LIBRARY_OUTPUT_PATH 是cmake系统变量,项目生成的库文件都放在这个目录下。此时可以使用cmake中的函数存储这些源文件。只需要在CMakeLists.txt中添加所依赖的.cpp文件,编译步骤和上面相同。他的作用是把dir目录中的所有源文件都储存在var变量中。根据上面的《三》和《四》。
2024-03-31 17:43:22
45
原创 百度飞桨大模型训练营:人工智能与大语言模型
解释这些概念AI是计算机学科下的一个分支学科,旨在使用计算机使之能像人类一样学习和思考问题机器学习是AI的一个子集,它的一个重要特点就是不需要人去做显示编程(不用手撕函数),让计算机自行学习迭代总结规律,做出预测和决策。
2024-03-15 21:44:33
1637
原创 【数据结构】B树
B树(英语:B-tree),是一种在计算机科学自平衡的树,能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作,都在对数时间内完成。B树,概括来说是一个一般化的二叉搜索树(binary search tree)一个节点可以拥有2个以上的子节点。与自平衡二叉查找树不同,B树适用于读写相对大的数据块的存储系统,例如磁盘。B树减少定位记录时所经历的中间过程,从而加快访问速度。B树这种数据结构可以用来描述外部存储。这种数据结构常被应用在数据库和文件系统的实现上。
2024-03-03 21:10:27
1197
原创 【算法】二叉搜索树的插入、删除、转换操作
对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。如果前一个节点小于当前节点,则将插入数据放到前一个节点的右子树上;二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。如果前一个节点大于当前节点,则将插入数据放到前一个节点的左子树上;另一个正确答案是 [5,2,6,null,4,null,7]。
2024-02-29 08:28:47
958
原创 【LeetCode刷题】146. LRU 缓存
(a)如果 key 不存在,使用 key 和 value 创建一个新的节点,在双向链表的头部添加该节点,并将 key 和该节点添加进哈希表中。然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项;通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值。(b)如果 key 存在,则与 get 操作类似,先通过哈希表定位,再将对应的节点的值更新为 value,并将该节点移到双向链表的头部。// 缓存是 {1=1, 2=2}
2024-02-27 22:11:00
1230
原创 CMU15/445 2023 Spring-project0 基于字典树的增删改查
CMU15/445 2023 Spring-project0 基于字典树的增删改查
2024-02-21 08:27:25
564
一个可用的MinGW(gcc version 8.1.0 (x86-64-win32-seh-rev0, Built by M)
2023-08-06
VS code配置C++环境,上传我自己的MinGW编译环境,直接解压即可
2023-08-04
python爬取豆瓣电影top250
2020-09-15
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人