1.开发环境搭建:
系统:ubuntu16.04
1.1:SSH环境搭建
这里我是用的是使用buildroot制作的最小文件系统,在选项里把SSH服务勾上,制作得到具备SSH功能的文件系统。这里大家可以自行搜索,或者开发板自带文件系统已经有SSH功能可以略过。
1.1.1搭建网络
设备:win10笔记本,网线,iMX6uL/ULL,网线转接口(轻薄本无法直接连接网线)
第一步:共享主机网络(我这里共享的是无线网卡)
这里选择以太网4是因为我开发板的网卡适配器就是以太网4,大家这里这里根据实际选择。
第二部:设置开发板适配器的静态IP
配置iPv4属性,IP地址可以随便填,只要不冲突(双击适配器看详细信息,如果出现两个IPv4说明IP冲突,需要更改),注意这里的IP前3段需要跟主机的相同,也就是所谓的同一网段,这里大家可以查看自己的无线网IP
这里可以看出我的网段就是192.168.31.xx ,所以开发板适配器只要网段一致即可。
开发板使用 命令设置静态IP,例如我的地址设为192.168.31.20:
ifconfig eth0 192.168.31.20 up //eth0可根据实际更改
配置好后,win10与开发板互ping
注意不要ping win10的无线网卡。
1.1.2开发板配置SSH
终端输入 vi /etc/ssh/sshd_config (注意这里一定是SSHD_config,sshh后面有个d不要改错)
将登录密码选项改掉:
改为
permitRootLogin yes :
否则win10登录将被拒。
配置好后,键入命令
/etc/init.d/S50ssh restart //这里的ssh的文件名字可能不一样,但是都在init.d这个目录下,自己找到
这里用到的的软件是L:
连接192.168.31.20,连接成功就可以在win10十分轻松拖动文件到开发板运行。
把文件拖到这里就可以同步在开发板,是不是很方便。
1.2:linux内核编译,与设备树移植
为了方便大家编译设备树源码,本章节将介绍如何编译 imx6ull 设备树源码。
第一步设置交叉编译环境
1 Ubuntu14.04(参考用户手册或者入门视频教程,关于搭建编译环境的部分)
输入以下命令安装设备树编译器,如下图所示:
apt-get install device-tree-compiler
2 下载 uboot 和内核的源码和编译器,源码是 linux-imx-rel_imx_4.1.15_2.1.0_ga_20200611.tar.gz,编译器是gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
3 编译器的安装和设置环境变量
拷贝 gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz 到 Ubuntu“/usr/local/arm/”目录下,然
后输入以下命令解压,如下图所示:
tar -vxf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
拷贝内核源码到 Ubuntu 上并解压,进入解压源码“linux-imx-rel_imx_4.1.15_2.1.0_ga”目录下,输入以
下命令设置临时环境变量(注意,设置临时环境变量后,此终端窗口不能关闭,关闭了的话,设置的临时
环境变量就失效了),如下图所示
导入环境变量//
export ARCH=arm //指明系统架构
export CROSS_COMPILE=arm-linux-gnueabihf-
//这里大家灵活变通,交叉编译链能用就行
第二步 编译命令
设置好环境变量后,在“linux-imx-rel_imx_4.1.15_2.2.0_ga”目录下,输入 kernel 和设备树一起编译的
命令,如下图所示:
cp arch/arm/configs/imx_v7_defconfig .config
./create.sh
create.sh的脚本代码:
#!/bin/bash
export ARCH=arm
#export CROSS_COMPILE=/usr/local/arm/gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12/fsl-linaro-toolchain/bin/arm-none-linux-gnueabi-
export CROSS_COMPILE=arm-linux-gnueabihf-
#make mrproper # means CLEAN
make imx_v7_defconfig
#if [ "$1" = "nand" ]
#then
# cp arch/arm/boot/dts/imx6ul-14x14-evk_nand.dts arch/arm/boot/dts/imx6ul-14x14-evk.dts
#else
# cp arch/arm/boot/dts/imx6ul-14x14-evk_emmc.dts arch/arm/boot/dts/imx6ul-14x14-evk.dts
#fi
make uImage LOADADDR=0x10008000 -j8
make modules
make topeet_emmc_4_3.dtb
make topeet_emmc_5_0.dtb
make topeet_emmc_7_0.dtb
make topeet_emmc_1024x600.dtb
make topeet_emmc_9_7.dtb
make topeet_emmc_10_1.dtb
make topeet_emmc_hdmi.dtb
make topeet_nand_4_3.dtb
make topeet_nand_5_0.dtb
make topeet_nand_7_0.dtb
make topeet_nand_1024x600.dtb
make topeet_nand_9_7.dtb
make topeet_nand_10_1.dtb
make topeet_nand_hdmi.dtb
cd ./arch/arm/boot/dts/
./create_dtb imx6ul_topeet_nand.dtb topeet_nand_4_3.dtb topeet_nand_7_0.dtb topeet_nand_10_1.dtb topeet_nand_1024x600.dtb topeet_nand_5_0.dtb topeet_nand_9_7.dtb topeet_nand_hdmi.dtb
arch/arm/configs/imx_v7_deconfig 是 默 认 的 编 译 配 置 文 件 , 如 果 修 改 内 核 配 置 文 件 , 需 要 覆 盖 掉
arch/arm/configs/imx_v7_deconfig,才能编译成功。我们需要在内核源码目录下面输入命令
cp arch/arm/configs/imx_v7_defconfig .config
export ARCH=arm
make menuconfig
我们在图形化界面配置驱动后,然后我们将系统默认配置文件arch/arm/configs/arch/arm/configs/imx_v7_defconfig备份为arch/arm/configs/imx_v7_defconfigbak
,输入以下命
令:
cp arch/arm/configs/imx_v7_defconfig arch/arm/configs/imx_v7_defconfigbak
我们再将根目录上配置好的.config 覆盖原来的配置文件,输入以下命令:
cp .config arch/arm/configs/imx_v7_defconfig
现在我们现在配置好的.config 变成了我们配置的默认文件,返回到我们的内核根目录下,运行我们的
脚本
./create.sh
编译完成如下图所示
第三步生成的镜像目录
内核镜像:”arch/arm/boot”目录下生成“zImage”文件
设备树镜像:“arch/arm/boot/dts”目录下生成设备树文件
最后将所有烧写到开发板。
成功进入系统后,再重新配置下SSH服务。
驱动编写与编译
Linux 下的应用程序是如何调用驱动程序的?
Linux 设备驱动会以内核模块的形式出现,因为 linux 内核的整体架构就非常庞大,包含的组件也非常多,
如果把所有的功能都编译到 linux 内核中会使得内核非常臃肿,为了解决这个问题,更方便地新增和删除功
能,linux 提供了这样的机制,这种机制被称为模块。为了大家对模块有一个感性的认识,我们先来看一个
最简单的驱动-helloworld。
驱动分为四个部分:
头文件
驱动模块的入口函数和出口函数
声明信息
功能实现
我们在 windows 上面新建一个 helloworld.c 文件,这里使用 sourceinsight 来编辑文件,大家也可以用其
他编译器来编写程序。
第一步 包含头文件
#include <linux/init.h> //包含宏定义的头文件
#include <linux/module.h> //包含初始化加载模块的头文件
第二步 驱动模块的入口函数和出口函数
module_init();
module_exit();
第三步 声明模块拥有开源许可证
MODULE_LICENSE("GPL");
第四步 功能实现:内核模块加载的时候打印 hello world! ,内核模块卸载的时候打印 gooodbye!
注意:内核打印函数不能用 printf,因为内核没有办法使用 C 语言库。
static int hello_init(void){
printk("hello world! \n");
return 0;
}
static void hello_exit(void){
printk("gooodbye! \n");
}
完整的一个最简单的 Linux 内核模块,如下图所示。
大致流程如图,但先不必深究,我们现在只需要知道需要两个函数。`
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int hello_init (void)
{
printk("hello word!\n");
return 0;
}
static void hello_exit(void)
{
printk("bye bye !\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL"); //版本申明
写好代码后将代码放在内核源码下进行编译。
代码编译:
创建Makefile文件
obj-m += helloworld.o //先写生成的中间文件的名字是什么,-m 的意思是把我们的驱动编译成模块
KDIR:=/home/topeet/driver/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga/
PWD?=$(shell pwd) //获取当前目录的变量
all:
make -C $(KDIR) M=$(PWD) modules //make 会进入内核源码的路径,然后把当前路径下的代码编译成
模块
注意:
1 KDIR:=/home/topeet/driver/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga/是设备树内核的源码路径,请大家根
据自己的实际情况进行修改。
2 设备树内核源码一定要先编译通过,才能编译驱动,否则会报错。
3 make -C 前面的空格是一个 tab 键
设置交叉编译器,输入以下命令:
export CROSS_COMPILE=arm-none-linux-gnueabi-
export ARCH=arm
编译它会产生 helloworld.ko 目标文件,如下图所示
使用SSH传输到开发板即可。
使用命令:
insmod hello.ko//挂载
rmmod hello //卸载
第一个驱动成功,麻雀虽小五脏俱全,理解这个简单的驱动就一通百通了。