1
votes

I have just started to explore the CMSIS for ARM controllers. It seems rather convenient to use it, however I was wondering where are the actual register values defined. Let's just take for example the GPIOs.

There is a structure GPIOA_AHB_Type defined with various members. Then, for GPIOB, there is a memory (or register?) address defined, let's say GPIOB_AHB_BASE. Afterwards, a pointer is set to GPIOB_AHB_BASE, like this:

#define GPIOB_AHB        ((GPIOA_AHB_Type*) GPIOB_AHB_BASE)

GPIOB_AHB's member variables as GPIOB_AHB->DIR for example, to set it input or output. My question is, where precisely are these member variables initialized? I guess the actual address of the registers is device specific, so I tried to find them in the device specific header, but all I found was the GPIOB_AHB_BASE define and the declaration of the member variables. How does the compiler know that when I type GPIOB_AHB->DIR, I want to write into the register that sets that port's I/O direction?

1

1 Answers

1
votes

If you look in your CMSIS header, you'll see all the structure definitions. Here's an example from my current project:

typedef struct
{
  __IO uint32_t DATA;              /*!< Port A Data Register                         */
  __IO uint32_t CR;                /*!< Port A Output Control Register               */
  __IO uint32_t FR1;               /*!< Port A Function Register 1                   */
  __IO uint32_t FR2;               /*!< Port A Function Register 2                   */
       uint32_t RESERVED0[6];
  __IO uint32_t OD;                /*!< Port A Open Drain Control Register           */
  __IO uint32_t PUP;               /*!< Port A Pull-up Control Register              */
       uint32_t RESERVED1[2];
  __IO uint32_t IE;                /*!< Port A Input Control Register                */
} TSB_PA_TypeDef;

Later on, a pointer to a structure of that type is defined:

#define PERI_BASE                  (0x40000000UL)
#define TSB_PA_BASE                (PERI_BASE  + 0x00C0000UL)
#define TSB_PA                     ((     TSB_PA_TypeDef *)    TSB_PA_BASE)

So that you can use it like:

TSB_PA->CR |= (1U << 2);          // make Port A, bit 2 an output
value = TSB_PA->DATA & (1U << 5); // read Port A, bit 5.