Какова цель использования смещения для получения полного адреса регистра в микроконтроллере? - PullRequest
2 голосов
/ 19 мая 2019

Я новичок в программировании встраиваемых систем и пытаюсь пробиться. Используя Stellaris LM4F120 Оценочная плата LaunchPad с таблицей данных LM4F120H5QR Microcontroller Я нашел полный адрес некоторых регистров, которые вы всегда должны добавлять смещение! что я не понимаю, так как вместо этого мы можем использовать полный адрес напрямую!

Например, чтобы настроить порт F (который начинается с 0x4002.5000 до 0x4002.5FFF) и его контакты (с использованием шины APB)

  1. Активируйте clk для этого порта, установив (бит 5) значение 1 в RCGCGPIO зарегистрируйте его базовый адрес 0x400F.E000 со смещением 0x608, так полный адрес 0x400FE608
  2. Сконфигурируйте GPIODIR reg, базовый адрес которого равен 0x4002.5000 со смещением 0x400, поэтому полный адрес 0x4002.5400
  3. Настройте GPIODEN рег, для которого его базовый адрес равен 0x4002.5000 со смещением 0x51C, поэтому полный адрес равен 0x4002.551C
  4. Настройте GPIODATA reg, для которого его базовый адрес равен 0x4002.5000 с 0x3FC таким полным адресом является 0x4002.50x3FC

Если я могу предположить, что это смещение используется здесь, чтобы сделать его менее подверженным ошибкам, как мы можем написать это так:

#define GPIO_PORTF_BASE 0x40025000
#define GPIO_PORTF_DATA (*((volatile unsigned long *)(GPIO_PORTF_BASE + 0x3FC)))
#define GPIO_PORTF_DIR (*((volatile unsigned long *)(GPIO_PORTF_BASE + 0x400)))
#define GPIO_PORTF_DEN (*((volatile unsigned long *)(GPIO_PORTF_BASE + 0x51C)))

Повышает ли использование смещения удобочитаемость и делает его более простым и неприхотливым, поскольку нам нужно только записать смещение, чтобы получить нужный регистр?


Обновление

Я обнаружил, что Базовый адрес используется чаще, чем получение полного адреса регистра.

Например,

: GPIODATA контролирует 0-7 pins и имеет 255 регистров, которые позволяют нам настраивать каждый вывод отдельно и даже их комбинацию, просто добавляя смещение к базовому адресу, например, Если мы хотим настроить Red Led на Port F, мы пишем по адресу base address 0x4002.5000 + offset 0x008 напрямую.

Ответы [ 4 ]

3 голосов
/ 19 мая 2019

Это потому, что заголовок, из которого вы скопировали эти определения, автоматически генерируется из формата описания системы CMSIS . Этот формат используется производителями микросхем для стандартного описания основных и периферийных элементов их микропроцессоров. Обычно вы можете загрузить эти так называемые файлы ".svd" в каком-либо хранилище или на домашней странице производителя.

Одной из описанных периферийных устройств LM4F120H5QR будет порт ввода-вывода общего назначения F (GPIOF). Файл .svd будет содержать элемент для порта с некоторым базовым адресом, а затем подэлемент для каждого регистра, который имеет периферийное устройство с некоторым смещением.

3 голосов
/ 19 мая 2019

Вы можете написать #define GPIO_PORTF_DATA 0x400253FC, который даст вам абсолютный адрес регистра данных порта F. Это всего лишь макрос, и вам, как программисту, легче знать, что вы говорите о регистре данных какого-либо порта.

Как я вижу в своей работе программиста по встроенным системам, вы используете смещение для того, чтобы как можно меньше писать абсолютный адрес.

Некоторые из причин, о которых я могу подумать, это когда вы обнаружите ошибку с адресом, или вы получите новую версию аппаратного обеспечения, или то, что когда-либо происходило, что вам нужно написать новый драйвер с новыми адресами, идавайте предположим, что структура регистров не изменилась, а только адреса, со смещениями вам нужно изменить только базовый адрес, а не все регистры в вашем коде.

0 голосов
/ 20 мая 2019
  1. Поскольку документация написана таким образом.

enter image description here

Но на самом деле никто (кроме изобретателей колеса) так не поступает.Файлы STM CMSIS определяют структуры, а компилятор сам вычисляет смещения:
      #define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

    typedef struct
    {
      __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
      __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
      __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
      __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
      __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
      __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
      __IO uint32_t BSRR;     /*!< GPIO port bit set/reset register,      Address offset: 0x18      */
      __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
      __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
    } GPIO_TypeDef;
0 голосов
/ 20 мая 2019

Конкретный код, который вы разместили, не имеет особого смысла.Но в общем случае вы должны сделать что-то вроде этого, чтобы обрабатывать несколько аппаратных периферийных устройств на одном чипе:

#define PORTF 0x40025000ul
...
#define GPIO_PORT_DATA(base) (*((volatile unsigned long *)(base + 0x3FCul)))
#define GPIO_PORT_DIR(base)  (*((volatile unsigned long *)(base + 0x400ul)))
#define GPIO_PORT_DEN(base)  (*((volatile unsigned long *)(base + 0x51Cul)))

Учитывая, что все периферийные устройства имеют одинаковое отображение памяти, теперь вы можете написать один драйверкоторый может обрабатывать несколько периферийных устройств.GPIO может быть не лучшим примером, так как написание слоев абстракции поверх GPIO обычно просто добавляет беспорядок.Но теоретически у нас мог бы быть этот драйвер:

void gpio_set (volatile unsigned long* port, uint8_t pin);

...

gpio_set (PORTF, 5);

Где gpio не знает, с каким конкретным портом он работает, он выполняет ту же самую работу независимо от доступа к макросам.

Это распространенный способ написания драйверов для таких вещей, как SPI, UART, CAN, ADC и т. Д., Где у вас может быть несколько идентичных периферийных устройств на кристалле и вы хотите, чтобы один и тот же код обрабатывал их все, без повторения кода.

Недостатком является незначительная часть накладных расходов на выполнение, поскольку адрес должен вычисляться во время выполнения.

...