嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十五)具体单板的按键驱动程序(查询方式)

简介: 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十五)具体单板的按键驱动程序(查询方式)

1.具体单板的按键驱动程序(查询方式)


1.1 GPIO操作回顾


参考章节《第四章 普适的GPIO引脚操作方法》、《第五章 具体单板的GPIO操作方法》。

1670920973286.jpg


1.2 百问网IMX6ULL的按键驱动程序(查询方式)


1.2.1 先看原理图确定引脚及操作方法


1670921013091.jpg

平时按键电平为高,按下按键后电平为低。 按键引脚为GPIO5_IO01、GPIO4_IO14。

注意:视频里使用QEMU来做实验,QEMU里的按键平时为低电平,按下后为高电平,跟实际开发板刚好相反。


1.2.2 再看芯片手册确定寄存器及操作方法


1670921070333.jpg

步骤1:使能GPIO5

1670921078757.jpg

步骤二:使能GPIO4

1670921086935.jpg

1670921093188.jpg

设置CCM_CCGR1 b[31:30]、CCM_CCGR3 b[13:12]就可以使能GPIO5、GPIO4,设置为什么值呢?

注意:在imx6ullrm.pdf中,CCM_CCGR1的b[31:30]是保留位;我以前写程序时错用了imx6ul(不是imx6ull)的手册,导致程序中额外操作了这些保留位。不去设置b[31:30],GPIO5也是默认使能的。


看下图,设置为0b11:

1670921101414.jpg

① 00:该GPIO模块全程被关闭

② 01:该GPIO模块在CPU run mode情况下是使能的;在WAIT或STOP模式下,关闭

③10:保留

④ 11:该GPIO模块全程使能


步骤3:设置GPIO5_IO01、GPIO4_IO18为GPIO模式

① 对于GPIO5_IO01,设置如下寄存器:

1670921110381.jpg

② 对于GPIO4_IO14,设置如下寄存器:

1670921122421.jpg

步骤4:设置GPIO5_IO01、GPIO4_IO14为输入引脚,读取引脚电平


寄存器地址为:

1670921130777.jpg

1670921139729.jpg

设置方向寄存器,把引脚设置为输出引脚:

1670921147964.jpg

读取引脚状态寄存器,得到引脚电平:

1670921156462.jpg


1.2.3 编程


1.2.3.1 程序框架


使用GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart\
05_嵌入式Linux驱动开发基础知识\source\
04_button_drv\02_button_drv_for_boards\05_button_drv_for_100ask_imx6ull

1670921186034.jpg


1.2.3.2 硬件相关的代码


主要看board_100ask_imx6ull.c。


涉及的寄存器挺多,一个一个去执行ioremap效率太低。 先定义结构体,然后对结构体指针进行ioremap。

对于IOMUXC,可以如下定义:

struct iomux {
  volatile unsigned int unnames[23];
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO01;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO02;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO05;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO08;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA;
  volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B;
};


对于GPIO,可以如下定义:

struct imx6ull_gpio {
  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;
};
struct imx6ull_gpio gpio4 = ioremap(0x020A8000, sizeof(struct imx6ull_gpio));
struct imx6ull_gpio gpio5 = ioremap(0x20AC000, sizeof(struct imx6ull_gpio));


看一个驱动程序,先看它的入口函数,代码如下。

第127行向上层驱动注册一个button_operations结构体,该结构体在第119~123行定义。

119 static struct button_operations my_buttons_ops = {
120     .count = 2,
121     .init = board_imx6ull_button_init,
122     .read = board_imx6ull_button_read,
123 };
124
125 int board_imx6ull_button_drv_init(void)
126 {
127     register_button_operations(&my_buttons_ops);
128     return 0;
129 }


button_operations结构体中有init函数指针,它指向board_imx6ull_button_init函数,在里面将会初始化LED引脚:使能、设置为GPIO模式、设置为输出引脚。代码如下。

值得关注的是第71~78行,对于寄存器要先使用ioremap得到它的虚拟地址,以后使用虚拟地址访问寄存器。

50 /* enable GPIO4 */
 51 static volatile unsigned int *CCM_CCGR3;
 52
 53 /* enable GPIO5 */
 54 static volatile unsigned int *CCM_CCGR1;
 55
 56 /* set GPIO5_IO03 as GPIO */
 57 static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1;
 58
 59 /* set GPIO4_IO14 as GPIO */
 60 static volatile unsigned int *IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B;
 61
 62 static struct iomux *iomux;
 63
 64 static struct imx6ull_gpio *gpio4;
 65 static struct imx6ull_gpio *gpio5;
 66
 67 static void board_imx6ull_button_init (int which) /* 初始化button, which-哪个button */
 68 {
 69     if (!CCM_CCGR1)
 70     {
 71         CCM_CCGR1 = ioremap(0x20C406C, 4);
 72         CCM_CCGR3 = ioremap(0x20C4074, 4);
 73         IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1 = ioremap(0x229000C, 4);
 74                 IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B        = ioremap(0x20E01B0, 4);
 75
 76         iomux = ioremap(0x20e0000, sizeof(struct iomux));
 77         gpio4 = ioremap(0x020A8000, sizeof(struct imx6ull_gpio));
 78         gpio5 = ioremap(0x20AC000, sizeof(struct imx6ull_gpio));
 79     }
 80
 81     if (which == 0)
 82     {
 83         /* 1. enable GPIO5
 84          * CG15, b[31:30] = 0b11
 85          */
 86         *CCM_CCGR1 |= (3<<30);
 87
 88         /* 2. set GPIO5_IO01 as GPIO
 89          * MUX_MODE, b[3:0] = 0b101
 90          */
 91         *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1 = 5;
 92
 93         /* 3. set GPIO5_IO01 as input
 94          * GPIO5 GDIR, b[1] = 0b0
 95          */
 96         gpio5->gdir &= ~(1<<1);
 97     }
98     else if(which == 1)
 99     {
100         /* 1. enable GPIO4
101          * CG6, b[13:12] = 0b11
102          */
103         *CCM_CCGR3 |= (3<<12);
104
105         /* 2. set GPIO4_IO14 as GPIO
106          * MUX_MODE, b[3:0] = 0b101
107          */
108         IOMUXC_SW_MUX_CTL_PAD_NAND_CE1_B = 5;
109
110         /* 3. set GPIO4_IO14 as input
111          * GPIO4 GDIR, b[14] = 0b0
112          */
113         gpio4->gdir &= ~(1<<14);
114     }
115
116 }


button_operations结构体中还有有read函数指针,它指向board_imx6ull_button_read函数,在里面将会读取并返回按键引脚的电平。代码如下。

118 static int board_imx6ull_button_read (int which) /* 读button, which-哪个 */
119 {
120     //printk("%s %s line %d, button %d, 0x%x\n", __FILE__, __FUNCTION__, __LINE__, which, *GPIO1_DATAIN);
121     if (which == 0)
122         return (gpio5->psr & (1<<1)) ? 1 : 0;
123     else
124         return (gpio4->psr & (1<<14)) ? 1 : 0;
125 }
126


1.2.4 测试


先启动IMX6ULL挂载NFS文件系统。 安装驱动程序之后执行测试程序,观察它的返回值(执行测试程序的同时操作按键):

# insmod button_drv.ko
# insmod board_drv.ko
# insmod board_100ask_imx6ull.ko
# ./button_test  /dev/100ask_button0
# ./button_test  /dev/100ask_button1


1.2.5 课后作业


① 修改button_test.c,使用按键来点灯

相关文章
|
17天前
|
缓存 JavaScript IDE
鸿蒙开发:基于最新API,如何实现组件化运行
手动只是让大家了解切换的原理,在实际开发中,可不推荐手动,下篇文章,我们将通过脚本或者插件,快速实现组件化模块之间的切换,实现独立运行,敬请期待!
鸿蒙开发:基于最新API,如何实现组件化运行
|
23天前
|
开发者
鸿蒙开发:资讯项目实战之项目初始化搭建
目前来说,我们的资讯项目只是往前迈了很小的一步,仅仅实现了项目创建,步虽小,但概念性的知识很多,这也是这个项目的初衷,让大家不仅仅可以掌握日常的技术开发,也能让大家理解实际的项目开发知识。
鸿蒙开发:资讯项目实战之项目初始化搭建
|
23天前
|
存储 C++ UED
鸿蒙5开发宝藏案例分享---优化应用包体积大小问题
本文分享了鸿蒙应用包体积优化的实用技巧,包括SO库压缩、HSP动态共享包、OHPM依赖冲突解决、按需加载和扫描工具定位优化点等方法。通过具体配置示例和实战经验,如启用`compressNativeLibs`、使用共享资源包、强制统一依赖版本以及动态导入功能模块,帮助开发者显著减少包体积,提升用户体验。文中还提供了图标优化、资源混淆和无用代码剔除等补充建议,助力打造更轻量的鸿蒙应用。
|
23天前
|
SQL 弹性计算 数据库
鸿蒙5开发宝藏案例分享---优化应用时延问题
鸿蒙性能优化指南来了!从UI渲染到数据库操作,6大实战案例助你提升应用流畅度。布局层级优化、数据加载并发、数据库查询提速、相机资源延迟释放、手势识别灵敏调整及转场动画精调,全面覆盖性能痛点。附赠性能自检清单,帮助开发者高效定位问题,让应用运行如飞!来自华为官方文档的精华内容,建议收藏并反复研读,共同探讨更多优化技巧。
|
23天前
|
缓存
鸿蒙5开发宝藏案例分享---Swiper组件性能优化实战
本文分享了鸿蒙系统中Swiper组件的性能优化技巧,包括:1) 使用`LazyForEach`替代`ForEach`实现懒加载,显著降低内存占用;2) 通过`cachedCount`精准控制缓存数量,平衡流畅度与内存消耗;3) 利用`onAnimationStart`在抛滑时提前加载资源,提升构建效率;4) 添加`@Reusable`装饰器复用组件实例,减少创建开销。实际应用后,图库页帧率从45fps提升至58fps,效果显著。适合处理复杂列表或轮播场景,欢迎交流经验!
|
18天前
|
Linux
Linux命令拓展:为cp和mv添加进度显示
好了,就这样,让你的Linux复制体验充满乐趣吧!记住,每一个冷冰冰的命令背后,都有方法让它变得热情起来。
58 8
|
23天前
|
安全 Linux 定位技术
Linux环境下必备的基础命令概览
以上就是Linux系统中的基本命令和工具,掌握它们就能帮你在Linux世界里游刃有余。这其实就像是学习驾驭一辆新车,熟悉了仪表盘,调整好了座椅,之后的旅程就只需要享受风驰电掣的乐趣了。
42 4
|
24天前
|
JSON 自然语言处理 Linux
linux命令—tree
tree是一款强大的Linux命令行工具,用于以树状结构递归展示目录和文件,直观呈现层级关系。支持多种功能,如过滤、排序、权限显示及格式化输出等。安装方法因系统而异常用场景包括:基础用法(显示当前或指定目录结构)、核心参数应用(如层级控制-L、隐藏文件显示-a、完整路径输出-f)以及进阶操作(如磁盘空间分析--du、结合grep过滤内容、生成JSON格式列表-J等)。此外,还可生成网站目录结构图并导出为HTML文件。注意事项:使用Tab键补全路径避免错误;超大目录建议限制遍历层数;脚本中推荐禁用统计信息以优化性能。更多详情可查阅手册mantree。
linux命令—tree
|
Linux 索引
linux命令—ls
`ls` 是 Linux 系统中用于列出目录内容的基础命令,功能强大且使用频率极高。它可以帮助用户查看文件、分析磁盘空间及检查权限等。常用选项如 `-l` 显示详细信息,`-a` 包含隐藏文件,`-h` 以易读格式展示大小,`-t` 按修改时间排序等。通过组合选项,可实现复杂需求,如递归遍历目录(`-R`)、显示 inode 号(`-i`)或结合正则过滤特定文件。注意权限限制、特殊字符处理及大规模目录操作可能带来的性能问题。掌握 `ls` 是高效使用 Linux 的关键一步。
|
27天前
|
Unix Linux
linux命令—cd
`cd` 命令是 Linux/Unix 系统中用于切换工作目录的基础命令。支持相对路径与绝对路径,常用选项如 `-L` 和 `-P` 分别处理符号链接的逻辑与物理路径。实际操作中,可通过 `cd ..` 返回上级目录、`cd ~` 回到家目录,或利用 `cd -` 在最近两个目录间快速切换。结合 Tab 补全和 `pwd` 查看当前路径,能显著提升效率。此外,需注意特殊字符路径的正确引用及脚本中绝对路径的优先使用。