imx6ull设备树

概念

  • 什么是设备树

描述设备树的文件叫DTS,实际上就是在这个DTS文件里面,用树状的结构存储设备之间的关系。在以前这棵树就是设备树。

  • 什么是DTS、DTB、DTC

DTS就是我们上面的设备树源码文件、DTB是它的二进制文件、DTC是我们编译DTS的工具,类似于我们的gcc

设备树下的驱动开发

添加驱动设备节点

打开我们在内核移植时复制的dts文件

我们添加的alpha_led设备,是在根设备节点下面创建的一个节点,具有以下属性。

属性

compatible(兼容性):

一个字符串列表,比如上面gpio_spi设备中,有“fairchild, 74hc595”,fairchild表示厂商,74hc595一般是模块对应驱动名字。

也可以为字符串列表,如 :compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

status(设备状态):

#address-cells 和#size-cells 属性--------reg属性

#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,reg的属性值与地址相关,
格式为reg = <address1 length1 address2 length2 address3 length3……>,其中 address 是起始地址, length 是地址长度, #address-cells 表明 address 这个数据所占用的字长, #size-cells 表明 length 这个数据所占用的字长

添加了设备节点后我们到顶层目录编译我们的设备树文件

make  dtbs                                 

生成新的设备树文件

复制.dts文件到tftpboot里

工程文件的创建

我们在

创建一个我们以后写驱动的目录,在VScode打开,ctrl + shift + p,添加如下

前面改为自己的目录

编写程序

几个常用函数

程序如下(都在my_driver里)

dtsled.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define DTSLED_CNT      1        //device number
#define DTSLED_NAME     "dtsled" //device name

//映射后寄存器虚拟地质指针
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

//dteled设备结构体
struct dtsled_dev{
    dev_t devid;                //设备号
    struct cdev cdev;           //CDEV
    struct class *class;        //类
    struct device *device;      //设备
    int major;                  //主设备号
    int minor;                  //次设备号
    struct device_node *nd;     //设备节点
};

struct dtsled_dev dtsled;       //设备

void led_set(u8 set_value)      //1打开led, 0关闭
{
    u32 val = 0;
    if(set_value == 1)
    {
        val = readl(GPIO1_DR);
        val &= ~(1 << 3);
        writel(val, GPIO1_DR);s
    }
    else if(set_value == 0)
    {
        val = readl(GPIO1_DR);
        val |= (1 << 3);
        wtitel(val, GPIO1_DR);
    }
}

static int led_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &dtsled;   //设置私有数据
    return 0;
};

static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t offt)
{
    return 0;
}

static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    int ret;
    unsigned char databuf[1];
    unsigned char ledstat;

    ret = copy_from_user(databuf, buf, cnt);
    if(ret < 0)
    {
        printk("kernel copy_from_user failed: %d\n", ret);
        return -EFAULT;
    }

    ledstat = databuf[0];
    if(1 == ledstat)            //开
    {
        led_set(1);
    }
    else if(0 == databuf[0])    //关
    {
        led_set(0);
    }

    return 0;
}

static int led_close(struct inode *inode, struct file *file)
{
    return 0;
}

static struct file_operations dtsled_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .read = led_read,
    .write = led_write,
    .release = led_close,
};

static int __init led_init(void)
{
    u32 val = 0;
    int ret;
    u32 regdata[14];
    const char *str;
    struct property *proper;

    dtsled.nd = of_find_node_by_path("/alphaled");  //通过路径查找指定节点,返回节点
    if(dtsled.nd == NULL)
    {
        printk("find_node_by_path failed\n");
        return -EINVAL;
    }
    printk("alphaled node has been found\n");

    proper = of_find_property(dtsled.nd, "compatible", NULL);   //查找指定属性(节点, 属性名, 字节数)返回属性结构体
    if(proper == NULL)
    {
        printk("find_perpor_err failed\n");       
    }
    else 
    {
        printk("compatoble = %s\n", (char *)proper->value);
    }

    ret = of_property_read_string(dtsled.nd, "status", &str);   //读取属性中字符串值(设备节点,要读取的属性名,读取到的字符串值)
    if(ret < 0)
    {
        printk("property_read_string_err failed\n");
    }
    else 
    {
        printk("status = %s\n", str);
    }

    ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);    //获取reg属性内容存到regdata数组,在下面调用
    if(ret < 0)
    {
        printk("reg property_read_u32_array_err failed\n");
    }
    else 
    {
        u8 = i;
        printk("reg data:\n");
        for(i = 0; i < 10; ++i)
        {
            printk("%#x ", regdata[i]);
        }
        printk("\n");
    }


#if 0
    IMX6U_CCM_CCGR1 = ioremap(regdata[0], regdata[1]);
    SW_MUX_GPIO1_IO03 = ioremap(regdata[2], regdata[3]);
    SW_PAD_GPIO1_IO03 = ioremap(regdata[4], regdata[5]);
    GPIO1_DR = ioremap(regdata[6], regdata[7]);
    GPIO1_GDIR = ioremap(regdata[8], regdata[9]);
#else
    IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0);
    SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1);
    SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2);
    GPIO1_DR = of_iomap(dtsled.nd, 3);
    GPIO1_GDIR = of_iomap(dtsled.nd, 4);
#endif                                          //直接内存映射

    val = readl(IMX6U_CCM_CCGR1);               //使能GPIO1时钟
    val &= ~(3 << 26);
    val |= (3 << 26);
    writel(val, IMX6U_CCM_CCGR1);

    writel(5, SW_MUX_GPIO1_IO03);

    writel(0x10B0, SW_PAD_GPIO1_IO03);

    val = readl(GPIO1_GDIR1);                   // 设置GPIO IO03为输出
    val &= ~(1 << 3);
    val |= (1 <<3);
    writel(val, GPIO1_GDIR);

    val = readl(GPIO1_DR);                      //默认关闭LED
    val |= (1 << 3);
    writel(val, GPIO1_DR);

    if(dtsled.major)                            //如果定义了设备号用它
    {
        dtsled.devid = MKDEV(dtsled.major, 0);
        register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);
    }
    else                                        //没定义设备号,自动创建
    {
        alloc_chrdev_region(&dtsled.devid, 0, DTSLED.CNT, DTSLED.NAME);
        dtsled.major = MAJOR(dtsled.devid);
        dtsled.minor = MINOR(dtsled.devid);
    }
    printk("dtsled major = %d minor = %d\n", dtsled.major, dtsled.minor);  //打印主次设备号

    dtsled.cdev.owner = THIS_MODULE;                //初始化cdev
    cdev_init(&dtsled.cdev, &dtsled.fops);

    cdev_add(&dtsled.cdev, &dtsled.devid, DTSLED_CNT);  //添加cdev

    dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);  //创建类
    if(IS_ERR(dtsled.class))
    {
        return PTR_ERR(dtsled.class);
    }

    dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);//创建设备
    if(IS_ERR(dtsled.device))
    {
        return PTR_ERR(dtsled.device);
    }
    return 0;
}

static void __exit led_exit(void)
{
    iounmap(IMX6U_CCM_CCGR1);
    iounmap(SW_MUX_GPIO1_IO03);
    iounmap(SW_PAD_GPIO1_IO03);
    iounmap(GPIO1_DR);
    iounmap(GPIO1_GDIR);

    cdev_del(&dtsled.cdev);
    unregister_chrdev_region(&dtsled.devid, DTSLED_CNT);
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

ledapp.c

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"

int main()
{
    int fd = open("/dev/dtsled", O_RDWR);
    char a[1] = {1};
    char b[1] = {0};
    if(fd < 0)
    {
        printf("cant open file: /dev/dstled\n");
        return -1;
    }
    
    while(1)
    {
        write(fd, a, 1);
        sleep(1);
        write(fd, b, 1);
        sleep(1);
    }

    close(fd);
    return 0;
}

编写Makefile

KERNELDIR := /home/violet/imx6ul/uboot/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)
obj-m := dtsled.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

执行make -j3将dtsled.ko放到根目录文件下/lib/modules/4.1.15

编译ledapp.c同样放到这个目录下

在板子上

然后执行ledapp

灯闪烁

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

echart实现数据传输动态效果

function setDataTransfer(id) {var chart echarts.init(document.getElementById(id)); var items [{level: 1,name: "传感器",label: beijing,value: [20, 10],symbol: "",symbolSize: [30, 30]},{level: 1,symbol: "",name: "物联中心…

imazing64位2.17.6.0新功能介绍以及 iMazing最新版免费激活下载

iMazing for mac是一款可以在苹果电脑Mac os平台上使用的帮助用户管理手机的Mac手机助手&#xff0c;iMazing for mac是能力远超 iTunes 提供的终极的 iOS 设备管理器。IMazing 与你的 iOS 设备 &#xff08;iPhone、 iPad 或 iPod&#xff09;相连&#xff0c;使用起来非常的方…

openstack-图形管理 6

安装并配置组件 重启web服务及会话存储服务 图形化登录 删除云主机 使用管理员登录 删除子网网络 删除云主机网络 创建网络 创建云主机 控制节点配置 配置私有网络&#xff0c;配置虚拟子网&#xff1a; 配置ML2插件 配置Linuxbridge&#xff08;桥接&#xff09; 配置laye…

ROS仿真小车(二)——添加摄像头雷达传感器

文章目录 前言一、在 Rviz 中显示一个盒状机器人1.1 创建ROS功能包1.2 在 launch 文件中集成 URDF 与 Rviz1.3 在 Rviz 中显示机器人模型1.4 优化 rviz 启动 二、创建一个四轮圆柱状机器人模型2.1 配置urdf和launch文件2.2 URDF优化_xacro2.2.1 配置xacro文件2.2.2 编写 Xacro …

Windows平台下的Oracle 19c补丁升级

Windows平台下的Oracle 19c补丁升级 文章目录 Windows平台下的Oracle 19c补丁升级第一章 概述第二章 安装前备份2.1 软件目录备份2.2 权限备份2.3 备份数据库 第三章 安装前检查3.1 查看数据库版本3.2 升级opatch版本 第四章 安装补丁4.1 设置环境变量4.2 关闭oracle相关服务4.…

c++11 标准模板(STL)本地化库 - 平面类别(std::collate) - 定义字典序比较和字符串的散列(二)

本地化库 本地环境设施包含字符分类和字符串校对、数值、货币及日期/时间格式化和分析&#xff0c;以及消息取得的国际化支持。本地环境设置控制流 I/O 、正则表达式库和 C 标准库的其他组件的行为。 平面类别 定义字典序比较和字符串的散列 std::collate 类 std::collate 封…

VLOOKUP函数使用,为什么会报错“引用有问题”?

VLOOKUP函数的使用非常广泛&#xff0c;在excel2007版之后的软件中&#xff0c;使用VLOOKUP函数也许会遇到这样的场景&#xff0c;明明公式是没有问题的&#xff0c;公式还会报错“引用有问题”。 一、报错场景 输入公式后&#xff0c;回车确认&#xff0c;显示如下报错&…

【论文阅读】Attention is all you need

摘要 主要的序列转换模型是基于复杂的循环或卷积神经网络&#xff0c;其中包括一个编码器和一个解码器。性能最好的模型还通过一种注意力机制将编码器和解码器连接起来。我们提出了一种新的简单的网络架构&#xff0c;Transformer&#xff0c;完全基于注意机制&#xff0c;完全…

javaEE初阶——多线程(五)

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享关于多线程的文章第五篇关于 多线程代码案例二 阻塞队列 如果有不足的或者错误的请您指出! 目录 2.阻塞队列2.1常见队列2.2 生产者消费者模型有利于进行解耦合程序进行削峰填谷…

力扣---填充每个节点的下一个右侧节点指针 II

给定一个二叉树&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NULL 。 初始状态下&#xff0c;所有 next 指针都…

大厂面试精华面试刷题

1.自定义unshift实现相同效果 2.数组去重 用vs2019来写这种练习题可以更直观的查看代码执行的效果&#xff0c;最后的代码是控制控制台执行完毕后不自动关闭 use strict;let arr [1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] //1.//查重最简单的方法for循环结合splice从数组中…

win10 系统怎么开启 guest 账户?

win10 系统怎么开启 guest 账户&#xff1f; 段子手168 前言&#xff1a; guest 账户即所谓的来宾账户&#xff0c;我们可以通过该账户访问计算机&#xff0c;如打印机共享等&#xff0c;但会在一定程度上受到限制。下面分享 WIN10 系统开启 guest 来宾账户的几种方法。 方法…

【Transformer】detr梳理

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 detr detr 1. 引言 论文&#xff1a; https://arxiv.org/pdf/2005.12872v3.pdf 时间&#xff1a; 2020.5.26 作者&#xff1a; Nicolas Carion?, Fra…

SnapGene Mac激活版 分子生物学软件

SnapGene Mac是一款功能全面、操作便捷的综合性分子生物学软件&#xff0c;专为Mac用户打造。它集成了DNA序列编辑、分析、可视化和团队协作等多种功能&#xff0c;为科研人员提供了一个高效、可靠的分子生物学研究工具。 SnapGene Mac激活版下载 在SnapGene Mac中&#xff0c;…

【Hadoop大数据技术】——Sqoop数据迁移(学习笔记)

&#x1f4d6; 前言&#xff1a;在实际开发中&#xff0c;有时候需要将HDFS或Hive上的数据导出到传统关系型数据库中&#xff08;如MySQL、Oracle等&#xff09;&#xff0c;或者将传统关系型数据库中的数据导入到HDFS或Hive上&#xff0c;如果通过人工手动进行数据迁移的话&am…

美容预约小程序:简单三步,开启高效预约模式

在当今的数字化时代&#xff0c;一个小程序可以极大地提高美容院的效率和客户满意度。下面我们将详细说明如何通过以下步骤来搭建一个美容院预约小程序。 首先&#xff0c;你需要注册并登录到乔拓云网&#xff0c;这是 一个在线平台&#xff0c;可以帮助你快速创建并管理你的小…

Kafka集群搭建可视化指南

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Kafka集群搭建可视化指南 前言准备工作硬件要求环境准备 kafka集群的部署与配置3.1 单节点部署与多节点集群搭建单节点部署&#xff1a;多节点集群搭建&#xff1a; 3.2 Broker配置与优化3.3 Topic的创…

快速访问github

修改本地hosts文件 GitHub访问慢的原因在于域名解析&#xff0c;通过修改本地的hosts文件&#xff0c;将远程DNS解析改为本地DNS解析。 fang 步骤1&#xff1a;打开hosts文件&#xff08;没有就创建&#xff09; host所在位置&#xff1a; C:\Windows\System32\drivers\etc…

销售经理(多继承/虚基类)

根据下图类之间的继承关系&#xff0c;以及main和输出定义&#xff0c;定义Staff类、Saleman类、Manager类和SaleManager类。 Staff类包含的数据成员有编号&#xff08;num)&#xff0c;姓名&#xff08;name)&#xff0c;基本工资&#xff08;basicSale&#xff09;。Saleman类…

[lesson42]类型转换函数(下)

类型转换函数(下) 类型转换函数 C类中可以定义类型转换函数 类型转换函数用于将类对象转换成其他类型 语法规则&#xff1a; 类型转换函数 与转换构造函数具有同等的地位使得编译器有能力将对象转换为其他类型编译器能够隐式的使用类型转换函数 无法抑制隐式的类型转换函…