- 为了准备电赛临时学一下TM4C123G,简单记录学习内容
- 大家可以在这里下载我收集的资源,非常全面,花了很大功夫收集来的,还有书籍、例程代码等
- 还可以在TI官网下载相关文档TI官网
这两天学习TM4C的时候,看到了不少ROM前缀的库函数(比如ROM_SysCtlClockSet
),还有很多库函数底层用了HWREG
函数,比较迷糊,查资料学习了一下,在此稍作总结
一、ROM前缀函数
1、介绍
- M4的ROM中集成了外设驱动库等代码。使用带ROM的函数,会直接跳转到ROM中去执行。如果不带ROM的话,代码会在Flash中执行。也就是说使用ROM函数可以节省内存空间,而带ROM前缀的函数在功能上和不带的没有区别
- 使用ROM前,需要包含头文件
#include "rom.h"
,并且按这个头文件中的格式定义芯片型号(因为不同型号芯片,函数在ROM中的存储情况不一样,rom.h中会根据这个芯片选择定义进行条件编译,打开看一下就知道了),如TARGET_IS_TM4C123_RB1
,一般这种选型的定义可以放在MDK的Opinion菜单的C/C++选项栏中
2、ROM函数调用分析
以ROM_SysCtlClockSet
函数为例,分析一下调用过程
(1)直接Goto Defination,如下
#if defined(TARGET_IS_TM4C123_RA1) || \
defined(TARGET_IS_TM4C123_RA3) || \
defined(TARGET_IS_TM4C123_RB1) || \
defined(TARGET_IS_TM4C123_RB2)
#define ROM_SysCtlClockSet \
((void (*)(uint32_t ui32Config))ROM_SYSCTLTABLE[23])
#endif
- 首先可以看出定义芯片信号
TARGET_IS_TM4C123_RB1
的作用,这里是一个条件编译 - 分析
ROM_SysCtlClockSet
的定义,可以看到这里是一个强制类型转换,把ROM_SYSCTLTABLE[23]
转换为一个函数指针void (*)(uint32_t ui32Config)
,指向地址ROM_SYSCTLTABLE[23]
处
(2)看一下ROM_SYSCTLTABLE[23]
是什么
#define ROM_APITABLE ((uint32_t *)0x01000010)
#define ROM_VERSION (ROM_APITABLE[0])
....
#define ROM_SYSCTLTABLE ((uint32_t *)(ROM_APITABLE[13]))
- 看到这里是一个基址寻址,
ROM_APITABLE
是一个uint32_t
型指针,指向地址 0x01000010
,这样可以把它看做一个uint32_t数组 -
ROM_SYSCTLTABLE
是(uint32_t *)(ROM_APITABLE[13])
,即取ROM_APITABLE
数组的第13个元素(地址为0x01000010+13*4)的值,然后用一个unt32_t
型指针指向这个值。可以推测,ROM_APITABLE
数组存储的应当也是地址值
(3)小结一下
- ROM中API表从地址0x0100010开始,每4个字节存一个uint32_t型数据,指向一个子表的首地址
- 子表中,每4个字节存一个uint32_t型数据,指向一个函数地址
(1)顾名思义HWREG()的意思就是操作硬件寄存器的意思,里面的参数是tm4c芯片的硬件外设寄存器地址,可以在芯片手册memory地址分配找到。
(2)查看一下定义,有不少类似的函数
//*****************************************************************************
//
// Macros for hardware access, both direct and via the bit-band region.
//
//*****************************************************************************
#define HWREG(x) \
(*((volatile uint32_t *)(x)))
#define HWREGH(x) \
(*((volatile uint16_t *)(x)))
#define HWREGB(x) \
(*((volatile uint8_t *)(x)))
#define HWREGBITW(x, b) \
HWREG(((uint32_t)(x) & 0xF0000000) | 0x02000000 | \
(((uint32_t)(x) & 0x000FFFFF) << 5) | ((b) << 2))
#define HWREGBITH(x, b) \
HWREGH(((uint32_t)(x) & 0xF0000000) | 0x02000000 | \
(((uint32_t)(x) & 0x000FFFFF) << 5) | ((b) << 2))
#define HWREGBITB(x, b) \
HWREGB(((uint32_t)(x) & 0xF0000000) | 0x02000000 | \
(((uint32_t)(x) & 0x000FFFFF) << 5) | ((b) << 2))
- 由定义不难看出,
HWREG(x)
函数的作用,就是先把x转为一个指向x的volatile uint32_t指针,然后从中取值,这样只要知道寄存器地址,我们就可以方便地对其进行读写操作
(3)更多介绍,参考TIVA中HWREG()使用详解