Linux之LED驱动开发--寄存器版

linux驱动开发一般不会直接操作寄存器,主要是学习一下地址映射。
什么是地址映射?
将逻辑地址(虚拟空间地址)转换为真实的物理地址。
虚拟空间地址是虚拟出来扩充内存空间的,并不是扩充真实的物理地址。对于真实的物理地址,运行程序必须将程序一次性放入,这样就导致大内存程序无法在小内存地址运行,只能等待。大大降低了处理器的利用率。实际上程序运行并不需要同时把程序加载进来,虚拟地址就解决了这样一个问题,当程序运行时把需要运行的程序和数据加载进来,暂时不需要的放入交换区(硬盘–外存),这样就可以实现运行大于实际物理内存的程序。打个比方,对于32位的处理器,虚拟地址就是2的32次方即4GB,开发板是512MB的DDR3,即物理内存,经过MMU就可以将512的物理内存映射到4GB虚拟空间。
在这里插入图片描述图片来自正点原子手册

为什么要用到地址映射?
因为我们的开发都是面向虚拟地址的,真实物理地址空间是很小的,当运行的时候就需要将虚拟地址映射到真实物理地址,否则cpu是找不到的。
imx6ull裸机开发和STM32基本相同,都可以直接操作寄存器物理地址,但是linux是不能直接操作物理地址的,linux内核一启动便会启动MMU(memory manage uint),即内存管理单元。MMU是硬件,他主要完成下面两项功能:
①它用来将虚拟内存地址翻译到实际的物理内存地址。
②内存保护,可以设置特定的内存块的读写属性,只读、可读可写。
暂时知道这些概念即可,接下来学习操作寄存器进行led驱动开发。
led驱动开发
如果没有MMU,那么裸机开发是直接操作物理寄存器,,一旦linux的MMU设置好内存映射,就不能在对你当时记得那个物理寄存器地址操作了,cpu寻址是从虚拟地址开始的,因为这个地址名已经不再是物理地址的编号了,而是映射出了一个新编号来和它对应。我们操作的就是这个虚拟地址。如何将物理地址与内存地址之间转换,很简单,官方给了两个API函数:
1) ioremap
获取指定物理地址空间对应的虚拟地址空间。
在arch/arm/include/asm/io.h定义如下:

#define ioremap(cookie,size)		__arm_ioremap((cookie), (size), MT_DEVICE)
extern void __iomem *__arm_ioremap(phys_addr_t, size_t, unsigned int);
//cookie 为物理起始地址
//size  要映射的空间大小(单位字节) 比如在imx6ull的寄存器为4字节。
//返回值为void __iomem 指针

举例说明

//寄存器物理地址
#define  CCM_CCGR1_BASE                      0X020C406C
//映射虚拟地址指针
static void __iomem *IMX6U_CCM_CCGR1;
//地址映射
IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);

2) iounmap
与ioremap相反,释放ioremap映射的虚拟空间地址。
在arch/arm/include/asm/io.h定义如下:

#define iounmap				__arm_iounmap
extern void __arm_iounmap(volatile void __iomem *addr);
//参数就是前面定义的地址映射指针
/*比如释放掉前面映射的虚拟地址*/
iounmap(IMX6U_CCM_CCGR1 );

地址映射完成后就可以对获得的虚拟地址进行读写操作了(和裸机开发一样),API如下
1)读寄存器函数 *readx,根据寄存器的位数,分为如下三种

#define readb(c)  ({ u8  __v = readb_relaxed(c); __iormb(); __v; })//8位
#define readw(c)  ({ u16 __v = readw_relaxed(c); __iormb(); __v; })//16位
#define readl(c)  ({ u32 __v = readl_relaxed(c); __iormb(); __v; })//32位
//返回值u8/u16/u32
//举例
//u32 val = readl(地址映射指针);

2)写寄存器函数 writex

#define writeb(v,c)	({ __iowmb(); writeb_relaxed(v,c); })//8位寄存器
#define writew(v,c)	({ __iowmb(); writew_relaxed(v,c); })//16位寄存器
#define writel(v,c)	({ __iowmb(); writel_relaxed(v,c); })//32位寄存器
//参数v:要写入寄存器的值
//c:虚拟地址指针

关键的就说完了,剩余的流程就参看
字符设备驱动开发框架笔记

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值