DSP28335代码学习 下载本文

1.2、外设位域结构体方法综述 1.2.1、传统#define的方法

C代码访问寄存器的传统方法是使用#define宏为每一个寄存器分配一个地址。例如: #define CPUTIMER0_TIM (volatile unsigned long *) 0x0c00 #define CPUTIMER0_PRD (volatile unsigned long *) 0x0c02 #define CPUTIMER0_TCR(volatile unsigned long *) 0x0c04 #define CPUTIMER0_TPR (volatile unsigned long *) 0x0c06 …..

同样的#define方法将在每一个外设寄存器上不断重复 弊端:

不容易访问寄存器中的位域部分 不容易在CCS观察窗口显示位域的值 不能利用CCS的自动完成功能

对于重复的外设,头文件的开发者不能获得重复利用的便利。

1.2.2、位域及结构体的方法

位域及结构体方法采用C代码的结构体方式,将属于某个指定外设的所有寄存器组成一个集合。通过链接器,每个C代码结构体就是外设寄存器的内存映射。这一映射允许编译器通过使用CPU数据页指针(DP)直接访问外设寄存器。另外,多数寄存器都定义了位域,从而使编译器能够读取或者操作某一个寄存器中的单个位域。 (1)下面代码是

下面代码示例是一个DSP28335的CPU定时器存器对应的C代码结构体类型。 // CPU Timer Register File: //

struct CPUTIMER_REGS {

union TIM_GROUP TIM; // Timer counter register union PRD_GROUP PRD; // Period register union TCR_REG TCR; // Timer control register Uint16 rsvd1; // reserved

union TPR_REG TPR; // Timer pre-scale low union TPRH_REG TPRH; // Timer pre-scale high };

该结构体类型包括6个成员组成,前后顺序与他们在内存中的顺序相同。CPUTIMER_REGS代表了一个结构体类型。他和系统已经定义的标准类型如int,char等一样可以用来作为定义变量的类型。 注意:

1、寄存器名字出现的顺序必须与他们在内存中被安排的顺序相同

2、在结构体中,通过使用保留变量rsvd1等来预留内存中的保留位置。这种保留结构体仅仅用以预留内存中的空间 3、Uint16 是无符号16位数类型定义,相应的类型定义申明由DSP2833x_Device.h文件建立。 (2)申明可访问寄存器的变量

寄存器结构类型可被用来申明一个可访问寄存器的变量,对器件的每个外设都采用这一相同的做法,同一种外设的复用外设可以采用同样的结构体类型定义。例如一个器件上有3个CPU-timer,可以创建如下所示的3个具有struct CPUTIMER_REGS结构体类型的变量。

volatile struct CPUTIMER_REGS CpuTimer0Regs ; // 定义CpuTimer0Regs是一个具有CPUTIMER_REGS类型的变量 volatile struct CPUTIMER_REGS CpuTimer1Regs ; volatile struct CPUTIMER_REGS CpuTimer2Regs ;

关键字volatile在变量声明中十分重要。它告诉编译器,这些变量的内容可由硬件改变,并且编译器无需优化使用volatile变量的代码。

(3)分配专用的数据区

单有上面的两个定义还不够,还必须为3个CPU定时器分配数据区。分配某个定时器在数据区的起始地址必须与系统定义的该定时器的内存地址一致。在DSP2833x_GlobalVariableDefs.c文件中,通过使用编译器的#pragma DATA_SECTION指令,与外设寄存器结构体类型相对应的每一个变量分配一个专用的数据区。任何使用DSP2833x外设头文件的项目都必须包含这个源文件。该文件时外设寄存器结构体变量及数据区分配的一个声明,在source目录中建立。下面代码为定时器0,1,2分配的数据区。 // FILE: // TITLE:

DSP2833x_GlobalVariableDefs.c// 全局变量默认文件 DSP2833x Global Variables and Data Section Pragmas.//

//########################################################################### // $TI Release: DSP2833x/DSP2823x C/C++ Header Files V1.31 $ // $Release Date: August 4, 2009 $

//########################################################################### #include \ // DSP2833x Headerfile Include File //--------------------------------------------------------------------------- // Define Global Peripheral Variables: //----------------------------------------

#ifdef __cplusplus // 用于C++代码 #pragma DATA_SECTION(\#else

#pragma DATA_SECTION(CpuTimer0Regs,\ // 用于C代码 #endif

volatile struct CPUTIMER_REGS CpuTimer0Regs;

//---------------------------------------- #ifdef __cplusplus

#pragma DATA_SECTION(\#else

#pragma DATA_SECTION(CpuTimer1Regs,\#endif

volatile struct CPUTIMER_REGS CpuTimer1Regs;

//---------------------------------------- #ifdef __cplusplus

#pragma DATA_SECTION(\#else

#pragma DATA_SECTION(CpuTimer2Regs,\#endif

volatile struct CPUTIMER_REGS CpuTimer2Regs; 注:

#ifdef #else #endif 为预处理器条件编译指令。对器件的每个外设寄存器结构体变量,都会重复这一数据区分配操作。 (4)映射到外设寄存器

当每个结构体都分配到自身的数据区以后,通过使用链接命令文件DSP2833x_Header_nonBIOS.cmd ,

FILE: DSP2833x_Headers_nonBIOS.cmd

// TITLE: DSP2833x Peripheral registers linker command file // DESCRIPTION:

// This file is for use in Non-BIOS applications. // Linker command file to place the peripheral structures // used within the DSP2833x headerfiles into the correct memory // mapped locations.

// This version of the file includes the PieVectorTable structure.

// For BIOS applications, please use the DSP2833x_Headers_BIOS.cmd file // which does not include the PieVectorTable structure.

//########################################################################### MEMORY /*定义存储区域*/ {

PAGE 0: /* Program Memory */ PAGE 1: /* Data Memory */

CPU_TIMER0 : origin = 0x000C00, length = 0x000008 /* CPU Timer0 registers */

CPU_TIMER1 : origin = 0x000C08, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ CPU_TIMER2 : origin = 0x000C10, length = 0x000008 /* CPU Timer0 registers (CPU Timer1 & Timer2 reserved TI use)*/ }

SECTIONS /*分配存储区域*/ {

CpuTimer0RegsFile : > CPU_TIMER0, PAGE = 1 /* 将CpuTimer0RegsFile段分配到CPU_TIMER0区域*/ CpuTimer1RegsFile : > CPU_TIMER1, PAGE = 1 CpuTimer2RegsFile : > CPU_TIMER2, PAGE = 1 }

通过把变量直接映射到外设寄存器的同一内存地址,用户采用C代码对寄存器进行访问,只需要通过访问变量中所需的成员即可。例如对CpuTimer0 TCR寄存器进行写操作,只需访问CpuTimer0Regs变量中的TCR成员,如以下代码所示: CpuTimer0Regs.TCR.all = TSS_MASK;

上面的操作是对CpuTimer0Regs.TCR整体赋值操作,可以通过添加位域结构体,直接访问某位。 1.2.3 添加位域结构体 (1)增加位域定义

我们经常需要直接访问寄存器中的某一位,C2833x C头文件及外设示例所涉及的位域结构体方法,为多数片上外设寄存器提供了位域定义。例如CPU_Timer控制寄存器的位域定义如下 // CPU Timer Register Bit Definitions: // TCR: Control register bit definitions:

struct TCR_BITS { // bits description Uint16 rsvd1:4; // 3:0 reserved Uint16 TSS:1; // 4 Timer Start/Stop Uint16 TRB:1; // 5 Timer reload Uint16 rsvd2:4; // 9:6 reserved

Uint16 SOFT:1; // 10 Emulation modes Uint16 FREE:1; // 11

Uint16 rsvd3:2; // 12:13 reserved Uint16 TIE:1; // 14 Output enable

Uint16 TIF:1; // 15 Interrupt flag };

然后通过共用体进行申明,以便访问位域结构体定义的各个成员或者16位或32位寄存器的值。例如,定时器的控制寄存器共用体如下所示:

// FILE: DSP2833x_CpuTimers.h

union TCR_REG // 定义共用体类型TCR_REG(不是变量) {

Uint16 all;

struct TCR_BITS bit; //bit是一个具有TCR_BITS结构体类型的变量 }; 还例如:

// TPR: Pre-scale low bit definitions:

struct TPR_BITS { // bits description Uint16 TDDR:8; // 7:0 Divide-down low Uint16 PSC:8; // 15:8 Prescale counter low };

union TPR_REG { Uint16 all; struct TPR_BITS bit; };

// TPRH: Pre-scale high bit definitions:

struct TPRH_BITS { // bits description

Uint16 TDDRH:8; // 7:0 Divide-down high Uint16 PSCH:8; // 15:8 Prescale counter high };

union TPRH_REG { Uint16 all; struct TPRH_BITS bit; };

等等,一旦每个寄存器的位域结构体和共用体的定义都建立起来了,则在CPU定时器(CPU-Timer)的寄存器结构体类型中,各个成员可以通过采用共用体定义的形式写。如前文所给的示例: // FILE: DSP2833x_CpuTimers.h // CPU Timer Register File: struct CPUTIMER_REGS {

union TIM_GROUP TIM; // Timer counter register union PRD_GROUP PRD; // Period register union TCR_REG TCR; // Timer control register Uint16 rsvd1; // reserved

union TPR_REG TPR; // Timer pre-scale low union TPRH_REG TPRH; // Timer pre-scale high };

到此,我们就可以既能访问CPUTimer寄存器中的某位,也可以对整个寄存器进行访问: CpuTimer0Regs.TCR.bit.TSS = 1;