- 博客(66)
- 收藏
- 关注
原创 Linux开发讲课39---设置和查看Linux系统的环境和Shell这两种变量
希望这对你的工作也有帮助。Shell 会话有不同的启动方式,比如,连接到终端的交互式 Shell 与未连接到终端的非交互式 Shell,还有登录式 Shell 与非登录式 Shell, 而 bash Shell 会根据会话不同的启动方式而读取不同的配置文件。Shell 会话有不同的启动方式,比如,连接到终端的交互式 Shell 与未连接到终端的非交互式 Shell,还有登录式 Shell 与非登录式 Shell, 而 bash Shell 会根据会话不同的启动方式而读取不同的配置文件。
2024-07-21 13:27:03
437
原创 头文件的用法和规则
预编译user1.c时,读取到了include "calc.h"语句后,会将calc.h中的内容搬运过来,放在临时文件之中。饭店在制作菜单时,往往只会写上菜名,而不会暴露过多的细节,如某道菜里面有哪些佐料,是如何烹饪的。如果你是在嵌入式IDE中进行实验的话,可以把相关文件的编译指令复制出来,去掉-o参数和-d参数,加上-E参数即可。:依次编译每一个源代码文件,包括C文件,C++文件,汇编文件(.s),生成对应的目标文件(.o)。对外接口的声明及其所依赖的类型定义、变量声明,在这里,是不是都齐了呢。
2024-07-20 16:40:42
848
原创 Linux开发讲课38--- 调试程序打印日志
上述示例中,LOG_D("rssi:%d", 30)中的"rssi:%d"是格式化字符串,对应于LOG_D(fmt, ...)中的fmt参数,30则属于变长参数。logger_output的实现如下,先打印时间和来源,之后调用了va_list版本的snprintf,即vsnprintf,以打印用户传递的格式化字符串和变长参数。单片机的驱动库往往只提供基础的操作外设的接口,如uart,i2c,spi,而不提供高层次的SDK。如果根据日志内容的重要性对日志分级,以不同的颜色来显示不同级别的内容,则更容易观察。
2024-07-18 21:37:36
653
原创 new和malloc
在C++和C语言编程中,动态内存分配是一个核心概念,它允许程序在运行时根据需要分配或释放内存。New(在C++中)和Malloc(在C中)是两种常用的动态内存分配方法。newmalloc在C++中,new操作符用于动态地分配内存。它不仅分配所需的内存量,还调用对象的构造函数(对于非内置类型)。类似地,在C语言中,malloc函数用于在堆上分配指定字节数的内存。这两者都不会初始化所分配的内存(除了new可能会调用对象的构造函数进行初始化)。
2024-07-18 21:19:43
694
原创 C语言指针
指针类型不指针类型不是是单独存在的,它是由其他类型派生而来的,它的类型可以是指向int的指针类型,或者“指向double的指针类型”,可以分别使用这些方法定义。虚拟存储器是一块很大的空间,可以把它看成一个一个连续的小方格,每个方格的大小是一个字节(byte),也就是八个比特位,可以存放一个八位的二进制数,比如101010。可以这样定义一个数组,当李华定义了一个长度为5的整形(int)数组b时,C程序在内存中连续划分出5个大小为4字节的存储空间,并把第一个格子的地址作为整个数组的地址,数据便被保存在其中,
2024-07-15 20:08:47
897
原创 AD9026芯片开发实录7----API中的Error 模块
2.report方法:该方法用来记录错误,并更新设备结构体中的错误模块,主要是更新error结构体中的所有成员,但是这里需要结合上述的错误行为的策略,report接口中会判断当前传入的action和error结构体中的newAction,如果严重程度比newAction大,则会更新错误结构体,包括错误码,错误源以及错误信息等,并将原来的newAction保存到lastAction中,更新newAction为输入到report接口中的action。宏接口为 ADI_ERROR_REPORT。
2024-07-14 16:36:53
900
原创 DRAM,SRAM,FLASH和新型NVRAM
DRAM是易失性存储器,这意味着当存储位放电的电容器时,DRAM将丢失其存储器的内容。这样做的原因是,当擦除FLASH位时,需要大的电势电压(大约20 V)才能去除捕获在浮栅中的电子。与DRAM不同,FLASH存储器是非易失性的,这意味着FLASH存储器在关闭时将保留存储到其中的所有数据。这意味着,当从DRAM中读取一个位时,所访问的存储位的内容将被遗忘,因此需要回写操作。尽管本文绝不是对所有内存技术的全面讨论,但在讨论所提出的内存技术时,DRAM,SRAM和FLASH可以为我们提供有用的比较点。
2024-07-13 19:23:03
648
原创 中断的五个步骤
无论是外部中断还是内部中断,中断处理过程 都要经历以下步骤: 请求中断→响应中断→关闭中断→保留断点→中断源识别→保护现场→中断服务子程序→恢复现场→中断返回。CPU响应中断后,输出中断响应信号,自动将状态标志寄存器FR或EFR的内容压入堆栈保护起来,然后将FR或EFR中的中断标志位IF与陷阱标志位TF清零,从而自动关闭外部硬件中断。中断服务是执行中断的主体部分,不同的中断请求,有各自不同的中断服务内容,需要根据中断源所要完成的功能,事先编写相应的中断服务子程序存入内存,等待中断请求响应后调用执行。
2024-07-13 19:13:54
393
原创 Linux开发讲课37--- ARM的22个常用概念
一个典型的应用就是应用程序存储在Flash/ROM中,初始这些存储器地址是从0开始的,但这些存储器的读 时间比SRAM/DRAM长,造成其内部执行频率不高,故一般在前面一段程序将代码搬移到SRAM/DRAM中去,然后重 新映射存储器空间,将相应SRAM/DRAM映射到地址0,重新执行程序可达到高速运行的目的。指令预取中止⑤:若处理器的预取指令的地址不存在,或该地址不允许当前指令访问,存储器会向理器发出中止信号,当预取指令被执行时,才会产生指令预取中止异常(异常向量:0x0000,000C);
2024-07-13 12:40:35
710
原创 Linux开发讲课36--- ARM中的进程
为什么引入进程的概念? 从理论角度看,是对正在运行的程序过程的抽象; 从实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。 什么是进程? 狭义定义:进程就是一段程序的执行过程。 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。 进程有怎么样的特征? 动态性:进程的实质是程序在多道程序系统中的一次
2024-07-12 23:31:34
508
原创 Linux开发讲课35--- 文件I/O
总之,如果需要强制刷新内核缓冲区,那么在设计应用程序时就应该考虑是否可以使用大尺寸的write()缓冲区,或者调研fsync或fdatasync时谨慎行事,而不是打开文件时就使用O_sync标志。
2024-07-11 21:37:13
1709
原创 Linux开发讲课34---文件描述符
内核空间是虚拟地址空间的一部分,想死磕的读者请猛击《C语言内存精讲》,不想纠缠细节的读者可以这样理解:进程启动后要占用内存,其中一部分内存分配给了文件描述符表。控制块,PCB 内部有一个文件描述符表(File descriptor table),记录着当前进程所有可用的文件描述符,也即当前进程所有打开的文件。文件描述符表每个进程都有一个,打开文件表和 i-node 表整个系统只有一个,它们三者之间的关系如下图所示。通过文件描述符,可以找到文件指针,从而进入打开文件表。
2024-07-10 20:18:06
1884
原创 Linux开发讲课33---线程实现与线程控制步骤简析
当信号量sem 的值大于或等于0时,该进程(或线程)具有公共资源的访问权限;这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。由于线程共享进程的资源和地址空间,因此在对这些资源进行操作时,必须考虑到线程间资源访问的惟一性问题,这里主要介绍 POSIX 中线程同步的方法,主要有互斥锁和信号量的方式。要注意的是,由于线程共享了进程的资源和地址空间,因此,任何线程对系统资源的操作都会给其他线程带来影响,因此,多线程中的同步就是非常重要的问题了。
2024-07-06 22:38:05
737
原创 Linux开发讲课32---宏定义与volatile有何功能
(unsigned int *)0xC000A001:表示取出地址(unsigned int *)0xC000A001指向的内存空间里的内容。(unsigned int *)0xC000A001:数值0xC000A001经过(unsigned int *)强制转换成:表示地址。或 GPIOALT &= (~(0x3 << 8));等号右边:表示取出地址(unsigned int *)0xC000A001里面的值(数据)等号左边:地址(unsigned int *)0xC000A001指向的内存空间。
2024-07-06 21:51:38
526
原创 Linux开发讲课31---Linux开发环境下的Arm gcc交叉编译介绍
为了让这个流程变得简单,开发者们为不同的芯片开发了不同的编译器,比如针对 Arm 平台的 arm-linux-gcc,针对 mips 平台的 mips-linux-gnu-gcc,这些编译器都是基于 GCC 针对具体的架构指令集进行对应配置,所以它们在运行的时候就就会生成和该目标平台对应的可执行文件。程序最后运行的环境变了,比如你的开发板是基于 Arm 的——程序在 X86 上编辑,编译,最终运行在另一个和 X86 完全不同的架构的 Arm 芯片上。带 [] 的是可选部分。
2024-07-06 21:50:02
849
原创 Linux开发讲课30---基于ARM体系的内核启动解析
* 禁用抢占的情况下调用cpu_idle */ cpu_startup_entry(CPUHP_ONLINE);内核启动有两种方式,压缩格式或不压缩格式,压缩模式所不同的就是其入口位于arch//boot/compressed/head.S,为与该路径下的代码主要负责执行执行前期的初始化为解压内核做准备。/*创建init进程,第一个用户空间进程我们 *需要首先生成init,以便它获得pid 1,但是 *init任务最终将要创建kthread,如果在创建 *kthreadd之前对其进行调度,则OOPS。
2024-07-04 21:16:19
1253
原创 AD9026芯片开发实录6-example code
3. 通过daughterBoard->DeviceCreate,完成Clock/FPGA/TrxBoard 的Dispatch方法注册,用于后续的Clock/FPGA/TrxBoard的硬件初始化和配置操作,然后实例化Clock/FPGA/ADRV902X设备,在代码中对应结构体`adi_ad9528_Device_t`/`adi_adrv9025_Device_t`/`adi_fpga9010_Device_t`;这些库的构建,均可以通过./c_src/boards下的makefile触发。
2024-07-02 21:15:57
802
原创 Linux开发讲课29---Linux USB 设备驱动模型
对于控制传输、批量传输、中断传输,有 3 个同步函数可以用来直接发起传输。这些函数内部会创建、填充、提交一个 URB("usb request block"),并等待它完成或超时。使用 URB 进行传输时,它是异步方式:需要先分配、构造、提交一个 URB("usb request block"),当传输完成后,它的回调函数被调用。这个 buffer 可以是一般的 buffer,也可以是 DMA Buffer。构造好 URB 后,需要提交到 USB 系统里,才能启动传输。
2024-06-30 00:32:54
1016
原创 Linux开发讲课28---USB驱动实例
设备描述符包含了设备遵循的 USB 的版本号、设备类、设备子类、制造商、产品编号等信息,主机会通过控制传输的方式获取这个设备描述符,通过这个设备描述符就能知道当前是什么设备了。当USB设备插入系统之后,根据硬件设计的特性,会被USB主机控制器第一时间知道,然后主机控制器就会问当前插入的设备是什么设备。中断传输的经典代表是USB鼠标和USB键盘,这里说的中断不是真正硬件发出的中断,而是一种轮询机制,。USB电子扫码枪的驱动与USB键盘驱动通用,只是数据包的大小是64字节,匹配的类型也是使用键盘的类型。
2024-06-30 00:23:58
1139
原创 Linux开发讲课27---USB驱动介绍
Linux内核支持两种主要类型的USB驱动程序:USB主机(Host)驱动程序和USB设备(device)驱动。主机驱动程序控制插入其中的USB设备,而USB设备驱动程序控制该设备如何作为一个USB设备和主机通信(注重的是方式)。
2024-06-30 00:07:46
912
原创 Linux开发讲课26---PCIe
每通道数据传输速率从PCIe 5.0的32 GT/s翻番至64 GT/s,PCIe 6.0*16通道的带宽高达256 GB/s,除了带宽和效率的提升外,PCIe 6.0还具有更低的延迟,是PCIe技术的又一大飞跃。PCIe连接开始链路训练过程并进入配置阶段,在该阶段中,由于通道长度变化而导致数据中的任何偏差都能得到校准,PCIe链路的宽度、链路速率、链路翻转和链路极性也在此阶段确定。然而在某些主板设计中,尤其是那些具有长通道链路的主板,这种信号质量无法实现,可能需要另外的信号调节。
2024-06-29 23:31:40
888
原创 Linux开发讲课25---GPIO(和单片机、ARM上的引脚是一个概念?)
很多模块的功能管脚,严格意义上来讲也是IO,比如CANH,CANL,所以这里为了避免混淆,就将没有定义成模块功能管脚 的那些单片机管脚定义成General Purpose的IO了,以示区别。比如定义成SPI模块的管脚,那就按照具体芯片的规定,或者定义成MOSI, 或者定义成MISO,或者定义成SCLK,这些不是任意的。数据寄存器的每一位是和GPIO的硬件引脚对应的,而数据的传递方向是通过控制寄存器设置的,通过控制寄存器可以设 置每一位引脚的数据流向。当定义成GPIO时,可以定义成高阻,输入,或者输出。
2024-06-29 20:13:11
156
原创 Linux开发讲课24---GPIO(以单片机举例)
这里需要注意的是,当GPIO工作在模拟模式下时,不论输入还是输出,都只使用到I/O引脚;当GPIO配置为输出、复用模式时会使用到输出驱动器,输出信号从输出数据寄存器或片上外设送至到输出驱动器,由输出类型寄存器配置双MOS管的工作以及输出速度寄存器配置输出控制的工作,以实现输出驱动器的驱动功能,最终通过I/O引脚输出,如图。当需要输出高电平时,P-MOS管不工作,N-MOS管关闭,引脚不输出任何电平,呈现高阻态,要想使其能够输出高电平,还需要通过外接上拉电阻的方式才能输出,输出电压就是上拉电阻的电源电压;
2024-06-29 20:10:54
630
原创 Linux开发讲课22---I2C读写 EEPROM 实验(含代码)
在 I2C 通讯的很多过程,都需要检测事件,当检测到某事件后才能继续下一步的操作,但有时通讯错误或者 I2C 总线被占用,我们不能无休止地等待下去,所以我们设定每个事件检测 都有等待的时间上限,若超过这个时间,我们就调用 I2C_TIMEOUT_UserCallback 函数输出调试信息(或可以自己加其它操作),并终止 I2C通讯。EEPROM 芯片中还有一个 WP 引脚,具有写保护功能,当该引脚电平为高时,禁止写入数据,当引脚为低电平时,可写入数据,我们直接接地,不使用写保护功能。
2024-06-29 19:33:44
630
原创 Linux开发讲课21--- I2C
若配置的方向传输位为“写数据”方向, 即第一幅图的情况, 广播完地址,接收到应答信号后, 主机开始正式向从机传输数据(DATA),数据包的大小为 8 位,主机每发送完一个字 节数据,都要等待从机的应答信号(ACK),重复这个过程,可以向从机传输 N 个数据,这个 N 没有大小限制。当主机接收到这些数据后,会产生“EV7”事件, SR1 寄存器的 RXNE 被置 1,表示接收数据寄存器非空,我们读取该寄存器后,可对 数据寄存器清空,以便接收下一次数据。(4) 发送非应答信号后,产生停止信号§,结束传输。
2024-06-29 19:22:15
844
原创 Linux开发讲课20--- QSPI
因此,QSPI 还提供了间接模式,间接模式下,需要指定每一次数据传输过程的每一个细节:如指令阶段的参数是什么,地址阶段的具体地址值是多少等,虽然复杂,但给了我们充分通过 QSPI 访问 QSPI Flash 的方法,例如,当我们希望写修改 QSPI Flash 中的数据时,就可以使用间接写模式,将数据阶段的传输方向由 QSPI Flash 到 Host 转变为 Host 到 QSPI Flash,而在直接模式下,数据阶段只能是由 QSPI Flash 到 Host。写使能和写失能,只需要指令阶段;
2024-06-29 18:34:48
814
原创 Linux开发讲课19--- SPI原理
在一主多从模式下,每个从设备都有一条独立的CS信号线,如果要和特定的从机进行通讯,可以将相应的CS(下图使用NSS表示)信号线拉低。SPI接口为收发为双全工串行方式传输,收发同步,主设备发出一位给从设备时,从设备也发出一位给主设备。SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是MOSI(主出从入)、MISO(主入从出)、SCLK(时钟)、CS(片选)。CPOL=1,空闲时为高电平。
2024-06-29 18:24:28
230
原创 AD9026芯片开发实录5-ADRV9026 - FAQ
1. What information should I provide to help speed resolution of my issue? Please provide as much detail as possible including all of the detail described in the table below2. What are the key specifications of ADRV9026 chip? The ADRV9026 is a 4 Transmit
2024-06-29 17:27:24
755
原创 Linux开发讲课18--- “>file 2>&1“ 和 “2>&1 >file“ 的区别
在 Bash 脚本和命令行操作中,输出重定向是一项基本且强大的功能。它允许用户控制命令的输出流,将数据从一个地方转移到另一个地方,实现更加灵活和高效的工作流程。本文旨在记录 Bash 中几种常见的输出重定向方法,包括:-.2. 基本概念文件描述符(File Descriptor, FD)是 Unix 和 Unix-like 操作系统中的基本概念,用于表示一个进程打开的文件、管道、套接字或其他输入/输出资源。每个进程都有一个文件描述符表,管理其所有打开的文件。
2024-06-29 12:15:02
1152
原创 Linux开发讲课17--- 在shell脚本中,如何将一个命令存储在一个变量中
是一个非常容易引发错误的内置命令,在没有警告用户可能存在不可预料的解析行为风险的情况下,不应推荐使用它。对于带有管道或重定向的组合命令最推荐的方式是将其封装到一个函数里,然后在需要时直接调用即可。命令时需要非常小心,因为它可以使得代码可读性较差并且容易引入安全漏洞。将一个命令保存到一个变量中,以便稍后再使用(不是命令的输出,而是命令本身)。如何将这样(带有管道/多个命令)的命令存储在变量中以供以后使用?然而,当尝试一些更复杂的东西时,它失败了。命令的坑吗,可以在评论区留言交流一下。里面命令的末尾加上分号。
2024-06-29 11:29:00
246
原创 Linux开发讲课16--- 【内存管理】页表映射基础知识2
Linux内核的内存管理已经适配了X86的页表项,我们可以通过软件适配的办法来解决这个问题。一套页表是为了迎合ARM硬件的真实页表,另一套页表是为了迎合Linux真实的页表。对于PTE页表来说,一下子就多出了一套页表,一套页表256表项,每个表项占用4字节。历史原因:Linux最初是基于x86的体系结构设计的,因此Linux内核很多的头文件的定义都是基于x86的,特别是关于PTE页表项里面的很多比特位的定义。这一套方案的话,相当于每个PGD页表项有8字节,包含指向两套PTE页表项的entry。
2024-06-26 21:09:46
243
转载 Linux开发讲课16--- 【内存管理】页表映射基础知识
Linux内核中封装了很多宏来处理页表pte_val(pte)) //pte是否存在#define pte_present(pte) (pte_isset((pte), L_PTE_PRESENT)) //present比特位#define pte_valid(pte) (pte_isset((pte), L_PTE_VALID)) //pte是否有效#define pte_write(pte) (pte_isclear((pte), L_PTE_RDONLY)) //pte是否可写。
2024-06-26 21:08:07
900
原创 Linux开发讲课15--- ARM嵌入式系统为什么要做内存对齐
全局变量value.v初始值是0, 程序开多线程,对全局变量value.v进行多次~位取反操作,直觉上最后结果value.v的位结果不是全0就是全1,但是最后value.v的位结果居然是一半1一半0, 这就是由于cross cache line 操作是非原子性的,导致一个线程对value.v前半部分取反的时候,另外的线程对后半部分在另一个cache line同时取反,然后前一个线程再对另一个cache line的value.v后半部分取反,导致和直觉不一致。
2024-06-26 21:00:21
1019
原创 Linux开发讲课14--- CPU100%该如何处理
CPU占用率突然飙升是技术人员常遇到的一个棘手问题,它是一个与具体技术无关的普遍挑战。这个问题可以很简单,也可以相当复杂。有时候,只是一个死循环在作祟。有时候,是死锁导致的。有时候,代码中有不必要的同步块。有时候,是大量计算密集型任务在运行。有时候,是线程数过多引起的。有时候,是频繁的上下文切换。有时候,是内存不足的问题。有时候,是频繁的垃圾回收。有时候,是内存泄漏导致的。等等。导致CPU占用率飙升的问题多种多样,不同系统中的不同场景,其原因可能各不相同。
2024-06-26 20:53:10
507
转载 AD9026芯片开发实录3-初始化介绍
adi_adrv9025_ArmProfileWrite(adi_adrv9025_Device_t *device, const adi_adrv9025_Init_t *init),把配置写进片子。),配置PLLs,配置 radio control initialization structure,开始intial calibration。adi_adrv9025_PreMcsInit_v2在adi_adrv9025_utilities.c/h 定义,数据路由灵活,可隔离,可TDD共享。
2024-06-24 21:31:29
47
原创 Linux开发讲课13--- SPI、I2C、UART三种串行总线协议的区别
异步传输的实现比较容易,由于每个信息都加上了“同步”信息,因此计时的漂移不会产生大的积累,但却产生了较多的开销。在数据输出过程中,CPU把要输出的字符(并行地)送入“数据输出寄存器”,“数据输出寄存器”的内容传输到“发送移位寄存器”,然后由“发送移位寄存器”移位,把数据1位1位地送到外设。如果用通用IO口模拟SPI总线,必须要有一个输出口(SDO),一个输入口(SDI),另一个口则视实现的设备类型而定,如果要实现主从设备,则需输入输出口,若只实现主设备,则需输出口即可,若只实现从设备,则只需输入口即可。
2024-06-23 20:06:53
854
原创 Linux开发讲课12--- /proc 目录
proc 目录是一个强大的工具,可以让系统管理员、开发人员和用户深入了解系统和进程的详细信息。由于其动态和内存驻留的特性,访问 /proc 目录中的信息通常是高效且即时的。
2024-06-23 19:57:54
334
原创 Linux开发讲课11--- Linux Systemd
systemd是Linux系统的一套基本构建模块。它提供了一个系统和服务管理器,作为PID 1运行并启动系统的其余部分。systemd提供积极的并行化功能,使用套接字和D-Bus激活来启动服务,提供按需启动守护进程,使用Linux控制组跟踪进程,维护挂载和自动挂载点,并实现一个精心设计的基于事务依赖的服务控制逻辑。systemd支持SysV和LSB初始化脚本,可以替代sysvinit。
2024-06-23 16:34:58
764
VMware-workstation-full-17.0.0-20800274,文章有安装教程
2024-06-05
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人