分类: LINUX
2015-09-01 17:41:37
本文的部分内容可能来源于网络,该内容归原作者所有,如果侵犯到您的权益,请及时通知我,我将立即删除,原创内容copyleft归所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。欢迎加入嵌入式交流群:3462094
本文主要介绍了以下内容,核心就是让大家了解嵌入式学习,本教程配有视频、文档,大家可以把文档下载下来,里面我的联系方式,包括视频地址等等,想看视频,可以移步到我的优酷视频空间。? 嵌入式系统介绍
? Tingkman出品
? 目录
? 1、嵌入式系统概述
? 2、嵌入式开发流程
? 3、嵌入式学习步骤及相关参考
? 4、Linux设备驱动预览
? 1、嵌入式系统概述
典型嵌入式系统 计算机
1、嵌入式系统:
以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计算机系统。
? 2、嵌入式开发流程
在介绍开发流程之前,先了解一些嵌入式系统所涉及的相关概念:
包括宿主机、目标板、交叉编译链、虚拟机、bootloader、内核、文件系统、Makefile、驱动、操作系统、上层、底层、体系结构。
嵌入式产品,与普通电子产品一样,开发过程都需要遵循一些基本的流程,都是一个从需求分析到总体设计,详细设计到最后产品完成的过程,大致流程图如下:
? 2、嵌入式开发流程
硬件设计基本上是原理图绘制、pcb绘制、发送厂家制板、板子回来后、焊接元器件、然后硬件调试,接下来就是程序下载,这个过程我们不做详细介绍。
软件设计应该是大家更关心一些,可能还不太熟悉。嵌入式linux的开发很大一部分都是在linux系统下来完成开发的,基本流程就是
编译bootloader –》编译内核-》生成文件系统-》编译应用程序
下载bootloader-下载内核-下载文件系统-下载应用程序
? 2、嵌入式开发流程
上面提到很多概念:
Bootloader:在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境,在嵌入式开发中,bootloader 还有一个功能就是下载内核和文件系统,常用的bootloader有 u-boot 、ViVi、red boot。
内核:是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能,是操作系统工作的基础,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性
文件系统:是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构;即在存储设备上组织文件的方法。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统
? 2、嵌入式开发流程
那么首先就是开发环境,也就是开发用的工具,比方说我们开发51单片机,使用的是keil软件,这个软件就算是51的开发环境,它可以编写代码,编译代码生成目标镜像下载到板子,我们使用的codewarrior 7.1、nios ide、visualdsp++ 均是相应的开发环境。那么嵌入式linux的开发环境,一般是linux,比如Ubuntu 、 Fedora、 CentOS、 Red Hat Linux。
一般开发者使用的是windows系统,但是开发linux需要linux系统,那么这时候虚拟机是一个很好的选择。
虚拟机: 虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。
在windows下使用虚拟软件虚拟一个linux系统。
编译u-boot、内核:
编译需要交叉编译链,交叉编译简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓 平台,实际上包含两个概念:体系结构(Architecture)、操作系统(Operating System)。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。举例来说,我们常说的x86 Linux平台实际上是Intel x86体系结构和Linux for x86操作系统的统称;而x86 WinNT平台实际上是Intel x86体系结构和Windows NT for x86操作系统的简称。
? 2、嵌入式开发流程
芯片厂商一般提供做好的交叉编译链,不需要我们自己去编译交叉编译链,其实,对于开发者来讲,最好自己去编译交叉编译链,这样对编译方法会有更深入的了解。
1)准备好源码、交叉编译链,准备开始编译
2)执行make 命令就可以对源码进行编译了,编译后会产生目标文件。
Makefile : 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
3)编译uboot、kernel、rootfs、应用程序 ,下载到板子上,重启,一个典型的嵌入式系统就完成了。
? 2、嵌入式开发流程
? 2、嵌入式开发流程
? 3、嵌入式学习步骤及相关参考
一、熟悉linux系统应用:命令+服务搭建(一个月)
参考视频:
IT播吧 - 寒冰老师 - 零起点学习Linux系列培训视频教程 共61集
下载地址:
参考书籍:鸟哥的linux私房菜基础学习篇
零起点学习linux系列课程计划表:
第1讲了解linux 第2讲基础操作 第3讲文件 第4讲目录
第5讲过滤器、输入输出及管道 第6讲文件查找与文件管理
第7讲vi编辑器 第8讲BASH 第9讲系统监视 第10讲用户管理
第11讲硬件配置与管理 第12讲文件系统第13讲计划任务 第14讲RPM 包及其管理 第15讲sed,awk,和其他语言 第16讲linux开机与启动
第17讲基础网络配置 第18讲服务 第19讲系统安全
第20讲网络安全 第21讲怎么使用源码安装一些软件
第22讲介绍access control list (ACL)
获取知识:linux的由来,linux 常用命令、服务搭建
? 3、嵌入式学习步骤及相关参考
二、ARM 嵌入式入门了解( 2 周)
参考书籍:
ARM 嵌入式 Linux 系统开发从入门到精通
获取知识:深入了解交叉编译链的生成、
初步了解arm体系结构、初步了解bootloader、
初步了解uboot移植、内核移植、文件系统移植
初步了解设备驱动、上层应用开发QT
? 3、嵌入式学习步骤及相关参考
三、嵌入式c语言( 1个月)
linux 基本上是由c语言编写的,所以c语言必须要
学会
参考书籍:
Linux C编程从初学到精通(华清远见)
获取知识:学会使用c语言
? 3、嵌入式学习步骤及相关参考
四、动手移植uboot、内核、文件系统( 1个月)
软件开发,实践很重要,嵌入式学习也不例外。
这里首先得有一个开发板,市面上很多,随便买个
按照里面的步骤一步一步都做做。
参考视频:
国嵌、华清远见嵌入式培训视频
获取知识:亲身体会嵌入式开发步骤。
? 3、嵌入式学习步骤及相关参考
五、linux环境高级编程(2周)
linux驱动、内核编程针对嵌入式初学者来讲是
比较难的 刚入门的也不适合我们先去学习,这个
时候建议大家先去 学习一下稍微简单的编程,那
就是linux环境高级编程
参考书籍:
unix环境高级编程
本书是被誉为UNIX编程“圣经”,可想这本书的含金量。
获取知识:linux应用编程基础,初步了解进程、线程、信号、进程间
通信、套接字等相关操作系统相关的知识和相关编程方法。
? 3、嵌入式学习步骤及相关参考
六、linux驱动(n年)
学习完高级编程后可以学习linux驱动了
参考书籍:
Linux设备驱动开发详解(宋宝华)
Linux 设备驱动程序(科波特著)简称LDD
精通Linux设备驱动程序开发
这3本书还是比较不错的,是那种可以当字典查看的书籍
获取知识:初步了解linux驱动的分类以及驱动模型、驱动 的编写方法。
? 3、嵌入式学习步骤及相关参考
五、linux内核(n年)
了解完linux驱动的同时,还要去学习linux内核,学习内核的同时,最好学习一下数据结构
参考书籍:
深入理解LINUX内核 简称ULK
深入Linux内核架构
数据结构与算法分析
获取知识:初步了解linux内核,包括进程管理和调度、内存管理、锁与进程间通信、设备驱动程序、模块、虚拟文件系统、网络、页缓存和块缓存、数据同步等等。
? 4、 Linux设备驱动预览
? 4、 Linux设备驱动预览
? 4、 Linux设备驱动预览
驱动大分类如下:
1、字符设备
2、块设备
3、网络设备
区别:
? (1) 字符设备:提供连续的数据流,应用程序可以顺序读取,通常不支持随机存取。相反,此类设备支持按字节/字符来读写数据。举例来说,调制解调器是典型的字符设备。
? (2) 块设备:应用程序可以随机访问设备数据,程序可自行确定读取数据的位置。此外,数据的读写只能以块(通常是512B)的倍数进行,与字符设备不同,块设备并不支持基于字符的寻址。
? (3)网络设备是面向数据包的接收和发送而设计的。它并不对应于文件系统(/dev目录下)的节点,而是由系统分配一个唯一的名字(如eth0)。
? 4、 Linux设备驱动预览
驱动分类子系统如下:
1、字符设备驱动程序 如:cmos ,rtc子系统,混杂设备驱动,伪字符设备
2、串行设备驱动程序 如:UART驱动程序,TTY驱动程序
3、输入设备驱动程序 如:键盘、鼠标、触摸控制器,加速度控制器、输出事件
4、I2C子系统 如:I2C核心、EEPROM、
5、SPI子系统
6、PCMCIA和CF 如: PCMCIA核心、PCMCIA卡
7、PCI
8、USB子系统 如:大容量存储设备、usb串行端口转换、蓝牙、gadget驱动
9、视频子系统 如:桢缓冲API及驱动程序、控制台驱动程序
10、音频子系统 如:MP3
11、块设备驱动程序
12、网络接口卡驱动
13、无线设备驱动 如:蓝牙、红外、wifi、蜂窝网络
14、存储技术设备 如:NORFLASH、NANDFLASH、MTD子系统
15、其他 如:ACPI、ISA、MCA、火线、智能输入\输出
业余无线电、VOIP、高速互联
? 4、 Linux设备驱动预览
驱动实例:
Linux驱动程序都是以模块的形式存在的,所以我们称之为驱动模块。
字符设备驱动(最简单的驱动)
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("leander");
#define MINIOR_NUM 0
#define DEVICE_SUM 1
#define MAJOR_NUM 254 /* major device number */
#define MINOR_NUM 0 /* minor device number */
static int globalvar_open(struct inode *inode, struct file *filp);
static int globalvar_release(struct inode *, struct file *filp);
static ssize_t globalvar_read(struct file*, char*, size_t, loff_t*);
static ssize_t globalvar_write(struct file*, const char*, size_t, loff_t*);
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
/* the major device number */
static int globalvar_major = MAJOR_NUM;
static int globalvar_minor = MINOR_NUM;
/* init the file_operations structure */
struct file_operations globalvar_fops =
{
.owner = THIS_MODULE,
.open = globalvar_open,
.release = globalvar_release,
.read = globalvar_read,
.write = globalvar_write,
};
/* define a cdev device */
struct cdev *cdev;
static int global_var = 0; /* global var */
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
/* module init */
static int __init globalvar_init(void)
{
int ret = 0;
dev_t devno = MKDEV(MAJOR_NUM, MINOR_NUM);
cdev = cdev_alloc();
/* register the device driver */
/*ret = alloc_chrdev_region(MAJOR_NUM, "globalvar", &globalvar_fops);*/
if(register_chrdev_region(devno, DEVICE_SUM, "globalvar"))
{
/* register fail, so use automatic allocate */
if(alloc_chrdev_region(&devno, globalvar_minor, DEVICE_SUM, "globalvar"))
printk("globalvar register failure.\n");
globalvar_major = MAJOR(devno);
}
else
{
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
/*
* cdev_init should be use if use the way of static statement.
* struct cdev cdev;
* cdev_init(&cdev, &globalvar_fops);
* cdev.owner = THIS_MODULE;
*
* if using dymatic allocation.
* struct cdev *cdev;
* cdev = cdev_alloc();
* cdev->owner = THIS_MODULE;
* cdev->ops = &globalvar_fops;
*/
cdev->owner = THIS_MODULE;
cdev->ops = &globalvar_fops;
if ((ret = cdev_add(cdev, devno, 1)))
printk(KERN_NOTICE "Error %d adding globalvar.\n", ret);
else
printk("globalvar register success.\n");
}
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
return ret;
}
/* module exit */
static void __exit globalvar_exit(void)
{
dev_t devno = MKDEV(globalvar_major, 0);
/* remove cdev from kernel */
cdev_del(cdev);
/* unregister the device driver */
unregister_chrdev_region(devno, 1);
/* free the dev structure */
if(cdev)
kfree(cdev);
cdev = NULL;
}
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
/* open device */
static int globalvar_open(struct inode *inode, struct file *filp)
{
int ret = 0;
printk("open success.\n");
return ret;
}
/* release device */
static int globalvar_release(struct inode *inode, struct file *filp)
{
printk("release success.\n");
return 0;
}
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
/* read device */
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
printk("reading...\n");
if(copy_to_user(buf, &global_var, sizeof(int)))
{
return -EFAULT;
}
return sizeof(int);
}
/* write device */
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
printk("writing...\n");
if(copy_from_user(&global_var, buf, sizeof(int)))
{
return -EFAULT;
}
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
return sizeof(int);
}
/* module register */
module_init(globalvar_init);
module_exit(globalvar_exit);
2、Makefile文件
#
# Makefile -- for driver
#
module=globalvar
ifneq ($(KERNELRELEASE),)
obj-m := ${module}.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -f *.o *.ko *.mod.c *~
insmod:
sudo insmod ${module}.ko
dmesg | tail
rmmod:
sudo rmmod ${module}
dmesg | tail
endif
3、测试程序
/*
* test.c -- a test file for globalvar reading and writing
*/
#include
#include
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
int main(void)
{
int fd, num;
/*打开"/dev/globalvar"*/
fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);
if (fd != -1 )
{
/*初次读globalvar*/
read(fd, &num, sizeof(int));
printf("The globalvar is %d\n", num);
/*写globalvar*/
printf("Please input the num written to globalvar\n");
scanf("%d", &num);
write(fd, &num, sizeof(int));
/*再次读globalvar*/
read(fd, &num, sizeof(int));
printf("The globalvar is %d\n", num);
/*关闭"/dev/globalvar"*/
close(fd);
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
else
{
/* if not sudo, maybe come here */
printf("Device open failure\n");
}
return 0;
}
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
模块入口函数:
module_init(globalvar_init);
模块退出函数:
module_exit(globalvar_exit);
模块操作函数: struct file_operations globalvar_fops =
{
.owner = THIS_MODULE,
.open = globalvar_open,
.release = globalvar_release,
.read = globalvar_read,
.write = globalvar_write,
};
上层应用编程:上面的测试程序
使用 fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);
会调用模块的globalvar_open
写函数write(fd, &num, sizeof(int))会调用globalvar_write
读函数read(fd, &num, sizeof(int));会调用globalvar_read
? 4、 Linux设备驱动预览
驱动实例:
字符设备驱动(最简单的驱动)
上面这样一个简单的驱动程序实现了我们平时编程的习惯,
Open read write
要实现一个字符设备驱动,就要实现上面驱动所使用的相关函数,这些函数,都需要我们平时记忆。
打个比方说,module_init(globalvar_init);函数难度相当于1+1=2
一个字符设备驱动就相当于 2+3=5一样
可以想象,还有很多其他驱动程序,都有各自的规则和函数,而且复杂度远高于这个字符设备,
驱动程序各自的规则和函数,理解起来需要时间,上面的字符设备驱动程序还没有涉及硬件,驱动程序的规则和硬件设备各自的特性这两个方面,是它不能在短时间学习的主要原因。