What does ((Port *)0x41004400UL) mean here?

本秂侑毒 提交于 2019-12-01 14:45:59

Generally you can access a hardware register in C in this manner:

#define PORT  (*(volatile uint8_t*)0x1234)
  • 0x1234 is the register address
  • uint8_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.

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).

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.


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.

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:

  • 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.

I would investigate this further.

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.

Nothing happens, because you only present some declarations. I'm not entirely sure what the question actually is, but to briefly explain that code:

  • 0x41004400UL is obviously an address in I/O space (not regular memory) where a port starts (a set of I/O registers)

  • This Port consists of two groups with a similar arrangement of single registers

  • struct PortGroup models these registers exactly in the layout present on the hardware

To know the meaning of the Registers, look up the hardware documentation.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!