• 为了准备电赛临时学一下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型数据,指向一个函数地址
  • TM4C123G学习记录(4)--关于ROM前缀函数和HWREG函数_寄存器


二、HWREG函数

(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()使用详解​