((Port *)0x41004400UL) 在这里是啥意思?
Posted
技术标签:
【中文标题】((Port *)0x41004400UL) 在这里是啥意思?【英文标题】:What does ((Port *)0x41004400UL) mean here?((Port *)0x41004400UL) 在这里是什么意思? 【发布时间】:2015-07-07 07:56:37 【问题描述】:我正在开发一块带有 32 位基于 ARM 的微控制器的开发板(即开发板是 Atmel SAM D21J18A)。我仍处于学习阶段,还有很多工作要做,但我真的很喜欢嵌入式系统。
我有一些 C 的背景。但是,这显然还不够。我正在查看 Atmel 的示例项目的代码,但我并没有真正了解其中的某些部分。这是其中之一:
#define PORT ((Port *)0x41004400UL) /**< \brief (PORT) APB Base Address */
端口定义为:
typedef struct
PortGroup Group[2]; /**< \brief Offset: 0x00 PortGroup groups [GROUPS] */
Port;
PortGroup 定义为:
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上看过很多。类似的问题在这里问:***.com/questions/2417195/…and then what happens
- 请参阅您的设备手册。作为一般参考,您可能喜欢例如superuser.com/q/703695/52365
@MohitJain 我看不到这个问题。我现在看了看,但我似乎仍然不明白该定义/分配是如何工作的:(
【参考方案1】:
什么都没有发生,因为您只提出了一些声明。我不完全确定问题到底是什么,但简要解释一下代码:
0x41004400UL
显然是 I/O 空间(不是常规内存)中端口开始的地址(一组 I/O 寄存器)
此端口由两组具有相似排列的单个寄存器组成
struct PortGroup
完全按照硬件上的布局对这些寄存器进行建模
要了解寄存器的含义,请查阅硬件文档。
【讨论】:
【参考方案2】:通常您可以通过这种方式访问 C 中的硬件寄存器:
#define PORT (*(volatile uint8_t*)0x1234)
0x1234
是注册地址
uint8_t
是寄存器的类型,在本例中为 1 个字节。
volatile
是必需的,以便编译器知道它无法优化这样的变量,但必须实际完成对代码中所述变量的每次读取或写入。
(volatile uint8_t*)
将整型文字转换为所需类型的地址。
最左边的*
然后获取该地址的内容,这样宏就可以像 PORT 是一个常规变量一样使用。
请注意,这不会分配任何东西!它只是假设给定地址存在一个硬件寄存器,可以通过指定的类型 (uint8_t
) 访问它。
使用相同的方法,您还可以让其他 C 数据类型直接对应硬件寄存器。例如,通过使用方便的结构,您可以映射特定硬件外围设备的整个寄存器区域。然而,这样的代码有点危险和可疑,因为它必须考虑对齐/结构填充和别名等因素。
至于您示例中的特定代码,它是特定微控制器上特定硬件外围设备(看起来像普通的通用 I/O 端口)的典型糟糕寄存器映射。每个支持 MCU 的编译器通常都会提供一个这样的野兽。
遗憾的是,此类寄存器映射总是以糟糕的、完全不可移植的方式编写的。例如,两个下划线 __
在 C 中是一个禁止的标识符。编译器和程序员都不允许声明这样的标识符(7.1.3)。
真正奇怪的是他们省略了volatile
关键字。这意味着您在此处遇到以下情况之一:
Port
定义下。很可能是这种情况,或者
寄存器映射充满致命错误,或者
编译器太糟糕了,它根本不优化变量。这将使volatile
的问题消失。
我会进一步调查。
至于结构填充和别名,编译器供应商可能隐含地假设只使用他们的编译器。他们没有兴趣为您提供可移植的寄存器映射,以便您可以为同一个 MCU 切换竞争对手的编译器。
【讨论】:
在头文件中,它们具有以下定义:#define __I volatile、#define __O volatile、#define __IO volatile。感谢您的回答先生,我会尝试消化这个“寄存器映射”。对于初学者来说仍然很困惑:)以上是关于((Port *)0x41004400UL) 在这里是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章
the setting of serial port in the SecureCRT
理解I/O Completion Port(完成端口)(转载)