I.MXUL使用Linxu点亮一个LED

明确:1.LED属于字符设备驱动,2.关于字符设备的介绍在上篇文章中有介绍,3.关于GPIO的操作在之前文章中也有介绍。

字符设备驱动介绍:https://blog.csdn.net/qq_35947329/article/details/102709469

I.MX6UL IO分析: https://blog.csdn.net/qq_35947329/article/details/102594242

问题一:点亮一个LED灯需要配置寄存器,在linux下也是直接操作地址吗?

在编写驱动之前,我们需要先简单了解一下 MMU(内存管理单元)

1.MMU主要功能有:完成虚拟空间到物理空间的映射。

2.内存保护,设置存储器访问权限。

linux中主要通过虚拟地址来访问物理地址。

问题二:如何通过虚拟地址获取物理地址?

ioremap 函 数 用 于 获 取 指 定 物 理 地 址 空 间 对 应 的 虚 拟 地 址 空 间函数原型如下:

#define ioremap(cookie,size) __arm_ioremap((cookie), (size),MT_DEVICE)

void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size,unsigned int mtype)
 {
     return arch_ioremap_caller(phys_addr, size, mtype,__builtin_return_address(0));
 }

ioremap 是个宏,有两个参数:cookie 和 size,真正起作用的是函数__arm_ioremap,此函数有三个参数和一个返回值,这些参数和返回值的含义如下:

phys_addr:要映射给的物理起始地址。
size:要映射的内存空间大小。
mtype:ioremap 的类型,可以选择 MT_DEVICE、MT_DEVICE_NONSHARED、MT_DEVICE_CACHED MT_DEVICE_WC,ioremap 函数选择 MT_DEVICE。
返回值:__iomem 类型的指针,指向映射后的虚拟空间首地址。

例子:

#define SW_MUX_GPIO1_IO03_BASE  (0X020E0068)
static void __iomem* SW_MUX_GPIO1_IO03;
SW_MUX_GPIO1_IO03 = ioremap(GPIO1_GDIR_BASE, 4);

即可获得I.MX6ULL 的 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器对应的虚拟地址

看起来获取虚拟地址就像申请了一个内存,有申请就应该有释放,当卸载驱动的时候需要把虚拟地址释放掉,释放虚拟地址的函数是iounmap,函数原型如下:

void iounmap (volatile void __iomem *addr)

该函数只有一个参数,addr,此参数即为要释放的虚拟地址。

假如我们现在要取消掉 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器的地址映射,使用如下代码即可:
iounmap(SW_MUX_GPIO1_IO03);

问题三:是不是直接对虚拟地址赋值就能操作相应寄存器?

在linux下不建议直接对地址进行操作。而是通过读写函数。

1 、读操作函数
读操作函数有如下几个:
1 u8 readb(const volatile void __iomem *addr)
2 u16 readw(const volatile void __iomem *addr)
3 u32 readl(const volatile void __iomem *addr)
readb、readw 和 readl 这三个函数分别对应 8bit、16bit 和 32bit 读操作,参数 addr 就是要读取写内存地址,返回值就是读取到的数据。
2 、写操作函数
写操作函数有如下几个:
1 void writeb(u8 value, volatile void __iomem *addr)
2 void writew(u16 value, volatile void __iomem *addr)
3 void writel(u32 value, volatile void __iomem *addr)
writeb、writew 和 writel 这三个函数分别对应 8bit、16bit 和 32bit 写操作,参数 value 是要写入的数值,addr 是要写入的地址。

例如:

#define GPIO1_DR_BASE (0X0209C000)

static void __iomem * GPIO1_DR ;

32 val = 0;

GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);

val = readl(GPIO1_DR);
val &= ~(1 << 3);
writel(val, GPIO1_DR);

这段话的含义是将GPIO1_DR_BASE 寄存器的物理地址映射到GPIO1_DR虚拟地址。

通过虚拟地址读取GPIO1_DR_BASE寄存器的值(readl)。

通过虚拟地址向GPIO1_DR_BASE寄存器赋值(writel)

问题四:如何编写完整的LED驱动?

LED需要准备工作:

1.LED初始化(打开时钟,设置IO复用,设置IO为输出模式,设置上下拉和速度)

2.LED操作,使其输出高电平或低电平。

结合字符设备驱动模型,我们应该能够想到将LED初始化放在字符设备加载函数中

将LED操作放在设备操作集中(write响应函数)

问题五:剩余工作?

重要事情说三遍!!!

既然我们使用了虚拟内存就应该再不用的时候释放掉。因此在驱动卸载函数中要做寻你内存的释放!!!

既然我们使用了虚拟内存就应该再不用的时候释放掉。因此在驱动卸载函数中要做寻你内存的释放!!!

既然我们使用了虚拟内存就应该再不用的时候释放掉。因此在驱动卸载函数中要做寻你内存的释放!!!

总结:

1.linux下一般使用虚拟地址来访问物理地址。

2.linux一般不直接对地址操作,而是使用读写函数。

3.驱动卸载的时候记得把申请的虚拟内存释放掉。

4.结合字符设备驱动模型吧LED初始化和LED操作函数插入到相应位置

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值