writeb、 writew 和 writel 这三个函数分别对应 8bit、 16bit 和 32bit 写操作,参数 value 是要写入的数值,addr 是要写入的地址 。
readb、 readw 和 readl 这三个函数分别对应 8bit、 16bit 和 32bit 读操作,参数 addr 就是要读取写内存地址,返回值就是读取到的数据 。
此时我们可以把上一节的led_init函数led_drv_write函数进行修改:
文章插图
文章插图
与STM32一样,对于i.MX 6ULL的GPIO外设来说,也有很多寄存器:
文章插图
上面我们只是点一个灯,如果是要点多个灯呢?那就得操控多个GPIO 。如果进行地址映射的写法还像上面那样,代码就会显得很臃肿 。回想一下我们STM32,GPIO外设通过结构体来管理它的寄存器:
文章插图
这里的__IO是个宏,代表C语言的关键字volatile ,为了防止编译器对我们的一些硬件操作进行优化,从而得不到想要的结果 。比如:
/* 假设REG为寄存器的地址 */uint32 *REG;*REG = 0; /* 点灯 */*REG = 1; /* 灭灯 */
此时若是REG不加volatile进行修饰,则点灯操作将被优化掉,只执行灭灯操作 。在这里,我们也可以模仿STM32那样子,用一个结构体来对i.MX 6ULL的GPIO的寄存器进行管理,如:
struct GPIO_RegDef{ volatile unsigned int DR; volatile unsigned int GDIR; volatile unsigned int PSR; volatile unsigned int ICR1; volatile unsigned int ICR2; volatile unsigned int IMR; volatile unsigned int ISR; volatile unsigned int EDGE_SEL;};
结构体里的成员排序是要按照特定顺序来的:文章插图
因为这些寄存器都是相对于GPIO外设的基地址作偏移得到的,比如:
文章插图
不能打乱顺序,否则就不能正确访问到对应的寄存器了 。用结构体进行管理之后,我们就可以用类似下面的方式进行映射:
【Linux驱动基础篇:LED驱动】
struct GPIO_RegDef *GPIO5 = ioremap(0x20AC000, sizeof(struct GPIO_RegDef));
然后就可以向STM32那样来操控GPIO寄存器,如:GPIO5->DR &= ~(1 << 3);/* GPIO5_IO03输出低电平 */GPIO5->DR |= (1 << 3);/* GPIO5_IO03输出高电平 */
与硬件有关的LED驱动(升级版)上一节我们分享的LED驱动是一个常规的LED驱动,只能适用于我们当前的开发版,所以是一个专用的LED驱动程序 。若是换了另一块板,led所连接的gpio引脚可能不一样了,我们就修改我们的驱动程序led_drv.c里与寄存器相关的操作 。有没有更好的办法不用再修改我们的led_drv.c驱动程序了?若是led_drv.c不用再修改了,那么这个led_drv.c驱动就是一个通用的驱动程序了 。具体可查看韦东山老师的《嵌入式Linux应用开发完全手册第2版》第五篇第3~7节进行学习 。
下面来简单地梳理一下:
文章插图
由于篇幅问题,具体的部分就不贴出来了 。
之前的笔记中:C语言、嵌入式重点知识:回调函数 中我也有提到通用与专用的含义,可以了解了解加深对这两个词的认识 。
这里我们学到了很重要的思想软件分层的思想及技巧,但也只是点了一下,未来的路还很长,需要持续学习,继续提高 。
以上就是本次的分享,如有错误,欢迎指出!谢谢
参考/学习资料:
- 百问网《嵌入式Linux应用开发完全手册第2版》
- 正点原子《I.MX6U嵌入式Linux驱动开发指南V1.2》
- 野火《i.MX Linux开发实战指南》
推荐阅读
- 你知道Linux中用户们的密码藏在哪儿吗?
- Linux文件系统EXT2,EXT3,ReiserFS详解
- 安装 Linux,只需三步
- linux中tar命令的用法
- linux中tar命令实测
- 零基础学太极 如何快速掌握动作要领
- Bash 脚本实现每次登录到 Shell 时可以查看 Linux 系统信息
- 都Linux的老司机了,连个echo都用不好,大概火候差在这
- 快速上手几个 Linux 命令:每家公司都有自己的黑话
- Web渗透测试——密码学基础