今天拿到了周立功的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 *) 0x48000000 ) 对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。 举个例子,比如像寄存器A(地址假定为0x48000000)写入数据0x01,那么就可以这样设置了。 #define A (*(volatile unsigned long *) 0x48000000 ) 这实际上就是内存映射机制的方便性了。其中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语言的语法规则()的优先级最高,那先算()里面的呗。b<<2=b*4记为b1;(x)&0xF000000就得到高4位的值,低28位置0记为X1;x&0x000FFFFFF就得到低20位的值,高12位置0记为X2;X2<<5=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头文件里面的宏都差不多弄清楚了。说差不多是因为还有些我不懂的东西,贴图期待高手解决:
用户314664 2011-3-9 20:29
用户178146 2009-9-23 13:18
用户195195 2009-9-23 10:27