首页 > 编程语言 >最简单的LED驱动程序编写流程--基于IMX6ULL

最简单的LED驱动程序编写流程--基于IMX6ULL

时间:2024-01-17 09:22:21浏览次数:22  
标签:__ led 驱动程序 GPIO5 -- SNVS 地址 LED class

一.查看芯片手册 根据芯片手册找到3个条件 1.根据芯片手册找到对应端口,并对相应端口组使能,而IMX6ULL使能是默认的 2.找到对应引脚的模式,设置为GPIO模式或者其他串口模式 IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14 设置引脚模式的地址 3.并在GPIO模式下,设置引脚是输入模式或者是输出模式 GPIO5_GDIR地址:0x020AC0 设置输入输出模式的地址 4.对引脚的数据寄存器进行数据的写入 GPIO5_DR地址:0x020AC000设置数据的地址   二.用source insight打开liunx内核源码 参照内核驱动程序编写LED的驱动程序   三.编写LED驱动 1.设置LED入口函数和出口函数 a.入口函数 //入口函数 static int __init led_init(void) { printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__); major = register_chrdev(0, "100ask_led", &led_fops); //ioremap 映射寄存器地址,实际地址到虚拟地址 //IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14   IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3=ioremap(0x02290000 + 0x14, 4); //映射大小为4但是是一个页为4K   //GPIO5_GDIR地址:0x020AC0 GPIO5_GDIR = ioremap(0x020AC0,4);   //GPIO5_DR地址:0x020AC000 GPIO5_DR = ioremap(0x020AC000,4);     led_class = class_create(THIS_MODULE, "myled"); device_create(led_class, NULL, MKDEV(major,0),NULL,"myled");//前面两行系统就会自己创建名为myled的设备节点,就不需要手动创建 return 0; } module_init(led_init);   入口函数做的事情如下: 1.调用register_chrdev函数向内核注册驱动程序,而驱动程序写在file_operations结构体的led_fops中。并分配主设备号。 2.将实际的物理地址通过ioremap函数映射为机器的虚拟地址,通过对虚拟地址指针的操作就可以操作物理地址。 3.创建两个类class_create和device_create创建这两个类的目的是使机器自动创建设备节点。 4.调用module_init函数将led_init告诉内核为led驱动程序的入口函数   b.出口函数 static void __exit led_exit(void) { //IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14 iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3); //GPIO5_GDIR地址:0x020AC0 iounmap(GPIO5_GDIR); //GPIO5_DR地址:0x020AC000 iounmap(GPIO5_DR);   class_destroy(led_class); device_destroy(led_class, MKDEV(major,0)); unregister_chrdev(major, "100ask_led"); } module_exit(led_exit);   出口函数做的事情如下: 1.对入口函数内部做的ioremap销毁 2.对绕口令函数内部做的class_create和device_create这两个类进行销毁 3.将注册函数也进行销毁 4.module_exit告诉内核led_exit为出口函数   2.编写驱动程序 static const struct file_operations led_fops = { .owner= THIS_MODULE, .write= led_write, .open= led_open, };   这里声明了驱动程序里面有那些函数:led_write和;led_open函数   a.led_open函数 static int led_open(struct inode *inode, struct file *filp) { //enable gpio已经默认设置 //configure pin as gpio5_3 *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf; *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5; //configure gpio as output *GPIO5_GDIR |= (1<<3); return 0; }   led_open函数作用是:打开引脚驱动,打开的时候证明将要用这个驱动。所有设置这个驱动的配置。也就是上面芯片手册所查到的物理地址设置成相应的值。   b.led_write函数 static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { char val; int ret; // copy_from_user : get data from app ret = copy_from_user(&val, buf, 1); // to set gpio register : out 1/0 if(val) { *GPIO5_DR &= ~(1<<3); } else { *GPIO5_DR |= (1<<3); } return 1; }   通过用户层传来的命令向驱动引脚写数据,这里要注意用户层和核心层之间的数据通信是通过copy_from_user来通信的。然后对引脚的数据寄存器进行数据的填写。   完整代码 #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/mutex.h> #include <linux/wait.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/device.h>   static int major; static struct class *led_class;   //IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14   static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;   //GPIO5_GDIR地址:0x020AC0 static volatile unsigned int *GPIO5_GDIR;   //GPIO5_DR地址:0x020AC000 static volatile unsigned int *GPIO5_DR;   static ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { char val; int ret; // copy_from_user : get data from app ret = copy_from_user(&val, buf, 1); // to set gpio register : out 1/0 if(val) { *GPIO5_DR &= ~(1<<3); } else { *GPIO5_DR |= (1<<3); } return 1; }   static int led_open(struct inode *inode, struct file *filp) { //enable gpio已经默认设置 //configure pin as gpio5_3 *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf; *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5; //configure gpio as output *GPIO5_GDIR |= (1<<3); return 0; }   static const struct file_operations led_fops = { .owner= THIS_MODULE, .write= led_write, .open= led_open, };     //入口函数 static int __init led_init(void) { printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__); major = register_chrdev(0, "100ask_led", &led_fops); //ioremap 映射寄存器地址,实际地址到虚拟地址 //IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14   IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3=ioremap(0x02290000 + 0x14, 4); //映射大小为4但是是一个页为4K   //GPIO5_GDIR地址:0x020AC0 GPIO5_GDIR = ioremap(0x020AC0,4);   //GPIO5_DR地址:0x020AC000 GPIO5_DR = ioremap(0x020AC000,4);     led_class = class_create(THIS_MODULE, "myled"); device_create(led_class, NULL, MKDEV(major,0),NULL,"myled");//前面两行系统就会自己创建名为myled的设备节点,就不需要手动创建 return 0; } //出口函数 static void __exit led_exit(void) { //IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14 iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3); //GPIO5_GDIR地址:0x020AC0 iounmap(GPIO5_GDIR); //GPIO5_DR地址:0x020AC000 iounmap(GPIO5_DR);   class_destroy(led_class); device_destroy(led_class, MKDEV(major,0)); unregister_chrdev(major, "100ask_led"); }   module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL");  

标签:__,led,驱动程序,GPIO5,--,SNVS,地址,LED,class
From: https://www.cnblogs.com/kn-zheng/p/17969050

相关文章

  • 如何给shopify的URL做301跳转
    很多shopify的运营者或者推广者由于缺货或者货物变更,又或者自己更换了使用的主题,导致自己的URL结构发生了变化,由于不想浪费掉自己原有URL的流量,就想做个301跳转,让自己新的网址来承接原有的流量。接下来给大家介绍下如何给自己的URL做301跳转。首先你要在后台先访问你的所要修改......
  • centos 服务器buffer/cache缓存占用太大
    修改服务器此相关的参数在/proc/sys/vm目录下 vm.min_free_kbytes=409600;vm.vfs_cache_pressure=200;vm.swappiness=40。调整MIN_FREE_KBYTES的目的是保持物理内存有足够的空闲空间,防止突发性的换页。swapiness缺省为60,减少swapiness会使系统尽快通过swapout不使用的进程资源......
  • Blazor SSR/WASM IDS/OIDC 单点登录授权实例讲解1
    目录:OpenID与OAuth2基础知识BlazorwasmGoogle登录BlazorwasmGitee码云登录BlazorSSR/WASMIDS/OIDC单点登录授权实例讲解1BlazorSSR/WASMIDS/OIDC单点登录授权实例讲解2BlazorSSR/WASMIDS/OIDC单点登录授权实例讲解3源码BlazorOIDC/Server1.建立Bl......
  • Codeforces Round 861 (Div. 2)
    CodeforcesRound861(Div.2)C题直接数位dp即可#include<cstdio>#include<algorithm>#include<cstring>#include<map>#include<queue>#include<bitset>#include<cmath>#include<set>#include<unordered_map>#def......
  • latex中Missing $ inserted. \end{align*}
    有这么一段代码:1\begin{align*}2\text{解:}(x+\mathrm{i}y)(x-\mathrm{i}y)&=x^2+\mathrm{i}xy-\mathrm{i}xy-\mathrm{i}^2y^2\text{(其中$\mathrm{i}$是虚数单位)}\\3&=x^2+y^2\text{$\cdots\cdots\cdots$2分}\\4\intertext{\hspace{7.5em......
  • 记一次go应用在k8s pod已用内存告警不准确分析
    版权说明: 本文章版权归本人及博客园共同所有,转载请在文章前标明原文出处(https://www.cnblogs.com/mikevictor07/p/17968696.html),以下内容为个人理解,仅供参考。 一、背景起因:自监控应用凌晨告警:Pod内存使用率大于80%(规格为1c1G)。内存缓慢增长,持续到早上内存使用率停止在8......
  • SA&SAM 小记
    0.Front纯笔记,不含教学内容,部分有拓展,部分太简单所以以”显然“带过了,总结了部分oi-wiki的内容。字符串为\(S\),长度为\(n\),且应有\(|\Sigma|\len\)。通常来说,大写字母表示为字符串,小写字母表示为字符。后缀的编号为\(i\),表示是以\(i\)为起点的后缀。基础小练习1.......
  • E2. Minibuses on Venus (medium version)(卷积加速dp)
    数的范围是在k进制下的n位数一个数是lucky的当且仅当在k进制下,存在一个数位上的数,等于其他数位上的数在模k意义下的和。利用减法原理假设一个数的数位和为s,如果存在一个数,那么有s-x%k=x%k->s%k=2x%k那么我们找到这样的x,就是说在计算和为s的方案数是不能使用这些x类似于dp......
  • 大学专业 格物自测!为高考,从高一准备自己的知识储备! 工学 工学 理学 理学 哲学 哲学 经
    大学专业格物自测!为高考,从高一准备自己的知识储备! 工学理学哲学经济学法学教育学农学医学管理学艺术学文学历史学 https://www.gewuxue.com/......
  • Python pickle 二进制序列化和反序列化 - 数据持久化
    模块pickle实现了对一个Python对象结构的二进制序列化和反序列化。"pickling"是将Python对象及其所拥有的层次结构转化为一个字节流的过程,而"unpickling"是相反的操作,会将(来自一个binaryfile或者bytes-likeobject的)字节流转化回一个对象层次结构。pickling(和unp......