《linux应用开发完全手册》核心笔记(全)

xiaoxiao2021-02-28  112

** 本文未附任何实例代码,基于目标板的不同操作不尽相同,网络资源针对比较成熟的开发板均可找到对应的成套实例代码【开发环境构建】 1. 开发环境搭建:操作系统或虚拟机Ubuntu安装、网络服务配置、工具安装等     工具资源<云盘>:https://pan.baidu.com/s/1bpakJtP   // env/嵌入式linux软件开发环境(不定期更新)     步骤整理<博客>:http://blog.csdn.net/sinat_36184075/article/details/71194832 2. 编程基础内容:交叉编译使用、Makefile规则、常用汇编指令     交叉编译工具链制作<博客>:http://blog.csdn.net/sinat_36184075/article/details/71195114     Makefile编写<博客>:http://blog.csdn.net/sinat_36184075/article/details/54917518     汇编指令快速查询<博客>:http://blog.csdn.net/sinat_36184075/article/details/55819869 3. 常用工具使用:     windows下工具的使用(SourceInsight、SecureCRT、keil、IAR等)     linux下工具的使用(tftp、nfs、vi、man手册、基本命令行命令及grep/find/tar/diff/patch等)     // 常用工具上手简单,可自查。【ARM9嵌入式系统基础】 1. GPIO接口 1) 嵌入式开发步骤:     编程:主要以.c .h文件为主;     编译:make命令调用Makefile中写好的交叉编译规则来编译出.bin二进制文件;     烧写:PC并口与JTAG连接或PC的USB与串口连接,使用对应的工具和命令烧写;     运行测试:命令运行或复位开发板,观察运行效果。 2) 通过GPIO引脚实现软件如何控制硬件:     单个引脚的操作有3种:输出高低电平、检测引脚状态、中断;     对某个引脚的操作通过读、写寄存器来实现;     读写寄存器方法:通过编程程序,读写寄存器的地址;     // 需结合2点:目标板电路图(确定引脚)、ARM芯片手册Datasheet(操作说明) 2. 存储控制器 1)目标板地址空间布局:     32位CPU虚拟地址4G,其中1G为CPU内核空间,3G为用户空间;    // 1G:0x0000_0000 ~ 0x4000_0000     // 3G:0x4000_0000 ~ 0xFFFF_FFFF     // 表:目标板功能部件与寄存器地址对照表     // 表:存储控制器与所接外设的访问地址对照表 3. 内存管理单元MMU 1) 虚拟地址和物理地址关系     MMU:负责虚拟地址到物理地址的映射,提供硬件机制的内存访问权限检查。     通过MMU使得各个用户进程都有自己独立的地址空间。     ARM的CPU上地址转换有3个概念:虚拟地址VA、变换后的虚拟地址MVA、物理地址PA。     没启动MMU时,CPU、cache、MMU、外设等所有部件使用的是物理地址;     启动MMU之后,CPU对外发出虚拟地址VA,VA被转换为MVA供cache、MMU使用,MVA在这里被转换为PA,最后使用PA读写实际的硬件设备(内部寄存器或外接设备)。     CPU核看到的、用到的只是虚拟地址VA。实际设备看不到VA和MVA,读写他们时使用的是物理地址PA。 2) 通过设置MMU来控制虚拟地址到物理地址的转化     虚拟地址VA >> 物理地址PA 方法有2:用一个确定的数学公式转换、用表格存储虚拟地址对应的物理地址(表格:页表Page Table)。     页表:由一个个条目(Entry)组成,每个条目存储了一段VA对应的PA及其访问权限,或者下一页表的地址。     ARM的CPU核使用的是第二种方法:页表。 3) MMU的内存访问权限机制     内存的访问权限检查是MMU的主要功能之一,决定了一块内存是否允许被读或被写。    // 表:AP位、S、R位的访问权限对照表 4. Nand Flash控制器 1) Nand Flash芯片接口     类似于PC上的硬盘,掉电不丢失,保存系统运行所必须的操作系统、应用程序、用户数据、其他数据等。     容量:16M~512M     与Nor Flash相比优点:Nand Flash性能高即擦写速度快3ms、可擦写次数多、生命周期10倍以上、容量大、价格低。     与Nor Flash相比缺点:Nand Flash可靠性较低必须要有校验措施、易用性不如Nor Flash、不支持XIP(XIP:代码可以直接在Nor Flash上运行,无需加载到内存)。     Flash存储器件的可靠性要考虑3点:位反转、坏块、可擦除次数。     Nand Flash发生位反转的概率更高,推荐使用EDC/ECC进行错误检测和恢复。     嵌入式linux对两种Flash的支持都很成熟,在Nor Flash上常用jffs2文件系统,在Nand Flash上常用yaffs文件系统。在更底层,有MTD驱动程序实现了对他们的读、写、擦除操作,也实现了EDC/ECC校验。 2) 通过Nand Flash控制器访问Nand Flash的方法     对Nand Flash进行访问控制时,需要先发出命令,然后发出地址序列,最后读写数据;需要使用各个使能信号来分辨是命令、地址、还是数据。 5. 中断体系结构 1) ARM的CPU中7种工作模式     用户模式usr、快速中断模式fiq、中断模式irq、管理模式svc、数据访问终止模式abt、系统模式sys、未定义指令终止模式und。     大多数程序运行与用户模式usr,进入其他6种特权模式是为了处理中断、异常、或者访问被保护的系统资源。     ARM的CPU中有两种工作状态:32bit的ARM指令、16bit的Thumb指令。     ARM9中有31个32bit寄存器 + 6个状态寄存器 = 37个寄存器。 2) 中断服务程序编写方法     CPU运行过程中,知道各类外设发生了某些事件如串口接收到了新数据、USB接口插入了设备、按下了某个按键等,主要通过2种方法:     轮询:循环检查设备状态并作出相应反应。实现简单,常用在功能单一的系统中,如温控系统;缺点是占用CPU资源过高,不适用于多任务系统;     中断:当某时间发生时,硬件会设置某个寄存器,中断当前程序,跳转执行此事件,最后返回被中断的程序。实现相对复杂,但效率很高,是常用的方法。     使用中断的步骤:     ①设置好中断模式和快速中断模式下的栈;     ②准备好中断处理函数(ISR);     ③设置中断优先级;     ④进入、退出中断模式或快速中断模式时,需要保存、恢复被中断程序的运行环境;     ⑤根据具体中断,设置相应外设;     ⑥确定使用此中断的方式:FIQ或IRQ;     ⑦使能中断。 6. 系统时钟和定时器 1) 系统时钟体系结构     时钟控制逻辑给整个芯片提供三种时钟,     FCLK:用于CPU核;     HCLK:用于AHB总线(用高性能模块的连接)上的设备,如CPU核、存储器控制、中断控制器、LCD控制器、DMA和USB主机模块等;     PCLK:用于APB总线(用于低带宽外设的连接)上的设备,如IIS、I2C、PWM定时器、MMC接口、ADC、UART、GPIO、RTC和SPI; 2) 通过设置MPLL改变系统时钟的方法     ①设置分频/倍频     ②启动MPLL     ③设置存储控制器SDRAM     ④初始化定时器0     ⑤定时器0中断使能及中断服务程序 7. 通用异步收发器UART 1) UART原理     全双工方式串行双向数据收发。     通信管脚跳线接线方式:     RxD <=> TxD     TxD <=> RxD     GND <=> GND     RS232逻辑电平:高电平(3~12V)表示0,低电平(-3~-12V)表示1。     重要参数:     >>数据位个数: 5 ~ 8 bit   (开发板那端定好的是 8 bit / 帧数据)     >>验证方式:奇校验、偶校验、无校验     >>停止位宽度:1~2bit     >>通信的速率:bps (bit per second - 每秒传输bit位,即波特率)     数据收发原理:     发送数据时,CPU先将数据写入发送FIFO中,然后UART会自动将FIFO中的数据复制到发送移位器(TS)中,发送移位器将数据一位一位的发送到TxDn数据线上。     接收数据时,接收移位器(RS)将RxDn数据线上的数据一位一位的接收进来,然后复制到接收FIFO中,CPU即可从中读取数据。 2) UART使用     ①将所涉及的UART通道管脚设为UART功能     ②设置波特率     ③设置传输格式     ④设置时钟源、中断方式(或DMA模式)     ⑤发送数据:往寄存器写入;接收数据:从寄存器读取     ⑥UTRSTATn状态寄存器检测数据是否发送完毕、是否接收到数据     结合PC上的串口工具windows下SecureCRT工具,linux下kermit(Page195)工具进行测试。 8. I2C接口 1) I2C总线协议     飞利浦公司开发的串行总线,连接微控制器及其外围设备。     两条总线:SDA数据线,SCL时钟线。         多主机总线。         主从设备通信方式。         主机收发均可。         多主机冲突仲裁。         8bit双向数据传输,100kbit/s,400kbit/s,3.4Mbit/s。         从设备地址唯一。     三种类型信号:开始(S)、响应(ACK-8bit后的第9个时钟周期拉低SDA电平)、结束(P)     数据传输格式:     master:--S--从addr|W---接ACK---0x0d---接ACK---SR---从地址|R---接ACK---收---NACK---T--     slave: --------接---------发ACK-----接---发ACK-----------接-------发ACK--- 2) I2C接口使用     ①I2C控制器初始化     ②主机发送函数     ③主机接收函数     ④中断服务程序i2c_Handle:清中断、写操作、读操作 9. LCD控制器 1) LCD显示器的接口及时序     LCD,液晶显示器。     CPU或显卡发出的信号时TTL信号,LCD本身接收的也是TTL信号。     LCD控制器被用来传输LCD图像数据,并提供必要的控制信号。     1幅图像为1帧frame。显示器从屏幕左上角,一行行的取得每个像素的数据并显示,沿着Z字形的路线进行扫描。     分辨率:有效像素数据的 行数 × 列数。 2) LCD控制器的使用方法     ①main.c 提供菜单以选择不同的显示模式来操作LCD     ②lcdlib.c 条用以下两个文件的函数操作LCD     ③lcddrv.c 设置LCD控制器、调色板     ④framebuffer.c 画点、画线、画同心圆、清屏 10. ADC和触摸屏接口 1) ADC和触摸屏结构     ADC,数模转换。可以将模拟信号输入转换为二进制数据。    // 图:ADC和触摸屏接口结构图 2) ADC和触摸屏的使用方法     ADC启动方法:手工启动、读结果时就自动启动下一次转换;     是否已经结束:查询状态位、转换结束时发出中断。     ADC操作只涉及三个寄存器:ADCCON、ADCTSC、ADCDAT0。     ①设置ADCCON寄存器,选择输入信号通道,设置A/D转换器时钟;     ②设置ADCTSC寄存器,使用设为普通转换模式,不适用触摸屏功能;     ③设置ADCCON寄存器,启动A/D转换;     ④转换结束时,读取ADCDAT0寄存器获得数值。    // 拓展:电阻触摸屏原理(Page241)

【嵌入式linux系统移植】 1. 移植u-boot 1) bootloader作用及工作流程     作用:一小段程序,在系统上电时开始执行,初始化硬件设备、准备好软件环境、最后调用操作系统内核。     也可以增强bootloader的功能,如增加网络功能、从PC上通过串口或网络下载文件、烧写文件、将Flash上压缩的文件解压后再运行等,强大的bootloader也叫Monitor。     工作过程:仅对开发人员使用,在开发时通常需要各种命令操作bootloader,一般通过串口工具连接pc和目标板,可以在串口上输入各种命令,观察运行结果。     嵌入式linux系统通常分为4个层次:bootloader、kernel、filesystem、Application     bootloader启动流程分为两个阶段:     第一阶段:         1>硬件设备初始化         2>为bootloader第二阶段准备RAM空间         3>复制bootloader第二阶段代码到RAM中         4>设置好栈         5>跳转到第二阶段代码的C入口点     第二阶段:         1>初始化本阶段要使用到的硬件设备         2>检测系统内存映射         3>将内核映像和根文件系统映像从Flash上读到RAM空间中         4>为内核设置启动参数         5>调用内核     u-boot是通用的bootloader,支持平台包括X86、ARM、PowerPC。 2) u-boot代码结构及编译过程     u-boot开源源码官方ftp下载地址:ftp://ftp.denx.de/pub/u-boot/     以u-boot-1.1.6为例,根目录下有26个子目录,可以分为4类:         1>平台相关(cpu/ lib_i386/)或开发板相关(board/)的;         2>通用的函数(include/ lib_generic/ common/);         3>通用的设备驱动程序(disk/ drivers/ dtt/ fs/ nand_spl/ net/ post/ rtc/);         4>u-boot工具(tools/)、示例程序(examples/)、文档(doc/)。     从readme和Makefile入手,根据目标开发板的名字board_name,通常执行2步进行编译:         1> $:' make <board_name>_config             // 配置对应目标板的配置文件         2> $:' make all             // 编译,生成u-boot.bin、u-boot、u-boot.srec三个文件     注意:tools/目录下生成的mkimage文件,在编译内核时用来生成u-boot格式的内核映像文件。 3) 移植u-boot流程     使用网卡芯片硬件,tftp服务器软件进行移植:     1> 配置开发板ip地址,服务器地址的环境变量     2> 使用tftp命令进行指定起始地址位置下载u-boot.bin文件     3> 修改相关文件使bootloader支持内核烧写、yaffs根文件系统移植;     4> 修改默认配置参数方便使用,如linux启动参数、自动启动命令、默认网络设置     (Page302) 4) 常用u-boot命令     help:查看所有u-boot中的命令及其作用,也可以help [命令]查看单个命令;也可以用?代替help进行执行。     下载命令:loadb、loads、loadx、loady和tftpboot、nfs         如loadb [off] [baud]         如tftpboot [loadAddress] [bootfilename]         如nfs [loadAddress] [host ip addr:bootfilename]     内存操作命令:         查看内存命令:md,如md[.b,.w,.l] address [count]         修改内存命令:mm         填充内存命令:mw         复制内存命令:cp     Nor Flash操作命令:         查看Flash信息:flinfo         加/解写保护命令:protect         擦除命令:erase     Nand Flash操作命令:         nand命令,根据不同的参数进行不同的操作,如擦除、读取、烧写。     启动命令:         boot、bootm命令都是执行环境变量bootcmd所指定的命令。 2. 移植linux内核 1) 内核源码结构,内核启动过程     获取内核源码:https://www.kernel.org/     下载、解压得到linux内核源码文件。     // 表:linux内核子目录结构     Makefile:顶层的Makefile是所有Makefile文件的核心,总体控制内核的编译和连接。     .config:配置文件,配置内核时产生。所有Makefile文件都是根据.config来决定使用哪些文件来编译。     Linux内核启动过程:         开始→确定内核是否支持该架构→确定内核是否支持该单板→建立一级页表→禁止ICache等→使能MMU→设置栈指针并调用start_kernel→输出linux版本信息→设置与体系结构相关的环境→初始化控制台→启动init进程 2) 内核配置方法     $:' make menuconfig     System Type:系统类型子菜单,用来选择目标板类型。(Page324)     Device Drivers:设备驱动程序子菜单。(Page327) 3) 移植内核     配置内核→编译内核→烧写内核→启动内核 4) MTD设备分区方法     MTD,内存技术设备,是Linux中ROM、Nor Flash、Nand Flash等存储设备抽象出来的一个设备层。     分区方法:修改arch/arm/plat-s3c24xx/common-smdk.c文件中的smdk_default_nand_part结构即可。 5) yaffs根文件系统移植     yaffs,专门为Nand Flash设计的嵌入式文件系统,适用于大容量的存储设备。     移植(Page346) 3. 构建linux根文件系统 1) linux文件系统层次标准     FHS文件系统层次标准:http://www.pathname.com/fhs/ 2) 根文件系统下各目录的作用     /bin 目录:存放所有用户都可以使用的、基本的命令。     /sbin 目录:存放系统命令,即只有管理员能够使用的命令,用于启动系统、修复系统等。     /dev 目录:存放设备文件(字符设备、块设备)。(Linux下一切皆文件)     /etc 目录:存放各种配置文件。     /lib 目录:存放共享库和可加载模块(即驱动程序)。     /home 目录:用户目录,是可选的。目录下是以用户名命名的子目录。     /root 目录:根用户(root)目录,普通用户即为/home下的子目录。     /usr 目录:存放共享、只读的程序和数据。     /var 目录:存放可变的数据,与/usr内容相反。     /proc 目录:空目录,常作为proc文件系统的挂载点,proc文件系统是个虚拟的文件系统。     /mnt 目录:空目录,用于临时挂载某个文件系统的挂载点,如U盘、光盘等。     /tmp 目录:空目录,用于存放临时文件。 3) 构建根文件系统:移植Busybox、构造各个目录/文件等     Busybox开源工具下载地址:https://busybox.net/downloads/     下载、解压、开始配置:         // 表:Busybox配置选项分类(Page362)     配置完成、编译:make     安装并拷贝glibc库。     构建根文件系统:(Page367)         1> 创建etc/initab文件         2> 创建etc/init.d/rcS脚本文件         3> 创建etc/fstab文件(控制mount命令行为)         4> 构建dev/目录         5> 构建其他目录,如proc/ mnt/ tmp/ sys/ root/等 4) 制作yaffs、jffs2文件系统映像文件     yaffs根文件系统:Page367     jffs2根文件系统:Page375     烧写... 4. linux内核调试技术 1) 几种调试内核的方法:printk、kgdb     【printk】调试驱动、内核最简单的方法,使用printk打印信息。与用户空间的printf函数格式完全相同。可在字符串内的头部加入<n>(0~7)表示记录级别。     printk信息常常用于串口输出,这时串口被称为串口控制台。     使用u-boot时,设置了命令行参数"console=ttySAC0",它使得printk的信息从串口0中输出。     系统启动后,查看printk信息,直接运行dmesg命令即可。     【kgdb】源码级别的linux内核调试器。使用kgdb时,需要结合gdb一起使用,使得调试内核就像调试应用程序一样,可在内核代码中设置断点、一步一步执行、观察变量的值。     内核需要添加kgdb补丁才可以使用kgdb调试。     kgdb补丁下载地址:http://kgdb.cvs.sourceforge.net/kgdb/kgdb-2/?pathrev=linux2_6_22_uprev     使用cvs工具下载:(Page382)     $:' cd /work/debug     $:' cvs -z3 -d:pserver:anonymous@kgdb.cvs.sourceforge.net:/cvsroot/kgdb co -p -r linux2_6_22_uprev kgdb-2     ...     配置内核,使能kgdb功能。     集合可视化图形前端ddd和gdb来调试。 2) 调试工具:gdb、ddd     【ddd】ddd调用gdb来调试内核,可以在图形界面上完成调试工作。     安装ddd:$:' sudo apt-get install ddd     调试方法(Page388)【嵌入式linux设备驱动开发】 1. 字符设备驱动程序 1) linux系统中驱动程序的地位和作用     从下到上,一个软件系统能够运行的结构:硬件 → 驱动程序 → 操作系统(内核) → 库 → 应用程序     linux驱动程序分类:字符设备、块设备、网络接口。     编写驱动程序注意点:         1> 驱动程序可能同时被多个程序使用,考虑并发问题;尽可能发挥硬件作用以提高性能。         2> 硬盘驱动程序中使用DMA也可以不用,使用DMA的程序比较复杂,但是可以提高效率。         3> 处理硬件的各种异常情况,即使概率很低,否则出错时可能导致整个系统崩溃。 2) 驱动程序开发一般流程     1> 查看原理图、数据手册,了解设备的操作方法;     2> 在内核中找到相近的驱动程序,以它为模板进行开发,有时候需要从0开始;     3> 实现驱动程序的初始化:比如向内核注册这个驱动程序,这样应用程序传入文件名时,内核才能找到相应的驱动程序;     4> 设计所要实现的操作,比如open、close、read、write等函数;     5> 实现中断服务(中断并不是每个设备驱动所必须的);     6> 编译该驱动程序到内核中,或者使用insmod命令加载;     7> 测试驱动程序。 3) 简单字符设备驱动程序开发方法     字符设备驱动程序操作函数集合,在结构体: struct file_operations {...}     调用哪个驱动程序的操作函数集合中的函数呢?         1> 设备文件有主/次设备号;         2> 模块初始化时,将主设备号与file_operations结构一起向内核注册;     编写字符设备驱动程序的流程:         1> 编写驱动程序初始化函数;         2> 构造file_operations结构中要用到的各个成员函数。     常用的操作函数集合中的函数:open、ioctl、write、read...     驱动程序编译:将.c文件放入内核的driver/char目录下,在driver/char/Makefile中增加对应模块编译的一个语句(obj-m +=...),然后在内核的根目录下执行命令make modules,就可以生成对应的.ko驱动程序模块文件。     驱动程序测试(Page409)。 2. 异常处理体系结构 1) linux异常处理体系结构     init/main.c中内核在start_kernel函数中调用trap_init和init_IRQ两个函数来设置异常的处理函数。     trap_init() 函数(arch/arm/kernel/traps.c)被用来设置各种异常的处理向量,包括中断向量。     init_IRQ() 函数(arch/arm/kernel/irq.c)被用来初始化中断的处理框架,设置各种中断的默认处理函数。当发生中断时,中断总入口函数asm_do_IRQ就可以调用这些函数做进一步处理。     常见异常分类5种:未定义指令异常、指令预取中止异常、数据访问中止异常、中断异常、swi异常。 2) 中断处理体系结构及重要的数据结构     linux内核将所有的中断统一编号,使用一个结构数组来描述这些中断: struct irq_desc {...}     其中结构体成员 handle_irq 是这个或这组中断的处理函数入口。 3) 中断处理函数的注册、处理、卸载流程     初始化中断处理体系结构函数: init_IRQ (void);     用户向内核注册中断处理函数的函数: request_irq (...);     中断的C语言总入口函数: asm_do_IRQ (...);     用户从内核注销中断处理函数的函数: free_irq (...); 4) 驱动程序中使用中断的方法     按键驱动使用中断方式实现的实例。 3. 扩展串口驱动程序移植 1) 串口终端设备驱动程序的层次结构     串口驱动程序从上到下分为4层:终端设备层、行规程、串口抽象层、串口芯片层、(硬件)。 2) 移植标准串口驱动程序的方法(Page438) ...更多内容详见《嵌入式linux应用开发完全手册》:

链接:https://pan.baidu.com/s/1BFVbE4k03GzZb8Bothys6w  提取码:jns1

转载请注明原文地址: https://www.6miu.com/read-66283.html

最新回复(0)