版权说明
本手册由华南木棉嵌入式工作室编写,版权归其所有,并保留一切权利。非经同意(书面形式),任何单位和个人均不可擅自抄录本手册的部分或全部,以任何形式用于商业目的。
公司网址:http://www.arm123.net
华南木棉嵌入式工作室1.建立linux开发环境 (2)
1.1建立linux开发环境 (2)
1.2开发工具 (4)
1.2.1Jflash (4)
1.2.2minicom (4)
2配置和编译BIOS(vivi) (8)
3配置和编译内核(kernel) (9)
4制作YAFFS文件系统映象 (10)
4.1基本文件系统映象 (10)
4.2Qtopia文件系统映象 (10)
5应用程序开发指南 (10)
5.1Hello,FriendlyARM (10)
5.2测试LED (11)
5.3UDP网络编程 (12)
5.4数学函数调用示例 (17)
5.5C++编程示例 (18)
5.6线程编程示例 (19)1.建立linux开发环境
1.1建立linux开发环境
以下安装步骤基于Redhat9.0。安装开发工具之前请确保您的硬盘有1GB的剩余空间。
以下安装步骤使用的是光盘中linux目录里面的文件,您可以在http://www.arm123.net
下载最新的文件(文件名有可能不同,主要是版本和日期的差异),恕不再另行通知。
注意:执行以下步骤请以root用户登录。
1.1.1安装arm-linux-gcc编译器
#tar xvzf arm-linux-gcc-3.4.1.tgz–C/
说明:执行该命令,将把arm-linux-gcc(版本3.4.1)安装到/usr/loca/arm/3.4.1目录。
为了可以方便的使用arm-linux-gcc编译器系统,建议把arm-linux工具链目录加入到环境变量PATH中,如图修改/etc/profile文件,保存退出,重新启动系统使之生效:
1.1.2解压安装linux内核源代码
#tar xvzf linux-2.6.13-qq2440.tgz–C/opt/FriendlyARM/QQ2440
/opt/FriendlyARM/QQ24400说明:执行该命令,将把linux-2.6.13内核源代码安装到/opt/FriendlyARM/QQ244
目录下。
1.1.3解压安装root文件系统
#tar xvzf root_default.tgz–C/opt/FriendlyARM/QQ2440
说明:执行该命令,将把root_default文件系统解压到/opt/FriendlyARM/QQ2440
目录下。
#tar xvzf root_qtopia_tp.tgz–C/opt/FriendlyARM/QQ2440
说明:执行该命令,将把带触摸屏支持的root文件系统目录root_qtopia_tp解压到
/opt/FriendlyARM.QQ2440目录下。
#tar xvzf root_qtopia_mouse.tgz–C/opt/FriendlyARM/QQ2440
说明:执行该命令,将把带USB鼠标支持的root文件系统目录root_qtopia_mouse解压到/opt/FriendlyARM.QQ2440目录下。
#tar xvzf root_mizi.tgz–C/opt/FriendlyARM/QQ2440
说明:执行该命令,将把mizi公司提供的中文qpe文件系统目录root_mizi解压到/opt/FriendlyARM/QQ2440目录下。
1.1.4安装yaffs文件系统映象制作工具
#tar xvzf mkyaffsimage.tgz–C/usr/bin
说明:把mkyaffsimage工具解压安装到/usr/bin目录,该程序用于把root文件系统制作成yaffs文件系统映象。
1.1.5解压安装示例程序源代码
#tar xvzf examples.tgz–C/opt/FriendlyARM/QQ2440
说明:该命令将把示例程序安装到/opt/FriendlyARM/QQ2440/examples目录。
1.1.6解压安装busybox源代码
#tar xvzf busybox-1.2.0.tgz–C/opt/FriendlyARM/QQ2440
说明:该命令将把busybox-1.2.0源代码解压安装到/opt/FriendlyARM/QQ2440目录,用户可以在busybox官方网站下载最新版本。
1.1.7解压安装Jflash2440
#tar xvzf jflash2440.tgz–C/opt/FriendlyARM/QQ2440
说明:该命令将把Linux下Jtag烧写程序Jflash及其源代码安装到/opt/FriendlyARM/QQ2440目录。
1.1.8解压安装qtopia源代码
#tar xvzf qtopia.tgz–C/opt/FriendlyARM/QQ2440
说明:该命令将把qtopia源代码解压安装到/opt/FriendlyARM/QQ2440目录。
最后的目录结构如下所示:
1.2开发工具
1.2.1Jflash
jflash2440是Linux下通过JTAG接口烧写BIOS到Nand Flash的工具。
使用JTAG接口下载程序需要一条JTAG电缆(已经随开发套件附送),把JTAG电缆连接板子和主机的并口,然后打开目标板电源开关
#cd/opt/FriendlyARM/QQ2440/
Jflash
opt/FriendlyARM/QQ2440/Jflash
注意:该目录下包含了Jflash的源代码,你可以运行“make clean”删除已经编译好的的程序,运行“make”重新编译。
执行以下命令可以查看Jflash的使用方法:
#./Jflash-s3c2440--help
可见,对应不同类型的Flash,Jflash程序使用不同的选项参数,因为我们使用的是M三星Nand Flash,因此使用“/t=5”。
执行以下命令开始烧写vivi,如图所示。
#./Jflash-s3c2440vivi/t=5
注意:如果您在当前目录下执行该命令,请先copy一份vivi二进制文件到该目录。
1.2.2minicom
minicom是Linux上最常用的终端仿真程序,它类似于Windows下的“超级终端”的程序,一般完全安装大部分发行版的Linux时都会包含它,下面介绍它的使用方法。
使用minicom 之前先设置一下,如下图所示:
运行“minicom -s ”设置minicom
选择菜单中的“Serial port setup ”,按回车,进入如下图所示界面。此时按“A ”以设置“Serial Device ”(如果您使用串口1,则输入/dev/ttyS0,如果您使用串口
2,则输入/dev/ttyS1)。
设置“Serial Device ”
#minicom -s ;加“-s ”选项设置minicom
设置波特率
然后按回车退回到上一级菜单,按“F”键设置“Hardware Flow Control”为“NO”,其他选项使用缺省值,如下图所示。
设置“Hardware Flow Control”
设置完毕,按回车键返回到串口设置主菜单,选择“Save setup as dfl”,按回车键保存刚才的设置,如下图所示。
保存设置
再选择“Exit”退出设置模式。刚才的设置被保存到“/etc/minirc.dfl”。
设置完毕,如果此时打开板子的电源开关,就会看到vivi的启动信息,当Linux启动以后,minicom就相当于虚拟终端,你就能通过它来操作目标板了。
要退出minicom,同时按下“Ctrl+A”键,松开后紧接着再按下“Q”键,在跳出的窗口中,选择“Yes”,如图所示。
退出minicom
2配置和编译B IOS(vivi)
首先,进入vivi源代码目录:
/vivi
#cd/opt/FriendlyARM/QQ2440
opt/FriendlyARM/QQ2440/vivi
再执行“make”开始编译:
#make
如果编译过程顺利,将会在当前目录下生成vivi二进制映象文件。
nfig”
menuconfig 说明:该编译过程为默认设置,如果你想改变vivi的某些配置,可以执行“make menuco
来定制vivi。
3配置和编译内核(kernel)
QQ2440所用的内核源代码位于/opt/FriendlyARM/QQ2440/linux-2.6.13目录。该目录下有三个config_开头的文件:
config_cs00_n35
config_cs00_s35
config_cs00_tft0480
您可以选择适合自己LCD型号的配置文件,复制一个名为.config的文件
.config
config_cs00_tft0480.config
#cp config_cs00_tft0480
注意:config之前有个”。”
然后执行make menuconfig
#make menuconfig
注意:该步骤一定要执行。
如果您对内核的配置不熟悉,先不用作任何修改,保存退出即可。
最后执行make zImage开始编译内核。
#make zImage
编译完毕,将在arch/arm/boot目录下生成zImage文件,即linux内核文件映象。
4制作YAFFS文件系统映象
使用mkyaffsimg程序可以把一个目录做成一个yaffs映象文件,然后使用USB下载到板子中。
4.1基本文件系统映象
为了制作板子所需要的基本系统映象文件,可以按照这样的步骤执行操作:
#cd/opt/FriendlyARM/QQ2440
#mkyaffsimage root_default root_default.img
将在/opt/FriendlyARM/QQ2440目录下生成root_default.img,在BIOS模式下
使用”loadyaffs root u”就可以把它下载到板子里面去了。
4.2Qtopia文件系统映象
为了制作板子所需要的基本系统映象文件,可以按照这样的步骤执行操作:
#cd/opt/FriendlyARM/QQ2440
#mkyaffsimage root_qtopia_tp root_qtopia_tp.img
将在/opt/FriendlyARM/QQ2440目录下生成root_qtopia_tp.img,在BIOS模式下使用”loadyaffs root u”就可以把它下载到板子里面去了。
用户可以参考以上方法把以上方法把root_qtopia_mouse/root_mizi做成映象文件下载到板子里。
5应用程序开发指南
5.1Hello,FriendlyARM
Step1:编辑源代码
led控制程序的源代码位于/opt/FriendlyARM/QQ2440/examples/hello目录下
#include int main(void) { printf("Hello,FriendlyARM\\n"); return0;} Step2:编译hello 使用以下命令编译: #arm-linux-gcc–o hello hello.c 将生成hello可执行文件。 Step3:下载并运行 将可执行文件移动到板子目前主要有两种方式: (1)复制到介质(下面以优盘为例) 把优盘插入PC的USB,然后执行以下命令把hello复制到优盘 #mount/dev/sda1/mnt #cp hello/mn t #umount/m nt 把优盘拔下来插入到板子的USB HOST端口,按照以下命令操作: #mount/dev/sda1/mnt;挂接优盘 #cp/mnt/hello/bin;把hello复制到bin目录 #hello;执行hello (2)通过网络移动(推荐使用) 通过网络下载程序的主要步骤是:先把hello复制到ftp共享目录,然后在板子上使用ftp下载,并修改执行权限运行,如下: 在PC端执行: #cp hello/home/ftp;把hello复制到ftp共享目录 在板子端执行: #cd/bin;进入bin目录 #ftp192.168. 192.168.11.1;登录ftp服务器 >get hello;下载hello >bye;退出ftp登录 #chmod a+x hello;改变hello的可执行权限 #hello;执行hello 5.2测试LED led控制程序的源代码位于/opt/FriendlyARM/QQ2440/examples/led目录下,下面是程序清单及注释。 程序清单: #include #include #include #include { int on; int led_no; int fd; /*检查led控制的两个参数,如果没有参数输入则退出。*/ if(argc!=3||sscanf(argv[1],"%d fprintf(stderr,"Usage:leds led_no0|1\\n"); exit(1); } /*打开/dev/leds设备文件*/ fd=open("/dev/leds if(fd<0){ perror("open device leds"); exit(1); } /*通过系统调用ioctl和输入的参数控制led*/ ioctl(fd,on,led_no); /*关闭设备句柄*/ close(fd); return0; } 你可以按照上面的hello程序的步骤手工编译出led可执行文件,然后下载到板子运行它。 5.3UDP网络编程 TCP/IP提供了无连接的传输层协议:UDP(User Datagram Protocol,即用户数据报协议)。UDP 与TCP有很大的区别,因为无连接的socket编程与面向连接的socket编程也有很大的差异。由于不用建立连接,因此每个发送个接收的数据报都包含了发送方和接收方的地址信息。 在发送和接收数据之前,先要建立一个数据报方式的套接字,该socket的类型为 SOCK_DGRAM,用如下的调用产生: sockfd=socket(AF_INET,SOCK_DGRAM,0); 由于不需要建立连接,因此产生socket后就可以直接发送和接收了。当然,要接收数据报也必须绑定一个端口,否则发送方无法得知要发送到哪个端口。Sendto和recvfrom两个系统调用分别用于发送和接收数据报,其调用格式为: int sendto(int s,const void*msg,int len,unsigned int flags,const struct sockaddr*to,int tolen); int recvfrom(int,s,void*buf,int len,unsigned int flags,struct sockaddr*from,int fromlen); 其中s为所使用的socket,msg和buf分别为发送和接收的缓冲区指针,len为缓冲区的长度,flags为选项标志,此处还用不到,设为0即可。to和from就是发送的目的地址和接收的来源地址,包含了IP地址和端口信息。tolen和fromlen分别是to和from这两个socket地址结构的长度。这两个函数的返回值就是实际发送和接收的字节数,返回-1表示出错。 使用无连接方式通信的基本过程如图所示。 上图描述的是通信双方都绑定自己地址端口的情形,但在某些情况下,也可能有一方不用绑定地址和端口。不绑定的一方的地址和端口由内核分配。由于对方无法预先知道不绑定的一方的端口和IP地址(假设主机有多个端口,这些端口分配了不同的IP地址),因此只能由不绑定的一方先发出数据报,对方根据收到的数据报中的来源地址就可以确定回送数据报所需要的发送地址了。显然,在这种情况下对方必须绑定地址和端口,并且通信只能由非绑定方发起。 与read()和write()相似,进程阻塞在recvfrom()和sendto()中也会发生。但与TCP方式不同的是,接收到一个字节数为0的数据报是有可能的,应用程序完全可以将sendto()中的msg设为NULL,同时将len设为0。 下面是一个基于以上原理分析的一个udp编程的例子(源代码位于/opt/FriendlyARM/QQ2440/examples/udptalk目录):/* *udptalk:Example for Matrix V * *Copyright(C)2004capbily-opt/FriendlyARM/QQ2440 *capbily@hotmail.com */ #include #include #include #include #define BUFLEN255 int main(int argc,char**argv) { struct sockaddr_in peeraddr,/*存放谈话对方IP和端口的socket地址*/ localaddr;/*本端socket地址*/ int sockfd; char recmsg[BUFLEN+1]; int socklen,n; if(argc!=5){ printf("%s exit(0); } sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd<0){ printf("socket creating err in udptalk\\n"); exit(1); } socklen=sizeof(struct sockaddr_in); memset(&peeraddr,0,socklen); peeraddr.sin_family=AF_INET; peeraddr.sin_port=htons(atoi(argv[2])); if(inet_pton(AF_INET,argv[1],&peeraddr.sin_addr)<=0){ printf("Wrong dest IP address!\\n"); exit(0); } localaddr.sin_family=AF_INET; if(inet_pton(AF_INET,argv[3],&localaddr.sin_addr)<=0){ printf("Wrong source IP address!\\n"); exit(0); } localaddr.sin_port=htons(atoi(argv[4])); if(bind(sockfd,&localaddr,socklen)<0){ printf("bind local address err in udptalk!\\n"); exit(2); } if(fgets(recmsg,BUFLEN,stdin)==NULL)exit(0); if(sendto(sockfd,recmsg,strlen(recmsg),0,&peeraddr,socklen)<0){ printf("sendto err in udptalk!\\n"); exit(3); } for(;;){ /*recv&send message loop*/ n=recvfrom(sockfd,recmsg,BUFLEN,0,&peeraddr,&socklen); if(n<0){ printf("recvfrom err in udptalk!\\n"); exit(4); }else{ /*成功接收到数据报*/ recmsg[n]=0; printf("peer:%s } if(fgets(recmsg,BUFLEN,stdin)==NULL)exit(0); if(sendto(sockfd,recmsg,strlen(recmsg),0,&peeraddr,socklen)<0){ printf("sendto err in udptalk!\\n"); exit(3); } } } 将udptalk.c编译好后就可以运行了,/opt/FriendlyARM/QQ2440/examples/udptalk目录下的Makefile指定了两个编译目标可执行文件,一个用于在主机端的x86-udptalk,一个是用于板子的arm-udptalk,运行make命令将把这两个程序一起编译出来。可以把arm-udptalk使用上面介绍的方法下载到板子中(预装的Linux不含该程序),假设主机的IP地址为192.168.0.1,板子的IP地址为192.168.0.230。 在主机的终端上输入: #./x86-udptalk192.168.0.2302000192.168.0.12000 在板子上的终端输入 #arm-udptalk192.168.0.12000192.168.0.2302000 则运行结果分别如图所示: 在主机上运行x86-udptalk 在板子上运行arm-udptalk 5.4数学函数调用示例 该程序的测试源代码位于/opt/FriendlyARM/examples/math目录下,该程序实现开平方运算:#include #include #include int main(void) { double a=8.733243; printf("sqrt(%f)=%f\\n return0; } 手工编译: arm-linux-gcc–o mtest mathtest.c–lm 编译后生成mathtest可执行文件,把该文件下载到板子里运行即可。注意编译时需要加上-lm选项。 5.5C++编程示例 下面是一个C++编程的简单例子,其源代码位于/opt/FriendlyARM/examples/c++目录:#include #include using namespace std; class String { private: char*str; public: String(char*s) { int lenght=strlen(s); str=new char[lenght+1]; strcpy(str,s); } ~String() { cout<<"Deleting str.\\n"; delete[]str; } void display() { cout< }; int main(void) { String s1="I like FriendlyARM."; cout<<"s1="; s1.display(); return0; double num,ans; cout<<"Enter num:"; } 手工编译: #arm-linux-g++-o cplus cplus.c++ 将生成的cplus可执行程序下载到板子中即可看到执行结果,编译时请注意使用arm-linux-g++命令 更多关于C++编程的知识可以参考相关书籍。 5.6线程编程示例 下面是一个线程编程的简单例子,在这个程序中,一个线程从共享的缓冲区中读取数据,并打印出来,另一个线程向共享的缓冲区中写数据,并把写入的数据打印出来,对共享的缓冲区的访问控制是通过使用一个互斥锁来实现的。 #include #include #include #include"pthread.h" void reader_function(void); void writer_function(void); char buffer; int buffer_has_item=0; pthread_mutex_t mutex; main() { pthread_t reader; pthread_mutex_init(&mutex,NULL); pthread_create(&reader,NULL,(void*)&reader_function,NULL); writer_function(); } void writer_function(void) { while(1) { pthread_mutex_lock(&mutex); if(buffer_has_item==0) {buffer=’a’; printf("make a new item\\n"); buffer_has_item=1; } pthread_mutex_unlock(&mutex); } } void reader_function(void) { while(1) { pthread_mutex_lock(&mutex); if(buffer_has_item==1) { buffer=’\\0’; printf("consume item\\n"); buffer_has_item=0; } pthread_mutex_unlock(&mutex); } } 手工编译: arm-linux-g++-o pthread pthread.c–lpthread 将生成的pthread可执行程序下载到板子中即可看到执行结果。下载本文