Значения регистров CMSIS

Я только начал изучать CMSIS для контроллеров ARM. Его использование кажется довольно удобным, однако мне было интересно, где же определены фактические значения регистров. Возьмем, к примеру, GPIO.

Существует структура GPIOA_AHB_Type, определенная с различными членами. Затем для GPIOB определен адрес памяти (или регистра?), Скажем, GPIOB_AHB_BASE. После этого устанавливается указатель на GPIOB_AHB_BASE, например:

#define GPIOB_AHB        ((GPIOA_AHB_Type*) GPIOB_AHB_BASE)

Переменные-члены GPIOB_AHB как GPIOB_AHB-> DIR, например, для установки ввода или вывода. Мой вопрос: где именно инициализируются эти переменные-члены? Я предполагаю, что фактический адрес регистров зависит от устройства, поэтому я попытался найти их в заголовке конкретного устройства, но все, что я нашел, это определение GPIOB_AHB_BASE и объявление переменных-членов. Как компилятор узнает, что когда я набираю GPIOB_AHB-> DIR, я хочу записать в регистр, который устанавливает направление ввода-вывода этого порта?


person Botond    schedule 28.01.2015    source источник


Ответы (1)


Если вы посмотрите в заголовок CMSIS, вы увидите все определения структур. Вот пример из моего текущего проекта:

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;

Позже определяется указатель на структуру этого типа:

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

Чтобы вы могли использовать это как:

TSB_PA->CR |= (1U << 2);          // make Port A, bit 2 an output
value = TSB_PA->DATA & (1U << 5); // read Port A, bit 5.
person Carl Norum    schedule 28.01.2015
comment
Спасибо! Итак, я вижу, что указатель TSB_PA указывает на структуру типа TSB_PA_TypeDef в местоположении TSB_PA_BASE. Однако внутри структуры, как компилятор узнает индивидуальное расположение DATA, CR и т. Д.? - person Botond; 29.01.2015
comment
Это структура. Все они смещены соответствующими размерами полей - поэтому там RESERVED поля - это дыры в карте памяти, где нет регистров. - person Carl Norum; 29.01.2015
comment
В этом есть смысл :) В этом случае, я думаю, порядок, в котором вы объявляете переменные-члены, тоже имеет значение, верно? - person Botond; 29.01.2015
comment
Это не переменные, это поля в структуре. Да, порядок имеет значение. - person Carl Norum; 29.01.2015
comment
Я только что погуглил и теперь вижу, что структуры хранятся в памяти непрерывно, так что теперь все это имеет смысл. Я пока не вижу разницы между переменной и полем в структуре: -S ... - person Botond; 29.01.2015
comment
@Botond: Вопреки комментарию Карла, члены структуры обычно называются членами в C, а не полями. Термин поле используется в контексте записей Паскаля, которые более или менее аналогичны C struct. В C ++, где классы и структуры также могут иметь члены функции, члены данных обычно называются переменными-членами, поэтому я не думаю, что вы были так далеко, но членство имеет решающее значение - они не независимы и не существуют вне экземпляра структуры. - person Clifford; 29.01.2015