首页 > 应用与设计 > 工业应用 > C2837x入门指南 >

电机驱动

最新课程

热门课程

C2837x入门指南(四) — 外设寄存器操作

大家好 本章节我们将要讨论的是外设寄存器的头文件 我们先会了解F2837xD寄存器 C代码头文件的使用 并且学会怎样去编程这些外设的寄存器 然后知道寄存器结构体 是如何以 Linker.cmd 进行映射的 首先我们看一个传统的底层驱动的C代码示例 在这个例子里 我们是通过宏定义的方式 将一个地址强制指针类型转化 将它赋给一个标号或者说寄存器的名字 然后在代码里就可以对该地址直接进行操作 比如赋一个值 或者仅对其内容的某一个位 进行某个逻辑运算等等 这个方法的优点其实是非常明显的 简单粗暴 然而它的缺点也一样明显 那就是当仅需要操作某一个位的时候 用户需要去设定一个独立的 mask 仅对该位进行处理 而且逻辑或和逻辑与需要两个不同的 mask 同时在调试的时候 不能很容易地在窗口里看到某些位的状态 最重要的一点是在很多的情况下 它编译生成的代码会比较累赘 效率很低 从而影响代码的执行时间 另一种办法是使用结构体的方式进行编程 如这个示例 将同一个外设的所有寄存器定义在一个结构体里 然后在一个寄存器里定义一个联合体 分别对应它的全部和某些位 以支持不同类型需要的操作 在生成代码的寻址方面 由于将统一外设的寄存器放在一起 而且物理上也确实是相连的 就可以只需要找到第一个寄存器的地址 然后通过 offset 偏移量的方式快速定位 从而提高效率 当然它的优缺点也非常明显 可以很容易的操作某个位 然后可以在调试窗口看到 最重要是可以生成更高效的代码 但是由于结构体本身和寄存器名比较长 不易记住且不易介入 从而会影响开发效率 下面我们先来看看细节的几个点 这是调试窗口可以看到的位的值可能发生的变化 而如果使用explorer功能介入 或者拷贝结构体名 然后展开加号 就可以看到所有的位置和整个寄存器的值 那么代码是否会真的更高效呢 我们可以通过一个例子生成的汇编代码 来比较看一看 这个例子要做的事情是先停止定时器 然后 load 一个新的周期到PRD 再重新开启定时器 可以看到生成的汇编代码里 首先有一个DP配置的赋值 查找到该定时器所在组的寄存器起始地址 然后对其偏移地址为4的元素 也就是 XAR4 寄存器进行一个逻辑或运算 实现停止定时器的功能 然后直接赋值周期值 到cpu寄存器 XAR4 再由他赋给偏移地址为二的元素 也就是PRD寄存器 最后重新开启定时器 直接继续逻辑与运算 操作偏移地址为四的元素 TCR 寄存器 总计用时为五条指令 代码量为 5 word 通用指令数可以计算为 n*2-m+1 m 是逻辑运算的个数 如果使用传统的 define 的方式 完成相同任务的C代码对应的汇编代码 又是怎样的呢 可以看到生成的汇编代码里 每个操作都是先取址 然后对其地址内的内容进行逻辑运算 或者赋值运算 最后再把值重新写到该地址 三条指令完成一个动作 对应三个动作就是九条指令 所以代码量为九个 word 而实际的通用指令数是 n*3 远远大于前面的方法 所以无论是从代码空间还是执行效率来看 结构体操作的方式都应该是最优的 使用结构体的方式进行编程 并不需要每个用户 自己去编写底层代码的头文件定义 因为TI已经做好了相应的工作 用户直接加入到应用程序中使用就可以了 TI提供的外设寄存器头文件结构体 有完整的命名规则 便于记忆和使用 简单来说就是结构体的名字就是外设名字 采取每个单词首字母大写 其它字母小写的方式 并由TI来定义 而寄存器名就是该外设的对应的寄存器的名字 与用户手册上的完全匹配 同样采取大小写规则 然后是位选择或者是全寄存器选择 由小写字母or或是bit决定 最后是选择为位的时候 位域名与用户手册上的位定义完全匹配 采取同样的大小写规则 这样每个外设的头文件合在一起 就组成了整个 F2837xD 芯片的 所有外设头文件 接下来这页我们将看到的是自动完成功能 它主要针对的是寄存器名太长 不易记忆和不易介入的问题 通过光标移动选择对应的寄存器 和位以及位域名就可以快速完成介入工作 这里是使用外设寄存器的头文件的例子 所有的外设寄存器的头文件 TI 已经打包并放在一起 对应在 F2837xD_headers\include 文件夹下 除此之外它还包含之前提到过的 Linker.cmd file 的应用例程 外设使用的基本程序和相关使用说明文档 统一封装并放置在 controlsuite 之下 用户可以下载并安装后 在以下的路径中查找到 C\TI\controlsuite\device support 这里是使用外设寄存器的头文件的例子 要使用哪一个外设 用户需要包含对应外设的头文件 由于外设众多 TI 已经将所有外设的头文件编写好 并且由另外一个总的头文件 F2837xD_Device.h 对他们进行了包含 因此用户在实际使用过程中 只需要在使用到任意外设的原文件中 包含 F2837xD_Device.h 即可 那其实仅仅是包含头文件还是不够 因为对于编译器来说 这些外设寄存器所在的结构体 始终还是个变量 那么就还需要像上一章节提到的那样 将这些变量映射到实际的物理内存上去 否则就是虚无缥缈不可操作的东西 好在TI也已经完成了这一部分的工作 用户只需要添加一个点C源文件 F2837xD_GlobalVariableDefs.c 和一个.cmd文件 F2837xD_nonBIOS.cmd 或者 F2837xD_BIOS.cmd 即可 前者是使用 pragma DATA_SECTION 预编译的方式 将所有寄存器结构体变量 指定到各自的一个标号 后者会将该标号一一对应的映射到 这些寄存器本身所在的芯片的物理地址上 完成了最后的连接 这样在编译的时候 整个过程就可以顺利的完成 最后我们看一下 除了外设寄存器的头文件之外 TI 还提供了每个外设的使用实例 既可以用来参考做底层驱动的设计 也可以作为标准来验证外设本身是否存在问题 最后我们总结一下 本章节我们讲解了 两种不同风格的底层驱动的编程 并分析了它们各自的优缺点 以及我们为什么使用结构体的方式 然后这些工作都已经由 TI 完成 用户需要怎样去配置和使用 接下来我们会开始涉及芯片本身 从系统到外设 下一章节将是复位和中断作为开始

大家好

本章节我们将要讨论的是外设寄存器的头文件

我们先会了解F2837xD寄存器

C代码头文件的使用

并且学会怎样去编程这些外设的寄存器

然后知道寄存器结构体

是如何以 Linker.cmd 进行映射的

首先我们看一个传统的底层驱动的C代码示例

在这个例子里

我们是通过宏定义的方式

将一个地址强制指针类型转化

将它赋给一个标号或者说寄存器的名字

然后在代码里就可以对该地址直接进行操作

比如赋一个值

或者仅对其内容的某一个位

进行某个逻辑运算等等

这个方法的优点其实是非常明显的 简单粗暴

然而它的缺点也一样明显

那就是当仅需要操作某一个位的时候

用户需要去设定一个独立的 mask

仅对该位进行处理

而且逻辑或和逻辑与需要两个不同的 mask

同时在调试的时候

不能很容易地在窗口里看到某些位的状态

最重要的一点是在很多的情况下

它编译生成的代码会比较累赘 效率很低

从而影响代码的执行时间

另一种办法是使用结构体的方式进行编程

如这个示例

将同一个外设的所有寄存器定义在一个结构体里

然后在一个寄存器里定义一个联合体

分别对应它的全部和某些位

以支持不同类型需要的操作

在生成代码的寻址方面

由于将统一外设的寄存器放在一起

而且物理上也确实是相连的

就可以只需要找到第一个寄存器的地址

然后通过 offset 偏移量的方式快速定位

从而提高效率

当然它的优缺点也非常明显

可以很容易的操作某个位

然后可以在调试窗口看到

最重要是可以生成更高效的代码

但是由于结构体本身和寄存器名比较长

不易记住且不易介入

从而会影响开发效率

下面我们先来看看细节的几个点

这是调试窗口可以看到的位的值可能发生的变化

而如果使用explorer功能介入

或者拷贝结构体名

然后展开加号

就可以看到所有的位置和整个寄存器的值

那么代码是否会真的更高效呢

我们可以通过一个例子生成的汇编代码

来比较看一看

这个例子要做的事情是先停止定时器

然后 load 一个新的周期到PRD

再重新开启定时器

可以看到生成的汇编代码里

首先有一个DP配置的赋值

查找到该定时器所在组的寄存器起始地址

然后对其偏移地址为4的元素

也就是 XAR4 寄存器进行一个逻辑或运算

实现停止定时器的功能

然后直接赋值周期值

到cpu寄存器 XAR4

再由他赋给偏移地址为二的元素

也就是PRD寄存器

最后重新开启定时器

直接继续逻辑与运算

操作偏移地址为四的元素 TCR 寄存器

总计用时为五条指令

代码量为 5 word 通用指令数可以计算为

n*2-m+1

m 是逻辑运算的个数

如果使用传统的 define 的方式

完成相同任务的C代码对应的汇编代码

又是怎样的呢

可以看到生成的汇编代码里

每个操作都是先取址

然后对其地址内的内容进行逻辑运算

或者赋值运算

最后再把值重新写到该地址

三条指令完成一个动作

对应三个动作就是九条指令

所以代码量为九个 word

而实际的通用指令数是 n*3

远远大于前面的方法

所以无论是从代码空间还是执行效率来看

结构体操作的方式都应该是最优的

使用结构体的方式进行编程

并不需要每个用户

自己去编写底层代码的头文件定义

因为TI已经做好了相应的工作

用户直接加入到应用程序中使用就可以了

TI提供的外设寄存器头文件结构体

有完整的命名规则

便于记忆和使用

简单来说就是结构体的名字就是外设名字

采取每个单词首字母大写

其它字母小写的方式

并由TI来定义

而寄存器名就是该外设的对应的寄存器的名字

与用户手册上的完全匹配

同样采取大小写规则

然后是位选择或者是全寄存器选择

由小写字母or或是bit决定

最后是选择为位的时候

位域名与用户手册上的位定义完全匹配

采取同样的大小写规则

这样每个外设的头文件合在一起

就组成了整个 F2837xD 芯片的

所有外设头文件

接下来这页我们将看到的是自动完成功能

它主要针对的是寄存器名太长

不易记忆和不易介入的问题

通过光标移动选择对应的寄存器

和位以及位域名就可以快速完成介入工作

这里是使用外设寄存器的头文件的例子

所有的外设寄存器的头文件

TI 已经打包并放在一起

对应在 F2837xD_headers\include 文件夹下

除此之外它还包含之前提到过的

Linker.cmd file 的应用例程

外设使用的基本程序和相关使用说明文档

统一封装并放置在 controlsuite 之下

用户可以下载并安装后

在以下的路径中查找到

C\TI\controlsuite\device support

这里是使用外设寄存器的头文件的例子

要使用哪一个外设

用户需要包含对应外设的头文件

由于外设众多

TI 已经将所有外设的头文件编写好

并且由另外一个总的头文件 F2837xD_Device.h

对他们进行了包含

因此用户在实际使用过程中

只需要在使用到任意外设的原文件中

包含 F2837xD_Device.h 即可

那其实仅仅是包含头文件还是不够

因为对于编译器来说

这些外设寄存器所在的结构体

始终还是个变量

那么就还需要像上一章节提到的那样

将这些变量映射到实际的物理内存上去

否则就是虚无缥缈不可操作的东西

好在TI也已经完成了这一部分的工作

用户只需要添加一个点C源文件

F2837xD_GlobalVariableDefs.c 和一个.cmd文件

F2837xD_nonBIOS.cmd

或者 F2837xD_BIOS.cmd 即可

前者是使用 pragma DATA_SECTION 预编译的方式

将所有寄存器结构体变量

指定到各自的一个标号

后者会将该标号一一对应的映射到

这些寄存器本身所在的芯片的物理地址上

完成了最后的连接

这样在编译的时候

整个过程就可以顺利的完成

最后我们看一下

除了外设寄存器的头文件之外

TI 还提供了每个外设的使用实例

既可以用来参考做底层驱动的设计

也可以作为标准来验证外设本身是否存在问题

最后我们总结一下

本章节我们讲解了

两种不同风格的底层驱动的编程

并分析了它们各自的优缺点

以及我们为什么使用结构体的方式

然后这些工作都已经由 TI 完成

用户需要怎样去配置和使用

接下来我们会开始涉及芯片本身

从系统到外设

下一章节将是复位和中断作为开始

视频报错
手机看
扫码用手机观看
收藏本课程

视频简介

C2837x入门指南(四) — 外设寄存器操作

所属课程:C2837x入门指南 发布时间:2016.06.06 视频集数:28 本节视频时长:00:08:31
C2837x概述;芯片架构; 开发环境;外设寄存器操作;复位和中断;系统初始化;模拟子系统 ADC DAC CMP SDFM;控制类外设PWM CAP QEP。
TI培训小程序