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

前端 未结 2 1530
野性不改
野性不改 2021-01-17 05:38

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

相关标签:
2条回答
  • 2021-01-17 05:40

    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.

    0 讨论(0)
  • 2021-01-17 05:43

    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.

    0 讨论(0)
提交回复
热议问题