Linux ARM 驱动笔记之一 : 准备
来源:互联网 发布:linux复制到上级目录 编辑:程序博客网 时间:2024/05/21 10:11
Linux ARM 驱动笔记之一 : 准备
转载请注明:http://blog.csdn.net/zkwsr/article/details/12510439
本文以Linux ARMSPI设备驱动为例记录Linux驱动的开发中的一些套路和准备.本文内容抛开具体代码,描述相关的准备知识,描述书本中很少提及的内容.
1 驱动编写的套路
Linux 驱动编写归根揭底,涉及到底部,就是设置寄存器, 从设置寄存器的角度来看,Linux驱动编写分为两种套路:
1) 直接操控寄存器: 这种方式写驱动代码结构简单,直接设置控制寄存器即可,但是对程序员的硬件知识要求比较高, 一个Arm的Datasheet看上3-5遍,才有可能写出个正确的驱动.(从单片机写过程序的程序员转到linux驱动,开始容易写这种代码.)
注意事项:
volatile 这个关键字, 有些时候必须加上.否则变量不会及时更新,导致程序出错.
管脚地址示例:
a) 使用内核设置
定义:S3C2410_GPB(0)//S3C2410 CPU GPIO_B第 0个管脚,linux内核提供了这个对应的宏.
设置/赋值 : s3c2410_gpio_setpin(S3C2410_GPB(0),0);
b) 直接使用寄存器地址
#define PMC_PCER 0xFFFFFC10 //sam9G15 PMC寄存器.
#definev_uint32_t volatile uint32_t
//根据寄存器的位数设置字节长度.uint32_t, uint16_t
v_uint32_t *pmc_pcer;
//ioremap地址映射
pmc_pcer =(uint32_t *)ioremap(PMC_PCER, 4);
* pmc_pcer = (1u<< 5); //设置寄存器值第的值
通过直接操控寄存器就可完成设备的驱动, 但是不建议使用这种方法.
2) 不直接操控寄存器: 通过Linux内核提供的驱动框架写程序,速度快,相对于直接控制寄存器,对硬件知识要求不那么高了.在编写个规范和可靠性方面,按linux驱动框架编写会更好.驱动架构分为:控制器驱动层/Linux驱动核心层/设备驱动层. 下面以SPI驱动为例介绍.(其他类型设备类似)
SPI驱动架构图:
SPI控制器驱动层:每种处理器平台都有自己的控制器驱动, 属于平台移植相关,一般厂商都会提供到linux内核中. (编译内核时将之编译进去,或者选择为module,编译后将之insmod)
//这样程序员就不用去过多了解硬件控制器部分的细节了.
SPI核心层:Linux SPI的核心部分,里面定义了相关的数据结构, 用于向上(SPI设备)提供统一的接口.提供了spi驱动相关数据结构和操作函数.
// linux-2.6.39/drivers/spi/spi.c
SPI设备驱动(设备协议驱动):针对不同设备的特定驱动.利用SPI核心层提供的接口编写协议驱动. //这个驱动是程序员需要开发的驱动.
2 控制器驱动模块的加载:
加载了控制器驱动后, spicore的功能才会正常使用,spidevice 才可以正常运行.
Linux内核编译时有 [*] [M] [ ] 三个选项:
[*] : 选中编入内核,启动时会加载.
[ M ] : Module 编译成模块,手动加载.
[ ] : 不选.
#make menuconfig //进行选择
#make zImage/uImage/…. 各种形式的内核镜像
#make modules //编译[M]选中的模块,然后在相关路径下找到, copy出来使用.
// 下图编译后module为 linux-2.6.39/drivers/spi/atmel_spi.ko
// 和自己写的module文件一样使用 #insmod.
3 设备注册形式:
根据设备的不同存在形式进行代码的对应编写.设备的存在形式分为板载设备和动态加载设备.
1) 板载设备:设备启动时加载的设备, 固定在板子/机器上的设备,不进行热插拔.
linux-2.6.39/arch/arm/mach-at91/board-sam9x5cm.c
// 在spi board_info中添加设备信息, 启动时通过spi core 的__init函数spi_register_board_info()函数进行初始化.
api_register_board_info() <-- at91_add_device_spi()
//加载spi devide 时会调用. //在深挖就找不到了,暂时放在这.
2) 动态加载设备: 加载设备驱动时加载上去的设备.
动态设备添加例子:
152 spi_master =spi_busnum_to_master(SPI_BUS);
153 spi_device =spi_alloc_device(spi_master);
154 pdev =bus_find_device_by_name(spi_device->dev.bus, NULL, buff);
155 if (pdev) {
156 spi_dev_put(spi_device);
157 } else {
158 status =spi_add_device(spi_device);
159 }
160
161 put_device(&spi_master->dev);
其他的驱动也有类似的方法.
4 设备驱动编写方法:
关于设备驱动的写法,没有捷径.多读代码,多写代码.设备驱动起初最好的方法就是—看内核源码,设备驱动最好的例子. 以spi驱动为例:
~/linux-2.6.39/drivers/spi/spidev.c就是第一个需要看的例子.参照这个例子就能写出spi设备驱动. 当然,spidev.c提供的仅仅是一种方式.还有其他的方式—internet资源模仿. 例如:git,github,…. 最终写出漂亮的驱动.
5 驱动的makefile
1 ifneq ($(KERNELRELEASE),)
2 #module name not same any file
3 MODULE_NAME := EEPROM
4 #module with init and exit
5 RESMAIN_CORE_OBJS :=eeprom.o
6 RESMAIN_GLUE_OBJS := twi.o
7 $(MODULE_NAME)-objs := $(RESMAIN_CORE_OBJS) $(RESMAIN_GLUE_OBJS)
8 obj-m := $(MODULE_NAME).o
9else
10 PWD=$(shell pwd)
11 KERNEL_SRC=~/linux-2.6.39
12default:
13 # -C input kernel src -M reback thismakefile
14 #$(MAKE) -C $(KERNEL_SRC) M=$(PWD)LDDINC=$(PWD) modules
15 $(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules
16clean:
17 rm *.o *.ko #and other generated code
18endif
6 关于中断号
写中断函数的时候,需要这样一个函数:
intrequest_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *devname, void*dev_id);
其中 unsignedint irq, 是中断号,这个中断号如何选取,怎么能和板子上的某个GPIO引脚对应上呢?下面介绍一下查找中断号的方法.
首先看CPUdatasheet,有类似下图的一张表格,列出了0-31个号码(具体CPU不同,可能编号数目不同 16 32 64…).
内部中断: 这32是CPU的内部中断 (外设中断), 这32个中断是由各外设产生的—外设—这里应该理解成CPU的外设控制器(这样和外部设备就能区别开来了).这32个中断对应的中断编号是(0-31),对外是没有引脚的.(记住,这些中断是没办法和真实的外部设备用线连起来的, 所以长说为内部中断, 所谓内部是CPU内部,相对于外部而言的).这些内部中断普通的驱动程序员是不需要去处理的,内核控制器驱动提供者已经做好了相关的工作,仅需要调用相关的处理函数即可.
外部中断:所谓的外部中断,是在设备编程时长用到的中断, GPIO_X_Y //GPIO的X控制器第Y个引脚.这个编号从32-255,根据GPIO的引脚数量而定.那GPIO的引脚的中断线时怎么编号的呢? 是以32为基数,向上累加的.具体使用可使用相关的头文件对应的定义即可.
下面举例说明:
例如SAM9G15芯片的 GPIO_D_21引脚对应的中断号,在linux-2.6.39/arch/arm/mach-at91/include/mach/gpio.h中定义
#define AT91_PIN_PD21 (PIN_BASE + 0x60 + 21) //32+96+21=149
//即GPIO_D_21号引脚对应的中断编号是 149.
//使用时多使用内核提供的定义,不要使用纯数字.
//那么149显然不在其上图0-31个中断号中, linux内核为了后续编写程序方便提供了映射.
//将149对应到了PIOD的寄存器上的第21位.然后进行处理.
//对于上层的程序员只需关心GPIO引脚对应的中断编号即可.
- Linux ARM 驱动笔记之一 : 准备
- arm linux驱动笔记
- ARM linux内核-----准备
- Linux驱动开发准备
- Linux驱动开发准备
- ARM-Linux驱动开发
- ARM,linux内核,驱动
- arm-linux驱动:hello
- 【ARM】Linux驱动移植
- linux驱动必备硬件知识--ARM笔记<一>
- s3c2440 arm+linux 开发板移植rt3070驱动笔记
- linux i2c 驱动之一
- Linux 块驱动之一
- ARM学习笔记之一:ARM体系结构
- Linux驱动学习笔记之一——高精度定时器2
- SMP3.0学习笔记之一 准备篇
- PMP学习笔记之一 准备篇
- [ARM笔记]字符设备驱动
- H.264优秀博客网摘
- attr_writer、attr_accessor、attr_reader
- UML_总结
- Source insight上修改samba共享ubuntu上内核源程序文件出现"Confirm by typing ‘yes' below"、"has been changed outside of
- 通信概述
- Linux ARM 驱动笔记之一 : 准备
- 一、家庭物品妙用
- 解析离线安装Eclipse的Android ADT开发插件的具体操作(图文)
- HttpContext.Current并非无处不在
- C#中静态方法和动态方法的理解
- springmvc+hibernate+security整合笔记
- PHP定时执行任务的实现
- 听《昙花》有感。
- 腾讯2014软件开发笔试题目