自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(24)
  • 收藏
  • 关注

原创 Linux驱动—CMWQ(Concurrency Managed Workqueue)

在传统工作队列中,每个工作队列都由一个独立的内核线程(kthread)来处理队列中的任务。而CMWQ通过共享内核的kworker线程池来高效管理工作队列的任务,减少线程数量,同时提供更高的并发性。CMWQ(并发管理工作队列)是引入的新的工作队列,其目标是提高系统的并发性能和资源利用率,替代旧的传统工作队列机制。WQ_UNBOUND允许任务在任何可用的CPU上运行,不绑定到特定的CPU,具有更高的灵活性。kworker/是系统中共享的内核工作线程,它们属于CMWQ的线程池。

2024-12-16 15:23:12 861

原创 Linux驱动—CMDQ(Command Queue,命令队列)和工作队列传参

CMDQ是一种硬件加速的命令队列机制,通常用于图像显示和多媒体处理,例如LCD显示驱动中的命令队列。它允许CPU将一系列命令批量提交到DMA硬件控制单元,使得这些命令能在硬件中异步执行,而不是让CPU逐条执行,从而减少CPU负载和延迟。延迟执行:与中断上下文的快速响应设计不同,工作队列的目标是在内核线程中处理任务,不阻塞中断处理。任务完成后,kfree()释放了my_work_data结构体的内存,避免内存泄漏。通过中断通知内核,表示一批命令已完成,传递的参数通常是命令的完成状态、执行结果等。

2024-12-15 17:19:21 1655

原创 linux驱动—中断

当中断发生时,CPU会暂停当前的任务,转去处理中断服务程序(ISR, interrupt service routine),处理完成后再恢复原任务。linux驱动中的中断是嵌入式和设备驱动开发中非常重要的概念。注意:上半部的中断上下文不能执行可能导致阻塞的操作,如休眠(msleep())和I/O操作)(如read()和write())。工作队列是内核中用于将任务延迟到内核线程中处理的机制,适用于I/O操作、长时间任务和需要睡眠的任务。5.中断退出:处理完中断后,恢复原来的任务上下文,继续执行被中断的任务。

2024-12-15 14:48:00 1556

原创 linux驱动—信号驱动I/O

当设备有数据可读时,内核通过kill_fasync()遍历监听队列,向设备的所有者进程发送SIGIO信号。当设备有数据可读或设备状态发生变化时,用户进程会接收SIGIO信号,然后在sigio_handler()中执行特定的处理逻辑(比如读取数据)。信号驱动I/O是一种异步I/O通知机制,当设备就绪(如可读或可写)时,内核发送一个信号给进程,通知它可以执行相应的I/O操作。设置O_ASYNC后,内核在数据可读可写时,使用kill_fasync()发送SIGIO信号,告诉监听的用户进程有数据可读。

2024-12-13 14:12:42 1164

原创 linux驱动—I/O多路复用poll用法

相比于select,poll的文件描述符数量不受1024的限制,但与epoll相比,poll在大规模的fd监控场景中性能较低。poll是一种IO多路复用机制,允许一个线程同时监视多个文件描述符(fd)的读、写和异常事件,并在事件就绪时做出响应。3.检查返回的事件:通过检查revents,判断哪些文件描述符上发生了感兴趣的事件。fds[0].fd = 0: 监听标准输入(stdin)的文件描述符(0)。当任意文件描述符的事件就绪,poll()立即返回,处理这些事件。监听多个文件描述符的读、写和异常事件。

2024-12-12 22:46:50 454

原创 linux驱动——等待队列实现阻塞访问

当一个进程/线程访问共享资源(如缓冲区、设备等)时,如果资源不可用,线程会挂起自己,并将自己放入等待队列,当资源可用时,操作系统会唤醒等待队列中的线程,这可以提高CPU利用率和系统性能。DECLARE_WAIT_QUEUE_HEAD(name)宏用于定义和初始化一个等待队列头,名字为my_wait_queue。buffer_not_empty:条件表达式,若为false,线程将休眠,若为true,线程不休眠。

2024-12-12 18:57:19 374

原创 linux驱动——阻塞IO 和非阻塞IO

在非阻塞I/O中,当一个线程调用I/O函数时,如果数据尚未准备好,函数不会等待,而是立即返回-1,并将errno设置为EAGAIN或EWOULDBLOCK。在阻塞I/O中,当一个线程调用I/O函数时,如果数据尚未准备好,线程会被挂起,直到数据准备好后线程才被唤醒,接着完成I/O操作并返回结果。文件I/O:大多数文件I/O使用阻塞I/O,因为他更简单,I/O操作快,切换开销低。实现简单,CPU开销低,当I/O阻塞时,操作系统会调度其他线程运行,避免CPU空转浪费。

2024-12-12 16:44:00 340

原创 linux驱动并发与竞争—信号量

void down(struct semaphore sem) 获取信号量,如果信号量为0,则阻塞。int down_trylock(struct semaphore sem) 尝试获取信号量,如果无法获取,立即返回。down(&sem)使信号量的count减1,如果count变为0,其他线程被阻塞。up(&sem)使信号量的count加1,如果有等待的线程,则唤醒它们。互斥锁的使用场景是保护临界区,如某个共享变量的访问,防止多个线程在同一时刻操作该变量。

2024-12-12 11:46:27 893

原创 linux驱动中的自旋锁死锁

中断处理程序会一直等待获取这把锁(自旋等待),但锁无法释放,因为被中断的线程已经被打断了,结果就是,中断和线程相互等待,出现死锁。简单来说,线程A持有资源1,等待资源2,而线程B持有资源2,等待资源1,这种交叉等待会导致死锁。如果一个线程已经持有了自旋锁,他不能再次请求同一把锁,否则会自旋等待自己释放锁,被卡住。线程A持有资源1,并尝试获取资源2,此时资源2已被线程B持有,所以线程A被阻塞。线程B持有资源2,并尝试获取资源1,但资源1已被线程A持有,所以线程B也被阻塞。

2024-12-11 18:02:31 705

原创 linux驱动并发与竞争—自旋锁

在自旋锁的实现中,atomic_exchange()通常用来尝试获取锁,如果旧值为0,表示锁是空闲的,当前线程就能成功获取锁,如果旧值是1,表示锁已被其他线程持有,当前线程需要继续等待尝试获取锁。多核环境中,当一个核正在执行短时间的关键代码,其他核的线程如果尝试获取锁,使用自旋等待比触发上下文切换更高效。4.释放锁:当持有锁的线程完成任务后,将标志位原子地重置为0,以便其他线程可以获取锁。忙等待:获取不到锁的线程不会休眠,而是不断地检查锁的状态,消耗CPU资源。Linux内核中的自旋锁示例。

2024-12-11 15:13:23 464

原创 linux驱动-并发与竞争之原子操作

int test_and_clear_bit(int nr,void *addr) 清除第nr位并返回旧值 int old = test_and_clear_bit(3, &flags);int test_and_set_bit(int nr, void *addr) 设置第nr位并返回旧值 int old = test_and_set_bit(3,&flags);bool refcount_dec_and_test(refcount_t *r) //自减1,若变为0返回true。

2024-12-11 12:31:09 754

原创 SPI总线学习

SPI是一个高速、全双工、同步的串行通信总线协议,常用于为控制器于外部设备(如传感器,存储器,显示屏)之间的数据交换。IIC硬件连接简单,用线更少,SPI每个从设备需要额外的CS线,连接复杂度高。SPI通信速度更快,适合高速传输,IIC速度较低,适合低速设备。使用发送的从设备地址区分多个从设备,无需额外的片选线。1.SCLK:时钟信号,由主设备生成,控制数据传输的节奏。4.完成通信后,主设备释放CS引脚(拉高),结束传输。2.MOSI:主设备输出,从设备输入的数据线。4.CS/SS:片选,从设备使能信号。

2024-11-20 22:21:02 596

原创 GPIO编程学习--控制led灯亮灭

配置GPIO引脚,例如输入输出、及特殊功能(I2C,SPI)。基于三星4412处理器学习对GPIO寄存器的操作和配置。用于设置引脚输出的电平(高/低)或读取引脚的输出状态。每个GPIO的引脚功能需要通过CON寄存器设置。每4位代表一个引脚功能,0001表示输出模式。GPK1CON控制GPK1组的功能。设置引脚是否使用上拉/下拉电阻。1.GPIO基本概念。设置引脚的驱动能力。

2024-11-20 11:04:58 476

原创 输入输出重定向

输入输出重定向是在linux系统中,将程序的标准输入、标准输出或标准错误输出从默认位置(通常是键盘和显示器)重定向到其他位置。command > output.txt(>:将标准输出重定向得到文件output.txt,覆盖文件内容)。command > output.txt(>>:将标准输出追加到文件output.txt,保留原有内容)。在ubuntu上linux系统printf标准输出定向到了显卡,打印内容显示在屏幕上。3.标准错误输出(stderr):显示器,错误信息或调试信息通过标准错误输出显示。

2024-11-18 23:44:26 231

原创 UART——串口通信

主要配置项:数据位(5、6、7、8位)、停止位(1或2位)、校验位(奇校验、偶校验或无校验)、数据传输模式(正常模式、红外线模式)。实现从终端打印数据给接收寄存器,接收到的数据进行一些处理再传送给发送寄存器,发送寄存器通过UART发送到终端。功能:用于存放需要通过UART发送的数据,写入此寄存器的数据会通过UART发送。功能:用于存放接收的数据,读取此寄存器可以获得通过UART接收到的数据。功能:显示中断的来源,例如发送完成中断,接收完成中断等。功能:设置波特率的小数部分,提高波特率的精确度。

2024-11-18 21:50:53 390

原创 智能路灯实验--I2C总线 MPU6050

设置GPIO引脚为UART接收和发送引脚,设置UART2的数据帧格式,设置UART2的发送接收模式,设置UART2的发送数据的速度:波特率。设置PWM0为自动重装载,自动重载模式可以在计数器减到0时自动加载TCNTB的值,避免手动加载,提高频率,适合持续输出的信号。3.TCON为定时器控制寄存器,主要用于启动,停止和设置PWM的运行模式,包括手动更新,自动重载,启动和停止等功能。2.TCFG1为二级分频:进一步细化PWM信号频率的控制,配置不同的分频系数,适应不同的应用需求。

2024-11-18 16:51:33 1795

原创 socket套接字编程

由第二部分的流程图可以总结常用的基本套接字编程函数依次为:3.1 socket()函数不论是客户端还是服务器端都必须首先调用socket函数,生成一个TCP套接字。

2024-11-18 11:23:02 1094

原创 C语言学习第七天

以0结尾的一串字符-\0,0标志字符串的结束,但它不是字符串的一部分。C语言的字符串是以字符数组的形态存在的,不能用运算符对字符串做运算。字符串以数组的形式存在,以数组或指针的形式访问。string.h里有很多处理字符串的函数。计算字符串长度的时候不包含这个0。通过数组的方式可以遍历字符串。那么指针和数组有什么 不同?如果要构造一个字符串->数组。如果要处理一个字符串->指针。更多的是以指针的形式访问。

2024-06-13 23:11:23 263

原创 C语言学习第六天

如果是个指针变量,则p[i]等价于*(p+i),可以认为到内存P的位置然后移动i个单元,检索储存在那里的值。在一个函数内部如果定义的局部变量的名字和局部变量名一样时,局部变量会屏蔽掉全局变量。在一个函数内部定义的变量或者函数的形参 都统称为局部变量。需要对十进制整数除以2取余,余数从从后往前排列,倒过来就转化成二进制整数了。一位数组名是个指针常量,他存放的是一维数组第一个元素的地址。*(p+3)表示p的第3个元素的值。不要混淆*(p+3)和*p+3。*p+3表示p第一个元素+3。总结:指针是C语言的灵魂。

2024-06-12 07:34:56 251

原创 一个指针占几个字节,原理是什么呢

我们一般需要32个0或1的组合就可以找到内存中所有的地址,而32个0或1的组合就是32位,也就是4个字节的大小(一个字节8位)。所以在32位计算机中,指针占4个字节,64位计算机中,指针占8个字节。假如,某计算机的地址总线是32位,那么它一次可以处理的信息是32条,每一条地址总线有0或1两种可能,那么32根地址总线一共有232种可能,也就是其描述的地址空间为0-(232-1)。我们平常说的计算机是64位,32位,指的是计算机CPU中通用寄存器一次性处理、传输、暂时储存的信息的最大长度。

2024-06-11 22:32:52 1486

原创 C语言学习第四天

今天学习了while循环,for和while循环比较,do while 和while、for比较,switch用法、(float)(5) 最终值是5.000000。(int)(4.5+2.2) 最终值是6。功能:把表达式的值强制转化为前面所执行的数据类型。格式:(数据类型)(表达式)

2024-06-10 13:44:47 371

原创 学习C语言第三天

尝试自己去编程解决它,大部分人自己都无法解决,如果解决不了就看答案,关键是把答案看懂,需要花很大的精力,也是我们学习的重点。看懂之后尝试自己去修改程序,并且知道修改之后程序的不同输出结果的含义,并调试错误,判断一个数是否为素数(1 3 5 7 11 13 17 19 ...)判断一个数是否为 回文数(1221,123321)printf ()--将变量的内容输入到显示器上。最后不看答案,自己独立把答案敲出来。如何使用scanf编写出高质量代码。else if (表达式2)else if (表达式3)

2024-06-06 23:06:35 985

原创 学习C语言第二天

/错误写法,因为双引号的“A”为字符串 代表‘A’ '\0'的组合。//正确写法,将单个字符'A'赋值给ch,注意单个字符必须用单引号。// x的值是1.2345。printf ( " 该一元二次方程有两个解, X1 = %f ,X2 = %f \n " X1, X2 }//printf("%c\n",ch);cpu不能直接处理硬盘上的数据,操作系统将硬盘上的数据传输到内存条上,CPU在处理内存条上的数据,//printf("%c\n",ch1);

2024-06-05 12:35:02 494

原创 学习C语言第一天

因此,建议新人在学习编程的时候就养成编程的好习惯,写程序前定义好程序的目标,然后再设计程序,跟着流程走。总体来说,源代码文件是程序员编写的高级语言代码文件,目标代码文件是编译器和汇编器生成的中间文件,可执行文件是链接器处理的最终文件。总的来说,编译器的任务是将高级语言源代码转换为目标代码或可执行代码,并完成相关的错误检查、代码优化、目标代码生成等任务。源代码文件通常以特定的文件扩展名(如.c、.cpp、.java等)保存,并且包含程序的逻辑和算法、变量和函数定义等信息。可以执行程序是可以运行的程序。

2024-05-27 20:50:05 1697 1

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除