Linux驱动开发基础(LED驱动)

news2024/11/14 18:33:18

所学来自百问网

目录

1. LED原理

2. 普适的GPIO引脚操作方法

2.1 GPIO模块的一般结构

2.2 GPIO框图

2.3 寄存器的操作

2.3.1 一般的操作方式

2.3.2 高效的操作方式

3. 基于IMX6UL_6ULL的GPIO操作方法

3.1 GPIO框图

3.2 CCM

3.3 IOMUXC

3.4 GPIO模块内部

3.5 读写GPIO

4. LED驱动程序框架

5. 基于IMX6UL_6ULL的LED操作方法

6. 基于IMX6UL_6ULL的LED驱动程序

6.1 驱动代码

6.2 应用代码

6.3 Makefile

6.4 效果


1. LED原理

LED 样子有很多种,像插脚的,贴片的。

点亮LED需要通电源,同时为了保护LED,加个电阻减小电流。

控制LED灯的亮灭,可以手动开关LED,但在电子系统中,不可能让人来控制开关,通过编程,利用芯片的引脚去控制开关。

LED 的驱动方式,常见的有四种。

1.使用引脚输出3.3V点亮LED,输出0V熄灭LED。

2.使用引脚拉低到0V点亮LED,输出3.3V熄灭LED。

有的芯片为了省电等原因,其引脚驱动能力不足,这时可以使用三极管驱动。

3.使用引脚输出1.2V点亮LED,输出0V熄灭LED。

4.使用引脚输出0V点亮LED,输出1.2V熄灭LED。

由此,主芯片引脚输出高电平/低电平,即可改变LED状态,而无需关注GPIO 引脚输出的是3.3V还是1.2V。所以简称输出1或0:

  • 逻辑1-->高电平

  • 逻辑0-->低电平

2. 普适的GPIO引脚操作方法

GPIO: General-purpose input/output,通用的输入输出口

2.1 GPIO模块的一般结构

有多组GPIO,每组有多个GPIO

使能:电源/时钟

模式(Mode):引脚可用于GPIO或其他功能(引脚复用)

方向:引脚Mode设置为GPIO时,可以继续设置它是输出引脚,还是输入引脚

数值:

◼ 对于输出引脚,可以设置寄存器让它输出高、低电平

◼ 对于输入引脚,可以读取寄存器得到引脚的当前电平

2.2 GPIO框图

图解:

主芯片存在多种GPIO(0~N),每组GPIO有多个GPIO引脚(0~m)

若想让引脚输出高/低电平,操作步骤如下:

1.使能模块:通过Power/Clock control去给GPIO模块提供电源或时钟

2.引脚模式选择:通过多路选择器(IO_MUX)获取数据,数据可能来自GPIO模块也可能来自串口(UART)模块

3.引脚方向:输入模式还是输出模式

4.输出电平:

  • 输出模式:设置寄存器

  • 输入模式:读取寄存器

2.3 寄存器的操作

2.3.1 一般的操作方式

由上图可知,设置电平模式需要操作寄存器

以数据寄存器为例:

图解:

bit0 ~ bitM为寄存器的位,gpio0_0 ~ gpio0_m为引脚

设置引脚的电平的操作步骤:

1.读取寄存器的值 val = data_reg

2.修改所要设置引脚的电平的位,此处修改bit0 val = val | 0x01

3.将修改后的值写入寄存器 data_reg = val

注意:操作寄存器的原则,不能影响其他位的值

2.3.2 高效的操作方式

此方式取决于芯片中是否有设置寄存器和清零寄存器

设置寄存器和清零寄存器配合使用,直接修改寄存器的位的值,对其他寄存器的位不影响

设置寄存器的操作方式:

赋值1则设置为1,0则不受影响

修改bit0,只需直接让set_reg = 1即可

修改bit0和bit2,让set_reg = 1 | (1 << 2)即可

清零寄存器的操作方法:

赋值1则设置为0,0则不受影响

修改bit0,让clk_reg = 1即可让bit0设置为0

修改bit0和bit2,让clk_reg = 1 | (1 << 2)即可让bit0和bit2为0

3. 基于IMX6UL_6ULL的GPIO操作方法

3.1 GPIO框图

图解:

名词解释
CCMClock Controller Module (时钟控制模块)
IOMUXCIOMUX Controller,IO 复用控制器
GPIOGeneral-purpose input/output,通用的输入输出口

IMX6UL_6ULL有五组GPIO,每组引脚数分别如下:

  • GPIO1有32个引脚:GPIO1_IO0~GPIO1_IO31;

  • GPIO2有22个引脚:GPIO2_IO0~GPIO2_IO21;

  • GPIO3有29个引脚:GPIO3_IO0~GPIO3_IO28;

  • GPIO4有29个引脚:GPIO4_IO0~GPIO4_IO28;

  • GPIO5有12个引脚:GPIO5_IO0~GPIO5_IO11;

3.2 CCM

作用:用于设置是否向GPIO模块提供时钟

CCM_CCGR寄存器中某2位的取值含义如下:

00:该GPIO模块全程被关闭

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

10:保留

11:该GPIO模块全程使能

GPIO2时钟控制:

图解:即控制CCM中的CCGR1的CG15的31-30这两位使能GPIO2,取值如图4.3

GPIO1、GPIO5时钟控制:

GPIO3时钟控制:

GPIO4时钟控制:

3.3 IOMUXC

作用:设置引脚的模式(Mode、功能)

对于某个/某组引脚,IOMUXC中有2个寄存器用来设置它:

选择功能:

a) IOMUXC_SW_MUX_CTL_PAD_ < PADNAME>:Mux pad xxx,选择某个pad的功能

b) IOMUXC_SW_MUX_CTL_GRP_< GROUP NAME>:Mux grp xxx,选择某组引脚的功能

某个引脚,或是某组预设的引脚,都有8个可选的模式(alternate (ALT) MUX_MODE)。

如:

设置上下拉电阻等参数:

a) IOMUXC_SW_PAD_CTL_PAD_ <PAD_NAME>:pad pad xxx,设置某 个pad的参数

b) IOMUXC_SW_PAD_CTL_GRP_< GROUP NAME>:pad grp xxx,设 置某组引脚的参数

如:

3.4 GPIO模块内部

3.5 读写GPIO

1.设置CCM_CCGRx寄存器中某位使能对应的GPIO模块 // 默认是使能 的,上图省略了

2.设置IOMUX来选择引脚用于GPIO

3.设置GPIOx_GDIR中某位为0,把该引脚设置为输入功能

4.读GPIOx_DR或GPIOx_PSR得到某位的值(读GPIOx_DR返回的是 GPIOx_PSR的值)

1.设置CCM_CCGRx寄存器中某位使能对应的GPIO模块 // 默认是使能 的,上图省略了

2.设置IOMUX来选择引脚用于GPIO

3.设置GPIOx_GDIR中某位为1,把该引脚设置为输出功能

4.写GPIOx_DR某位的值

注意:可以设置该引脚的 loopback 功能,这样就可以从 GPIOx_PSR 中读到引脚的真实电平;你从 GPIOx_DR 中读回的只是上次设置的 值,它并不能反应引脚的真实电平,比如可能因为硬件故障导致该引脚跟地短路了,你通过设置GPIOx_DR让它输出高电平并不会起效果。

4. LED驱动程序框架

图解:

  1. 应用程序(APP):用户通过APP发起文件或设备的操作请求,如打开(open)、读取(read)、写入(write)和控制(ioctl)等。

  2. C库:这些操作请求首先被传递给C库,C库提供了高级别的API接口,如fopen、fread、fwrite和ioctl等,这些接口封装了底层细节,简化了应用程序的开发。

  3. 内核(Kernel):C库中的系统调用(svc)将请求传递给内核。内核中的SVC异常处理机制负责解析这些调用,并转换为内核级别的函数执行,如drv_open、drv_read、drv_write和drv_ioctl,这些函数专门处理与驱动程序的交互。

  4. 驱动(Driver):驱动程序是内核与硬件之间的桥梁。它接收来自内核的指令,执行具体的硬件操作,如打开设备、从设备读取数据、向设备写入数据或控制设备行为等。

  5. 硬件(Hardware):最终,驱动程序与硬件直接交互,完成数据的实际读取、写入或控制操作。

  6. 数据拷贝:在数据从硬件传输到应用程序或从应用程序传输到硬件的过程中,涉及到内核空间与用户空间之间的数据拷贝。copy_to_user函数用于将数据从内核空间拷贝到用户空间,而copy_from_user则用于将数据从用户空间拷贝到内核空间。

5. 基于IMX6UL_6ULL的LED操作方法

原理图:

使能GPIO5:

设置GPIO5_3为GPIO模式:

设置GPIO5_3为输出:

设置GPIO5_3的输出电平:

6. 基于IMX6UL_6ULL的LED驱动程序

6.1 驱动代码

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/device.h>
#include <asm/io.h>
​
static int major;
static struct class *led_class;
​
// 寄存器物理地址
// 寄存器地址:0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3; // 设置GPIO5_3的模式
// 寄存器地址:0x020AC004
static volatile unsigned int *GPIO5_GDIR; // 设置GPIO5_3的方向
// 寄存器地址:0x020AC000
static volatile unsigned int *GPIO5_DR; // 设置GPIO5_3的电平
​
ssize_t led_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    char val;
    int err;
    // 获取数据
    err = copy_from_user(&val,buf,1);
    // 设置寄存器 0/1
    if(val)
    {
        // 设置LED打开 低电平
        *GPIO5_DR &= ~(1 << 3);
    }else{
        // 设置LED关闭 高电平
        *GPIO5_DR |= (1 << 3);
    }
    return 1;
}
​
int led_open (struct inode *node, struct file *file)
{
    // 使能gpio5 默认使能 时钟也默认使能
    // 配置gpio5_3引脚为GPIO
    *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;
    *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;
    *GPIO5_GDIR |= (1 << 3);
    
    return 0;
}
​
static struct file_operations led_fops = 
{
    .owner = THIS_MODULE,
    .open = led_open,
    .write = led_write,
};
​
// 入口函数
static int __init led_init(void)
{
    printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
    major = register_chrdev(0,"led_drv",&led_fops);
​
    // ioremap 映射 获得虚拟地址
    IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14,4);
    GPIO5_GDIR = ioremap(0x020AC004,4);
    GPIO5_DR = ioremap(0x020AC000,4);
    led_class = class_create(THIS_MODULE,"myled");
    device_create(led_class,NULL,MKDEV(major,0),NULL,"myled"); /* dev/myled */
    
    return 0;
}
​
// 出口函数
static void __exit led_exit(void)
{
    iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
    iounmap(GPIO5_GDIR);
    iounmap(GPIO5_DR);
    device_destroy(led_class,MKDEV(major,0));
    class_destroy(led_class);
    unregister_chrdev(major,"led_drv");
​
}
​
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

6.2 应用代码

#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
​
​
// ledtest /dev/myled on
// ledtest /dev/myled off
int main(int argc,char **argv)
{
    int fd;
    char status = 0;
    if(argc != 3)
    {
        printf("Usage: %s <dev> <on|off>\n",argv[0]);
        printf("   eg: %s /dev/myled on\n",argv[0]);
        printf("   eg: %s /dev/myled off\n",argv[0]);
        return -1;
    }
    // open
    fd = open(argv[1],O_RDWR);
    if(fd < 0)
    {
        printf("can not open %s\n",argv[0]);
        return -1;
    }
​
    // write
    if(strcmp(argv[2],"on") == 0)
    {
        status = 1;
    }
    write(fd,&status,1);
    return 0;
}

6.3 Makefile

KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88
​
all:
    make -C $(KERN_DIR) M=`pwd` modules 
    $(CROSS_COMPILE)gcc -o led_test led_test.c 
​
clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order
    rm -f led_test
​
obj-m   += led_drv.o

6.4 效果

Linux:

开发板:

转载驱动并查看

打开led

关闭led

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

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

相关文章

软件评审-需求评审、设计评审、编码评审、测试评审(原件)

1.需求规格说明评审报告 2.系统设计评审报告 3.编码与测试评审报告 软件全套资料部分文档清单&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xff0c;产品需求规格说明书&#xff0c;需求调研计划&#xff0c;用户需求调查单&#xff0…

工业大数据来自哪里?大数据技术如何助力制造企业数字化转型?

信息技术的迅猛发展正在重塑我们的世界&#xff0c;不仅改变了技术本身&#xff0c;也深刻影响了全球市场和人们的工作与生活方式。在工业生产这一关键领域&#xff0c;高性价比、长续航的微型传感器的诞生&#xff0c;以及物联网等新一代网络技术的兴起&#xff0c;正赋予无数…

【C语言篇】字符和字符串以及内存函数的详细介绍与模拟实现(上篇)

文章目录 字符函数字符输入输出函数字符输入函数字符输出函数 字符分类函数字符转换函数 字符串函数字符串输入输出函数字符串输入函数字符串输出函数 strlen函数的使用和模拟实现strcpy函数的使用和模拟实现strcat函数的使用和模拟实现strcmp函数的使用和模拟实现strncpy函数的…

Python基于TensorFlow实现卷积神经网络-双向长短时记忆循环神经网络分类模型(CNN-BiLSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 随着人工智能技术的快速发展&#xff0c;深度学习已经成为处理复杂数据集的关键工具之一。其中&#x…

【Kubernetes】k8s集群资源调度

目录 一、k8s的List-Watch机制 二、scheduler的调度过程 三、指定节点调度Pod 1.通过nodeName调度Pod 2.通过节点标签选择器调度Pod 3.通过亲和性调度Pod 1&#xff09;节点亲和性 2&#xff09;Pod 亲和性 四、污点(Taint) 和 容忍(Tolerations) 1.污点(Taint) 2.…

靶机:DC-2

一、信息收集 1、主机发现 nmap 192.168.236.0/24 2、端口扫描 nmap 192.168.236.130 -p- -A 二、漏洞探测 访问192.168.236.130&#xff0c;URL重定向&#xff0c;在本地hosts文件中添加192.168.236.130 dc-2 在flag1中提示cewl工具&#xff0c;kali自带&#xff0c;把密码…

进阶SpringBoot之 Web 静态资源导入

idea 创建一个 web 项目 新建 controller 包下 Java 类&#xff0c;用来查验地址是否能成功运行 package com.demo.web.controller;import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;RestControl…

如何在linux系统上部署nginx

1&#xff09;首先去 nginx.org/download 官网下载你所需要的版本 我这里是下载的 nginx-1-23-3.tar.gz 2&#xff09;然后执行 yum -y install lrzsz 安装文件上传软件 执行 rz 选择你下载nginx的位置进行上传 yum -y install lrzsz 3&#xff09;执行 tar -zxvf nginx-1.23…

《RT-DETR》论文笔记

原文出处 [2304.08069] DETRs Beat YOLOs on Real-time Object Detection (arxiv.org)https://arxiv.org/abs/2304.08069 原文笔记 What DETRs Beat YOLOs on Real-time Object Detection 1、设计了一种高效的混合编码器&#xff0c;通过解耦尺度内交互和跨尺度融合来提高…

保障速度与安全合规的前提下,如何传文件到国外?

伴随着经济全球化&#xff0c;数据跨境活动日益频繁&#xff0c;数据出境场景越来越多&#xff0c;防范数据出境安全风险&#xff0c;保障数据依法有序自由流动成为我国关注的重要方面。涉及数据出海的行业多种多样&#xff0c;像跨国运营、全球研发、金融服务等领域的企业都涉…

音乐制作工具:Studio One 6 (WinMac)

Studio One 6是由PreSonus公司开发的一款专业音乐制作软件&#xff0c;它提供了丰富的功能&#xff0c;以满足音乐创作、录制、混音和母带处理的需求。 Studio One 6以其人性化的用户界面、强大的音频性能、以及丰富的功能&#xff0c;成为了音乐制作领域中一个非常受欢迎的选择…

JAVA练习(五)对象封装

选择题 1、【static使用】 如果有以下程序片段&#xff1a; public class Some{private Some some;private Some(){}public static Some create(){if(some null){some new Some();}return some;} }以下描述哪个正确&#xff1a; A、编译错误 B、客户端必须使用new Some()产…

政务数据共享交换平台的逻辑架构

政务数据共享交换平台基于主流大数据技术和政务数据共享交换规范&#xff0c;提供大数据工作门户、工单系统、资源目录管理平台、数据交换平台和API管理平台&#xff0c;如 政务数据共享交换平台主要包括大数据工作门户、数据资源目录管理平台、共享交换管理平台、API管理平台、…

Python07:循环结构 --> for-in循环

如果循环次数已经确定&#xff0c; for循环 """ eg05 - 循环结构 --> for-in循环Author: mimo_yy Date: 2024/5/15 """ # 如果循环次数已经确定 for循环 for i in range(100): # 产生0到100范围的整数&#xff0c;从0开始取数&#xff0c;1…

【Impala】学习笔记

Impala学习笔记 【一】Impala介绍【1】简介&#xff08;1&#xff09;简介&#xff08;2&#xff09;优点&#xff08;3&#xff09;缺点 【2】架构&#xff08;1&#xff09;Impalad&#xff08;守护进程&#xff09;&#xff08;2&#xff09;Statestore&#xff08;存储状态…

【智能控制】第8章 典型神经网络 ,单神经元网络,BP神经网络,RBF神经网络,Hopfield神经网络(北京航天航空大学)

目录 第8章 典型神经网络 1. 单神经元网络 2. BP神经网络 3. RBF神经网络 4. Hopfield神经网络 第8章 典型神经网络 根据神经网络的连接方式&#xff0c;神经网络可分为三种形式&#xff1a;前馈型神经网络、反馈型神经网络和自组织网络&#xff0c;。典型的前馈型神经…

嵌入式边缘计算软硬件开发实训室解决方案

一、 引言 随着5G通信技术、人工智能算法和大数据分析方法的迅猛发展&#xff0c;物联网(IoT)设备的数量正以前所未有的速度增长&#xff0c;这些设备每天产生着海量的数据。据预测&#xff0c;到2025年&#xff0c;全球将有超过750亿个连接的IoT设备。这些设备不仅包括常见的智…

ArcGIS基础:标注转注记及简单处理

注记是一个静态的标签图层&#xff0c;能够独立的保存为文件&#xff0c;并且具有计算功能&#xff1b; 标注是一个动态的标签图形&#xff0c;无法以文件的形式进行存储和计算&#xff1b; 2者各有优势和劣势&#xff0c;根据具体需求进行选择 需要注意的是注记要存储在GDB…

Spring-MyBatis整合:No qualifying bean of type ‘XXX‘ available: ...

1.看一下核心配置中有没有导入myBatis配置 2.看一下service和dao有没有相应注解 3.看一下MyBatisConfig中有没有对sqlSessionFactory和mapperScannerConfigurer注释成bean对象以及有没有配置映射文件路径

天机学堂 第七天 积分系统

签到 签到最核心的包含两个要素&#xff1a; 谁签到&#xff1a;用户id 什么时候签的&#xff1a;签到日期 同时要考虑一些功能要素&#xff0c;比如&#xff1a; 补签功能&#xff0c;所以要有补签标示 按照年、月统计的功能&#xff1a;所以签到日期可以按照年、月、日分…