程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

CCS中的IER和IFR寄存器:Symbol ‘IER‘ could not be resolved

发布于2021-10-16 19:15     阅读(2320)     评论(0)     点赞(25)     收藏(3)


问题现象

main函数初始化时,关闭CPU的中断使能,清除不断标志,一般都是这么写的:

  1. IER = 0x0000;
  2. IFR = 0x0000;

但是,CCS却提示:

Symbol 'IER' could not be resolved

 

 可是呢,编译整个工程时,也不会报错。

<Linking>
Finished building target: "DCDC.out"
 
"D:/ti/ccs1040/ccs/utils/tiobj2bin/tiobj2bin" "DCDC.out" "DCDC.bin" "D:/ti/ccs1040/ccs/tools/compiler/ti-cgt-c2000_20.2.5.LTS/bin/ofd2000" "D:/ti/ccs1040/ccs/tools/compiler/ti-cgt-c2000_20.2.5.LTS/bin/hex2000" "D:/ti/ccs1040/ccs/utils/tiobj2bin/mkhex4bin"
 

**** Build Finished ****

那么,IER是什么?为什么IER不能解析呢?这种写法到底是否符合C语言规范呢?

原因分析

首先,IER是一个寄存器。并且是CPU内核的寄存器。IFR也一样。

 

与外设寄存器类似,在CCS的编译环境中,都把这类寄存器当作一个全局变量来处理。

比如,要使能PIE中的ADCD1中断,则是直接改变PieCtrlRegs这个全局变量中的某个位。

    PieCtrlRegs.PIEIER1.bit.INTx6 = 1;    /* PIE Group 1.6, ADCD1_INT*/

C语言规范要求,在使用变量之前,必须先声明,并且要在合适的地方定义这个变量。那么,外设寄存器这一类的全局变量在哪里声明和定义的呢?

外设寄存器变量的声明

在headers\include文件夹中,有各个外设寄存器变量的类型定义,以及全局变量的声明。

比如,在F2837xD_piectrl.h中:

  1. struct PIE_CTRL_REGS {
  2. union PIECTRL_REG PIECTRL; // ePIE Control Register
  3. union PIEACK_REG PIEACK; // Interrupt Acknowledge Register
  4. union PIEIER1_REG PIEIER1; // Interrupt Group 1 Enable Register
  5. union PIEIFR1_REG PIEIFR1; // Interrupt Group 1 Flag Register
  6. union PIEIER2_REG PIEIER2; // Interrupt Group 2 Enable Register
  7. union PIEIFR2_REG PIEIFR2; // Interrupt Group 2 Flag Register
  8. union PIEIER3_REG PIEIER3; // Interrupt Group 3 Enable Register
  9. union PIEIFR3_REG PIEIFR3; // Interrupt Group 3 Flag Register
  10. union PIEIER4_REG PIEIER4; // Interrupt Group 4 Enable Register
  11. union PIEIFR4_REG PIEIFR4; // Interrupt Group 4 Flag Register
  12. union PIEIER5_REG PIEIER5; // Interrupt Group 5 Enable Register
  13. union PIEIFR5_REG PIEIFR5; // Interrupt Group 5 Flag Register
  14. union PIEIER6_REG PIEIER6; // Interrupt Group 6 Enable Register
  15. union PIEIFR6_REG PIEIFR6; // Interrupt Group 6 Flag Register
  16. union PIEIER7_REG PIEIER7; // Interrupt Group 7 Enable Register
  17. union PIEIFR7_REG PIEIFR7; // Interrupt Group 7 Flag Register
  18. union PIEIER8_REG PIEIER8; // Interrupt Group 8 Enable Register
  19. union PIEIFR8_REG PIEIFR8; // Interrupt Group 8 Flag Register
  20. union PIEIER9_REG PIEIER9; // Interrupt Group 9 Enable Register
  21. union PIEIFR9_REG PIEIFR9; // Interrupt Group 9 Flag Register
  22. union PIEIER10_REG PIEIER10; // Interrupt Group 10 Enable Register
  23. union PIEIFR10_REG PIEIFR10; // Interrupt Group 10 Flag Register
  24. union PIEIER11_REG PIEIER11; // Interrupt Group 11 Enable Register
  25. union PIEIFR11_REG PIEIFR11; // Interrupt Group 11 Flag Register
  26. union PIEIER12_REG PIEIER12; // Interrupt Group 12 Enable Register
  27. union PIEIFR12_REG PIEIFR12; // Interrupt Group 12 Flag Register
  28. };
  29. //---------------------------------------------------------------------------
  30. // PIECTRL External References & Function Declarations:
  31. //
  32. extern volatile struct PIE_CTRL_REGS PieCtrlRegs;

前面是PieCtrlRegs这个变量的类型定义:结构体struct PIE_CTRL_REGS;

后面是PieCtrlRegs这个变量的声明:extern volatile struct PIE_CTRL_REGS PieCtrlRegs;

再比如,在f28002x_gpio.h文件中:

  1. struct GPIO_DATA_REGS {
  2. union GPADAT_REG GPADAT; // GPIO A Data Register (GPIO0 to 31)
  3. union GPASET_REG GPASET; // GPIO A Data Set Register (GPIO0 to 31)
  4. union GPACLEAR_REG GPACLEAR; // GPIO A Data Clear Register (GPIO0 to 31)
  5. union GPATOGGLE_REG GPATOGGLE; // GPIO A Data Toggle Register (GPIO0 to 31)
  6. union GPBDAT_REG GPBDAT; // GPIO B Data Register (GPIO32 to 63)
  7. union GPBSET_REG GPBSET; // GPIO B Data Set Register (GPIO32 to 63)
  8. union GPBCLEAR_REG GPBCLEAR; // GPIO B Data Clear Register (GPIO32 to 63)
  9. union GPBTOGGLE_REG GPBTOGGLE; // GPIO B Data Toggle Register (GPIO32 to 63)
  10. Uint16 rsvd1[40]; // Reserved
  11. union GPHDAT_REG GPHDAT; // GPIO H Data Register (GPIO224 to 255)
  12. };
  13. struct GPIO_DATA_READ_REGS {
  14. Uint32 GPADAT_R; // GPIO A Data Read Register
  15. Uint32 GPBDAT_R; // GPIO B Data Read Register
  16. Uint16 rsvd1[10]; // Reserved
  17. Uint32 GPHDAT_R; // GPIO H Data Read Register
  18. };
  19. //---------------------------------------------------------------------------
  20. // GPIO External References & Function Declarations:
  21. //
  22. extern volatile struct GPIO_CTRL_REGS GpioCtrlRegs;
  23. extern volatile struct GPIO_DATA_REGS GpioDataRegs;
  24. extern volatile struct GPIO_DATA_READ_REGS GpioDataReadRegs;

同样的,前面也是寄存器变量的类型定义,后面是全局变量的声明。

外设寄存器变量的定义

变量声明只解决了编译问题,光声明还不够,如果只声明但不定义,则在链接过程中还会报错。那么,一定有一个地方去定义这些变量。答案就在headers\source\f28002x_globalvariabledefs.c文件中。

  1. //----------------------------------------
  2. #ifdef __cplusplus
  3. #pragma DATA_SECTION("GpioCtrlRegsFile")
  4. #else
  5. #pragma DATA_SECTION(GpioCtrlRegs,"GpioCtrlRegsFile");
  6. #endif
  7. volatile struct GPIO_CTRL_REGS GpioCtrlRegs;
  8. //----------------------------------------
  9. #ifdef __cplusplus
  10. #pragma DATA_SECTION("GpioDataReadRegsFile")
  11. #else
  12. #pragma DATA_SECTION(GpioDataReadRegs,"GpioDataReadRegsFile");
  13. #endif
  14. volatile struct GPIO_DATA_READ_REGS GpioDataReadRegs;
  15. //----------------------------------------
  16. #ifdef __cplusplus
  17. #pragma DATA_SECTION("GpioDataRegsFile")
  18. #else
  19. #pragma DATA_SECTION(GpioDataRegs,"GpioDataRegsFile");
  20. #endif
  21. volatile struct GPIO_DATA_REGS GpioDataRegs;

其中的“volatile struct GPIO_CTRL_REGS GpioCtrlRegs;”没有“extern”关键字,表示这是一个变量的定义。编译器会给该变量分配存储器空间。

特别需要说明的是,这里不光是定义了全局变量,还要与外设寄存器绑定起来。

外设寄存器全局变量与外设寄存器硬件的绑定关系

在每个全局变量的前面,都有类似这样的编译指令:

#pragma DATA_SECTION(GpioCtrlRegs,"GpioCtrlRegsFile");

这条指令的意思是,告诉编译器,GpioCtrlRegs这个变量,不要随便放置到RAM中,而是要放到GpioCtrlRegsFile这个section.

那么,问题又来了,这个section又有什么用呢?跟GPIO控制寄存器这个外设又是如何关联的呢?

答案在cmd文件里。

打开 headers\cmd\f28002x_headers_nonbios.cmd文件看看。这里节选了ADC和GPIO相关的内容:

  1. MEMORY
  2. {
  3. ADCA : origin = 0x00007400, length = 0x00000080
  4. ADCC : origin = 0x00007500, length = 0x00000080
  5. ADCARESULT : origin = 0x00000B00, length = 0x00000018
  6. ADCCRESULT : origin = 0x00000B40, length = 0x00000018
  7. …………
  8. GPIOCTRL : origin = 0x00007C00, length = 0x00000200
  9. GPIODATAREAD : origin = 0x00007F80, length = 0x00000010
  10. GPIODATA : origin = 0x00007F00, length = 0x00000040
  11. …………
  12. }
  13. SECTIONS
  14. {
  15. AdcaRegsFile : > ADCA, type=NOINIT
  16. AdccRegsFile : > ADCC, type=NOINIT
  17. AdcaResultRegsFile : > ADCARESULT, type=NOINIT
  18. AdccResultRegsFile : > ADCCRESULT, type=NOINIT
  19. …………
  20. GpioCtrlRegsFile : > GPIOCTRL, type=NOINIT
  21. GpioDataReadRegsFile : > GPIODATAREAD, type=NOINIT
  22. GpioDataRegsFile : > GPIODATA, type=NOINIT
  23. …………
  24. }

可以看到,在MEMORY中定义了各外设对应的区间,其地址也CPU外设地址一致。在SECTIONS中,指定各个节(比如GpioCtrlRegsFile)要放置的空间(比如放置至GPIOCTRL区间)。

这样,整个链条都打通了。在C语言代码中,对寄存器变量的访问,最终就等同于对硬件寄存器的访问。

以上语法完全符合ANSI C语言规范。CCS只是在此基础上扩展了编译器指令。

那么,针对IER和IFR,CCS又是如何做的呢?

IER和IFR的声明

在C代码中,想要给IER赋值,自然也要先告诉编译器,有IER这个变量。

这个,当然是有的。必须有。比如,在F2837xD_device.h文件中:

  1. //
  2. // User To Select Target Device:
  3. //
  4. #define F28_2837xD TARGET
  5. //
  6. // Common CPU Definitions:
  7. //
  8. extern __cregister volatile unsigned int IFR;
  9. extern __cregister volatile unsigned int IER;

再比如,在X:\ti\c2000\C2000Ware_3_04_00_00\device_support\f28002x\headers\include\f28002x_device.h文件中,也有类似的定义:

  1. #ifndef __TMS320C28XX__
  2. #define __cregister
  3. #endif //__TMS320C28xx__
  4. extern __cregister volatile unsigned int IFR;
  5. extern __cregister volatile unsigned int IER;

这里出现了一个新的关键字:__cregister。关于这个关键字的说明如下。

__cregister关键字

查询手册:《TMS320C28x Optimizing C_C++ Compiler v21.6.0.LTS User's Guide (Rev. W)-spru514w.pdf》 第6.5.2章节,

The compiler extends the C/C++ language by adding the cregister keyword to allow high level language access to control registers. This keyword is available in normal mode, but not in strict ANSI/ISO mode (using the --strict_ansi compiler option). The alternate keyword, __cregister, provides the same functionality but is available in either strict ANSI/ISO mode or normal mode.
When you use the cregister keyword on an object, the compiler compares the name of the object to a list of standard control registers for the C28x (see Table 6-2). If the name matches, the compiler generates the code to reference the control register. If the name does not match, the compiler issues an error.
 

 

使用DriverLib库

如果使用的是新的driverlib库,也有同样的声明。是在cpu.h文件中。比如

X:\ti\c2000\C2000Ware_3_04_00_00\driverlib\f28002x\driverlib\cpu.h文件中:

 

原文链接:https://blog.csdn.net/booksyhay/article/details/120795087



所属网站分类: 技术文章 > 博客

作者:sdjsdh

链接:http://www.phpheidong.com/blog/article/175404/16dd711b96c7e117030d/

来源:php黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

25 0
收藏该文
已收藏

评论内容:(最多支持255个字符)