2.17k likes | 2.32k Views
第五章 ARM 嵌入式系统软件设计. ◆ 要求熟悉嵌入式系统开发的硬件与软件环境; ◆ 掌握ADS与AXD开发工具的使用方法; ◆ 了解ARM的启动过程分析; ◆ 理解存储映射的机制; ◆ 熟悉与掌握嵌入式软件开发的一些常用技术. 5 .1 开发平台. 学习嵌入式技术,必须要有硬件平台作实践,它不象其它的基础理论课,学懂理论就行了,而它主要在于实践应用,没有在硬件平台上实践是很难学好嵌入式技术的。有了硬件平台,就可以开始从理论到实践交替进行。 给初学者一些快速入门的方法:. 1)从宏观上了解嵌入式系统的结构,要实现的功能;
E N D
◆ 要求熟悉嵌入式系统开发的硬件与软件环境; ◆ 掌握ADS与AXD开发工具的使用方法; ◆了解ARM的启动过程分析; ◆ 理解存储映射的机制; ◆ 熟悉与掌握嵌入式软件开发的一些常用技术
5.1 开发平台 学习嵌入式技术,必须要有硬件平台作实践,它不象其它的基础理论课,学懂理论就行了,而它主要在于实践应用,没有在硬件平台上实践是很难学好嵌入式技术的。有了硬件平台,就可以开始从理论到实践交替进行。 给初学者一些快速入门的方法:
1)从宏观上了解嵌入式系统的结构,要实现的功能;1)从宏观上了解嵌入式系统的结构,要实现的功能; 2)利用一块成熟的开发板,这里成熟的开发板是指硬件资源丰富,运行稳定可靠,配套的学习资料齐全(硬件与软件开发工具以及实例); 3)熟悉开发板的主要功能; 4)在没有操作系统的情况下,按模块学习
如:I/O口应用的LED实验、定时器实验、中断实验等, 如:I/O口应用的LED实验、定时器实验、中断实验等, 在学习的过程中,首先是读懂该模块的硬件功能,从电路图开始读懂再对应到该板卡的实际实物上。一个一个模块搞懂,在学习模块时要注意将硬件电路与配置寄存器相结合,真正了解它们的含义,最后变成程序代码。
5) 当模块学习到一定数量后,要将它们组成一个小系统进行联调。在嵌入式系统里用得最多的编程语言就是C语言。汇编语言主要用在系统的初始化部分。 6) 熟悉硬件后,为了开发出实用的嵌入式系统,一般是在操作系统上进行开发的。所以要熟悉uc/os、linux和wince等操作系统。
1.硬件开发环境 下面以基于ARM9内核的s3c2410的开发板为例,说明初学者要进行入门学习需要具备的一些开发条件: (1)基于ARM9内核的s3c2410的开发板一套 (2)常用的软件开发工具 (3)常用电子测试仪表,如万用表、示波器等
MY-2410-1开发板基于三星公司的ARM处理器S3C2410。是编者自主研制的一款ARM9实验开发板。MY-2410 开发板的实物与功能示意如下图所示。
1)JTAG接口 一般用来下载Bootloader。下载速度较慢。主要完成: (1)初始化CPU内部所有寄存器; (2)加载串口驱动; (3)加载USB驱动; (4)加载网卡驱动。
在进行嵌入式系统开发时,首先用到的接口就是JTAG接口,利用该接口对S3C2410X等开发板,配合sjf2410.exe烧写监控程序,如2410mons.bin监控程序。 在以后的开发中,用该接口进行调试。
2)USB接口 利用开发板上的USB_DEVICE接口,一般用来配合DNW.exe来下载文件。 下载速度较快。开发板上的USB_HOST可以外接应用设备,如:USB移动硬盘,USB摄像头等外设。
3)串口 串口一般配合DNW.exe或超级终端来监控板子的运行情况,有时也可以用来下载文件。很多情况下主要用来调试,调试很方便,只需往串口寄存器中填数据,就可以输出调试信息。 4)网口 网口用来下载数据,也完成网络通信。
2.软件开发环境 1)交叉开发概念 由于嵌入式系统硬件上的特殊性,一般不能安装windows操作系统和发行版的linux系统,因为它的CPU运行速度,FLASH的空间等都达不到通用PC系统的要求。所以在嵌入式系统上无法构建其自己的开发环境,于是,人们采用了所谓的交叉开发模式。
交叉开发就是指在一台通用计算机上进行软件的编辑编译,然后下载到嵌入式设备中进行运行调试的开发方式。 用来开发的通用计算机可以是PC机、工作站等,运行通用的Windows或Linux操作系统。开发计算机一般称宿主机,嵌入式设备称目标机。在宿主机上编译好程序,下载到目标机上运行,交叉开发环境提供调试工具对目标机上运行的程序进行调试。
交叉编译是指在宿主机——X86系统CPU的通用计算机上使用ADS,GCC等交叉开发软件为目标机开发程序,最后编译成可以在ARM体系结构的目标机上运行目标代码。宿主机与目标机的连接关系如下图所示。
在宿主机上编译好目标代码后,通过宿主机到目标机的调试通道将代码下载到目标机,然后由运行于宿主机的调试软件控制代码在目标机上进行调试。为了方便调试开发,交叉开发软件一般为一个整合编辑、编译汇编链接、调试、工程管理及函数库等功能模块的集成开发环境IDE(Integrated Development Environment),如ADS就是一个比较好的ARM开发IDE。
嵌入式系统开发的使用的主要工具之间的关系,如下图所示。开发工具分为不基于操作系统与基于操作系统两大块。 在不基于操作系统的开发中,主要用到的是ADS集成开发环境,与IAR 公司的IAR EWARM开发软件以及一些监控与引导程序程序。
2. ADS组成介绍 ADS全称为ARM Developer Suite,是ARM公司推出的新一代ARM集成开发工具。现在ADS的最新版本是1.2,它取代了早期的ADS1.1和ADS1.0,该版本支持包括Windows和Linux在内的多种操作系统。
1)ADS组成介绍 (1)编译器 ADS提供多种编译器,以支持ARM和Thumb指令的编译。 ◆ armcc是ARM C编译器; ◆ tcc是Thumb C编译器; ◆ armcpp是ARM C++编译器; ◆ tcpp是Thumb C++编译器; ◆ armasm是ARM和Thumb的汇编器。
(2)链接器 armlink是ARM链接器。该命令既可以将编译得到的一个或多个目标文件和相关的一个或多个库文件进行链接,生成一个可执行文件,也可以将多个目标文件部分链接成一个目标文件,以供进一步的链接。
(3)符号调试器 armsd是ARM和Thumb的符号调试器。它能够进行源码级的程序调试。用户可以在用C或汇编语言写的代码中进行单步调试、设置断点、查看变量值和内存单元的内容。
(4)fromELF 将ELF格式的文件转换为各种格式的输出文件,包括BIN格式映像文件、Motorola 32位S格式映像文件、Intel 32位格式映像文件和Verilog 16进制文件。FromELF命令也能够为输入映像文件产生文本信息,例如,代码和数据长度。
(5)armar armar是ARM库函数生成器,它将一系列ELF格式的目标文件以库函数的形式集合在一起。用户可以把一个库传递给一个链接器以代替几个ELF文件。
(6)CodeWarrior CodeWarrior集成开发环境(IDE)为管理和开发项目提供了简单多样化的图形用户界面,用户可以使用ADS的CodeWarrior IDE为ARM和Thumb处理器开发用C、C++或者ARM汇编语言编写的程序代码。
(7)调试器 ADS中包含有3个调试器:第一个是AXD(ARM eXtended Debugger),它是ARM扩展调试器;第二个是armsd(ARM Symbolic Debugger),它是ARM 符号调试器; 与老版本兼容的Windows 或Unix 下的 ARM 调试工具ADW/ADU。
(8)C和C++库 ADS提供ANSI C库函数和C++库函数,支持被编译的C和C++代码。用户可以把C库中的与目标相关的函数作为自己应用程序中的一部分,重新进行代码的实现。 针对自己的应用程序的要求,对与目标无关的库函数进行适当的裁剪。在C库中有很多函数是独立于其他函数的,并且与目标硬件没有任何依赖关系。对于这类函数,用户可以很容易地从汇编代码中使用。
3.编写应用程序都要用到的文件 利用下面的文件与程序,它们可以提高编程效率,节省时间,也使初学者能够尽快入门。达到一定水平后,自己再在此文件与程序的基础上修改,或重新编写自己的应用程序,尽可能地达到系统最优化的目的。
1)INC目录下的文件 2410addr.h 2410addr.inc 2410lib.h 2410slib.h Def.h Memcfg.inc Option.inc Uart0.h mmu.h Option.h
2)INC目录下的文件说明 • Def.h • 基本数据类型重定义头文件,在定义数据类型时尽量使用U32,U16,S32,S16,U8,S8等类型,以增强程序的可移植性,主要内容如下: • #ifndef __DEF_H__ • #define __DEF_H__ ;防止重复定义__DEF_H__ • #define U32 unsigned int • #define U16 unsigned short • #define S32 int • #define S16 short int • #define U8 unsigned char • #define S8 char • #define TRUE 1 • #define FALSE 0 • #endif /*__DEF_H__*/
(2) Option.h 是硬件系统重要设置头文件,如果要修改系统的工作频率,总线宽度,一些重要地址的值可在本文件中修改,主要内容如下: //#define FCLK 101250000 //SDRAM 2.5V use #define FCLK 202800000 // #define HCLK (FCLK/2) // #define PCLK (FCLK/4) // #define UCLK PCLK // BUSWIDTH : 16,32 #define BUSWIDTH (32)
//64MB // 0x30000000 ~ 0x30ffffff : Download Area (16MB) Cacheable // 0x31000000 ~ 0x33feffff : Non-Cacheable Area // 0x33ff0000 ~ 0x33ff47ff : Heap & RW Area // 0x33ff4800 ~ 0x33ff7fff : FIQ ~ User Stack Area // 0x33ff8000 ~ 0x33fffeff : Not Used Area // 0x33ffff00 ~ 0x33ffffff : Exception & ISR Vector Table #define _RAM_STARTADDRESS 0x30000000 #define _NONCACHE_STARTADDRESS 0x31000000 #define _ISR_STARTADDRESS 0x33ffff00 #define _MMUTT_STARTADDRESS 0x33ff8000 #define _STACK_BASEADDRESS 0x33ff8000 #define HEAPEND 0x33ff0000
(3) 2410addr.h 是2410的寄存器的地址宏定义头文件,方便使用,主要内容如下: // 存储器控制器的配置寄存器的起始地址是:0x48000000~0x48000030,由于ARM的寄存器是32位的,而一个地址放一个字节,所以需要4个地址。 // Memory control #define rBWSCON (*(volatile unsigned *)0x48000000) //Bus width & wait status …… //INTERRUPT的配置寄存器的起始地址是:0x4a000000~0x4a00001c。 // INTERRUPT #define rSRCPND (*(volatile unsigned *)0x4a000000) //Interrupt request status ……
注意:在汇编语言中,用2410addr.inc文件。 volatile的本意为 “暂态的”或.“易变的”,该说明符起到抑制编译器优化的作用。 如果在声明时用“volatile”关键字进行修饰,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供特殊地址的稳定访问。
(4) 2410lib.h 是调试时常用函数,还有一些其它的常用函数的头文件。 (5) 2410slib.h 包含MMU相关函数的头文件。
3)SRC目录下的文件 (1) 2410init.s 是2410初始化启动程序,由汇编语言写成 (2) 2410lib.c是描述了2410的调试常用函数的原型,用C语言写成。 (3) 2410slib.s包含汇编语言写的MMU相关的程序代码。 (4) mmu.c包含MMU相关的程序代码。 (5) Uart0.c包含了串口的常用函数原型,用C语言写成。
主程序模板.c //============================================ // File Name : 2410test.c // Function : S3C2410 Test Main Menu // Program : Shin, On Pil (SOP) // Date : June 13, 2003 // Version : 0.0 // History //=============================================== #include <stdlib.h> #include <string.h> #include "def.h" #include "option.h" #include "2410addr.h" #include "2410lib.h" #include "2410slib.h" #include "uart0.h" #include "mmu.h"
void Isr_Init(void); void HaltUndef(void); void HaltSwi(void); void HaltPabort(void); void HaltDabort(void); extern void __rt_lib_init( void ) ; void Temp_Function( void ) { ; } //======================================== void Main(void) { int i=0; // Led_Display(15); MMU_Init(); //初始化MMU
//===================================================== void Main(void) { int i=0; // Led_Display(15); MMU_Init(); //初始化MMU #if ADS10 __rt_lib_init(); //for ADS 1.0 #endif // ChangeClockDivider(0,0); // 1:1:1 // ChangeClockDivider(0,1); // 1:1:2 // rCLKDIVN |= (1<<2); // 1:4:4 // ChangeClockDivider(1,0); // 1:2:2 ChangeClockDivider(1,1); // 1:2:4 ChangeMPllValue(0xa1,0x3,0x1); // FCLK=202.8MHz
Port_Init(); //IO端口初始化 Isr_Init();//设中断 Uart_Init(0,115200);//COM口初始化 //Save the wasted power consumption on GPIO. rIISPSR=(2<<5)|(2<<0); //IIS_LRCK=44.1Khz @384fs,PCLK=50Mhz. rGPHCON = rGPHCON & ~(0xf<<18)|(0x5<<18); //CLKOUT 0,1=OUTPUT to reduce the power consumption. Uart_Printf("\n\nhello denggs\n") ; while( 1 ) { Uart_Printf("hello\n") ;//串口返回调试信息 Delay(2000);//延时 i++; if (i>15) i=0; Led_Display(i);//控制四个LED显示 }
void Isr_Init(void) { pISR_UNDEF = (unsigned)HaltUndef; pISR_SWI = (unsigned)HaltSwi; pISR_PABORT = (unsigned)HaltPabort; pISR_DABORT = (unsigned)HaltDabort; rINTMOD = 0x0; //All=IRQ mode // rINTCON=0x5; //Non-vectored,IRQ enable,FIQ disable rINTMSK = BIT_ALLMSK; //All interrupt is masked. rINTSUBMSK = BIT_SUB_ALLMSK; //All sub-interrupt is masked. <- April 01, 2002 SOP // rINTSUBMSK = ~(BIT_SUB_RXD0); //Enable Rx0 Default value=0x7ff // rINTMSK = ~(BIT_UART0); //Enable UART0 Default value=0xffffffff // pISR_UART0=(unsigned)RxInt; //pISR_FIQ,pISR_IRQ must be initialized }
//================================================= void HaltUndef(void) { Uart_Printf("Undefined instruction exception.\n"); while(1); } //===================================================== void HaltSwi(void) { Uart_Printf("SWI exception.\n"); while(1); }
//===========================================================//=========================================================== void HaltPabort(void) { Uart_Printf("Pabort exception.\n"); while(1); } //============================================================ void HaltDabort(void) { Uart_Printf("Dabort exception.\n"); while(1); } //============================================================
4)2410接口函数说明 void Delay(int time); //Watchdog Timer is used.延时 void *malloc(unsigned nbyte); //分配内存 void free(void *pt); //释放内存 void Port_Init(void); //初始化端口 void Uart_Select(int ch); //选择串口 void Uart_TxEmpty(int ch); void Uart_Init(int mclk,int baud); //串口初始化 char Uart_Getch(void); //从串口读取一个字符(阻塞) char Uart_GetKey(void); //从串口读取一个字符(非阻塞) int Uart_GetIntNum(void); //从串口读取一个数字 void Uart_SendByte(int data); //从串口发送一个字节 void Uart_Printf(char *fmt,...); //从串口输出的printf
void Uart_SendString(char *pt); void Timer_Start(int divider); //Watchdog Timer is used. int Timer_Stop(void); //Watchdog Timer is used. void Led_Display(int data); void ChangeMPllValue(int m,int p,int s); void ChangeClockDivider(int hdivn,int pdivn); void ChangeUPllValue(int m,int p,int s);
5.2 ADS的使用简介 1. ADS的应用 首先通过“开始”->“程序”->“ARM Developer Suite V1.2”->“Codewarrior for ARM Developer Suite”打开Codewarrior。如图所示。