嵌入式Linux驱动程序开发基本概念和方法

正点原子嵌入式linux驱动开发——U-boot启动流程详解 正点原子linux驱动开发的学习笔记,这一篇是uboot的源码解读,来学习uboot的启动详细流程 阅读详情

系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分。

Linux将设备主要分成两大类:一类是块设备,类似磁盘以记录块或扇区为单位,成块进行输入/输出的设备;另一类是字符设备,类似键盘以字符为单位,逐个进行输入/输出的设备。网路设备是介于块设备和字符设备之间的一种特殊设备。

块设备接口仅支持面向块的I/O操作,所有I/O操作都通过在内核地址空间中的I/O缓冲区进行,它可以支持随机存取的功能。文件系统通常都建立在块设备上。

字符设备接口支持面向字符的I/O操作,由于它们不经过系统的快速缓存,所以它们负责管理自己的缓冲区结构。字符设备接口只支持顺序存取的功能,一般不能进行任意长度的I/O请求,而是限制I/O请求的长度必须是设备要求的基本块长的倍数。

1.设备驱动程序的概念

设备驱动程序实际是处理和操作硬件控制器的软件,从本质上讲,是内核中具有最高特权级的、驻留内存的、可共享的底层硬件处理例程。驱动程序是内核的一部分,是操作系统内核与硬件设备的直接接口,驱动程序屏蔽了硬件的细节,完成以下功能:

对设备初始化和释放;

对设备进行管理,包括实时参数设置,以及提供对设备的操作接口;

读取应用程序传送给设备文件的数据或者回送应用程序请求的数据;

检测和处理设备出现的错误。

Linux操作系统将所有的设备全部看成文件,并通过文件的操作界面进行操作。对用户程序而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说,是把设备映射为一个特殊的设备文件,用户程序可以像对其他文件一样对此设备文件进行操作。这意味着:

由于每一个设备至少由文件系统的一个文件代表,因而都有一个“文件名”。

应用程序通常可以通过系统调用open()打开设备文件,建立起与目标设备的连接。

打开了代表着目标设备的文件,即建立起与设备的连接后,可以通过read()、write()、ioctl()等常规的文件操作对目标设备进行操作。

设备文件的属性由三部分信息组成:第一部分是文件的类型,第二部分是一个主设备号,第三部分是一个次设备号。其中类型和主设备号结合在一起惟一地确定了设备文件驱动程序及其界面,而次设备号则说明目标设备是同类设备中的第几个。

由于Linux 中将设备当做文件处理,所以对设备进行操作的调用格式与对文件的操作类似,主要包括open()、read()、write()、ioctl()、close()等。应用程序发出系统调用命令后,会从用户态转到核心态,通过内核将open()这样的系统调用转换成对物理设备的操作。

2.处理器与设备间数据交换方式

处理器与外设之间传输数据的控制方式通常有3种:查询方式、中断方式和直接内存存取(DMA)方式。

21.查询方式

设备驱动程序通过设备的I/O端口空间,以及存储器空间完成数据的交换。例如,网卡一般将自己的内部寄存器映射为设备的I/O端口,而显示卡则利用大量的存储器空间作为视频信息的存储空间。利用这些地址空间,驱动程序可以向外设发送指定的操作指令。通常来讲,由于外设的操作耗时较长,因此,当处理器实际执行了操作指令之后,驱动程序可采用查询方式等待外设完成操作。

2.2.中断方式

查询方式白白浪费了大量的处理器时间,而中断方式才是多任务操作系统中最有效利用处理器的方式。当CPU进行主程序操作时,外设的数据已存入端口的数据输入寄存器,或端口的数据输出寄存器已空,此时由外设通过接口电路向CPU发出中断请求信号。CPU在满足一定条件下,暂停执行当前正在执行的主程序,转入执行相应能够进行输入/输出操作的子程序,待输入/输出操作执行完毕之后,CPU再返回并继续执行原来被中断的主程序。这样,CPU就避免了把大量时间耗费在等待、查询外设状态的操作上,使其工作效率得以大大提高。中断方式的原理示意图如图6.1所示。

2.3.直接访问内存(DMA)方式

利用中断,系统和设备之间可以通过设备驱动程序传送数据,但是,当传送的数据量很大时,因为中断处理上的延迟,利用中断方式的效率会大大降低。而直接内存访问(DMA)可以解决这一问题。DMA可允许设备和系统内存间在没有处理器参与的情况下传输大量数据。设备驱动程序在利用DMA之前,需要选择DMA通道并定义相关寄存器,以及数据的传输方向,即读取或写入,然后将设备设定为利用该DMA通道传输数据。设备完成设置之后,可以立即利用该DMA通道在设备和系统的内存之间传输数据,传输完毕后产生中断以便通知驱动程序进行后续处理。在利用DMA进行数据传输的同时,处理器仍然可以继续执行指令。

3.驱动程序结构

3.1一个设备驱动程序模块的基本框架

设备驱动程序流程图

在系统内部,I/O设备的存取通过一组固定的入口点来进行,入口点也可以理解为设备的句柄,就是对设备进行操作的基本函数。字符型设备驱动程序提供如下几个入口点:

open入口点。打开设备准备I/O操作。对字符设备文件进行打开操作,都会调用设备的open入口点。open子程序必须对将要进行的I/O操作做好必要的准备工作,如清除缓冲区等。如果设备是独占的,即同一时刻只能有一个程序访问此设备,则open子程序必须设置一些标志以表示设备处于忙状态。

close入口点。关闭一个设备。当最后一次使用设备完成后,调用close子程序。独占设备必须标记设备方可再次使用。

read入口点。从设备上读数据。对于有缓冲区的I/O操作,一般是从缓冲区里读数据。对字符设备文件进行读操作将调用read子程序。

write入口点。往设备上写数据。对于有缓冲区的I/O操作,一般是把数据写入缓冲区里。对字符设备文件进行写操作将调用write子程序。

ioctl入口点。执行读、写之外的操作。

select入口点。检查设备,看数据是否可读或设备是否可用于写数据。select系统调用在检查与设备文件相关的文件描述符时使用select入口点。

3.1. file_operations结构体

struct file_operations {

structmodule *owner;

loff_t(*llseek) (struct file *, loff_t, int);

ssize_t(*read) (struct file *, char *, size_t, loff_t *);

ssize_t(*write) (struct file *, const char *, size_t, loff_t *);

int(*readdir) (struct file *, void *, filldir_t);

unsignedint (*poll) (struct file *, struct poll_table_struct *);

int(*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

int (*mmap)(struct file *, struct vm_area_struct *);

int (*open)(struct inode *, struct file *);

int(*flush) (struct file *);

int(*release) (struct inode *, struct file *);

int(*fsync) (struct file *, struct dentry *, int datasync);

int(*fasync) (int, struct file *, int);

int (*lock)(struct file *, int, struct file_lock *);

ssize_t(*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);

ssize_t(*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);

ssize_t(*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

unsignedlong (*get_unmapped_area)(

struct file*,

unsignedlong,

unsignedlong,

unsignedlong,

unsignedlong

);

};

lseek,移动文件指针的位置,只能用于可以随机存取的设备。

read,进行读操作,buf为存放读取结果的缓冲区,count为所要读取的数据长度。

write,进行写操作,与read类似。

select,进行选择操作。

ioctl,进行读、写以外的其他操作。

mmap,用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用。

open,打开设备进行I/O操作。返回0表示成功,返回负数表示失败。

release,即close操作

3.2.inode{}和file{}结构体

inode数据结构体提供关于特别设备文件的信息。file结构体主要是与文件系统对应的设备驱动程序使用。

struct file主要用于与文件系统相关的设备驱动程序,可提供关于被打开的文件的信息,定义如下:

struct file {

struct list_head f_list;

struct dentry *f_dentry;

struct vfsmount*f_vfsmnt;

struct file_operations *f_op;

atomic_t f_count;

unsigned int f_flags;

mode_t f_mode;

loff_t f_pos;

unsigned long f_reada,f_ramax, f_raend, f_ralen, f_rawin;

struct fown_struct f_owner;

unsigned int f_uid,f_gid;

int f_error;

unsigned long f_version;

/* needed for tty driver, and maybe others */

void *private_data;

/* preallocated helper kiobuf to speedup O_DIRECT */

struct kiobuf *f_iobuf;

long f_iobuf_lock;

};

在用户自己的驱动程序中,首先要根据驱动程序的功能,完成file_operations结构中函数的实现。不需要的函数接口可以直接在file_operations结构中初始化为NULL。file_operations中的变量会在驱动程序初始化时,注册到系统内部。每个进程对设备的操作,都会根据主次设备号,转换成对file_operations结构的访问。

4.设备注册和初始化

设备的驱动程序在加载的时候首先需要调用入口函数init_module(),该函数最重要的一个工作就是向内核注册该设备,对于字符设备调用register_chrdev()完成注册。register_chrdev 的定义为:int register_chrdev(unsignedint major, const char *name, struct file_ operations *fops);

其中,major是为设备驱动程序向系统申请的主设备号,如果为0,则系统为此驱动程序动态分配一个主设备号。name是设备名,fops是对各个调用的入口点说明。此函数返回0时表示成功;返回-EINVAL,表示申请的主设备号非法,主要原因是主设备号大于系统所允许的最大设备号;返回-EBUSY,表示所申请的主设备号正在被其他设备程序使用。如果动态分配主设备号成功,此函数将返回所分配的主设备号。如果register_chrdev()操作成功,设备名就会出现在/proc/dvices文件中。

Linux在/dev目录中为每个设备建立一个文件,用ls –l命令列出函数返回值,若小于0,则表示注册失败;返回0或者大于0的值表示注册成功。注册以后,Linux将设备名与主、次设备号联系起来。当有对此设备名的访问时,Linux通过请求访问的设备名得到主、次设备号,然后把此访问分发到对应的设备驱动,设备驱动再根据次设备号调用不同的函数。

当设备驱动模块从Linux内核中卸载,对应的主设备号必须被释放。字符设备在cleanup_module()函数中调用unregister_chrdev()来完成设备的注销。unregister_chrdev()的定义为:int unregister_chrdev(unsignedint major, const char *name);

此函数的参数为主设备号major和设备名name。Linux内核把name和major在内核注册的名称对比,如果不相等,卸载失败,并返回-EINVAL;如果major大于最大的设备号,也返回-EINVAL。

包括设备注册在内,设备驱动的初始化函数主要完成的功能是有以下5项。

(1)对驱动程序管理的硬件进行必要的初始化。

对硬件寄存器进行设置。比如,设置中断掩码,设置串口的工作方式、并口的数据方向等。

(2)初始化设备驱动相关的参数。

一般说来,每个设备都要定义一个设备变量,用以保存设备相关的参数。在这一步骤里对设备变量中的项进行初始化。

(3)在内核注册设备。

调用register_chrdev()函数来注册设备。

(4)注册中断。

如果设备需要IRQ支持,则要使用request_irq()函数注册中断。

(5)其他初始化工作。

初始化部分一般还负责给设备驱动程序申请包括内存、时钟、I/O端口等在内的系统资源,这些资源也可以在open子程序或者其他地方申请。这些资源不用时,应该释放,以利于资源的共享。

若驱动程序是内核的一部分,初始化函数则要按如下方式声明:

int __init chr_driver_init(void);

其中__init是必不可少的,在系统启动时会由内核调用chr_driver_init,完成驱动程序的初始化。

当驱动程序是以模块的形式编写时,则要按照如下方式声明:

int init_module(void)

当运行后面介绍的insmod命令插入模块时,会调用init_module函数完成初始化工作。

5.中断管理

设备驱动程序通过调用request_irq函数来申请中断,通过free_irq来释放中断。它们在linux/sched.h中的定义如下:

int request_irq(

unsigned int irq,

void (*handler)(int irq,void dev_id,structpt_regs *regs),

unsigned long flags,

const char *device,

void *dev_id

);

void free_irq(unsigned int irq, void*dev_id);

通常从request_irq函数返回的值为0时,表示申请成功;负值表示出现错误。

irq表示所要申请的硬件中断号。

handler为向系统登记的中断处理子程序,中断产生时由系统来调用,调用时所带参数irq为中断号,dev_id为申请时告诉系统的设备标识,regs为中断发生时寄存器内容。

device为设备名,将会出现在/proc/interrupts文件里。

flag是申请时的选项,它决定中断处理程序的一些特性,其中最重要的是决定中断处理程序是快速处理程序(flag里设置了SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT)。

下面的代码将在SBC-2410X的Linux中注册外部中断2。

eint_irq = IRQ_EINT2;

set_external_irq (eint_irq, EXT_FALLING_EDGE,GPIO_PULLUP_DIS);

ret_val =request_irq(eint_irq,eint2_handler, “S3C2410Xeint2”,0);

if(ret_val < 0){

return ret_val;

}

用来打开和关闭中断的函数如下:

#define cli() _asm_ _volatile_("cli"::)

#define sli() _asm_ _volatile_("sli"::) 。

6.设备驱动程序的开发过程

由于嵌入式设备由于硬件种类非常丰富,在默认的内核发布版中不一定包括所有驱动程序。所以进行嵌入式Linux系统的开发,很大的工作量是为各种设备编写驱动程序。除非系统不使用操作系统,程序直接操纵硬件。嵌入式Linux系统驱动程序开发与普通Linux开发没有区别。可以在硬件生产厂家或者Internet上寻找驱动程序,也可以根据相近的硬件驱动程序来改写,这样可以加快开发速度。实现一个嵌入式Linux设备驱动的大致流程如下。

(1)查看原理图,理解设备的工作原理。一般嵌入式处理器的生产商提供参考电路,也可以根据需要自行设计。

(2)定义设备号。设备由一个主设备号和一个次设备号来标识。主设备号惟一标识了设备类型,即设备驱动程序类型,它是块设备表或字符设备表中设备表项的索引。次设备号仅由设备驱动程序解释,区分被一个设备驱动控制下的某个独立的设备。

(3)实现初始化函数。在驱动程序中实现驱动的注册和卸载。

(4)设计所要实现的文件操作,定义file_operations结构。

(5)实现所需的文件操作调用,如read、write等。

(6)实现中断服务,并用request_irq向内核注册,中断并不是每个设备驱动所必需的。

(7)编译该驱动程序到内核中,或者用insmod命令加载模块。

(8)测试该设备,编写应用程序,对驱动程序进行测试。

7.设备驱动开发的基本函数

7.1.I/O口函数

无论驱动程序多么复杂,归根结底,无非还是向某个端口或者某个寄存器位赋值,这个值只能是0或1。接收值的就是I/O口。与中断和内存不同,使用一个没有申请的I/O端口不会使处理器产生异常,也就不会导致诸如“segmentationfault”一类的错误发生。由于任何进程都可以访问任何一个I/O端口,此时系统无法保证对I/O端口的操作不会发生冲突,甚至因此而使系统崩溃。因此,在使用I/O端口前,也应该检查此I/O端口是否已有别的程序在使用,若没有,再把此端口标记为正在使用,在使用完以后释放它。

这样需要用到如下几个函数:

int check_region(unsigned int from,unsigned int extent);

void request_region(unsigned int from,unsigned int extent,const char *name);

void release_region(unsigned int from, unsignedint extent);

调用这些函数时的参数为:

from表示所申请的I/O端口的起始地址;

extent为所要申请的从from开始的端口数;

name为设备名,将会出现在/proc/ioports文件里;

check_region返回0表示I/O端口空闲,否则为正在被使用。

在申请了I/O端口之后,可以借助asm/io.h中的如下几个函数来访问I/O端口:

inline unsigned int inb(unsigned shortport);

inline unsigned int inb_p(unsigned shortport);

inline void outb(char value, unsigned shortport);

inline void outb_p(charvalue,unsigned short port);

其中inb_p和outb_p插入了一定的延时以适应某些低速的I/O端口。

7.2.时钟函数

在设备驱动程序中,一般都需要用到计时机制。在Linux系统中,时钟是由系统接管的,设备驱动程序可以向系统申请时钟。与时钟有关的系统调用有:

#include <asm/param.h>

#include <linux/timer.h>

void add_timer(struct timer_list * timer);

int del_timer(struct timer_list * timer);

inline void init_timer(struct timer_list *timer);

struct timer_list的定义为:

struct timer_list {

struct timer_list *next;

struct timer_list *prev;

unsigned long expires;

unsigned long data;

void (*function)(unsigned long d);

};

其中,expires是要执行function的时间。系统核心有一个全局变量jiffies表示当前时间,一般在调用add_timer时jiffies=JIFFIES+num,表示在num个系统最小时间间隔后执行function函数。系统最小时间间隔与所用的硬件平台有关,在核心里定义了常数HZ表示一秒内最小时间间隔的数目,则num*HZ表示num秒。系统计时到预定时间就调用function,并把此子程序从定时队列里删除,可见,如果想要每隔一定时间间隔执行一次的话,就必须在function里再一次调用add_timer。function的参数d即为timer里面的data项。

7.3.内存操作函数

作为系统核心的一部分,设备驱动程序在申请和释放内存时不是调用malloc和free,而代之以调用kmalloc和kfree,它们在linux/kernel.h中被定义为:

void * kmalloc(unsigned int len, intpriority);

void kfree(void * obj);

参数len为希望申请的字节数,obj为要释放的内存指针。priority为分配内存操作的优先级,即在没有足够空闲内存时如何操作,一般由取值GFP_KERNEL解决即可。

7.4.复制函数

在用户程序调用read、write时,因为进程的运行状态由用户态变为核心态,地址空间也变为核心地址空间。由于read、write中参数buf是指向用户程序的私有地址空间的,所以不能直接访问,必须通过下面两个系统函数来访问用户程序的私有地址空间。

#include <asm/segment.h>

void memcpy_fromfs(void * to,const void *from,unsigned long n);

void memcpy_tofs(void * to,const void *from,unsigned long n);

memcpy_fromfs由用户程序地址空间往核心地址空间复制,memcpy_tofs则反之。参数to为复制的目的指针,from为源指针,n为要复制的字节数。

在设备驱动程序里,可以调用printk来打印一些调试信息,printk的用法与printf类似。printk打印的信息不仅出现在屏幕上,同时还记录在文件syslog里。

8.模块加载与卸载

虽然模块作为内核的一部分,但并未被编译到内核中,它们被分别编译和链接成目标文件。Linux中模块可以用C语言编写,用gcc命令编译成模块*.o,在命令行里加上-c的参数和“-D__KERNEL__-DMODULE”参数。然后用depmod -a 使此模块成为可加载模块。模块用insmod命令加载,用rmmod命令来卸载,这两个命令分别调用init_module()和cleanup_ module()函数,还可以用lsmod命令来查看所有已加载的模块的状态。

insmod命令可将编译好的模块调入内存。内核模块与系统中其他程序一样是已链接的目标文件,但不同的是它们被链接成可重定位映像。insmod将执行一个特权级系统调用get_kernel_sysms()函数以找到内核的输出内容,insmod修改模块对内核符号的引用后,将再次使用特权级系统调用create_module()函数来申请足够的物理内存空间,以保存新的模块。内核将为其分配一个新的module结构,以及足够的内核内存,并将新模块添加在内核模块链表的尾部,然后将新模块标记为uninitialized。

利用rmmod命令可以卸载模块。如果内核中还在使用此模块,这个模块就不能被卸载。原因是如果设备文件正被一个进程打开就卸载还在使用的内核模块,并导致对内核模块的读/写函数所在内存区域的调用。如果幸运,没有其他代码被加载到那个内存区域,将得到一个错误提示;否则,另一个内核模块被加载到同一区域,这就意味着程序跳到内核中另一个函数的中间,结果是不可预见的。

基于Linux的硬件驱动程序开发:深入探讨Linux驱动程序开发的基本知识! 🏆本文收录于「编程与技术实战」专栏,此专栏涵盖了C/C++编程、人工智能、数据结构、机器学习等技术领域的内容,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 阅读详情

相关推荐

嵌入式驱动编写-点亮LED驱动程序

在开发板上,有三个LED灯.如何通过应用程序点亮这三个灯如何编写驱动程序 操作硬件的时候,我们需要准备开发板的原理图和开发手册,,根据这两个文档来进行配置   在source insight 编写代码 1 第一个led驱动程序 #include #include #include #inclu

joshua_love的博客 1万+

linux跳过文件系统自检,linux-O_DIRECT是否绕过文件系统日志记录?

open(2)的手册页仅表明O_DIRECT绕过了页面缓存,但是网上的许多描述都将其描述为导致用户缓冲区直接DMA到驱动器.如果是这种情况,我想它也会绕过文件系统(例如xfs,ext4等)完成的日志记录.是这样吗我找不到有人声称一种方法或另一种方法.在我看来,这与数据库使用的O_DIRECT是一致的-O_DIRECT的常见示例是当数据库之类的应用程序在用户空间中进行自己的缓存时,并且我可以想象数据...

weixin_29867607的博客 461

嵌入式系统开发:深入理解和实践Linux

本文还有配套的精品资源,点击获取 简介:嵌入式系统开发是计算机科学的一个关键分支,主要关注于创建特定功能的硬件和软件集成系统。该文章集合将深入探讨嵌入式系统开发的关键概念和技术,重点是嵌入式Linux的使用。文章将涉及嵌入式系统的基本概念、Linux内核定制、硬件平台选择、内核和驱动程序的编写与定制、根文件系统的构建,以及系统集成和测试。文档可能还包括Linux发行版的选择...

weixin_42509507的博客 3496

SPDK中常用的性能测试工具

本文主要介绍磁盘性能评估的方法,针对用户态驱动Kernel与SPDK中各种IO测试工具的使用方法做出总结。其中fio是一个常用的IO测试工具,可以运行在Linux、Windows等多种系统...

weixin_37097605的博客 2441

深入嵌入式Linux驱动程序开发实战指南

本文还有配套的精品资源,点击获取 简介:嵌入式Linux驱动程序设计是连接硬件与Linux内核的桥梁,对硬件操作细节进行处理。本课程将深入探讨嵌入式系统与Linux驱动程序的设计,包含关键知识点如设备模型、I/O子系统、字符与块设备驱动、设备节点、驱动注册卸载、内核模块、中断处理、异步I/O、电源管理和调试技巧。学生将通过实例和实践指导掌握驱动开发的各个方面,以及如何提升系...

weixin_30978239的博客 1623

合宙Air780EP速连OneNET:AT+MQTT应用指南

本文详细讲解了合宙Air780EP使用AT指令通过MQTT接入OneNET的过程。

2401_82812461的博客 1389

【嵌入式环境下linux内核及驱动学习笔记-(1-linux内核结构)】

一个32位处理器的Linux的每个进程享有4G空间,一般0-3G属于用户空间,3G-4G属于内核空间。在ARM环境中,Linux系统充分利用CPU的硬件特性,实现了两级的操作模式,用户(usr)模式和管理模式(svc)。如图,虚拟文件系统为上层的应用程序提供了统一的调用接口,对下则负责调用具体底层文件系统或设备驱动中实现的file_operations结构体中的成员函数。如图,有操作系统后,应用程序可以不管具体的硬件细节,而都使用操作系统API的统一接口,这样利于大规模标准化开发,提高开发效率。

weixin_45499326的博客 2375

通达信-申万宏源金融终端本地数据转sqlite3,2、解析申万宏源C:/zd_swhy_gm/vipdoc/sh/lday的sh600000股票数据

为量化做准备,通达信-申万宏源金融终端本地数据转sqlite3,解析申万宏源C:/zd_swhy_gm/vipdoc/sh/lday的sh600000股票数据

wuyaqi的博客 511

嵌入式驱动开发流程

嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的。设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,可以像操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,完成以下功能: ◇ 驱动程序的注册和注销。 ◇ 设备的打开和释放。 ◇ 设备的读写操作。 ◇ 设备的控制操作。 ◇ 设备的中断和轮询处理。

The_King_Cloud的专栏 9752

告别复杂配置!5分钟在Vue/React项目中集成讯飞语音听写WebSocket API

本文详细介绍了如何在Vue/React项目中快速集成讯飞语音听写WebSocket API,实现高效语音识别功能。通过对比不同通信方案,突出WebSocket在实时语音交互中的优势,并提供框架适配、音频处理及性能优化等关键技术点,帮助开发者5分钟内完成专业级语音听写功能集成。

weixin_28730353的博客 274

GD32F303串口DMA发送数据避坑指南:为什么你的发送函数会卡住?

本文深入解析GD32F303单片机串口DMA发送数据时常见的卡死问题,提供详细的避坑指南。从DMA传输完成中断时序、发送状态管理到双通道DMA的特别注意事项,全面剖析问题根源并给出解决方案,帮助开发者构建健壮的DMA发送机制。

weixin_27038245的博客 295

Linux嵌入式驱动开发

嵌入式驱动程序是操作系统与硬件之间的中介,负责管理硬件设备的输入输出操作。例如,在嵌入式系统中,硬件设备可能包括传感器、显示器、存储设备等。Linux嵌入式驱动程序通过提供硬件抽象层,使得上层应用程序能够与硬件设备进行通信。???在嵌入式系统中,Linux内核的驱动程序与传统的PC驱动有所不同。嵌入式系统通常资源有限,CPU、内存、存储空间等都需要进行严格的优化。因此,在嵌入式系统中开发驱动程序时,需要特别关注资源的利用效率和驱动的稳定性。

2502_93659651的博客 477

二极管限幅电路和钳位电路

二极管限幅电路和钳位电路学习

HW-BASE的博客 928

python嵌入式怎么学_怎么自学嵌入式?

我在100ASK_IMX6ULL售后群里,发现很多初学者只有单片机基础,甚至没有单片机基础。在学习Linux时,对很多概念比较陌生,导致不知道学什么,也不知道学了之后有什么用。所以我趁着五一假期,编写此文。从事嵌入式Linux培训12年来,我们写过很多《关于如何学习linux》的文章,这是最新的,本文将不断更新,最新版可以扫描下方腾讯文档二维码获取:第1章 单片机和Linux的区别1.1 有哪些产...

weixin_39661129的博客 319

智能车图像处理1-基础图像规格

从厂家摄像头的库函数中,我们可以直接得到完整图像的灰度数组,经过二值化之后(算力允许,可以考虑大津法),就是我们要处理的0-1二值图像了。本系列所有的文章中,我们的图像规格如下。

taiyuezyh的博客 4330

掌握C++新特性中智能指针的综合指南

本文是一篇关于C++中智能指针的综合指南,旨在深入探讨现代内存管理的核心概念和技术。智能指针是C++中一种强大的工具,可以帮助开发人员更安全、高效地管理内存资源。通过详细解析各种类型的智能指针,包括unique_ptr、shared_ptr和weak_ptr,读者将了解它们的原理、用法和适用场景。本文将重点介绍智能指针的优势,如自动内存释放、避免内存泄漏和循环引用等问题。此外,还将讨论智能指针与传统指针的区别,并提供一些最佳实践和实用技巧,帮助读者在实际项目中正确、高效地使用智能指针。

Lion_Long的博客 1200

Linux设备驱动开发环境的搭建【转】

对Linux设备驱动开发有了个初步的认识,下面对Linux设备驱动开发环境的搭建做个小结,以方便自己以后查询,同时也能给同道的初学者一点帮助。 刚接触Linux设备驱动时,初学者往往连如何编译驱动程序都不懂,更别说编译进内核或加载测试了。一般都是在网上找个最简单的 helloworld驱动程序,然后严格按照网上所说的步骤编译,结果却得到一大堆见都没见过的错误,更不要说根据错误信息来解决问题了

hwmt2012的专栏 794

基于YOLO26深度学习框架的文档表格识别系统的算法研究实现方法

本文研究了基于YOLO26深度学习框架的文档表格识别系统实现方法。系统采用YOLO26网络架构,通过数据预处理、模型训练、检测推理和表格分析四个模块实现高效表格识别。研究详细阐述了数据归一化、增强等技术处理,以及采用迁移学习策略优化模型训练过程。实验表明,该系统能有效识别多种表格结构并生成结构化数据,为文档自动化处理提供了可靠解决方案。

一键难忘的博客 972

linux mmu的实现的讲解_正点原子Linux第四十一章嵌入式Linux LED驱动开发实验

1)资料下载:点击资料即可下载2)对正点原子Linux感兴趣的同学可以加群讨论:9354467413)关注正点原子公众号,获取最新资料更新第四十一章嵌入式Linux LED驱动开发实验上一章我们详细的讲解了字符设备驱动开发步骤,并且用一个虚拟的chrdevbase设备为例带领大家完成了第一个字符设备驱动的开发。本章我们就开始编写第一个真正的Linux字符设备驱动。在I.MX6U-ALPHA开发板上...

weixin_35395562的博客 363

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

作为一个新人,怎样学习嵌入式Linux,(韦东山)

还有一个比较好的文章,写的是具体的怎么按照韦东山的书和视频进行学习的。网址 https://www.zhihu.com/question/47881392 很早以前在网上看到的韦东山老师写的文章,复制到自己的博客,方便自己以后看。 在学习嵌入式Linux之前,肯定要有C语言基础。汇编基础有没有无所谓(就那么几条汇编指令,用到了一看就会)。 C语言要学到什么程度呢?越熟...

C/C++、嵌入式开发、深度学习算法、模型部署与推理优化 185

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

嵌入式Linux驱动程序开发

嵌入式Linux驱动程序开发

uffgfbft的博客 7181

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

嵌入式 Linux 开发基本概念

1.2.1 嵌入式 Linux 开发有哪些内容? 嵌入式 Linux 系统,就相当于一套完整的 PC 软件系统。 Windows 为例: ① 电脑一开机,那些界面是谁显示的? 是 BIOS,它做什么?一些自检,然后从硬盘上读入 windows,并启动它。 类似的,这个 BIOS 对应于嵌入式 Linux 里的 bootloader。 Bootloader 的作用就是去 Flash、SD 卡等设备上读入 Linux 内核,并启动它。 ② Windows 系统必需的软件,比如 IE、文件浏览器等保存在哪里?

韦东山嵌入式专栏 3999

嵌入式Linux开发环境搭建-(0)在进行嵌入式Linux开发前,你可能先要知道这些基本概念

嵌入式Linux开发前,你可能需要知道这些基本概念 作者之前编写了一系列嵌入式Linux的开发文档: 关注公众号【微联智控】,并回复【嵌入式Linux资料】,可获取以上pdf文档​的下载链接。 当编写到一定程度的时候,回过头再看看这些文档的内容,结合一部分网友的反馈,反思了一下。之前的文档,更多的是站在技术总结的角度去编写,而非入门初...

EmbedIoT Studio 8875

如何从头开始开发 Linux 驱动程序

我撰写了一系列主要侧重实践的文章,理论背景较少。我从《Linux 设备驱动程序》一书中学习了如何开发驱动程序,该书中讨论的示例代码可在GitHub上找到。首先介绍一下基础知识,Linux 操作系统分为内核空间和用户空间。访问硬件设备只能通过内核空间,而设备驱动程序可以被视为内核空间提供的 API,允许用户空间代码访问设备。基于这些基本概念,我发现了几个促使我学习驱动程序开发的问题。

2501_93209230的博客 1581

嵌入式Linux驱动程序和应用程序开发大全

1.嵌入式Linux驱动程序开发 嵌入式Linux驱动程序开发包罗万象,基本上每个点都要大概了解一下。 1.1软件工具 Makefile必须要掌握一些,至于Kconfig太简单了只是个配置文件算不上程序技能。shell也必须会一点,因为makefile经常调用shell指令。 1.2内核API 作为驱动程序的原料,大概了解有什么内核API函数可以用来组合驱动非常重要。 1.3基本概念和代码实现 内核的并发、阻塞非阻塞、异步通知、中断和时钟、内存管理等基本概念以及它们的代码实现。 1.4驱..

z3256789的博客 757

嵌入式linux/鸿蒙开发板(IMX6ULL)开发(一) 嵌入式Linux开发基本概念以及开发流程介绍

文章目录1.嵌入式Linux开发的基本概念2.日常工作中开发流程是怎样? 1.嵌入式Linux开发的基本概念 嵌入式Linux系统,就相当于一套完整的PC软件系统。 嵌入式Linux开发有哪些内容? Windows里含有: 简单地说,嵌入式LINUX系统里含有 ① 电脑一开机,那些界面是谁显示的? 是BIOS,它做什么?一些自检,然后从硬盘上读入windows,并启动它。 类似的,这个BIOS对应于嵌入式Linux里的bootloader。 Bootloader的作用就是去Flash、SD卡等设备上读入

da.的博客 4009
上一篇: curl 命令的使用:HTTP请求、下载文件、FTP上传下载
下一篇: mknod
菜鸟高工
博客等级 码龄16年 27粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值