![](https://img-blog.csdnimg.cn/20201014180756928.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
OrangePi H3 Linux设备驱动开发
文章平均质量分 57
jklinux
一个linux下的渣渣老码农
展开
-
01 OrangePi uboot编译
计算机系统的组成: CPU , 内存, 输入/输出设备, 外存(硬盘)单片机: 一个芯片上就是一个完整的计算机系统. SOC: 片上系统(system on chip), 其实就是功能更强大的单片机arm: 一种CPU核心(如:51(intel)). arm公司不会生产具体的硬件芯片, 只设计CPU核心.arm通过与芯片厂家合作, 生产基于arm核心的具体CPU芯片. 基原创 2017-05-22 13:24:52 · 8547 阅读 · 5 评论 -
02 uboot的常用命令及用法
uboot是bootloader的一种,主要是用于引导内核启动. uboot除此功能外, 还带有很多其它功能. 功能是通过命令来调用.uboot的命令: help //列出当前uboot所有支持的命令 help 命令 //查看指定命令的帮助 reset //重启uboot printenv //打印所有环境变量的值 printenv 环境变量原创 2017-05-23 13:19:00 · 7238 阅读 · 2 评论 -
03 OrangePi 内核编译
配置交叉编译器: 解包gcc-linaro-arm-linux-gnueabihf-4.7-2013.03-20130313_linux.tar.bz2 解包后,得到的目录名比较长,改下目录名为“arm-gcc" vim ~/.bash_profile 增加语句 export PATH=/disk3/myown/arm-gcc/bin:$PATH 保存退出后,原创 2017-05-24 14:16:09 · 7888 阅读 · 10 评论 -
04 用busybox制作自己的文件系统
busybox用于制作小型的文件系统.常用于嵌入式.在orangepi_sdk/source/busybox-1.25.0目录里有源码. 1). 先清除编译出来的文件及配置文件 make distclean 2). 配置busybox make menuconfig //进入配置界面 Busybox Settings --->原创 2017-05-24 17:11:45 · 3177 阅读 · 1 评论 -
05 OrangePi通过usb线实现与pc端的网络通信
minicom 是pc上操作uart设备的一个软件工具. minicom会捕捉用户的键盘输入,并把输入的内容通过uart接口发出去。但不显示发出的内容. minicom只显示通过uart接口接收到的内容.为什么接板子后,按键盘会有相应的显示? 1). 板上的uart通过usb线接到pc上. 板子可以通过uart口接收到pc端的uart口发出内容(pc端也可接收到板上发的内容原创 2017-05-25 11:46:49 · 5418 阅读 · 0 评论 -
06 OrangePiLite wifi驱动配置
OrangePiLite板上的wifi型号是rtl8189fs(用的接口是sdio).1).在前面的基础上配置内核,编译出所需的wifi驱动模块 make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- Device Drivers ---> [*] Network device support ...原创 2017-05-27 17:27:04 · 5441 阅读 · 6 评论 -
07 OrangePi 配置telnet服务
telnet是一个通过网络登录系统的服务,busybox里本身已有提供此服务程序,只要配置好即可使用。 对我们的好处是配置服务后,可以不再用通过uart线来操作板上系统,只要网络连通,即可通过网络来操作即可。让开发板启动进入文件系统后,在minicom上操作(不是在pc端): 修改/etc/init.d/rcS, 在后面增加语句: mkdir /dev/pts mount -原创 2017-05-29 11:25:50 · 1087 阅读 · 0 评论 -
08 uboot上增加自己的命令
在实现前需了解lds和里面的段在uboot源码目录里include/command.h:struct cmd_tbl_s { char *name; int maxargs; //命令功能函数支持的最大参数的个数 int repeatable; //此命令执行完后,再按"enter"键时是否重复执行.原创 2017-05-31 17:30:52 · 1164 阅读 · 1 评论 -
09 uboot的配置编译主过程分析
在orangepi_sdk目录下://////////////////////////////////////uboot的配置过程make config_uboot //配置uboot1). //当前目录的Makefile 26 PHONY += config_uboot 27 config_uboot : 28 @echo "+++++config uboot原创 2017-06-01 11:03:45 · 1586 阅读 · 0 评论 -
10 orangepi裸板控制IO
控制器就是相当于一个接口,这个接口用于与特定用途的硬件模块通信及数据的交互.gpio 表示通用的IO接口,这些接口上面可以接不同的硬件模块GPIO口共分成组: GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOL 每组里面有数据不等的IO口.PA21表示GPIOA组的第21个IO口.GPIO口都是多功能的, 可以做输入, 输出, 外部中断, 作控制器的引脚原创 2017-06-02 11:32:39 · 3230 阅读 · 11 评论 -
11 orangepi裸板实现printf函数
uart工作原理printf可变参数的获取原理在uboot上,首先uart第0个控制器已经被uboot驱动好了. uart控制器负责数据的收发,我们只要把数据交给uart控制器发出,和从uart控制器里把数据取回来即可. 也就是我们只要找到相应的uart控制器的配置寄存器即可.uart0的基地址0x01C28000UART_RBR : uart0的数据接收寄存器 0x01c28000, 我们通过这原创 2017-06-02 16:40:46 · 1283 阅读 · 0 评论 -
12 orangepi Linux设备驱动前言
需要了解的知识: 1. 驱动是硬件与用户进程之间的通信桥梁 用户进程是不可以直接访问硬件的. 如:hexdump /dev/input/event4 //这样,程序hexdump从设备文件里接收数据并按十六进制打印出来 数据是驱动先接收到硬件反馈的数据处理后再移交给用户进程驱动不属于任何一个用户进程, 可以给多个用户进程调用. 驱动是常驻于内存里,等待用户进程调原创 2017-06-05 11:55:59 · 1800 阅读 · 0 评论 -
13 linux设备驱动基础
内核功能模块: 进程调度, 内存管理(mmu, 分配进程内存), 文件系统管理(如支持的文件系统格式), 设备驱动(硬件驱动好后由内核来统一管理), 网络协议栈 1). 模块机制 静态加载, 把驱动模块编进内核, 在内核启动时加载 动态加载, 把驱动模块编为ko, 在内核启动后,需要用时加载2). 编写内核驱动 #include <linux/module.h> #原创 2017-06-05 12:39:56 · 1724 阅读 · 3 评论 -
14 orangepi 内核里控制IO口
在linux内核里mmu已经启用,不能直接访问物理地址.必须要把物理地址映射到一个虚拟地址上,然后通过该虚拟地址来访问原物理地址. 物理地址就是硬件上安排好的地址,如配置寄存器的地址.void *ioremap(cookie,size) //函数用于把指定的物理地址映射到一个虚拟地址上. // cookie用于指定要映射的物理地址, size表示映射的大小范围 //原创 2017-06-06 10:47:47 · 3589 阅读 · 3 评论 -
15 linux驱动模块的参数
模块参数是用于在加载驱动模块时,指定模块里面的特定变量的具体值.实现方法: 1). #include <linux/moduleparam.h> 2). 在驱动源码里定义变量 static int num = 0; //当加载模块不指定num的值时则为0 3). 声明指定的变量为驱动模块参数 module_param(变量名, 类型, 权限); //类型可有原创 2017-06-06 11:49:59 · 1399 阅读 · 0 评论 -
16 驱动模块的符号表与符号导出
查看elf文件的信息 readelf test.ko -ako文件组成:1). elf文件头 ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data:原创 2017-06-06 15:13:51 · 3125 阅读 · 2 评论 -
17 增加驱动源码到Linux内核里
1). 内核源码的配置项 在linux内核源码目录下,进行配置时: make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 上面命令执行,它又会调用: scripts/kconfig/mconf Kconfig //其中"scripts/kconfig/mconf"是一个专门在终端上显示界面的程序原创 2017-06-07 11:32:59 · 1612 阅读 · 2 评论 -
18 linux字符设备驱动之设备号
设备驱动通常是给用户进程来调用的, 但用户进程通过什么来调用驱动? 最常用的是设备驱动里实现字符设备驱动, 实现后在”/dev”目录里提供一个设备文件, 然后用户进程就可以通过操作设备文件来调用驱动.如pc上的uart设备文件: crw-rw—- 1 root dialout 4, 64 Jun 8 09:20 /dev/ttyS0 crw-rw—- 1 root dialout 4, 65原创 2017-06-08 10:32:44 · 1750 阅读 · 1 评论 -
19 linux字符设备驱动
记得内核里是用面向对象的思想来实现的。但不是完全面向对象. 在linux内核里使用”struct cdev”类型的一个对象来描述一个字符设备驱动。#include <linux/cdev.h>struct cdev { struct kobject kobj; //内核用于管理字符设备驱动, kobject就是内核里最底层的类. 内核里会自动管理此成员. struct原创 2017-06-08 11:49:50 · 1556 阅读 · 1 评论 -
20 linux字符设备驱动相关的函数及参数
当用户进程open设备文件时, 内核会根据打开的设备文件的设备号找到对应的cdev对象,检查cdev.ops->open, 如果不为空,则调用驱动里的open函数,如为空,内核直接返回fd.//注意用户进程打开设备文件得到文件描述符不是由设备驱动里指定的,设备驱动里的open函数仅仅是告诉内核是否已正常打开.用户进程: app: open ---> kernel ---> cdev.o原创 2017-06-08 17:35:08 · 1474 阅读 · 1 评论 -
21 用户进程操作GPIO
首先用户进程是不可以直接操作硬件,只能通过调用设备驱动,让设备驱动来操作硬件. 设备驱动又可以实现一个字符设备驱动接口让用户进程来调用.如让用户进程通过ioctl来控制板上的led灯(PA(15).驱动源码test.c:#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cd原创 2017-06-09 11:36:46 · 1308 阅读 · 8 评论 -
22 虚拟文件的实现
在驱动里用数据缓冲区代替文本文件的数据存取. 实现代码test.c:#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/slab.h>#include <asm/uaccess.h>#define MYMA 1234#de原创 2017-06-09 15:56:16 · 1409 阅读 · 2 评论 -
23 类型的封装(内核里的继承)
#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/slab.h>#include <asm/uaccess.h>#define MYMA 1234#define MYMI 7788#define COUNT 3 //三原创 2017-06-09 17:30:36 · 780 阅读 · 0 评论 -
24 ioctl的自定义命令
系统调用ioctl函数的作用: 用户进程用于通过相应的设备驱动来获取或者设置硬件状态.ioctl ---> kernel ---> cdev.fops->unlocked_ioctl(...)在字符设备驱动里, 其中unlock_ioctl函数原形:long (*unlocked_ioctl) (struct file *fl, unsigned int cmd, unsigned long ar原创 2017-06-11 10:35:34 · 3790 阅读 · 2 评论 -
25 mdev与驱动源码里创建设备文件的实现
前面设备驱动备加载后,都需要用命令”mknod”来创建出设备文件. 其实内核里有接口在驱动源码里实现创建出设备文件.首先busybox作的嵌入式文件系统里有提供”mdev”命令.(有些系统移植”udev”,工作方式有区别,但功能差不多)“mdev –help”命令执行输出的信息:mdev -s is to be run during boot to scan /sys and populate /原创 2017-06-11 14:33:57 · 1103 阅读 · 2 评论 -
26 register_chrdev函数
static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops){ return __register_chrdev(major, 0, 256, name, fops);}///int __regis原创 2017-06-11 15:48:40 · 1114 阅读 · 0 评论 -
27 miscdevice设备驱动应用及实现原理
miscdevice是字符设备驱动的简化版本,方便实现一个简单的字符设备驱动.#include <linux/miscdevice.h>struct miscdevice { int minor; //指定次设备号,次设备号为255则会自分配空闲的次设备号. 主设备已固定为10. //次设备号在(0~255)之间. const char *name; //名字原创 2017-06-11 17:25:13 · 1371 阅读 · 0 评论 -
28 atomic_t原子数与原子位操作
假如驱动里实现对write操作进行计算次数,当进程读操作时输出次数. test.c:#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/miscdevice.h>int count = 0;ssize_t myread(struct file *fl, char __use原创 2017-06-12 10:36:13 · 1448 阅读 · 0 评论 -
29 mutex互斥锁
在linux内核里用struct task_struct 的一个对象描述一个进程和线程:#include <linux/sched.h>struct task_struct { ... volatile long state; /*其实进程线程是否休眠就是改变这个状态 -1 unrunnable, 0 runnable, >0 stopped */ pid_t pid;原创 2017-06-12 14:48:59 · 1031 阅读 · 1 评论 -
30 spinlock_t自旋锁和semaphore信号量
自旋锁是一直循环检查, 直到锁上为止(锁不上也不会让进程休眠)。自旋锁只有两种状态,可锁上和锁不上. 锁上后确保执行的代码为原子操作, 直到解锁为止. 注意不能长时间锁上自旋锁, 不能在临界区里休眠.spinlock_t 自旋锁 #include <linux/spinlock.h>spinlock_t mylock;spin_lock_init(&mylock); //初始化自旋锁, 初始原创 2017-06-12 17:10:59 · 1120 阅读 · 0 评论 -
31 completion完成量,wait_queue_head_t等待队列和epoll
完成量, 功能与信号量差不多, 最大不同可以唤醒多个休眠的进程或线程#include <linux/completion.h>struct completion { unsigned int done; //done表示资源,上锁时done--. 当done为0时再上锁则会安排调用进程或线程进入休眠. //解锁时, done++ wait_queue_原创 2017-06-13 10:50:19 · 1766 阅读 · 0 评论 -
32 linux内核里的中断处理
中断: CPU在执行过程中, 硬件发生状态变化时, 打断CPU程序的执行,先做硬件状态变化时需要处理,再接着执行原程序. 中断其实就是由硬件主动来告诉我们它的状态发生改变了, 而不需要一直轮询硬件状态 .arm里有异常向量表,当发生中断异常,不是执行0x18就是执行0xffff0018上的代码指令.也就是不管是什么中断,都是由在这地址上的代码来处理.arm里只有一个中断异常功能,都由SOC里的中原创 2017-06-13 14:56:08 · 1359 阅读 · 1 评论 -
33 全志GPIO口的脚本配置及超声波测距模块的linux驱动
linux内核有gpiolib标准的gpio操作接口. 但这套接口只能配置输入,输出,获取或设置IO口的电平. 但GPIO口是多功能, 还有上/下拉功能. 全志的GPIO额外的配置在script.bin里指定(有些SOC是提供额外的函数接口来配置).script.bin是由sdk里的工具fex2bin把fex配置文件生成bin文件. bin文件也可由工具bin2fex转成fex文件.在script原创 2017-06-19 10:50:07 · 4462 阅读 · 0 评论 -
34 dht12单总线方式的Linux驱动及解决H3丢失中断的问题
DHT12温湿度传感器有两种工作方式, 一种是用I2C接口。 一种是单总线(也就是用一个GPIO口, DHT11只能用这种方式).DHT12精度比DHT11的高,温湿度都有小数部分的。dht12的测量范围(-20 ~ 60), dht11(0 ~ 50)应DHT12单总线的工作方式可以完全兼容DHT11,下面的图是从DHT11手册里抠出来的: 通过上图可得知,工作流程: 发开始信号 —> D原创 2017-06-19 11:50:28 · 2511 阅读 · 0 评论 -
35 红外接收头在linux内核里的驱动
红外是一种光, 对于人类是不可见的光,但摄像头可以捕捉到红外光.红外可用不同的频谱来表二进制的0和1(高/低电平). 传输分成发送端(遥控器),接收端(红外接收头)发送端发出表示高低电平的不同的光, 接收端收到红外光后还原成对应的高低电平来表示二进制的0和1.发送端可由专门的红外发射芯片来实现,如图: 红外发射芯片会自动扫描矩阵键盘电路,根据不同的键码,生成一串二进制数据,再按每位的二进制数据用原创 2017-06-20 14:38:10 · 6144 阅读 · 2 评论 -
36 linux内核里的HZ定时器与timer_list定时器
在linux内核里的设备驱动常常用到定时器定时器功能,而硬件上的定时器通常只有几个,如果每个设备驱动使用一个硬件定时器,那肯定是不够用,所以在linux内核里会把一个硬件定时器的功能扩展成多个软件定时器. 例如: 硬件定时器每秒钟触发检查一次,那么就可以设置如3秒,4秒,10秒的软件定时器.内核里的HZ定时器就是基于一个硬件的定时器来实现的. 它与内核源码目录的”.config”里的”CO...原创 2017-06-21 11:45:12 · 3050 阅读 · 0 评论 -
37 linux内核的中断底半部实现方法
linux内核里的中断处理: 在内核当发生中断时,会记录哪个中断产生并把中断相应的处理函数加入一个处理队列里, 直到把所有同一时间发生的中断全部记录好后,处理队列里的函数才会逐一得到调用。所以当一个中断处理函数处理过久时,就有可能影响它后面的中断处函数的执行时机。我们用的中断处理函数是可以被中断信号打断的。中断处理函数需要注意: 1.不能执行时间长的代码. 注意printk...原创 2017-06-21 16:56:21 · 1350 阅读 · 3 评论 -
38 全志平台的script.bin在linux内核里的应用分析
在全志平台里,script.bin用于指定SOC控制器和GPIO等相关的配置. script.bin是由script.fex用工具转换得来.在uboot启动系统时, uboot的环境变量bootcmd为: bootcmd=ext4load mmc 0:1 0x43000000 /script.bin; ext4load mmc 0:1 0x42000000 /uImage; bootm 0x420原创 2017-06-22 14:30:18 · 3568 阅读 · 7 评论 -
39 解决全志h3 linux内核源码里的关于script.fex的bug
在script.fex里有关于io口的配置: Port:端口+组内序号<功能分配><内部电阻状态><驱动能力><输出电平状态> [gpio_para] gpio_used = 1 ;gpio_num = 30 ;gpio_pin_1 = port:PL10<1><default><default><1> ;gpio_pi原创 2017-06-23 10:53:27 · 3282 阅读 · 1 评论 -
40 矩阵键盘在linux内核里的驱动实现
行线: MCU_SPICLK0, MCU_SPIFRM0列线: MCU_SPITXD0, MCU_SPIRXD0当按键按下时,它的1脚和2脚接通,行线与列线就会接通.判断是否有接键按下或松手: 首先,行线有接上拉电阻 ,默认高电平。列线全部输出低电平. 如K14按下时, 列线SPITXD0与行线SPICLK0接通, 行线的电平就会被列线输出的电平影响,变成低电平(有下降沿). 当K14松手原创 2017-06-23 16:06:49 · 2431 阅读 · 0 评论