EasyARM1138经验之谈.doc_第1页
EasyARM1138经验之谈.doc_第2页
EasyARM1138经验之谈.doc_第3页
EasyARM1138经验之谈.doc_第4页
EasyARM1138经验之谈.doc_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

内嵌USB仿真器的Cortex-M3开发板EasyARM1138是专门针对广大电子信息专业在校大学生而设计的一款基于ARM Cortex-M3先进内核的高性能、低价格开发板,用于教学、毕业设计、电子竞赛,等等。也是广大单片机爱好者、开发工程师首选的Cortex-M3开发板。EasyARM1138的核心MCU是Luminary Micro公司的Stellaris(群星)系列ARM之LM3S1138。该芯片采用的是国际上最优秀的MCU内核设计公司ARM最新推出的先进Cortex-M3处理器;国内最大、技术最强的晶圆制造公司台积电(TSMC)代工;世界上最专业的封装测试公司(OSE、i2a/IPAC)层层把关,确保产品的可靠性。Stellaris(群星)系列ARM芯片在电磁兼容性方面的优势明显。 今天拿到了周立功的EasyARM1138开发板,又要准备大干一场了!晒晒:我准备分以下几个方面开始学习:1.了解LM3s1138内部结构,包括存储器,ADC,GPIO,等等。其中我认为最重要的是对各个寄存器地址的掌握。因为个人认为写驱动程序就是对各种寄存器的读写,只要把各个寄存器的地址弄清楚了(个人愚见),那么很多问题也就迎刃而解了。2.熟悉软件开发平台IAR。这一点我就不想多啰唆了,反正每个处理器都有一个自己的软件开发平台,所以我就烦感:又得花时间去熟悉。那么多家大公司能不能合伙一起开发一个软件平台呢,这样给用户带来好多的方便。3.软件硬件结合开发。这就要好多东西了!有的搞的,呵呵。下面结合实例程序谈谈对这个板子的理解。这是一个简单的LED程序:第一行是添加到系统的头文件,我们找到这个头文件:在这个头文件里面,又包含了很多的头文件,还有一些宏定义,不要怕麻烦,在看看这些子头文件里面到底是什么:我们打开第一个头文件hw_types.h,字面意思应该是硬件类型的定义。打开看看就知道了:果然如此,第一句就说这是Stellaris外设驱动程序库3223的一部分;第二句蓝色字体就是说定义了一个Boolean类型,它的值是true 表示1,false表示0。我们接着往下看:同样,这里也无非就是些#define,咋一看有点复杂。不怕,我们看看蓝体字:意思是宏硬件访问,不管是直接访问还是通过bit-band区域访问。这里我对bit-band 就不了解了,没关系,现在就去了解它。查看lm3s1138的datasheet。这里说的很清楚。具体是这样的:Stellaris器件内部的SRAM的地址是0x2000.0000,为了减少读修改写(RMW)操作的时间,ARM在Cortex-M3处理器中引入了bit-banding技术。在bit-banding使能的处理器中,存储器映射的特定区域(SRAM和外设空间)能够使用地址别名,在单个原子操作中访问各个位。使用下面的公式来计算bit-band别名:bit-band别名 = bit-band基址 + (字节偏移量 * 32) + (位编号 * 4)例如,如果要修改地址0x2000.1000的位3,则bit-band别名计算如下:0x2200.0000 + (0x1000 * 32) + (3 * 4) = 0x2202.000C通过计算得出的别名地址,对地址0x2202.000C执行读/写操作的指令仅允许直接访问地址0x2000.1000处字节的位3。其中0x2200.0000是bit-band基址的起始地址,0x1000是偏移地址,3是位编号。好,这里先告一段落,我们继续看前面的宏:#define HWREG(x) (* ( (volatile unsigned long *) (x) ) 这一句后面的 (*(volatile unsigned long *)(x) 是什么意思呢?我也不知道了,那么百度一下吧。搜到这样的文章:#define A (* (volatile unsigned long *) 详解2008/08/03 09:00 A.M.#define A (* (volatile unsigned long *) 0x48000000 ) 对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。 举个例子,比如像寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了。#define A (*(volatile unsigned long *) 0x48000000 ). A = 0x01;. 这实际上就是内存映射机制的方便性了。其中volatile关键字是嵌入式系统开发的一个重要特点。volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变。volatile 限定编译器不对这个指针的指向的存储单元进行优化, 即不用通用寄存器暂时代替这个指针的指向的存储单元,而是每次取值都直接到指针的指向的存储单元取值.volatile 主要用于变量会异步改变的情况下,主要有三个方面:1.cpu外设寄存器 2.中断和主循环都会用到的全局变量 3.操作系统中的线程间都会用到的公共变量.上述表达式拆开来分析,首先(volatile unsigned long *) 0x48000000的意思是把0x48000000强制转换成volatile unsigned long类型的指针,即对指针的操作的范围是从0x48000000开始的4个字节(long型).暂记为p,那么就是#define A *p,即A为P指针指向位置的内容了。这里就是通过内存寻址访问到寄存器A,可以读/写操作!仔细看看这位兄台的文章,说的很清楚了。那么我们的那句:#define HWREG(x) (* ( (volatile unsigned long *) (x) )就是等于 #define HWREG(x) (x),这里的(x)就是你想设置的存储器地址了。例如HWREG(0x22000000)=0x12就是把0x12这个数存储在地址0x22000000里面。呵呵 A=HWREG(0x22000000)就是把存储空间0x22000000里面的数据读出来。OK,这里搞定!接下来看下面这个宏:#define HWREGBITW(x, b) HWREG(unsigned long)(x) & 0xF0000000) | 0x02000000 | (unsigned long)(x) & 0x000FFFFF) 5) | (b) 2)初一看有点长,其实不用怕。一步一步来:首先根据C语言的语法规则()的优先级最高,那先算()里面的呗。b2=b*4记为b1;(x)&0xF000000就得到高4位的值,低28位置0记为X1;x&0x000FFFFFF就得到低20位的值,高12位置0记为X2;X25=X2*32记为X3;X1|0x02000000记为X4;X3|X4记为X5;好,现在设x=0x20001000,b=3。那么算得X5=0x2202000C。这个X5貌似见过,对,哈哈就是上文的bit-band的值。现在清楚了:这个宏的作用就是计算对应的bit-band的地址。例如:HWREGBITW(0x20001000,3)=1就表示把1写进0x20001000存储空间的位3,而且对应的bit-band地址是0x2202000C的位3。同理下面两个define HWREGBITH(x, b) HWREGH(unsigned long)(x) & 0xF0000000) | 0x02000000 | (unsigned long)(x) & 0x000FFFFF) 5) | (b) 2)#define HWREGBITB(x, b) HWREGB(unsigned long)(x) & 0xF0000000) | 0x02000000 | (unsigned long)(x) & 0x000FFFFF) 5) | (b) 2)也是一样的,只是数据的宽度不同。至此,hw_types.h头文件里面的宏都差不多弄清楚了。说差不多是因为还有些我不懂的东西,贴图期待高手解决:今天是学习LM3s1138的第二天,我们接着昨天的继续学习。昨天我打开了SystemInit.h的头文件,深入学习了里面的hw_types.h子头文件。今天我开始学习另外的几个头文件:hw_memmap.h 。这个头文件就比较简单了从字面意思看就知道是存储器映射的头文件。我们打开看看,果不其然:这和LM3s1138datasheet上是一样的:只是这个头文件里面只定义了它的起始地址。还有些存储器的映射我这里就不一一例举了。好,接下来看看hw_ints.h里面的东西:从第一行看这是一个定义错误的任务;我们看看datasheet上是怎么说的:我的理解是这样的:CPU的中断是由异常引发的,异常也有多种。于是怎么处理多个异常呢?ARM Cortex-M3处理器和嵌套向量中断控制器(NVIC)区分所有的异常并对其进行处理。在出现异常时,处理器的状态被自动存储在堆栈中,并在中断服务程序结束后自动从堆栈中恢复。所以CPU先给每个异常分配一个堆栈地址即向量号。这样就处理好了异常的先后顺序。比如:#define FAULT_NMI 2 就表示不可屏蔽的中断(NMI)是优先级为2的级别 这里就用 FAULT_NMI 表示它在堆栈中的具体优先级2,这样既清楚又方便。其他的同理。继续往下看:这定义的是中断顺序号和上面的异常是一样的,这里就不在啰唆了。 好,那么关于hw_ints.h头文件就初步学习了。下午再看下面的:/*/ interrupt.h - Prototypes for the NVIC Interrupt Controller Driver./ Copyright (c) 2005-2008 Luminary Micro, Inc. All rights reserved./ / Software License Agreement#ifndef _INTERRUPT_H_#define _INTERRUPT_H_/*/ If building with a C+ compiler, make all of the definitions in this header/ have a C binding./*#ifdef _cplusplusextern C#endif/*/ Macro to generate an interrupt priority mask based on the number of bits/ of priority supported by the hardware./*#define INT_PRIORITY_MASK (0xFF (8 - NUM_PRIORITY_BITS) & 0xFF)/*/ Prototypes for the APIs./*extern tBoolean IntMasterEnable(void);extern tBoolean IntMasterDisable(void);extern void IntRegister(unsigned long ulInterrupt, void (*pfnHandler)(void);extern void IntUnregister(unsigned long ulInterrupt);extern void IntPriorityGroupingSet(unsigned long ulBits);extern unsigned long IntPriorityGroupingGet(void);extern void IntPrioritySet(unsigned long ulInterrupt, unsigned char ucPriority);extern long IntPriorityGet(unsigned long ulInterrupt);extern void IntEnable(unsigned long ulInterrupt);extern void IntDisable(unsigned long ulInterrupt);/*/ Mark the end of the C bindings section for C+ compilers./*#ifdef _cplusplus#endif看起来有点复杂,但是不要怕相信毛主席那句“一切反动派都是纸老虎”。一步一步来看。先看看说明文档。英文意思是说intrrupt.h头文件是NVIC中断控制器的驱动器原型。再下面的英文意思是如果是一个C+编译器,要把#ifdef _cplusplusextern C#endif 包含进去。这里声明了一个外部变量“C”,只要_cplusplus在前面被定义过,那么就可以使用 “C”这个字符了。这种条件编译对于提高C源程序的通用性是很有好处的。如果一个C源程序在不同计算机系统上运行,而不同的计算机又有一定的差异(例如,有的机器以16位存放一个整数,有的是32位存放一个整数),这样往往需要对源程序做必要的修改,这就降低了程序的通用性。再回到这里,那如果没有申明_cplusplus呢?查查C语言程序设计的条件编译那节说得很详细。就执行下面的程序。这里我想好好复习下C语言程序设计。条件编译是对意思就是希望程序中一部分内容旨在满足一定条件时才编译,这对于处理器节省内存是很有用的。具体的例子下次碰到再好好研究,呵呵继续往下看是说宏#define INT_PRIORITY_MASK (0xFF (8 - NUM_PRIORITY_BITS) & 0xFF) 生成一个中断优先码,这个优先码是由硬件支持的优先级别。算算这个INT_PRIORITY_MASK到底等于多少。先要查出NUM_PRIORITY_BITS是多少,我猜应该在上文说道的hw_ints.h里面。果不其然:我用鼠标划过的就是它的出处,再返回去hw_ints.h看看它是何方神圣。上面的英文说它是优先级的总数。再结合上面的 #define NUM_INTERRUPTS 64 。因为Cortex-M3有64个中断源,这样是为了方便统计。同理#define NUM_PRIORITY_BITS 3 也是对某种类型中断的统计并且这种中断有3个,但是具体哪三个我就真的不知道了。查了datasheet也没发现。先放在这里,以后再来解决。反正我知道NUM_PRITORITY_BITS就是3。再回去算得INT_PRIORITY_MASK 是224。这个224又有什么含义呢?我找了好久的资料,还是一头雾水。也先放着。我们重点看下面的API函数原型。看第一个:extern tBoolean IntMasterEnable(void); 它是一个外部函数,函数的返回值是tBoolean类型。那么什么是tBoolean类型呢?(字面意思是布尔型的)打开这个函数:tBooleanIntMasterEnable(void) / / Enable processor interrupts. / return(CPUcpsie();这是一个使能处理器中断的函数,ZLG是这么解释的:如果在调用该函数之前处理器中断是使能的,则返回false;如果在调用该函数之前处理器中断是禁止的,则返回true。那么接下来:extern tBoolean IntMasterDisable(void); 这个函数就好理解了,它是一个禁止处理器中断的函数。如果在调用该函数之前处理器中断是使能的,则返回false;如果在调用该函数之前处理器中断是禁止的,则返回true。写到这里,我决定要先放一放这个今天已经是学习LM3s1138的第三天了,通过前面两天的学习大概了解了这个M3处理器的一些寄存器信息。今天努力把剩下的两个头文件搞定。首先是sysctl.h头文件:看头文件的名字就知道是系统管理的头文件。这里宏定义了一大堆的系统控制寄存器的地址,这与前面的类似,不在多说。我们先把这些地址放到一边,因为地址是不会变的。我们关心的是它下面的API原型驱动函数的用法。比较多,我们选择一部分进行分析。系统控制总体上包含了:LDO控制、时钟控制、复位控制、外设控制、睡眠与深度睡眠、杂项功能、中断操作、时钟验证。一般我们只用前面6个,后面两个用的不多。废话不多说了。第一个:LDO控制。百度上面是这么描述的:LDO是“Low Drop-Out”的缩写,是一种线性直流电源稳压器。LDO的显著特点是输入与输出之间的低压差,能达到数百毫伏,而传统线性稳压器(如7805)一般在1.5V以上。例如,Exar(原Sipex)公司的LDO芯片SP6205,当额定的输出为3.3V/500mA时,典型压差仅为0.3V,因此输入电压只要不低于3.6V就能满足要求,而效率可高达90%。这种低压差特性可以带来降低功耗、缩小体积等好处。芯片的datasheet上面是这么描述的:Stellaris系列ARM集成有一个内部的LDO稳压器,为处理器内核及片内外设提供稳定的电源。这样,只需要为整颗芯片提供单一的3.3V电源就能够使其正常工作,简化了系统电源设计并节省成本。LDO输出电压默认值是2.50V,通过软件可以在2.252.75V之间调节,步进50mV。降低LDO输出电压可以节省功耗。LDO管脚除了给处理器内核供电以外,还可以为芯片以外的电路供电,但是要注意控制电流大小和电压波动,以免干扰处理器内核的正常运行。片内LDO输入电压是芯片电源VDD(范围3.03.6V),LDO输出到一个名为“LDO”的管脚。对于Fury和DustDevil家族(LM3S1000以上型号),LDO管脚要连接到内核电源VDD25管脚上,对于Sandstorm家族(LM3S1000以下型号)VDD25管脚是内置的,因此不必从外部连接。注意:在LDO管脚和GND之间必须接一个13.3F的瓷片电容。注意:在启用片内锁相环PLL之前,必须要将LDO电压设置在2.75V。到这里,我们对LDO的功能有了大致的了解。但是具体输出LDO电压是哪个函数设置?怎么设置?LDO对应的寄存器地址是多少?带着这些问题我们再看看上面列出来的函数吧。直接看函数名肯定就是这三个了:extern void SysCtlLDOSet(unsigned long ulVoltage);extern unsigned long SysCtlLDOGet(void);extern void SysCtlLDOConfigSet(unsigned long ulConfig);第一个是设置LDO的输出电压,来看看具体的原函数:voidSysCtlLDOSet(unsigned long ulVoltage) / / Check the arguments. / ASSERT(ulVoltage = SYSCTL_LDO_2_25V) | (ulVoltage = SYSCTL_LDO_2_30V) | (ulVoltage = SYSCTL_LDO_2_35V) | (ulVoltage = SYSCTL_LDO_2_40V) | (ulVoltage = SYSCTL_LDO_2_45V) | (ulVoltage = SYSCTL_LDO_2_50V) | (ulVoltage = SYSCTL_LDO_2_55V) | (ulVoltage = SYSCTL_LDO_2_60V) | (ulVoltage = SYSCTL_LDO_2_65V) | (ulVoltage = SYSCTL_LDO_2_70V) | (ulVoltage = SYSCTL_LDO_2_75V); / / Set the LDO voltage to the requested value. / HWREG(SYSCTL_LDOPCTL) = ulVoltage;现在很好理解了,只要设置好ulVoltage的值就可以输出允许输出范围内的电压值了。这个函数表面上看起来不难理解,但是具体ASSERT()代表什么意思呢?没关系,百度一下。搜到一篇这样的文章:void CRoundButton:DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) aix ASSERT(lpDrawItemStruct!=NULL); . . . 程序用这个函数是啥意思?起什么作用? - ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。 ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。 - ASSERT宏定义如下 #define ASSERT(f) do if (!(f) & AfxAssertFailedLine(THIS_FILE, _LINE_) AfxDebugBreak(); while (0) ASSERT(逻辑表达式) 如果括号中的逻辑表达式值为假的话,会弹出调试命令窗口,提示具体在哪个文件的哪一行发生了断言错误! - ASSERT Evaluates an expression, and displays a diagnostic message if the expression is FALSE. Ignored in retail builds. Syntax ASSERT( cond ); Parameters cond Expression to evaluate. Remarks In debug builds, if the expression is FALSE, this macro displays a message box with the text of the expression, the name of the source file, and the line number. The user can ignore the assertion, enter the debugger, or quit the application. Example ASSERT(rtStartTime = rtEndTime); - 断言(ASSERT)的使用,方法很简单。为什么要用,初学者可能比较迷惑。 契约式编程讲的比较清楚,建议可以先看看这类书。 一个函数由前置条件、后置条件和不变式组成。在VC中,我们可以通过断言来保证这三个条件。可以大大提高了软件的质量。 - 如果ASSERT()中的条件不成立(比如 ASSERT(0) ; ),会弹出一个比较吓人的对话框。 点击重试,可以到达 ASSERT 断言不成立的那一行, 此时可以在watch窗口查看变量值,找出出错的原因。 如果程序能够继续运行,可以按F5继续调试这位兄台说的很明白了,就是当ASSERT的()里面为1是,就执行下面的程序,为0是终止程序。好,我们再看看这个SYSCTL_LDO_2_25V 是不是就代表了输出电压是2.25V,链接它的定义出处,果然如此。它实际上是一个寄存器的的值:#define SYSCTL_LDO_2_25V 0x00000005 / LDO output of 2.25V 好了,这个sysclt.h头文件里面还有很多的宏和外部API原函数。这里就不一一例举了,我们旨在走通这个基本的函数框架,以后遇到问题在来深究。接着看下面的jpio.h头文件:同理,有了对上面各个头文件的理解过程,在这里就不在一一的说明,这是大概的理解就行了。I/O(Input/Output)接口是一颗微控制器必须具备的最基本外设功能。在Stellaris系列ARM里,所有I/O都是通用的,称为GPIO(General Purpose Input/Output)。GPIO模块由38个物理GPIO块组成,一块对应一个GPIO端口(PA、PB、PC、PD、PE、PF、PG、PH)。每个GPIO端口包含8个管脚,如PA端口是PA0PA7。GPIO模块遵循FiRM(Foundation IP for Real-Time Microcontrollers)规范,并且支持多达60个可编程输入/输出管脚(具体取决于与GPIO复用的外设的使用情况)。好了,关于对LM3s1138的寄存器学习先告一段落。下面我要开始自己动手写程序了。我的想法是遇到问题,然后解决问题,再把解决这个问题的过程写出来,和大家一起交流。好久没写东西了,不是我偷懒,而是最近很背。不说了,开始我们的LED吧!先上硬件电路图:既然是玩转LED,那么设计任务就不能草率。我的设计要求是:先依次点亮LED1,LED2,LED3,时间间隔为1s,并循环。当按下K1时,熄灭所有的LED,再次按下K1,重新点亮。LED的亮灭状态可以同过UART实时显示。这个任务不难,逻辑很清楚。设计的重点应该是UART实时显示和准确的定时。先不管UART,先做LED的亮灭。(编译软件是IAR)程序的开始先包含头文件和定义GPIO端口:#include systemInit.h/ 定义LED#define LED23_PERIPH SYSCTL_PERIPH_GPIOG#define LED23_PORT GPIO_PORTG_BASE#define LED23_PINS GPIO_PIN_2 | GPIO_PIN_3#define LED1_PERIPH SYSCTL_PERIPH_GPIOD#define LED1_PORT GPIO_PORTD_BASE#define LED1_PIN GPIO_PIN_0/定义KEY#define KEY_PERIPH SYSCTL_PERIPH_GPIOD#define KEY_PORT GPIO_PORTD_BASE#define KEY_PIN GPIO_PIN_1然后,在main函数里面先调用下面两个函数:jtagWait();clockInit(); 第一个是防止JTAG失效。什么是JTAG?为什么要防止它失效呢?这个函数又是怎么防止JTAG失效的呢?带着这些疑惑,我们来一一解答。不妨先百度一下JTAG:JTAG是英文“Joint Test Action Group(联合测试行为组织)”的词头字母的简写,该组织成立于1985 年,是由几家主要的电子制造商发起制订的PCB 和IC 测试标准。JTAG 建议于1990 年被IEEE 批准为IEEE1149.1-1990 测试访问端口和边界扫描结构标准。该标准规定了进行边界扫描所需要的硬件和软件。自从1990 年批准后,IEEE 分别于1993 年和1995 年对该标准作了补充,形成了现在使用的IEEE1149.1a-1993 和IEEE1149.1b-1994。JTAG 主要应用于:电路的边界扫描测试和可编程芯片的在系统编程。JTAG也是一种国际标准测试协议(IEEE 1149.1兼容),主要用于芯片内部测试。现在多数的高级器件都支持JTAG协议,如DSP、FPGA器件等。标准的JTAG接口是4线:TMS、TCK、TDI、TDO,分别为模式选择、时钟、数据输入和数据输出线。 相关JTAG引脚的定义为:TCK为测试时钟输入;TDI为测试数据输入,数据通过TDI引脚输入JTAG接口;TDO为测试数据输出,数据通过TDO引脚从JTAG接口输出;TMS为测试模式选择,TMS用来设置JTAG接口处于某种特定的测试模式;TRST为测试复位,输入引脚,低电平有效。GNDTI还定义了一种叫SBW-JTAG的接口,用来在引脚较少的芯片上通过最少的利用引脚实现JTAG接口,它只有两条线,SBWTCK,SBWTDIO。实际使用时一般通过四条线连接,VCC,SBWTCK,SBTDIO,GND,这样就可以很方便的实现连接,又不会占用大量引脚。JTAG最初是用来对芯片进行测试的,基本原理是在器件内部定义一个TAP(Test Access Port测试访问口)通过专用的JTAG测试工具对进行内部节点进行测试。JTAG测试允许多个器件通过JTAG接口串联在一起,形成一个JTAG链,能实现对各个器件分别测试。现在,JTAG接口还常用于实现ISP(In-System Programmable;在线编程),对FLASH等器件进行编程。JTAG编程方式是在线编程,传统生产流程中先对芯片进行预编程现再装到板上因此而改变,简化的流程为先固定器件到电路板上,再用JTAG编程,从而大大加快工程进度。JTAG接口可对PSD芯片内部的所有部件进行编程。在硬件结构上,JTAG 接口包括两部分:JTAG 端口和控制器。与JTAG 接口兼容的器件可以是微处理器(MPU)、微控制器(MCU)、PLD、CPL、FPGA、ASIC 或其它符合IEEE1149.1 规范的芯片。IEEE1149.1 标准中规定对应于数字集成电路芯片的每个引脚都设有一个移位寄存单元,称为边界扫描单元BSC。它将JTAG 电路与内核逻辑电路联系起来,同时隔离内核逻辑电路和芯片引脚。由集成电路的所有边界扫描单元构成边界扫描寄存器BSR。边界扫描寄存器电路仅在进行JTAG 测试时有效,在集成电路正常工作时无效,不影响集成电路的功能。关于简单JTAG电缆目前有各种各样简单JTAG电缆,其实只是一个电平转换电路,同时还起到保护作用。JTAG的逻辑则由运行在PC上的软件实现,所以在理论上,任何一个简单 JTAG电缆,都可以支持各种应用软件,如Debug等。可以使用同一个JTAG电缆写Xilinx CPLD,AXD/ADW调试程序。关键再于软件的支持,大多数软件都不提供设定功能,因而只能支持某种JTAG电缆。 关于简单JTAG电缆的速度 JTAG 是串行接口,使用打印口的简单JTAG电缆,利用的是打印口的输出带锁存的特点,使用软件通过I/O产生JTAG时序。由JTAG标准决定,通过JTAG 写/读一个字节要一系列的操作,根据我的分析,使用简单JTAG电缆,利用打印口,通过JTAG输出一个字节到目标板,平均需要43个打印口I/O, 在我机器上(P4 1.7G),每秒大约可进行660K次 I/O 操作,所以下载速度大约在660K/43, 约等于15K Byte/S. 对于其他机器,I/O速度大致相同,一般在600K 800K. JTAG接口解读通常所说的JTAG大致分两类,一类用于测试芯片的电气特性,检测芯片是否有问题;一类用于Debug;一般支持JTAG的CPU内都包含了这两个模块。一个含有JTAG Debug接口模块的CPU,只要时钟正常,就可以通过JTAG接口访问CPU的内部寄存器和挂在CPU总线上的设备,如FLASH,RAM,SOC(比如4510B,44Box,AT91M系列)内置模块的寄存器,象UART,Timers,GPIO等等的寄存器。上面说的只是JTAG接口所具备的能力,要使用这些功能,还需要软件的配合,具体实现的功能则由具体的软件决定。例如下载程序到RAM功能。了解SOC的都知道,要使用外接的RAM,需要参照SOC DataSheet的寄存器说明,设置RAM的基地址,总线宽度,访问速度等等。有的SOC则还需要Remap,才能正常工作。运行Firmware时,这些设置由Firmware的初始化程序完成。但如果使用JTAG接口,相关的寄存器可能还处在上电值,甚至时错误值,RAM不能正常工作,所以下载必然要失败。要正常使用,先要想办法设置RAM。在ADW中,可以在Console窗口通过Let 命令设置,在AXD中可以在Console窗口通过Set命令设置。下面是一个设置AT91M40800的命令序列,关闭中断,设置CS0-CS3, 并进行Remap,适用于AXD(ADS带的Debug)setmem 0xfffff124,0xFFFFFFFF,32 关闭所有中断setmem 0xffe00000,0x0100253d,32 设置CS0setmem 0xffe00004,0x02002021,32 设置CS1setmem 0xffe00008,0x0300253d,32 设置CS2setmem 0xffe0000C,0x0400253d,32 设置CS3setmem 0xffe00020,1,32 Remap如果要在ADW(SDT带的DEBUG)中使用,则要改为:let 0xfffff124=0xFFFFFFFF 关闭所有中断let 0xffe00000=0x0100253d 设置CS0let 0xffe00004=0x02002021 设置CS1let 0xffe00008=0x0300253d 设置CS2let 0xffe0000C=0x0400253d 设置CS3let 0xffe00020=1 Remap为了方便使用,可以将上述命令保存为一个文件config.ini, 在Console窗口输入 ob config.ini 即可执行。使用其他debug,大体类似,只是命令和命令的格式不同。设置RAM时,设置的寄存器以及寄存器的值必须和要运行程序的设置一致。一般编译生成的目标文件是ELF格式,或类似的格式,包含有目标码运行地址,运行地址在Link时候确定。Debug下载程序时根据ELF文件中的地址信息下载程序到指定的地址。如果在把RAM的基地址设置为0x10000000, 而在编译的时候指定Firmware的开始地址在0x02000000, 下载的时候,目标码将被下载到0x02000000,显然下载会失败。通过JTAG下载程序前应关闭所有中断,这一点和Firmware初始化时关闭中断的原因相同。在使用JTAG接口的时候,各中断的使能未知,尤其是FLASH里有可执行码的情况,可能会有一些中断被使能。使用JTAG下载完代码,要执行时,有可能因为未完成初始化就产生了中断,导致程序异常。所以,需要先关闭中断,一般通过设置SOC的中断控制寄存器完成。使用JTAG写Flash。在理论上,通过JTAG可以访问CPU总线上的所有设备,所以应该可以写FLASH,但是FLASH写入方式和RAM大不相同,需要特殊的命令,而且不同的FLASH擦除,编程命令不同,而且块的大小,数量也不同,很难提供这一项功能。所以一般Debug不提供写Flash功能,或者仅支持少量几种Flash。目前就我知道的,针对ARM,只有FlashPGM这个软件提供写FLASH功能,但使用也非常麻烦。AXD,ADW都不提供写FLASH功能。我写Flash的方法时是,自己写一个简单的程序,专门用于写目标板的FLASH,利用JTAG接口,下载到目标板,再把要烧写的目标码装成BIN格式,也下到目标板(地址和烧FLASH的程序的地址不同),然后运行已经下载的烧FLASH的程序。使用这种方式,比起FlashPGM的写Flash,速度似乎要快一些。关于简单JTAG电缆。目前有各种各样简单JTAG电缆,其实只是一个电平转换电路,同时还起到保护作用。JTAG的逻辑则由运行在PC上的软件实现,所以在理论上,任何一个简单JTAG电缆,都可以支持各种应用软件,如Debug等。我就曾使用同一个JTAG电缆写Xilinx CPLD,AXD/ADW调试程序。关键再于软件的支持,大多数软件都不提供设定功能,因而只能支持某种JTAG电缆。关于简单JTAG电缆的速度。JTAG是串行接口,使用打印口的简单JTAG电缆,利用的是打印口的输出带锁存的特点,使用软件通过I/O产生JTAG时序。由JTAG标准决定,通过JTAG写/读一个字节要一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论