嵌入式Linux应用开发-第七章-IMX6ULL-QEMU的LED驱动程序

news2025/1/10 21:29:00

嵌入式Linux应用开发-第七章-IMX6ULL-QEMU的LED驱动程序

  • IMX6ULL-QEMU的 LED驱动程序
    • 7.5 IMX6ULL-QEMU的 LED驱动程序
      • 7.5.1 看原理图确定引脚及操作方法
      • 7.5.2 所涉及的寄存器操作
      • 7.5.3 写程序
      • 7.5.4 上机实验
      • 7.5.5 课后作业

IMX6ULL-QEMU的 LED驱动程序

在这里插入图片描述

7.5 IMX6ULL-QEMU的 LED驱动程序

使用 QEMU模拟的硬件,它的硬件资源可以随意扩展。 在 IMX6ULL QEMU 虚拟开发板上,我们为它设计了 4个 LED。

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

在这里插入图片描述
从上图可知,这 4个 LED 用到了 GPIO5_3、GPIO1_3、GPIO1_5、GPIO1_6 共 4个引脚。 在芯片手册里,这些引脚的名字是:GPIO5_IO03、GPIO1_IO03、GPIO1_IO05、GPIO1_IO06。可以根据名字搜到对应的寄存器。 当这些引脚输出低电平时,对应的 LED被点亮;输出高电平时,LED熄灭。

7.5.2 所涉及的寄存器操作

在这里插入图片描述
步骤 1:
使能 GPIO1、GPIO5
在这里插入图片描述
设置 b[31:30]、b[27:26]就可以使能 GPIO5、GPIO1,设置为什么值呢?
注意:在 imx6ullrm.pdf中,CCM_CCGR1的 b[31:30]是保留位;我以前写程序时错用了 imx6ul(不是imx6ull)的手册,导致程序中额外操作了这些保留位。不去设置 b[31:30],GPIO5也是默认使能的。 看下图,设置为 0b11:
在这里插入图片描述
① 00:该 GPIO模块全程被关闭
② 01:该 GPIO模块在 CPU run mode情况下是使能的;在 WAIT或 STOP模式下,关闭
③ 10:保留
④ 11:该 GPIO模块全程使能

步骤 2:
设置 GPIO5_IO03、GPIO1_IO03、GPIO1_IO05、GPIO1_IO06为 GPIO模式
① 对于 GPIO5_IO03,设置如下寄存器:
在这里插入图片描述
② 对于 GPIO1_IO03,设置如下寄存器:
在这里插入图片描述

③ 对于 GPIO1_IO05,设置如下寄存器:
在这里插入图片描述
④ 对于 GPIO1_IO06,设置如下寄存器:
在这里插入图片描述

步骤 3:
设置 GPIO5_IO03、GPIO1_IO03、GPIO1_IO05、GPIO1_IO06为输出引脚,设置其输出电平 寄存器地址为:
在这里插入图片描述

设置方向寄存器,把引脚设置为输出引脚:
在这里插入图片描述
设置数据寄存器,设置引脚的输出电平:
在这里插入图片描述

7.5.3 写程序

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

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\02_led_drv\       
02_led_drv_for_boards\xxxxxx_imx6ull-qemu_src_bin 

硬件相关的文件是 board_xxxxxx_imx6ull-qemu.c,其他文件跟 LED框架驱动程序完全一样。
涉及的寄存器挺多,一个一个去执行 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; 

}; 
struct iomux  *iomux = ioremap(0x20e0000,  sizeof(struct iomux)); 

对于 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 *gpio1 = ioremap(0x209C000,  sizeof(struct imx6ull_gpio)); 
struct imx6ull_gpio *gpio5 = ioremap(0x20AC000,  sizeof(struct imx6ull_gpio)); 

开始详细分析 board_xxxxxx_imx6ull-qemu.c。 它首先构造了一个 led_operations结构体,用来表示 LED的硬件操作:

176 static struct led_operations board_demo_led_opr = { 
177     .num  = 4, 
178     .init = board_demo_led_init, 
179     .ctl  = board_demo_led_ctl, 
180 }; 
181 

led_operations结构体中有 init函数指针,它指向 board_demo_led_init函数,在里面将会初始化LED引脚:使能、设置为 GPIO模式、设置为输出引脚。
值得关注的是第 61~66行,对于寄存器要先使用 ioremap得到它的虚拟地址,以后使用虚拟地址访问寄存器:

57 static int board_demo_led_init (int which) /* 初始化 LED, which-哪个 LED */ 
58 { 
59     if (!CCM_CCGR1) 
60     { 
61         CCM_CCGR1 = ioremap(0x20C406C, 4); 
62         IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x2290014, 4); 
63 
64         iomux = ioremap(0x20e0000, sizeof(struct iomux)); 
65         gpio1 = ioremap(0x209C000, sizeof(struct imx6ull_gpio)); 
66         gpio5 = ioremap(0x20AC000, sizeof(struct imx6ull_gpio)); 
67     } 
68 
69     if (which == 0) 
70     { 
71         /* 1. enable GPIO5 
72          * CG15, b[31:30] = 0b11 
73          */ 
74         *CCM_CCGR1 |= (3<<30); 
75 
76         /* 2. set GPIO5_IO03 as GPIO 
77          * MUX_MODE, b[3:0] = 0b101 
78          */ 
79         *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = 5; 
80 
81         /* 3. set GPIO5_IO03 as output 
82          * GPIO5 GDIR, b[3] = 0b1 
83          */ 
84         gpio5->gdir |= (1<<3); 
85     } 
86     else if(which == 1) 
87     { 
88         /* 1. enable GPIO1 
89          * CG13, b[27:26] = 0b11 
90          */ 
91         *CCM_CCGR1 |= (3<<26); 
92 
93         /* 2. set GPIO1_IO03 as GPIO 
94          * MUX_MODE, b[3:0] = 0b101 
95          */ 
96         iomux->IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 5; 
97 
98         /* 3. set GPIO1_IO03 as output 
99          * GPIO1 GDIR, b[3] = 0b1 
100          */ 
101         gpio1->gdir |= (1<<3); 
102     } 
103     else if(which == 2) 
104     { 
105         /* 1. enable GPIO1 
106          * CG13, b[27:26] = 0b11 
107          */ 
108         *CCM_CCGR1 |= (3<<26); 
109 
110         /* 2. set GPIO1_IO05 as GPIO 
111          * MUX_MODE, b[3:0] = 0b101 
112          */ 
113         iomux->IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO05 = 5; 
114 
115         /* 3. set GPIO1_IO05 as output 
116          * GPIO1 GDIR, b[5] = 0b1 
117          */ 
118         gpio1->gdir |= (1<<5); 
119     } 
120     else if(which == 3) 
121     { 
122         /* 1. enable GPIO1 
123          * CG13, b[27:26] = 0b11 
124          */ 
125         *CCM_CCGR1 |= (3<<26); 
126 
127         /* 2. set GPIO1_IO06 as GPIO 
128          * MUX_MODE, b[3:0] = 0b101 
129          */ 
130         iomux->IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06 = 5; 
131 
132         /* 3. set GPIO1_IO06 as output 
133          * GPIO1 GDIR, b[6] = 0b1 
134          */ 
135         gpio1->gdir |= (1<<6); 
136     } 
137 
138     //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which); 
139     return 0; 
140 } 
141 

led_operations结构体中有 ctl函数指针,它指向 board_demo_led_ctl函数,在里面将会根据参数设置 LED引脚的输出电平:
142 static int board_demo_led_ctl (int which, char status) /* 控制 LED, which-哪个 LED, status:1-亮,0-灭 */

143 { 
144     //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off"); 
145     if (which == 0) 
146     { 
147         if (status)  /* on : output 0 */ 
148             gpio5->dr &= ~(1<<3); 
149         else         /* on : output 1 */ 
150             gpio5->dr |= (1<<3); 
151     } 
152     else if (which == 1) 
153     { 
154         if (status)  /* on : output 0 */ 
155             gpio1->dr &= ~(1<<3); 
156         else         /* on : output 1 */ 
157             gpio1->dr |= (1<<3); 
158     } 
159     else if (which == 2) 
160     { 
161         if (status)  /* on : output 0 */ 
162             gpio1->dr &= ~(1<<5); 
163         else         /* on : output 1 */ 
164             gpio1->dr |= (1<<5); 
165     } 
166     else if (which == 3) 
167     { 
168         if (status)  /* on : output 0 */ 
169             gpio1->dr &= ~(1<<6); 
170         else         /* on : output 1 */ 
171             gpio1->dr |= (1<<6); 
172     } 
173     return 0; 
174 } 
175 

下面的 get_board_led_opr函数供上层调用,给上层提供 led_operations结构体:

182 struct led_operations *get_board_led_opr(void) 
183 { 
184     return &board_demo_led_opr; 
185 } 
186 

7.5.4 上机实验

先启动 IMX6ULL QEMU模拟器,挂载 NFS文件系统。
运行 QEMU时, QEMU内部为主机虚拟出一个网卡, IP为 10.0.2.2, IMX6ULL有一个网卡, IP为 10.0.2.15, 它连接到主机的虚拟网卡。 这样 IMX6ULL就可以通过 10.0.2.2去访问 Ubuntu了。

然后执行以下命令安装驱动、执行测试程序:

# insmod  xxxxxx_led.ko 
# ./ledtest  /dev/xxxxxx_led0  on 
# ./ledtest  /dev/xxxxxx_led0  off 

7.5.5 课后作业

a. 在驱动里有 ioremap,什么时候执行 iounmap?请完善程序
b. 驱动程序中有太多的 if判断,请优化程序减少 if的使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1049567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

简化任务调度与管理:详解XXL-Job及Docker Compose安装

在现代应用程序开发中&#xff0c;任务调度和管理是至关重要的一部分。XXL-Job是一个强大的分布式任务调度平台&#xff0c;它使得任务的调度和管理变得更加轻松和高效。本文将介绍XXL-Job的基本概念&#xff0c;并详细演示如何使用Docker Compose进行快速安装和配置。 什么是X…

【大模型和智能问答系统】

大模型和智能问答系统 大模型前的智能问答系统传统管道式架构存在的问题 大模型前的智能问答系统 大模型统一代指以ChatGPT为代表的&#xff0c;参数量相比以前模型有明显量级变化的生成模型。 智能问答系统&#xff0c;按照应用可以划分*任务型 *和 非任务型。 任务型问答系…

Java集成Onlyoffice以及安装和使用示例,轻松实现word、ppt、excel在线编辑功能协同操作,Docker安装Onlyoffice

安装Onlyoffice 拉取onlyoffice镜像 docker pull onlyoffice/documentserver 查看镜像是否下载完成 docker images 启动onlyoffice 以下是将本机的9001端口映射到docker的80端口上&#xff0c;访问时通过服务器ip&#xff1a;9001访问&#xff0c;并且用 -v 将本机机/data/a…

容器启动报错

容器启动报错 docker: Error response from daemon: driver failed programming external connectivity on endpoint XXX 如下&#xff1a; 据百度&#xff1a; 在docker启动后在&#xff0c;再对防火墙firewalld进行操作&#xff0c;就会发生上述报错 详细原因&#xff1a…

flutter 【iOS】App Store介绍页中显示的语言列表如何设置

【iOS】App Store介绍页中显示的语言列表如何设置 iOS实现语言本地化

git新建仓库上传项目步骤

1、git init 2、git add . 3、git commit -m "first commit" 4、git remote add origin https://gitee.com... 5、git push origin master --force 为方式踩坑&#xff0c;浪费不必要的时间&#xff0c;以上步骤必须依次执行

京东大型API网关实践之路

概述 1、背景 京东作为电商平台&#xff0c;近几年用户、业务持续增长&#xff0c;访问量持续上升&#xff0c;随着这些业务的发展&#xff0c;API网关应运而生。 API网关&#xff0c;就是为了解放客户端与服务端而存在的。对于客户端&#xff0c;使开放给客户端的接口标准统…

时间复杂度、空间复杂度 O(1)和 O(logN)

时间复杂度&#xff08;time complexity&#xff09;&#xff1a;估算程序指令的执行次数&#xff08;执行时间&#xff09; 空间复杂度&#xff08;space complexity&#xff09;&#xff1a;估算所需占用的存储空间 public static void test1(int n) {// 确定的执行次数if …

AI创作系统ChatGPT商业运营版源码+AI绘画/支持GPT联网提问/支持Midjourney绘画+Prompt应用+支持国内AI提问模型

一、AI创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&am…

nodejs+vue装修公司CRM系统设计elementui

第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;技术背景 5 3.2.2经济可行性 6 3.2.3操作可行性&#xff1a; 6 3.3 项目设计目标与原则 6 3.4系统流程分析 7 3.4.1操作流程 7 3.4.2添加信息流程 8 3.4.3删除信息流程 9 第4章 系统设计 11 …

MonkeyRunner测试步骤

首先把安卓SDK的 环境变量给配置好&#xff0c;这里就不再多解释&#xff0c;自己google 然后将自己的安卓设备打开调试模式&#xff0c;USB连接至电脑&#xff0c;运行CMD,输入命令adb devices 查看你的安卓设备的ID&#xff08;ID后面写程序会调用&#xff09;&#xff0c;…

Cortex-A9 架构

一、Cortex-A 处理器运行模式 Cortex-A9处理器有 9中处理模式&#xff0c;如下表所示&#xff1a; 九种运行模式 在上表中&#xff0c;除了User(USR)用户模式以外&#xff0c;其它8种运行模式都是特权模式&#xff0c;在特权模式下&#xff0c;程序可以访问所有的系统资源。这…

目标检测:FROD: Robust Object Detection for Free

论文作者&#xff1a;Muhammad,Awais,Weiming,Zhuang,Lingjuan,Lyu,Sung-Ho,Bae 作者单位&#xff1a;Sony AI; Kyung-Hee University 论文链接&#xff1a;http://arxiv.org/abs/2308.01888v1 内容简介&#xff1a; 1&#xff09;方向&#xff1a;目标检测 2&#xff09;…

探索性测试最佳实践

探索性测试是一种软件测试风格&#xff0c;而不是一种具体的软件测试技术。探索性测试强调依据当前待测项目实际情况&#xff0c;选择合适的测试技术&#xff0c;而不局限于特定的测试技术。 测试人员探索软件、并尝试不同的场景、输入和交互&#xff0c;而不使用预先编写的测试…

【算法分析与设计】动态规划(上)

目录 一、学习要点二、算法总体思想三、动态规划基本步骤四、矩阵连乘问题4.1 完全加括号的矩阵连乘积4.2 穷举法4.3 动态规划4.3.1 分析最优解的结构4.3.2 建立递归关系4.3.3 计算最优值4.3.4 用动态规划法求最优解 五、动态规划算法的基本要素5.1 最优子结构5.2 重叠子问题5.…

AI项目十一:Swin Transformer训练

若该文为原创文章&#xff0c;转载请注明原文出处。 续上一篇&#xff0c;训练自己的数据集&#xff0c;并测试。 一、安装标注软件labelme # 安装labelme pip install labelme # 启动 labelme 这里数据集准本&#xff0c;标注图片数据过程自己探索。 最后文件结构如下&…

0x2C动态定义数据标识符服务

其实就是临时在指定地址创建个信息DID&#xff0c;里面可以存写临时数据&#xff0c;到时候可以给自己读写&#xff0c;但是这东西一重启或者过段时间就没了。要用0x22服务去读取&#xff0c;0x2A来写&#xff0c;不能用0x2E来写&#xff0c;协议认为0x2E不能指定地址来写。 这…

C++之容器类有趣的实验(二百四十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

处理conda安装工具的动态库问题——解决记录 libssl.1.0.0 系统中所有openssl位置全览 whereis openssl

处理conda安装工具的动态库问题——解决记录 处理conda安装工具的动态库问题——解决记录 - 简书 解决libssl.so.1.0.0: cannot open shared object file: No such file or directory问题 - 简书 openssl 默认版本问题&#xff08;Anaconda相关&#xff09;_anaconda openssl-…

Pikachu-xxe (xml外部实体注入漏洞)过关笔记

Pikachu-xxe过关笔记 有回显探测是否有回显file:///协议查看本地系统文件php://协议查看php源代码&#xff08;无法查看当前网页代码&#xff0c;只能看别的&#xff09;http://协议爆破开放端口&#xff08;两者的加载时间不同&#xff09; 无回显第一步第二步第三步 运行结果…