F28335第三篇——寄存器文件结构(CODE_SECTION,DATA_SECTION)

相对于传统的宏定义方式,F28335的寄存器定义方式更加复杂。为了说清楚这个问题,以系统控制寄存器为例。

系统控制寄存器

名称地址大小(*16)描述
PLLSTS0x70111PLL状态寄存器
保留0x7012~0x70198
HISPCP0x701A1高速外设时钟分频寄存器
LOSPCP0x701B1低速外设失踪分频寄存器
PCLKCR00x701C1外设时钟控制寄存器0
PCLKCR10x701D1外设时钟控制寄存器1
LPMCR00x701E1低功模式控制寄存器0
保留0x701F1
PCLKCR30x70201外设时钟控制寄存器
PLLCR0x70211PLL控制寄存器
SCSR0x70221系统控制和状态寄存器
WDCNTR0x70231看门狗计数寄存器
保留0x70241
WDKEY0x70251看门狗复位寄存器
保留0x7026~0x70283
WDCR0x70291看门狗控制寄存器
保留0x702A~0x702F6

1.相关结构体

//---------------------------------------------------------------------------
// System Control Register File:
//起始地址应该是0x7010
struct SYS_CTRL_REGS { 
   Uint16              rsvd7;     // 0
   union   PLLSTS_REG  PLLSTS;    // 1
   Uint16              rsvd1[8];  // 2-9
   union   HISPCP_REG  HISPCP;    // 10: High-speed peripheral clock pre-scaler
   union   LOSPCP_REG  LOSPCP;    // 11: Low-speed peripheral clock pre-scaler
   union   PCLKCR0_REG PCLKCR0;   // 12: Peripheral clock control register
   union   PCLKCR1_REG PCLKCR1;   // 13: Peripheral clock control register
   union   LPMCR0_REG  LPMCR0;    // 14: Low-power mode control register 0
   Uint16              rsvd2;     // 15: reserved
   union   PCLKCR3_REG PCLKCR3;   // 16: Peripheral clock control register
   union   PLLCR_REG   PLLCR;     // 17: PLL control register
   // No bit definitions are defined for SCSR because
   // a read-modify-write instruction can clear the WDOVERRIDE bit
   Uint16              SCSR;      // 18: System control and status register
   Uint16              WDCNTR;    // 19: WD counter register
   Uint16              rsvd4;     // 20
   Uint16              WDKEY;     // 21: WD reset key register
   Uint16              rsvd5[3];  // 22-24
   // No bit definitions are defined for WDCR because
   // the proper value must be written to the WDCHK field
   // whenever writing to this register.
   Uint16              WDCR;      // 25: WD timer control register
   Uint16              rsvd6[6];  // 26-31
};

此处通过一个结构体,将系统控制寄存器中所有寄存器都包含其中。

2.定义结构体变量

volatile struct SYS_CTRL_REGS SysCtrlRegs;

这个结构体变量就具有了系统控制寄存器的整体结构了。下面的任务就是将这个变量映射到对应的寄存器地址。通过对比可以知道,SysCtrlRegs变量的映射地址应该是0x7010;

在DSP编程中,用#pragma的编程方式将变量映射到对应的地址。其具体的格式为:

//为变量分配地址
#ifdef __cplusplus
#pragma DATA_SECTION("SysCtrlRegsFile")//C++语法
#else
#pragma DATA_SECTION(SysCtrlRegs,"SysCtrlRegsFile");//C语言语法,若是C开发,可以只写这一句。
#endif
//定义结构体变量
volatile struct SYS_CTRL_REGS SysCtrlRegs;

上面代码,即通过#pragma的编程方式,将SysCtrlRegs变量与SysCtrlRegsFile文件所连接的地址连接起来。下面就是解决如何将数据块文件与寄存器地址连接起来。这就需要cmd文件来解决了。

补充
DATA_SECTION函数
//在C语言中
#pragma DATA_SECTION ( symbol , " section name ");
//在C++语言中
#pragma DATA_SECTION (" section name ");

在C语言中,这条代码的含义就是为symbol变量申请数据空间。将symbol变量的数据存储在section name对应的地址。
举例:

#pragma DATA_SECTION(bufferB, "my_sect")
char bufferB[512];//此处不可以是指针,是已经分配空间的数据类型。
CODE_SECTION函数
#pragma CODE_SECTION (symbol , "section name ")

在C语言中,这条代码的含义就是为symbol变量申请程序空间。将symbol变量的数据存储在section name对应的地址。
举例

char bufferA[80];
char bufferB[80];
#pragma CODE_SECTION(funcA, "codeA")
char funcA(int i);//fancA放入codeA映射的位置
char funcB(int i);//fanB放入.txet映射的位置
void main()
{ 
char c;
c = funcA(1);
c = funcB(2);
}
char funcA (int i)
{ 
return bufferA[i];
}
char funcB (int j)
{ 
return bufferB[j];
}

3.cmd文件

MEMORY
{ 
 PAGE 0:    /* Program Memory */
   ...
 PAGE 1:    /* Data Memory */
   ...                 
   SYSTEM      : origin = 0x007010, length = 0x000020     /* System control registers */
   ...
}

 
SECTIONS
{ 
   ...
   SysCtrlRegsFile   : > SYSTEM,      PAGE = 1
   ...
}

如上代码所示,cmd文件中分成MEMORY和SECTIONS两个部分。需要注意的是,在cmd文件中注释方式只能是/**/,不可以为//。(我在CCS6.1上验证发现,//注释方式也是可以的。)
在MEMORY中,最多可以256个PAGE(PAGE0~PAGE255)。习惯上,将PAGE0作为程序空间,将PAGE作为数据空间。程序中的SYSTEM : origin = 0x007010, length = 0x000020,很容易理解,就是将SYSTEM的实际地址的起始地址为0x7010,长度为0x20(32个字长) 。
在SECTIONS中,将SysCtrlRegsFile 和SYSTEM链接起来。因而,上面定义的SysCtrlRegs就与系统控制寄存器建立起了以上关系。

结构体的位定义

取系统控制的第1个寄存器(锁相环状态寄存器)为例。

PLLSTS(锁相环状态寄存器)

名称描述
15~9保留
8~7DIVSEL时钟分频选择;
00,01:4分频;
10:2分频;11:1分频
6MCLKOFF时钟检测电路关闭位;
0:默认模式,时钟检测使能;
1:时钟检测电路关闭,系统不会进入limp-mode模式
5OSCOOF振荡器时钟禁止位;
0:晶振时钟信号会被送到PLL电路;
1:晶振时钟信号不会被送到PLL电路。
当此位=1时,
此时不要进入HALT或STANDBY模式,不要写入PLLCR寄存器,否则会倒追不可预知的后果;
看门狗行为与输入时钟有关,若X1或X1与X2,看门狗不工作。XCLKIN:看门狗工作。
OSCOFF用于测试时钟监视逻辑电路。
4MCLKCLR时钟丢失状态清除位
0:写无影响,读取返回0;
1:强制将时钟检测电路进行复位。如果OSCCLK(晶振时钟)依然丢失,时钟检测电路会再次产生一次系统复位信号,并将MCLKSTS置位,此时CPU的工作时钟为limp-mode模式产生的低速时钟
3MALKSTS对该位写无效,写MCLKCLR或者外部复位时候,该位被清除
0:正常模式,时钟信号没有丢失;
1:晶振信号丢失,CPU工作在limp-mode
2PLLOFFPLL电路关闭位,只有PLLCR=0时候,才能将PLL电路关闭
0:PLL电路正常工作
1:PLL电路关闭
1保留
0PLLLOCKSPLL电路状态位
0:表示锁相环依然正在锁相,此时最好等待
1:PLL电路已经锁相完成

位区结构体

struct PLLSTS_BITS   {     // bits description
   Uint16 PLLLOCKS:1;     // 0 PLL lock status
   Uint16 rsvd1:1;        // 1 reserved
   Uint16 PLLOFF:1;       // 2 PLL off bit
   Uint16 MCLKSTS:1;      // 3 Missing clock status bit
   Uint16 MCLKCLR:1;      // 4 Missing clock clear bit
   Uint16 OSCOFF:1;       // 5 Oscillator clock off
   Uint16 MCLKOFF:1;      // 6 Missing clock detect
   Uint16 DIVSEL:2;       // 7:8 Divide Select
   Uint16 rsvd2:7;        // 15:9 reserved
};

上面结构体定义了PLL状态寄存器的每一位的名称。位区结构体定义时需要注意:

  • 位定义由低位到高位
  • 每个名称后面带有冒号,冒号后接着是位长。
  • 并不是所有的寄存器都需要定义位区,从前面SYS_CTRL_REGS结构体中也可看出!

下面需要将位区与整个寄存器链接起来。在DSP的编程中,使用的方法是共同体。

共同体

union PLLSTS_REG 
{ 
   Uint16              all;
   struct PLLSTS_BITS  bit;
};

通过共同体,将结构体PLLSTS_REG中all变量和bit变量共享一块存储空间,而此时,通过操作结构体PLLSTS_REG变量即可方便操作整个寄存器或者寄存器的每一位。这里从上篇博客(F28335第二篇——系统控制初始化)中选取一个例子 。

SysCtrlRegs.PLLSTS.bit.DIVSEL = 0;//保证PLL是4分频

整体操作的也是类似:

SysCtrlRegs.PLLSTS.all = 0
    原文作者:海洋想想
    原文地址: https://blog.csdn.net/qq_17525633/article/details/102508323
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞