设备树在开发板上的查看
进入 sys/devices/platform
我们先用led 经行 查看
进入of_node (开放的固件) 里面有 compatible(属性) name pin(引脚) 进行查看 和设备树上面的一致
最后一个用hexdump -C 进行查看 可以进行二进制的查看
写设备树时引用原有的代码在哪查找
1 查看相关的文档
假设我现在使用的3.5的内核那么我就在--------->linux内核\linux-3.5-20160514\linux-3.5\Documentation\devicetree\bindings\arm
下面进行查看
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200514144434508.png寄存器 x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzg5ODA2Nw==,size_16,color_FFFFFF,t_70)
里面会有写设备树的规范
比如 compatible 里面必须填写的信息是 atmel,<chip>-pit"
reg 是寄存器集合的地址偏移长度
2 查找同类型的单板设备树文件 (在这个目录下的文件就是参考上面的相关文档写出来的驱动)
在---->linux内核\linux-3.5-20160514\linux-3.5\drivers 有各种的硬件相关的设施
如果我们查看输入子系统的设备 可以在里面查看别人写好的驱动程序
3 直接查看其他的设备树来修改我们的设备树
比如这两个设备树都是同一个单板的设备树 但是多了mmc 我们要是给自己单板增加mmc 可以查看这两个文件不同点
设备树环境的构造
在jz2440 中要更换新的内核—>linux4.19,才能使用设备树,由于需要编译新的内核也需要新的交叉编译链
- 编译器的选择:
一个完整的Linux系统包含三部分: u-boot, kernel, root filesystem.
a. 对于u-boot:
我们仍然使用u-boot 1.1.6, 在这个版本上我们实现了很多功能: usb下载,菜单操作,网卡永远使能等, 不忍丢弃.
b. 对于kernel:
我下载了目前(2018.09.19)最新的内核 (4.19)
c. 对于root filesystem
中文名为"根文件系统", 它包含一些必须的APP, 一些动态库。
一般来说这些动态库是从工具链里的lib目录复制得到的,
当然也可以自己去编译glibc等库。
在编译u-boot和kernel时, 我们可以使用新的工具链,
只要这个工具链支持ARM9的指令集(armv4)就可以(这通常可以通过编译参数来指定使用特定的指令集).
工具链可以从某些网站上下载,并不需要自己去制作。
比如可以访问这个网站: https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabi/
下载: gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz
但是在制作根文件系统时, 实际上我们是编译各种APP,
这些APP要用到一些动态库, 为了方便一般直接使用工具链中lib目录里的库。
新版工具链的lib库一般是支持新的芯片,比如cortex A7,A8,A9,并不支持ARM9。
所以在制作根文件系统、编译APP时我们还得使用比较老的工具链: arm-linux-gcc-4.3.2.tar.bz2
-
通过设置PATH环境变量来选择使用某个工具链:
2.1 安装工具链:
这非常简单, 解压即可:
sudo tar xjf arm-linux-gcc-4.3.2.tar.bz2 -C / (解压到根目录, /usr/local/arm/4.3.2/bin/下就是工具链)
tar xJf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz (解压到当前目录, 假设/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin下就是工具链)注意: “/work/system” 请自行替换为你的实际目录
2.2 设置环境变量使用某个工具链:
a. 要使用arm-linux-gcc 4.3.2, 执行如下命令:
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin
然后就可以执行 arm-linux-gcc -v 观看到版本号了
b. 要使用arm-linux-gnueabi-gcc 4.9.4, 执行如下命令:
export PATH=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin
然后就可以执行 arm-linux-gnueabi-gcc -v 观看到版本号了
-
u-boot的编译:
a. 首先设置环境变量使用要使用arm-linux-gnueabi-gcc 4.3.2
b.
把源文件u-boot-1.1.6.tar.bz2、补丁文件u-boot-1.1.6_device_tree_for_jz2440.patch放在同一个目录,
执行如下命令:
tar xjf u-boot-1.1.6.tar.bz2 // 解压
cd u-boot-1.1.6
patch -p1 < …/u-boot-1.1.6_device_tree_for_jz2440.patch // 打补丁
make 100ask24x0_config // 配置
make // 编译, 可以得到u-boot.bin -
kernel的编译:
a. 首先设置环境变量使用要使用arm-linux-gnueabi-gcc 4.3.2
b.
把源文件linux-4.19-rc3.tar.gz、补丁文件linux-4.19-rc3_device_tree_for_jz2440.patch放在同一个目录,
执行如下命令:
tar xzf linux-4.19-rc3.tar.gz // 解压
cd linux-4.19-rc3
patch -p1 < …/linux-4.19-rc3_device_tree_for_jz2440.patch // 打补丁
cp config_ok .config // 配置
make uImage // 编译, 可以得到arch/arm/boot/uImage
make dtbs // 编译, 可以得到arch/arm/boot/dts/jz2440.dtb
注意:
a. 如果提示"mkimage not found", 先编译u-boot, 把tools/mkimage复制到/bin目录
b. 如果提示"openssl/bio.h: No such file or directory"
先确保你的ubuntu可以上网, 然后执行如下命令:
sudo apt-get update
sudo apt-get install libssl-dev
-
制作root filesystem :
可以直接使用映象文件: fs_mini_mdev_new.yaffs2如果想自己制作,请参考视频:
从www.100ask.net下载页面打开百度网盘,
打开如下目录:
100ask分享的所有文件
009_UBOOT移植_LINUX移植_驱动移植(免费)
毕业班第3课_移植3.4.2内核
毕业班第3课第2节_移植3.4.2内核之修改分区及制作根文件系统.WMV -
烧写
a. 使用EOP烧写u-boot.bin到JZ2440的nor flash或nand flash
b. 启动u-boot, 在串口工具中输入相应菜单命令, 使用dnw_100ask.exe发送对应文件菜单 要发送的文件
[k] Download Linux kernel uImage uImage
[t] Download device tree file(.dtb) jz2440.dtb
[y] Download root_yaffs image fs_mini_mdev_new.yaffs2
烧写完毕即可重启进入板上LINUX系统。
写第一个简单的设备树驱动
驱动和dts进行匹配
在之前的led平台总线驱动里面 driver增加of_match_table(能匹配的dts数组) 再自己新增这个数组
数组里面填写能匹配的dts设备
写好后可以和设备树进行匹配了 这个写法不规范 但是能用。 一般写成 jz2440,led 表示厂家,设备
匹配成功后,和之前一样,probe 函数就被调用
驱动和dts进行参数互传
- 用自带属性reg 把引脚当做寄存器进行值的传输
- 用我们自己创建的属性 经行数值的传输
得到led的引脚之后就直接像之前一样对它初始化,赋值,调整高低电频
进行编译测试
在编译u-boot和kernel时, 我们可以使用新的工具链, 4.9.4 的arm-linux-gnueabi-
新版工具链的lib库一般是支持新的芯片,比如cortex A7,A8,A9,并不支持ARM9。
所以在制作根文件系统、编译APP时我们还得使用比较老的工具链: arm-linux-gcc-4.3.2.tar.bz2
使用4.9.4
export PATH=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin
使用4.3.2
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin
设备树的编译和烧写
把设备树文件 jz2440.dts 拷贝到内核的 arch/arm/boot/dts/ 下
在根目录进行make dtbs 再进入arch/arm/boot/dts/ 把编译好的设备树文件 jz2440.dtb取出
当uboot能够ping通虚拟机 而且虚拟机上nfs能挂载后 进行设备树的烧写
nfs 32000000 192.168.2.51:/work/nfs_root/jz2440.dtb
nand erase device_tree
nand write.jffs2 32000000 device_tree
驱动编译和上传
更改编译工具链为4.9.4
export PATH=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin
用下面的makefile 和驱动和应用文件 编译出驱动 led_drv.ko
在开发板上挂载nfs文件系统
ifconfig eth0 192.168.2.15
mount -t nfs -o nolock,vers=2 192.168.2.51:/work/nfs_root /mnt
进入nfs目录
insmod led_drv.ko
ls /dev/led
现在设备节点已经创建
应用编译
要先把编译器更换 换成4.3.2 才能编译应用
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin
源码
led_drv.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#define S3C2440_GPA(n) (0<<16 | n)
#define S3C2440_GPB(n) (1<<16 | n)
#define S3C2440_GPC(n) (2<<16 | n)
#define S3C2440_GPD(n) (3<<16 | n)
#define S3C2440_GPE(n) (4<<16 | n)
#define S3C2440_GPF(n) (5<<16 | n)
#define S3C2440_GPG(n) (6<<16 | n)
#define S3C2440_GPH(n) (7<<16 | n)
#define S3C2440_GPI(n) (8<<16 | n)
#define S3C2440_GPJ(n) (9<<16 | n)
static int led_pin;
static volatile unsigned int *gpio_con;
static volatile unsigned int *gpio_dat;
/* 123. 分配/设置/注册file_operations
* 4. 入口
* 5. 出口
*/
static int major;
static struct class *led_class;
static unsigned int gpio_base[] = {
0x56000000, /* GPACON */
0x56000010, /* GPBCON */
0x56000020, /* GPCCON */
0x56000030, /* GPDCON */
0x56000040, /* GPECON */
0x56000050, /* GPFCON */
0x56000060, /* GPGCON */
0x56000070, /* GPHCON */
0, /* GPICON */
0x560000D0, /* GPJCON */
};
static int led_open (struct inode *node, struct file *filp)
{
/* 把LED引脚配置为输出引脚 */
/* GPF5 - 0x56000050 */
int bank = led_pin >> 16;
int base = gpio_base[bank];
int pin = led_pin & 0xffff;
gpio_con = ioremap(base, 8);
if (gpio_con) {
printk("ioremap(0x%x) = 0x%x\n", base, gpio_con);
}
else {
return -EINVAL;
}
gpio_dat = gpio_con + 1;
*gpio_con &= ~(3<<(pin * 2));
*gpio_con |= (1<<(pin * 2));
return 0;
}
static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
/* 根据APP传入的值来设置LED引脚 */
unsigned char val;
int pin = led_pin & 0xffff;
copy_from_user(&val, buf, 1);
if (val)
{
/* 点灯 */
*gpio_dat &= ~(1<<pin);
}
else
{
/* 灭灯 */
*gpio_dat |= (1<<pin);
}
return 1; /* 已写入1个数据 */
}
static int led_release (struct inode *node, struct file *filp)
{
printk("iounmap(0x%x)\n", gpio_con);
iounmap(gpio_con);
return 0;
}
static struct file_operations myled_oprs = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_release,
};
static int led_probe(struct platform_device *pdev)
{
struct resource *res;
/* 根据platform_device的资源进行ioremap */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
led_pin = res->start;
}
else {
/* 获得pin属性 */
of_property_read_s32(pdev->dev.of_node, "pin", &led_pin);
}
if (!led_pin)
{
printk("can not get pin for led\n");
return -EINVAL;
}
major = register_chrdev(0, "myled", &myled_oprs);
led_class = class_create(THIS_MODULE, "myled");
device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
return 0;
}
static int led_remove(struct platform_device *pdev)
{
unregister_chrdev(major, "myled");
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
return 0;
}
static const struct of_device_id of_match_leds[] = {
{ .compatible = "jz2440_led", .data = NULL },
{ /* sentinel */ }
};
struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
.of_match_table = of_match_leds, /* 能支持哪些来自于dts的platform_device */
}
};
static int myled_init(void)
{
platform_driver_register(&led_drv);
return 0;
}
static void myled_exit(void)
{
platform_driver_unregister(&led_drv);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
jz2440.dts
// SPDX-License-Identifier: GPL-2.0
/*
* SAMSUNG SMDK2440 board device tree source
*
* Copyright (c) 2018 weidongshan@qq.com
* dtc -I dtb -O dts -o jz2440.dts jz2440.dtb
*/
#define S3C2410_GPA(_nr) ((0<<16) + (_nr))
#define S3C2410_GPB(_nr) ((1<<16) + (_nr))
#define S3C2410_GPC(_nr) ((2<<16) + (_nr))
#define S3C2410_GPD(_nr) ((3<<16) + (_nr))
#define S3C2410_GPE(_nr) ((4<<16) + (_nr))
#define S3C2410_GPF(_nr) ((5<<16) + (_nr))
#define S3C2410_GPG(_nr) ((6<<16) + (_nr))
#define S3C2410_GPH(_nr) ((7<<16) + (_nr))
#define S3C2410_GPJ(_nr) ((8<<16) + (_nr))
#define S3C2410_GPK(_nr) ((9<<16) + (_nr))
#define S3C2410_GPL(_nr) ((10<<16) + (_nr))
#define S3C2410_GPM(_nr) ((11<<16) + (_nr))
/dts-v1/;
/ {
model = "SMDK24440";
compatible = "samsung,smdk2440";
#address-cells = <1>;
#size-cells = <1>;
memory@30000000 {
device_type = "memory";
reg = <0x30000000 0x4000000>;
};
/*
cpus {
cpu {
compatible = "arm,arm926ej-s";
};
};
*/
chosen {
bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";
};
led {
compatible = "jz2440_led";
pin = <S3C2410_GPF(5)>;
};
};