开发环境 linux
Realview mdk ARM开发工具
Eclipse java开发工具
Android sdk 安卓软件开发工具
H-JTAG 烧写工具
嵌入式开发环境的搭建:
命令行:
1,sudo apt-get install build-essential 基本的开发环境
2,sudo apt-get install bison flex 安装bison,flex分别是语法,词法分析器
3,sudo apt-get install manpages-dev 安装c函数库的man手册
http://www.kernel.org/
http://www.arm.linux.org.uk/
http://gcc.gnu.org/
http://sourceware.org/gdb/download/
http://www.busybox.net/
http://www.linux-mtd.infradead.org/index.html
Makefile文件: 编译规则
安装交叉编译器:
toolchains_for_s3c2410.tar.bz2
基于gcc和glibc来制作工具链,可使用crosstool来进行编译
基于gcc和uClibc来制作工具链,可以使用bulidroot来进行编译
gcc编译成共享库:
gcc –shared –fpic –o libtest.so libtest.c
cp libtest.so /lib
-fpic产生位置无关的代码(pic)
Arm-linux交叉编译工具链介绍
1,arm-linux-gnu-gcc –O2 –c –o crt0.o crt0.s 将汇编文件编译成目标文件
2,arm-linux-gnu-gcc –O2 –c –o led.o led.c 将.c文件编译成.o文件
3,arm-linux-gnu-gcc-ld –Ttext 0x00000000 –O2 crt0.o led.o –o led-elf 将.o文件链接成为lef文件,-Ttext 0x00000000 指定当前运行地址
4,arm-linux-gun-objcopy –O binary –S led-lef led.bin 将elf文件转换成.bin文件
5,arm-linux-gnu-objdump –D –m arm led_elf > len.dis 将led_elf反汇编成为.dis文件
注意:cc1命令路径在/usr/lib/gcc/i486-linux-gnu/4.1.2/cc1
size :列出目标文件每一段的大小以及总体的大小。
readelf :显示elf格式的可执行文件的信息
strip :丢弃目标文件中的全部或者特定的符号,减少文件体积。
nm :列出目标文件的符号。
objcopy :文件格式转换。
objdump :显示一个或者更多目标文件的信息,主要用来反编译。
编译内核:
make zImage
make bzImage
编译好的内核位于:arch/<cpu>/boot/目录下
编译内核模块:
Make modules
Make modules__install
清除临时文件、中间文件和配置文件:
make clean (保留config文件)
make mrproper
make distclean(取消与体系结构的链接)
内核配置:make config :基于文本模式的交互式配置
make menuconfig :基于文本模式的菜单型配置。
Make modules_install
u-boot移植与编译
u-boot从tftp服务器下载zImage/uImage 应该设置参数为:
setevn bootcmd tftp 30800000 zImage\;go 30800000
setevn bootcmd tftp 30800000 uImage\;bootm
setenv serverip 192.168.7.X 设置主机ip
setenv ipaddr x 192.168.7.Y 设置目标板ip
saveenv 保存环境变量
内核烧写:
tftp 30008000 zImage.2.6.35(将zImage 下载到0x30008000)
nand erase 40000 200000
nand read addr off size :从nandflash偏移地址off处的size个字节数据存放在开始地址为addr的内存中。
nand write addr off size :把开始地址为addr的内存中的size个字节数据写到flash的偏移地址off处。
例如:nand write 30008000 40000 200000
文件系统烧写
tftp 30008000 rootfs.cramfs
nand erase 240000 800000(文件大小)
nand write 30008000 240000(起始地址) 800000
按键驱动led灯亮: (平台基于fs2410开发板,arm920t,s3c2410)
必须对硬件相关的信息要很熟悉,知道它是怎么去控制电路的信息。然后从软件方面去分析。GPIO编程,GPG3 设为input模式 ,GPE11设为output模式,
GPE11引脚output = 0状态,设GPG3引脚状态。
GPIO至少有两个寄存器:即GPIO控制寄存器,GPIO数据寄存器。
GPxCON: 选择引脚的功能。因为大多数的引脚都复用。
GPxDAT: 读写引脚数据。即若引脚被配置为输出模式,写此寄存器相应位可另此引脚输出高电平或低电平;若引脚被设置为输入模式,读此寄存器可知相应的电平状态是高还是低)
GPxUP : 确定是否使用内部上拉
用c语言写驱动,须有启动代码:禁看watchdog,初始化堆栈(ldr sp,=4096,因为代码一般是烧写到nandflash内,容量是4KB,ARM中的栈是满递减堆栈,sp须初始),设置跳转到main函数。
嵌入式系统相关存储器:
寄存器(37个包括31个通用寄存器,6个状态寄存器): 读写数据最快,但是数量有限。
SRAM(4KB):0x40000000~0x40001000
SDRAM(64MB):0x30000000 它是栅列形式,行地址线13根,列地址线9根,ADDR25和ADDR24。所以64MB = 213+9+2 * 32/8 32为数据线。
Norflash(2MB):又22根地址总线(其中2根为NC状态),16根数据总线,所以2M = 222-2 * 2。特点是芯片内执行(XIP,Execute In Place),jffs2文件系统。
Nandflash(64MB): 没有相关的地址总线,不能够寻址。当程序烧写到Nandflash中,它自动读取4KB数据到SRAM,若数据大于4KB时,首先拷贝4KB到SRAM中(包括一些copysdram程序),由它完成将剩下数据拷贝到SDRAM,yaffs文件系统。
Nandflash一页分为A、B、C三个区:A区位0~255字节,B区为256~511字节,C为512~527字节。命令00h让地址指针指向A区,命令01h让地址指针指向B区,命令50h让地址指针指向C区。
1 block = 32 page, 1 page = 512 byte (main area)+ 16 byte(spare area,存放校验的数据);Nandflsh (k9f1028)有4096 block。 528MB = 4096 * 32 * 512 byte。Nandflash 以页为单位读写数据,以块为单位擦除数据。
命令、地址、数据都通过8个I/O口输入/输出。写入数据、命令、地址时,都需要将WE#、CE#信号拉低。数据在WE#信号的上升沿被锁存,命令锁存使能CLE,地址锁存使能ALE信号,用来分辨、锁存命令或地址。
Flash存储器件的可靠性因素:位反转,坏块,可擦除次数。
存储控制器
它对外引出27根地址线(ADDR0-ADDR26,227 = 128MB),对外又引出8根片选信号线(nGCS0 – nGCS7,分别对应于BANK0 – BANK7)。当访问BANKx地址空间时,nGCSx输出低电平来选择外接设备。
128MB * 8 = 1GB。8表示bank区域的个数,每个bank的容量为128MB。
注意:S3C2400使用2片16位的SDRAM芯片并联成32位的带宽,与CPU
的32跟数据线相连。
存储控制器共有13个寄存器:
BWSCON (位宽等待), BANKCON0 – BANKCON5,BANKCON6,BANKCON7,REFRESH,BANKSIZE,MRSR6 – MRSR7
ARM体系异常/中断
ARM指令集:ARM,Thumb,Jazelle指令集。
ARM体系的CPU的七种工作模式:用户模式,fir模式(快速中断请求处理),irq模式(中断请求处理),svc模式(保护模式),abt模式(虚拟内存或存储器保护),sys模式,und模式。
特权模式 : 处理中断、异常或者访问被保护的系统资源。
中断是指cpu在正常执行程序的过程中,遇到外部或内部的紧急事件需要处理,暂时中断当前程序的执行,转去为事件服务,待事件处理完毕,再返回继续执行原有的程序。
注意:中断或异常时,需保存现场,即cpsr->spsr_mode,pc->lr 。异常/中断处理结束时,spsr->cpsr ,lr->pc。
异常向量表:
复位异常(0x00~0xffff0000),主要功能:设置异常中断向量表,初始化堆栈和寄存器,初始化存储系统,改变处理器模式或状态,使能中断等。
未定义指令异常(0x04)
软中断(swi,0x08):处理器处于特权模式(supervisor)。
预取指令异常(0x0c) 若系统中不包含MMU时,指令预取异常中断只是简单的报告异常错误并退出;若包含MMU,则引起异常的指令的物理地址被存储到内存中。
数据访问终止异常(0x10):返回地址寄存器r14的值只与发生数据异常的指令地址有关,与pc值无关。
注意:0x14 为保留地址
外部中断异常(0x18)
快速中断异常(0x1c)
vector table 的入口是一些跳转指令,跳转到专门处理某个异常或中断的子程序。
ARM异常的优先级:
从高到低依次是:复位异常,数据终止,快速中断请求,外部中断请求,预取指令异常,swi,未定义指令(swi和未定义异常享有相同的优先级。但不能同时发生)
中断响应:保护断点,即保存下一将要执行的指令的地址,也就是压栈保存地址;寻找中断入口;执行中断处理程序;中断返回。
本人个人理解:保护现场(寄存器压栈:stmfd sp!,{r0-r3,r12,lr}),恢复现场(恢复寄存器:ldmfd sp!,{r0-r3,r12,lr})。
恢复现场指令如下:
movs pc,lr
subs pc,lr,#4
ldmfd sp!,{pc}!
异常和返回地址:
三级流水线:
取指 译码 执行
PC PC-4 PC-8
五级流水线:
取指 译码 执行 防存(Memory) 回写(write)
注意:PC指向正被读取的指令,而非正在执行的指令。
ARM哈佛架构,实现对指令和数据存储器的同时访问。
UART串口通信
发送数据时,cpu先将数据写入发到FIFO中,然后URTA会自动将FIFO中的数据复制到发送移位器(Transmit Shifter)中,发送移位器将数据一位一位地发送到TxDn数据线上(添加上开始位,校验位和停止位)。
接受数据时,接受移位器(Receive Shifter)将RxDn数据线上的数据一位一位接受进来,然后复制到接受FIFO中,cpu可从中读取数据。
IPC通信机制
信号量
Semget(key_t key,int num_sems,int sem_flags):创建信号量或取得一个已有的信号量的键。
Semop(int sem_id,struct sembuf *semops,size_t num_sem_opt):改变信号量的值。
Struct sembuf{
short sem_num; 信号量的编号
short sem_op; 0 等待;1释放资源;-1 分配资源
short sem_flag; 常被设置为SEM_UNDO
}
Semctl(int semid,int semnum,int cmd,...):用来直接控制信号量的值。
eg :semctl(sem_id,0,SETVAL,sem_union)
command: GETVAL: 获取信号量的值
SETVAL:设置信号量的值
IPC_RMID: 删除信号量。
共享内存
Shmget(key_t key,size_t size,int shmflg): 创建共享内存
Shmat(int shm_id,const void *shmaddr,int shmflg):建立映射
Shmdt(const void *shmaddr) : 解除映射
Shmctl(int shmid,int cmd,struct shmid_ds *buf) 控制内存映射
CMD: IPC_STAT(获取对象属性)
IPC_SET(设置对象属性)
IPC_PRIM(删除对象)
Buf:用来指定IPC_STAT/IPC_SET时用以保存/设置属性。
消息队列
Msgctl() 控制消息队列
Msgget() 创建和访问一个消息队列
Msgrcv() 从消息队列中获取信息
Msgsnd() 向消息队列中添加信息
linux kernel(linux 内核)
GPL(GNU General Public License) 通用公共许可证
内核的模块化,主要由文件系统模块,进程调度/控制模块,进程间通信模块,内存管理模块,网络接口模块等:
内核编译:
内核配置、裁剪、编译:make menuconfig make uImage。
内核系统最关键的组成元素是各个目录下的Kconfig和Makefile文件。
进程由可执行的指令代码,数据和堆栈区组成。
分时技术:把cpu的运行时间划分成一个个规定长度的时间片,让每个进程在一个时间片内运行。当进程的时间片用完时系统就调度程序切换到另一个进程去运行。
Linux系统中,进程可以在内核态或用户态下执行,因此linux系统的内核堆栈和用户堆栈是分开的。
task_struct 任务数据结构
内核通过进程表来管理进程,每个进程在进程表中占有一项。PCB(process control block)进程控制块
进程上下文:一个进程在执行时,cpu的所有寄存器中值、进程的状态、堆栈中的内容。进程切换时,须保存当前进程的上下文。
内核的初始化:
init进程:
文件系统:
内存管理机制:控制多个进程安全地共享内存。
Linux内存管理采用页式管理,通过伙伴算法管理和分配页。
内存映射,将cpu的虚拟地址空间映射到系统的物理内存。通常由MMU来完成。
X86地址空间:物理地址空间,逻辑地址空间,线性地址空间。
逻辑地址是cpu所能处理的地址空间的总和,对32位cpu来说,它的逻辑地址空间是4GB = 232byte。
进程线性地址被分为:页目录索引,页表索引和偏移量。Page directory是一个指向页表的指针数组,page table 是一个指向页面的指针数组。因此地址映射就是一个跟踪指针链的过程。一个页目录能够确定一个页表,继而得到一个页面,然而页面中的偏移量(offset)能够指出该页面的地址。
内存区域zone,由一个自己的伙伴系统来管理。
TLB(Translation Lookaside Buffer)转换旁视缓冲区/页表缓冲,它负责将虚拟地址翻译成为实际的物理内存地址,cpu寻址时会优先在TLB中寻址。
ARM虚拟地址转换为物理地址:以段的方式进行转换时只用到一级页表;以页的方式进行的转换时要用到两级页表。
条目也称为“描述符”:段描述符,大页/小页/极小页描述符,它们保存了相应的起始物理地址。