LM3S API函数解读范例
来源:互联网 发布:淘宝售后时间 编辑:程序博客网 时间:2024/06/04 19:52
jtagWait()函数解读
1.通常在主函数的开始都要调用jtagWait()函数,如工程模版的主函数,
int main(void)
{
jtagWait(); // 防止JTAG失效,重要!
clockInit(); // 时钟初始化:晶振,6MHz
for (;;)
{
}
}
2.关于函数的解释,先要找到函数的定义,可以在函数的调用处指向函数名后右键选择“Go to definition of …”。
函数jtagWait()在systemInit.c文件中,其功能是防止JTAG接口失效。函数定义:
void jtagWait(void)
{
SysCtlPeriEnable(KEY_PERIPH); // 使能KEY所在的GPIO端口
GPIOPinTypeIn(KEY_PORT, KEY_PIN); // 设置KEY所在管脚为输入
if (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00) // 若复位时按下KEY,则进入
{
for (;;); // 死循环,以等待JTAG连接
}
SysCtlPeriDisable(KEY_PERIPH); // 禁止KEY所在的GPIO端口
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
① 第一个函数SysCtlPeriEnable()的功能是使能外围设备,原名是SysCtlPeripheralEnable(),用#define替换是为了使用的方便,该函数在sysctl.c文件中,可以先加入该文件以便使用“Go to definition of …”找到其定义。其定义为:
Void SysCtlPeripheralEnable(unsigned long ulPeripheral)
{
ASSERT(SysCtlPeripheralValid(ulPeripheral)); // Check the arguments.
HWREG(g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)]) |=
SYSCTL_PERIPH_MASK(ulPeripheral); // Enable this peripheral.
}
该函数中的ASSERT()是一个宏,其定义在debug.h中,其作用是计算括号中的表达式,为0则程序报告错误并终止执行,非0则继续向下执行。函数SysCtlPeripheralValid()用于判断传入参数的有效性,即判断是否为该函数可以处理的外围设备,是则返回真,否则返回假,在调用中传入参数KEY_PERIPH,其实为SYSCTL_PERIPH_GPIOG,其值为0x20000040,该值不是寄存器的地址,暂时不清楚该值的意义。
HWREG()又是定义的一个宏,在文件hw_types.h中,其定义为:
#define HWREG(x) (*((volatile unsigned long *)(x)))
其中(volatile unsigned long *)(x)是将x强制转换为无符号长整型的指针,*((volatile unsigned long *)(x))是引用该指针所指向的存储单元,例如HWREG(0x20000000)=1;就是向地址为0x20000000的存储单元写入1。
传入HWREG ()的参数为g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)]。
首先看g_pulRCGCRegs[],这是一个静态只读的无符号长整型数组,其定义为:
static const unsigned long g_pulSCGCRegs[] =
{
SYSCTL_SCGC0, //0x400FE110
SYSCTL_SCGC1, //0x400FE114
SYSCTL_SCGC2 //0x400FE118
};
这其实是三个睡眠模式时钟选通控制寄存器,每个位控制一个给定接口、功能、或单元的时钟使能,如果置位,则对应的单元接收时钟并运行,否则,对应的单元不使用时钟并禁止(节能),这些位的复位状态都为0(不使用时钟),即所有功能单元都禁止,应用所需的端口需通过软件来使能。分了三个寄存器来管理所有接口、功能、或单元的时钟。SYSCTL_SCGC0=0x400FE110 表示寄存器的地址。
再看SYSCTL_PERIPH_INDEX(ulPeripheral),此处的ulPeripheral=KEY_PERIPH =SYSCTL_PERIPH_GPIOG=0x20000040。SYSCTL_PERIPH_INDEX()的定义为:
#define SYSCTL_PERIPH_INDEX(a) (((a) >> 28) & 0xf),此处计算结果SYSCTL_PERIPH_INDEX(0x20000040)=2,而g_pulSCGCRegs[2]正好是睡眠模式时钟选通控制寄存器2 (SCGC2),正好是控制GPIOA—GPIOH的时钟使能。因此不难猜想SYSCTL_PERIPH_INDEX(a)是为了选择寄存器SCGC0、SCGC1、SCGC2中的一个。
因此HWREG(g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)])意思就是选中寄存器SCGC2,整句的意思是要改写该寄存器的值。于是继续看后半句SYSCTL_PERIPH_MASK(ulPeripheral),当然 |= 是复合赋值a|=b相当于a=a|b。
#define SYSCTL_PERIPH_MASK(a) (((a) & 0xffff) << (((a) & 0x001f0000) >> 16)),该句比较复杂,暂时不知道为什么要这样写,但此处计算结果SYSCTL_PERIPH_MASK(0x20000040)=0x0040。因此HWREG(g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)]) |=
SYSCTL_PERIPH_MASK(ulPeripheral);
一句的目的是将寄存器SCGC2的第6位GPIOG置1而使能GPIOG端口。另外,再看一下SCGC2的定义如下:
7
6
5
4
3
2
1
0
GPIOH
GPIOG
GPIOF
GPIOE
GPIOD
GPIOC
GPIOB
GPIOA
这就不难理解为什么有如下定义
#define SYSCTL_PERIPH_GPIOA 0x20000001 // GPIO A
#define SYSCTL_PERIPH_GPIOB 0x20000002 // GPIO B
#define SYSCTL_PERIPH_GPIOC 0x20000004 // GPIO C
#define SYSCTL_PERIPH_GPIOD 0x20000008 // GPIO D
#define SYSCTL_PERIPH_GPIOE 0x20000010 // GPIO E
#define SYSCTL_PERIPH_GPIOF 0x20000020 // GPIO F
#define SYSCTL_PERIPH_GPIOG 0x20000040 // GPIO G 本例中使用
#define SYSCTL_PERIPH_GPIOH 0x20000080 // GPIO H
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
② 第二个函数GPIOPinTypeIn()其实为GPIOPinTypeGPIOInput(),该函数在gpio.c文件中,其定义为:
Void GPIOPinTypeGPIOInput(unsigned long ulPort, unsigned char ucPins)
{
ASSERT(GPIOBaseValid(ulPort)); // Check the arguments.
GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_IN); // Make the pin(s) be inputs.
GPIOPadConfigSet(ulPort, ucPins, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
// Set the pad(s) for standard push-pull operation.
}
调用该函数时传入的参数为ulPort =GPIO_PORTG_BASE= 0x40026000和ucPins =GPIO_PIN_5= 0x00000020。
第一句有关ASSERT()宏的应用如前所述,不再赘述。
现在来看第二句GPIODirModeSet(ulPort, ucPins, GPIO_DIR_MODE_IN);其中新的参数GPIO_DIR_MODE_IN =0x00000000,该函数的目的是要将GPIOG的第5个管脚置为输入。该函数也在gpio.c文件中,其定义为:
Void GPIODirModeSet(unsigned long ulPort, unsigned char ucPins, unsigned long ulPinIO)
{
ASSERT(GPIOBaseValid(ulPort));
ASSERT((ulPinIO == GPIO_DIR_MODE_IN) || (ulPinIO == GPIO_DIR_MODE_OUT) ||
(ulPinIO == GPIO_DIR_MODE_HW)); // Check the arguments.
HWREG(ulPort + GPIO_O_DIR) = ((ulPinIO & 1) ?
(HWREG(ulPort + GPIO_O_DIR) | ucPins) :
(HWREG(ulPort + GPIO_O_DIR) & ~(ucPins)));
HWREG(ulPort + GPIO_O_AFSEL) = ((ulPinIO & 2) ?
(HWREG(ulPort + GPIO_O_AFSEL) | ucPins) :
(HWREG(ulPort + GPIO_O_AFSEL) &
~(ucPins))); // Set the pin direction and mode.
}
同上,前两句不再赘述,第三句赋值表达式的左边为HWREG(ulPort + GPIO_O_DIR),此处ulPort= =GPIO_PORTG_BASE= 0x40026000,是GPIOG块的基地址,每个块都有相同的GPIO寄存器,因此可以用BASE+OFFSET的方式寻址各个块的寄存器,GPIO_O_DIR= 0x00000400,表明GPIO方向寄存器GPIODIR的偏移量为0x400,因此HWREG(ulPort + GPIO_O_DIR)寻址到了GPIOG的寄存器GPIODIR,该寄存器是数据方向寄存器,GPIODIR 寄存器中设为1的位将相应的管脚配置成输出,而设为0的位将相应的管脚配置成输入,所有位在复位时都会被清零,即默认情况下所有GPIO管脚都是输入。赋值号右边是一个条件表达式,条件为(ulPinIO & 1),ulPinIO为传入的第三个参数,为0则置为输入管脚,为1则置为输出管脚,此处传入GPIO_DIR_MODE_IN =0x00000000,因此条件为假,所以会将(HWREG(ulPort + GPIO_O_DIR) & ~(ucPins))的值写入寄存器GPIODIR,下面分析如何实现,HWREG(ulPort + GPIO_O_DIR)取出GPIODIR的值,此处的ucPins =GPIO_PIN_5= 0x00000020,取反后只有第5位为0,其余位为1,与原值相与后把第5为清0,然后送回寄存器。
第四句与第三句形式一样,不再详细分析,只简单说明其作用,HWREG(ulPort + GPIO_O_AFSEL)为选中GPIO 备用功能选择(GPIOAFSEL)寄存器,向该寄存器中的任意位写“1”表示选择该GPIO线路所对应的硬件控制(功能)。由于所有的位都在复位时都会清零,因此在默认的情况下,并无GPIO线被设为硬件控制(功能)。而参数ulPinIO有三种选择,如下:
#define GPIO_DIR_MODE_IN 0x00000000 // Pin is a GPIO input
#define GPIO_DIR_MODE_OUT 0x00000001 // Pin is a GPIO output
#define GPIO_DIR_MODE_HW 0x00000002 // Pin is a peripheral function
因此ulPinIO=2时则将GPIOAFSEL寄存器的相应位置1,表示选择其硬件控制功能。本例中第5位清0。
③ 第三个函数为GPIOPinRead(),猜想其功能为读取某端口某管脚的状态,该函数也在gpio.c中,其定义为:
Long GPIOPinRead(unsigned long ulPort, unsigned char ucPins)
{
ASSERT(GPIOBaseValid(ulPort));
return(HWREG(ulPort + (GPIO_O_DATA + (ucPins << 2)))); // Return the pin value(s).
}
其中HWREG(ulPort + (GPIO_O_DATA + (ucPins << 2)))这句很重要,体现了一种利用地址线屏蔽而实现可对任意位操作的机制,将地址总线的位[9:2]用作屏蔽位,在读操作过程中,如果与数据位相关联的地址位被设为1,那么读取该值,如果与数据位相关联的地址位被设为0,那么不管它的实际值是什么,都将该值读作0。下面结合本例解释,将各个参数的值代入为HWREG(0x40026000 + (0x000 + (0x00000020 << 2))),结果为HWREG(0x40026080)。
ADDR[9:2]
9
8
7
6
5
4
3
2
1
0
0x080
0
0
1
0
0
0
0
0
0
0
GPIODATA
7
6
5
4
3
2
1
0
如上表所示,GPIODATA寄存器中除第5位外,其余都被屏蔽,可以只读出第5位的状态。
④ 第四个函数SysCtlPeriDisable()的原型为void SysCtlPeripheralDisable(unsigned long ulPeripheral),在sysctl.c文件中,其定义为:
Void SysCtlPeripheralDisable(unsigned long ulPeripheral)
{
ASSERT(SysCtlPeripheralValid(ulPeripheral));
HWREG(g_pulRCGCRegs[SYSCTL_PERIPH_INDEX(ulPeripheral)]) &=
~SYSCTL_PERIPH_MASK(ulPeripheral); // Disable this peripheral.
}
其形式和SysCtlPeripheralEnable()相似,不再赘述。
- LM3S API函数解读范例
- hbase API操作范例
- Runtime API使用范例
- IntPrioritySet lm3s
- Windows API函数调用范例源码大全(一) -- 完全自定义窗体和按钮
- API创建窗体范例代码
- asset transfer api测试范例
- hadoop c++ api调用范例
- 百度地图api定位范例
- 函数的范例
- API解读:Collections
- API解读:StringTokenizer
- API解读:Thread
- API解读:Thread
- Java API详细解读
- ZStack API解读3
- ZStack API解读
- ZStack API解读
- 导入外部JS文件和外部CSS文件以及定义样式表
- 白马非马
- DataGrid中的DataGridCheckBoxColumn用法
- c++学习笔记-------《c++自学通》第四章 表达式与语句
- live writer 写CSDN 博客
- LM3S API函数解读范例
- 使用 SchemaExport 自动建表
- Javascript中类的定义和继承
- c++学习笔记-------《c++自学通》第五章 函数
- MM飞信融合,靠谱
- mediator模式-调停者模式
- C#中virtual,abstract,override修饰符
- 函数指针和指针函数
- 在线编辑器原理