驱动中如何控制硬件之点亮LED

我们先思考一下,我们在驱动中去操作硬件,哪些地方没变?
1.硬件的物理原理没变
2.硬件的操作接口寄存器没变
3.硬件的操作代码不变

那么哪些地方变了呢?
1.寄存器地址不同。原来是直接用物理地址,现在需要用该物理地址在内核虚拟地址空间相对应的虚拟地址。寄存器的物理地址是CPU设计时决定的,从datasheet中查找到的
2.编程方法不同。裸机中习惯直接用指针操作寄存器地址,而kernel中习惯用封装好的io读写函数来操作寄存器,以实现最大程度可移植性。
总结一下:就是以前我们是直接用寄存器的物理地址去操作的寄存器,而在内核里面,开了MMU,我们用到的都是虚拟地址,所以操作寄存器的时候需要去用该寄存器对应的虚拟地址。
寄存器的读写函数,最好使用内核提供的读写函数


内核的虚拟地址映射方法?
内核中有2套虚拟地址映射方法:动态和静态
静态映射:
内核移植时以代码的形式硬编码,如果要更改必须改源代码后重新编译内核在内核启动时建立静态映射表,到内核关机时销毁,中间一直有效
对于移植好的内核,你用不用他都在那里
动态映射:
驱动程序根据需要随时动态的建立映射、使用、销毁映射
映射是短期临时的
总结一下:2种映射并不排他,可以同时使用,已经静态映射好了的寄存器,你再动态映射的时候,无非就是多了一个虚拟地址可以指向那个物理地址
静态映射的好处是执行效率高,坏处是始终占用虚拟地址空间;动态映射的好处是按需使用虚拟地址空间,坏处是每次使用前后都需要代码去建立映射&销毁映射(还得学会使用那些内核函数的使用)


关于静态映射要注意的:
1.不同版本内核中静态映射表位置、文件名可能不同
2.不同SoC的静态映射表位置、文件名可能不同
3.所谓映射表其实就是头文件中的宏定义

三星版本内核中的静态映射表:
虚拟地址基地址定义在:arch/arm/plat-samsung/include/plat/map-base.h
虚拟地址的基地址为:0xFD000000
三星移植时确定的静态映射表的基地址,表中的所有虚拟地址都是以这个地址+偏移量来指定的,那么这个虚拟地址对应的物理地址应该就是我们第一个寄存器

#define S3C_ADDR_BASE (0xFD000000)
#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))

主映射表位于:arch/arm/plat-s5p/include/plat/map-s5p.h
它基于虚拟地址基地址
CPU在安排寄存器地址时不是随意乱序分布的,而是按照模块去区分的。每一个模块内部的很多个寄存器的地址是连续的。所以内核在定义寄存器地址时都是先找到基地址,然后再用基地址+偏移量来寻找具体的一个寄存器。
表中是GPIO的各个端口的基地址的定义
#define S5P_VA_GPIO S3C_ADDR(0x00500000)
所以:S5P_VA_GPIO = 0xFD000000 + 0x00500000 = 0xFD500000

GPIO相关的主映射表位于:arch/arm/mach-s5pv210/include/mach/regs-gpio.h
#define S5PV210_GPJ0_BASE (S5P_VA_GPIO + 0x240)
S5PV210_GPJ0_BASE = 0xFD500000 + 0x240 = 0xFD500240

GPIO的具体寄存器定义位于:arch/arm/mach-s5pv210/include/mach/gpio-bank.h
#define S5PV210_GPJ0CON (S5PV210_GPJ0_BASE + 0x00) //FD500240
#define S5PV210_GPJ0DAT (S5PV210_GPJ0_BASE + 0x04)//FD500244
#define S5PV210_GPJ0PUD (S5PV210_GPJ0_BASE + 0x08)
#define S5PV210_GPJ0DRV (S5PV210_GPJ0_BASE + 0x0c)
#define S5PV210_GPJ0CONPDN (S5PV210_GPJ0_BASE + 0x10)
#define S5PV210_GPJ0PUDPDN (S5PV210_GPJ0_BASE + 0x14)


硬件原理图:
在这里插入图片描述我们的4个灯,接的分别是:GPJ0_3 GPJ0_4 GPJ0_5 PWMOUT1
根据原理图:当引脚输出低电平的时候,灯会亮
当引脚输出高电平的时候,灯会灭


静态映射操作LED
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)

1.实现在insmod的时候,去把灯点亮,rmmod的时候,把灯灭掉
点亮:
rGPJ0CON |= (1<<12) | (1<<16) | (1<<20);
rGPJ0DAT &= ~((1<<3) | (1<<4) | (1<<5));
熄灭:
rGPJ0DAT |= ((1<<3) | (1<<4) | (1<<5));
2.完成驱动的写函数,让应用层可以控制硬件
驱动层:
int ret = -1;
printk(KERN_INFO “test_char_device_write\n”);
memset(buf, 0, sizeof(buf));
ret = copy_from_user(buf, ubuf, count);
if (ret)
{
printk(KERN_INFO “copy from user fail\n”);
return -EINVAL;
}
if (‘1’ == buf[0])
{
rGPJ0DAT &= ~((1<<3) | (1<<4) | (1<<5));
}
else if (‘0’ == buf[0])
{
rGPJ0DAT |= ((1<<3) | (1<<4) | (1<<5));
}
驱动层的memset函数位于,linux/string.h中
应用层:
write(fd, “1”, 1);
read(fd, buf, 1);
sleep(1);

write(fd, "0", 1);
read(fd, buf, 1);
sleep(1);

write(fd, "1", 1);
read(fd, buf, 1);
sleep(1);

write(fd, "0", 1);
read(fd, buf, 1);
sleep(1);

动态映射操作LED
如何建立动态映射?
两个函数:
request_mem_region,向内核申请(报告)需要映射的内存资源。
ioremap,真正用来实现映射,传给他物理地址他给你映射返回一个虚拟地址
如何销毁动态映射?
iounmap
release_mem_region
注意:映射建立时,是要先申请再映射;然后使用;使用完要解除映射时要先解除映射再释放申请。
看代码:
struct resource * res = NULL;
static unsigned int * pBase = NULL;
init函数:
if (!(res = request_mem_region(PHY_GPJ0CON, 8, “GPJ0_BASE”)))
{
printk(KERN_INFO “request_mem_region fail\n”);
return -EINVAL;
}
if (!(pBase = ioremap(PHY_GPJ0CON, 8)))
{
printk(KERN_INFO “request_mem_region fail\n”);
return -EINVAL;
}

*pBase |= (1<<12) | (1<<16) | (1<<20);
*(pBase+1) &= ~((1<<3) | (1<<4) | (1<<5));

exit函数:
*(pBase+1) |= ((1<<3) | (1<<4) | (1<<5));
unregister_chrdev(TEST_MAJOR, TEST_NAME);
iounmap(pBase);
release_mem_region(PHY_GPJ0CON, 8);


函数参数说明:
request_mem_region
第一个参数:需要申请映射的物理地址的起始地址
第二个参数:申请的字节数
第三个参数:名字,好像没什么重要的作用
返回值:resource *类型,正确返回一个指针,错误返回空

ioremap
第一个参数:需要申请映射的物理地址的起始地址
第二个参数:申请的字节数
返回值:正确返回申请的物理地址对应的虚拟地址的首地址,错误返回空

iounmap:参数是申请的物理地址对应的虚拟地址的首地址,ioremap的返回值
release_mem_region:
第一个参数:需要申请映射的物理地址的起始地址
第二个参数:申请的字节数


注意驱动里面的资源回收的处理顺序,倒映式回收机制。
驱动里面使用的内存也都是虚拟地址空间,如果只知道物理地址,不知道虚拟地址就要使用ioremap函数来进行转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值