利用GPIO子系统完成点灯

作业要求:利用GPIO子系统完成点灯实验

目录

1.GPIO子系统框架:

 2.GPIO子系统API

 3.gpio设备树的编写

3.1 led灯的硬件连接图

 3.2 gpio控制器的设备树节点

 3.3编写led灯的设备树节点

4.利用GPIO子系统完成点灯的实例代码

5.实验结果:


实验过程:

1.GPIO子系统框架:

内核层又细分为三层分别为设备驱动层、核心层、厂商驱动层

设备驱动层:利用下层的接口实现对硬件的控制

核心层:为设备驱动层提供接口,隐藏下层细节

厂商驱动层:主要根据设备驱动层调用的接口来实现硬件寄存器的映射,初始化和相关配置

 2.GPIO子系统API

1.解析对应设备的设备树节点
struct device_node *of_find_node_by_name(struct device_node *from,
    const char *name);
功能:根据设备树节点的名字解析设备树节点
参数:
from:当前节点父节点首地址(不知道就填NULL,默认从设备树根节点开始解析)
name:设备树节点名字  mynode
返回值:成功获取到解析的设备树节点信息结构体首地址,失败返回NULL
#include<linux/of_gpio.h>
2.根据解析得到的设备树节点结构体去解析得到对应的gpio编号
 int of_get_named_gpio(struct device_node *np,
                                   const char *propname, int index)
功能:根据设备树节点信息结构体解析得到gpio编号
参数:
np:设备树节点结构体指针
proname:gpio编号对应的键名
index:选用的键值对中值的索引号(第一个值为0)
返回值:成功返回GPIO编号,失败返回错误码
3.向内核申请要使用的gpio编号
int gpio_request(unsigned gpio, const char *label)
参数:
    gpio:要申请的gpio编号
    label:填NULL
    返回值:成功返回0,失败返回错误码
4.int gpio_direction_input(unsigned gpio)
设置gpio编号对应的gpio管脚为输入模式
5.int gpio_direction_output(unsigned gpio, int value)
设置gpio编号对应的gpio管脚为输出模式,并且输出电平(0:低电平,1:高电平)
6.void gpio_set_value(unsigned gpio, int value)
设置输出指定的数值(0:低电平,1:高电平)
7.int gpio_get_value(unsigned gpio)
根据返回值读取gpio编号对应的管脚状态(0:低电平,1:高电平)
8.void gpio_free(unsigned gpio);
将注册的gpio编号在内核中注销

 3.gpio设备树的编写

3.1 led灯的硬件连接图

gpio控制器的设备树节点已经在内核中被编写完成,我们现在要做的事是在LED设备树节点中引用指定的gpio控制器对应的设备树节点即可,不必自己申请注册设备节点。

 3.2 gpio控制器的设备树节点

gpio控制器设备树节点:

查看stm32mp157a-fsmp1a.dts文件头文件,找到了 stm32mp15xxac-pinctrl.dtsi
进入,得到:
&pinctrl {
    gpioe: gpio@50006000 {
        status = "okay";
        ngpios = <16>;//表示这组gpio中管脚的数量
        gpio-ranges = <&pinctrl 0 64 16>;//这组gpio的编号的七十至
    };
 };

查看stm32mp157a-fsmp1a.dts文件头文件,找到了 stm32mp157.dtsi->stm32mp153.dtsi
->stm32mp151.dtsi
      pinctrl: pin-controller@50002000 {
            #address-cells = <1>;//地址的个数
            #size-cells = <1>;//地址长度的个数
            compatible = "st,stm32mp157-pinctrl";//厂商信息
                       gpioe: gpio@50006000 {
                gpio-controller;//空属性,起到声明作用
                #gpio-cells = <2>;//在引用当前节点时,属性值u32的个数
                
                reg = <0x4000 0x400>;//当前节点地址和地址长度
                clocks = <&rcc GPIOE>;//使能GPIO控制器时钟
                st,bank-name = "GPIOE";//名字时GPIOE
                status = "disabled";//控制器工作状态
                                //disabled(不工作),okay(工作)
            };


 3.3编写led灯的设备树节点

在内核顶层目录下有一个Documentation文件夹,它是内核的帮助文档
在这个目录下/Documentation/devicetree/bindings/gpio目录中有gpio相关设备树的帮助信息
vi gpio.txt
gpioe: gpio@50006000 {
                gpio-controller;//空属性,起到声明作用
                #gpio-cells = <2>;
    };
    
//编写自己的led设备树节点
myleds{
    led1=<&gpioe 10 0>;
    led2=<&gpiof 10 0>;
    led3=<&gpioe 8 0>;
};

4.利用GPIO子系统完成点灯的实例代码

#include <linux/init.h>
#include <linux/module.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/slab.h>
#include<linux/uaccess.h>
#include<linux/of.h>
#include<linux/io.h>
#include<linux/of_gpio.h>
struct cdev *cdev;
dev_t devno;
unsigned int minor=0;
#if 0
unsigned int major=0;
#else
unsigned int major=500;
#endif
struct timer_list timer;
struct device_node *dnode;
char kbuf[128]={0};
struct class *cls;
struct device *dev;
int gpioe10;
int gpiof10;
int gpioe8;
int gpioz5;
int gpioz6;
int gpioz7;

void timer_handler(struct timer_list *timer)
{
    gpio_set_value(gpioe10,!gpio_get_value(gpioe10));
    gpio_set_value(gpiof10,!gpio_get_value(gpiof10));
    gpio_set_value(gpioe8,!gpio_get_value(gpioe8));
    gpio_set_value(gpioz5,!gpio_get_value(gpioz5));
    gpio_set_value(gpioz6,!gpio_get_value(gpioz6));
    gpio_set_value(gpioz7,!gpio_get_value(gpioz7));
    mod_timer(timer,jiffies+HZ);
}
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t mycdev_read (struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
    int ret;
  
 
    if(size >sizeof(kbuf)) size=sizeof(kbuf);
    ret = copy_to_user(ubuf,kbuf,size);
    if(ret)
    {
        printk("copy to user is error\n");
        return -EIO;
    }


    return size; //5.返回拷贝数据大小
}
ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
     int ret;
   
    if(size >sizeof(kbuf)) size=sizeof(kbuf);
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret)
    {
        printk("copy from user is error\n");
        return -EIO;
    }
 
    return size; //5.返回拷贝数据大小
}
int mycdev_close (struct inode *inode, struct file *file)
{ 
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

const struct file_operations fops = {
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};
static int __init mycdev_init(void)
{
    dnode=of_find_node_by_name(NULL,"myleds");
    if(dnode==NULL)
    {
        printk("解析设备树节点失败\n");
        return -EIO;
    }
    printk("解析设备树节点成功\n");\
    gpioe10=of_get_named_gpio(dnode,"led1",0);
    if(gpioe10<0)
    {
        printk("解析gpioe10编号失败\n");
        return -EIO;
    }
    printk("解析gpioe10编号成功\n");

    gpiof10=of_get_named_gpio(dnode,"led2",0);
    if(gpiof10<0)
    {
        printk("解析gpiof10编号失败\n");
        return -EIO;
    }
    printk("解析gpiof10编号成功\n");

        gpioe8=of_get_named_gpio(dnode,"led3",0);
    if(gpioe8<0)
    {
        printk("解析gpioe8编号失败\n");
        return -EIO;
    }
    printk("解析gpioe8编号成功\n");

     gpioz5=of_get_named_gpio(dnode,"led4",0);
    if(gpioz5<0)
    {
        printk("解析gpioz5编号失败\n");
        return -EIO;
    }
    printk("解析gpioz5编号成功\n");

     gpioz6=of_get_named_gpio(dnode,"led5",0);
    if(gpioz6<0)
    {
        printk("解析gpioz6编号失败\n");
        return -EIO;
    }
    printk("解析gpioz6编号成功\n");

    gpioz7=of_get_named_gpio(dnode,"led6",0);
    if(gpioz7<0)
    {
        printk("解析gpioz7编号失败\n");
        return -EIO;
    }
    printk("解析gpioez7编号成功\n");

    gpio_request(gpioe10,NULL);
    gpio_request(gpiof10,NULL);
    gpio_request(gpioe8,NULL);
    gpio_request(gpioz5,NULL);
    gpio_request(gpioz6,NULL);
    gpio_request(gpioz7,NULL);
    gpio_direction_output(gpioe10,0);
    gpio_direction_output(gpiof10,0);
    gpio_direction_output(gpioe8,0);
    gpio_direction_output(gpioz5,0);
    gpio_direction_output(gpioz6,0);
    gpio_direction_output(gpioz7,0);
   timer.expires=jiffies+HZ;
   timer_setup(&timer,timer_handler,0);
   add_timer(&timer);
  
   return 0;

 
}

static void __exit mycdev_exit(void)
{
    /*
    1.销毁设备节点
    2.销毁目录
    3.注册驱动对象
    4.释放设备资源
    5.释放对象空间
    */
gpio_free(gpioe10);
gpio_free(gpiof10);
gpio_free(gpioe8);
gpio_free(gpioz5);
gpio_free(gpioz6);
gpio_free(gpioz7);
del_timer(&timer);
  

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

5.实验结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值