问题描述
我工作的一个开发板,上有一个32位基于ARM microntroller(即板是Atmel SAM D21J18A)。我仍然在学习阶段,我有很多去,但我真的到嵌入式系统中。
I'm working on a developing board that has a 32-bit ARM based microntroller on it (namely the board is Atmel SAM D21J18A). I'm still at the learning phase and I have a lot to go, but I'm really into embedded systems.
我在C.一些背景然而,这显然是不够的。我一直在寻找在$ C $由Atmel实例项目的CS,我并没有真正得到它的某些部分。这里是其中的一个:
I have some background in C. However, it's obviously not enough. I was looking at the codes of an example project by Atmel, and I didn't really get some parts of it. Here is one of them:
#define PORT ((Port *)0x41004400UL) /**< \brief (PORT) APB Base Address */
端口被定义为:
typedef struct {
PortGroup Group[2]; /**< \brief Offset: 0x00 PortGroup groups [GROUPS] */
} Port;
和端口组的定义是:
typedef struct {
__IO PORT_DIR_Type DIR; /**< \brief Offset: 0x00 (R/W 32) Data Direction */
__IO PORT_DIRCLR_Type DIRCLR; /**< \brief Offset: 0x04 (R/W 32) Data Direction Clear */
__IO PORT_DIRSET_Type DIRSET; /**< \brief Offset: 0x08 (R/W 32) Data Direction Set */
__IO PORT_DIRTGL_Type DIRTGL; /**< \brief Offset: 0x0C (R/W 32) Data Direction Toggle */
__IO PORT_OUT_Type OUT; /**< \brief Offset: 0x10 (R/W 32) Data Output Value */
__IO PORT_OUTCLR_Type OUTCLR; /**< \brief Offset: 0x14 (R/W 32) Data Output Value Clear */
__IO PORT_OUTSET_Type OUTSET; /**< \brief Offset: 0x18 (R/W 32) Data Output Value Set */
__IO PORT_OUTTGL_Type OUTTGL; /**< \brief Offset: 0x1C (R/W 32) Data Output Value Toggle */
__I PORT_IN_Type IN; /**< \brief Offset: 0x20 (R/ 32) Data Input Value */
__IO PORT_CTRL_Type CTRL; /**< \brief Offset: 0x24 (R/W 32) Control */
__O PORT_WRCONFIG_Type WRCONFIG; /**< \brief Offset: 0x28 ( /W 32) Write Configuration */
RoReg8 Reserved1[0x4];
__IO PORT_PMUX_Type PMUX[16]; /**< \brief Offset: 0x30 (R/W 8) Peripheral Multiplexing n */
__IO PORT_PINCFG_Type PINCFG[32]; /**< \brief Offset: 0x40 (R/W 8) Pin Configuration n */
RoReg8 Reserved2[0x20];
} PortGroup;
所以在这里,我们正在寻找在地址0x41004400UL,得到的数据在那里,然后发生了什么?
So here, we are looking at the address 0x41004400UL, get the data in there, and then what happens?
我抬头一看这个,但找不到任何有用的东西。如果您有任何建议(教程,书籍等),请让我听到。
I looked up for this but couldn't find anything useful. If you have any suggestions (tutorials, books etc.), please let me hear.
推荐答案
一般来说,你可以访问硬件寄存器用C以这种方式:
Generally you can access a hardware register in C in this manner:
#define PORT (*(volatile uint8_t*)0x1234)
-
0×1234
是寄存器地址 -
uint8_t有
是寄存器的类型,在这种情况下,1个字节大。 -
挥发性
是必需的,这样编译器知道它不能优化这样一个变量,但每次读或写在code规定的变量必须实际上是完成。 -
(挥发性uint8_t有*)
注塑整数文字所需类型的地址。 - 最左边的
*
然后采取地址的内容,使宏可用于就像PORT是一个普通的变量。 0x1234
is the register addressuint8_t
is the type of the register, in this case 1 byte large.volatile
is required so that the compiler knows it cannot optimize such a variable, but that each read or write to the variable stated in the code must actually be done.(volatile uint8_t*)
casts the integer literal to an address of the desired type.- The left-most
*
then take the contents of that address, so that the macro can be used just as if PORT was a regular variable. - volatile关键字隐藏在
下方端口
定义。最有可能的是这种情况,或者 - 寄存器映射充满了致命的错误,或者
- 编译器就是这样一个可怕的一块垃圾,它并没有在所有优化变量。这将使问题与
挥发性
走开。 - The volatile keyword is hidden beneath the
Port
definition. Most likely this is the case, or - The register map is full of fatal bugs, or
- The compiler is such an awful piece of crap that it doesn't optimize variables at all. Which would make the issues with
volatile
go away.
请注意,这不分配任何东西!它只是假定有一个硬件寄存器present在给定的地址,可以通过指定的类型进行访问( uint8_t有
)。
Note that this does not allocate anything! It just assumes that there is a hardware register present at the given address, which can be accessed by the type specified (uint8_t
).
使用,还可以有其他的C数据类型直接对应硬件寄存器的方法相同。例如,通过使用一个方便的结构,可以映射特定的硬件外设的整个寄存器区域。例如code然而有点危险和可疑的,因为它必须采取的东西像对齐/结构填充和走样帐户。
Using the same method you can also have other C data types to correspond directly hardware registers. For example by using a handy struct, you can map the whole register area of a particular hardware peripheral. Such code is however a bit dangerous and questionable, since it must take things like alignment/struct padding and aliasing in account.
至于在你的榜样具体code,它是一个典型的可怕的寄存器映射为一个特定的硬件外设(看起来像一个普通的通用I / O口)在某微控制器。一个这样的野兽一般具有每个编译器支持MCU。
As for the specific code in your example, it is a typical awful register map for a particular hardware peripheral (looks like a plain general-purpose I/O port) on a certain microcontroller. One such beast is typically provided with each compiler supporting the MCU.
这样的寄存器映射黯然总是写在可怕的,完全不可移植的方法。例如,两个下划线 __
是C.禁标识符无论是编译器和程序员被允许这样的声明标识符(7.1.3)。
Such register maps are sadly always written in awful, completely non-portable ways. For example, two underscores __
is a forbidden identifier in C. Neither the compiler nor the programmer is allowed to declare such identifiers (7.1.3).
什么是真正奇怪的是,他们已经省略了挥发性
关键字。这意味着,你这里有这些情形之一:
What's really strange is that they have omitted the volatile
keyword. This means that you have one of these scenarios here:
我将进一步展开调查。
至于结构填充和混叠,编译器厂商可能已经隐含地假定只有他们的编译器将被使用。他们在为您提供一个便携式寄存器映射,这样就可以切换竞争对手的编译器相同的MCU没有兴趣。
As for struct padding and aliasing, the compiler vendor has likely implicitly assumed that only their compiler is to be used. They have no interest in providing you with a portable register map, so that you can switch the the competitor's compiler for the same MCU.
这篇关于什么是((端口*)0x41004400UL)的意思是在这里吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!