stm32 и работа со стуктурами и указателями

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
Novosib_3000
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс янв 15, 2017 18:02:24
Откуда: Тула

stm32 и работа со стуктурами и указателями

Сообщение Novosib_3000 »

Пытаюсь разобраться как работают структуры, и наткнулся на один непонятный момент. Возьмем к примеру, вендор производителя (stm32f4xx.h), в нем есть, кусок кода, содержащий набор регистров для работы с портами ввода-вывода.

Здесь создается структура и она же объявляется как новый тип

Код: Выделить всё

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 uint16_t BSRRL;    /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */
  __IO uint16_t BSRRH;    /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */
  __IO uint32_t BSRR;
  __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;
Далее следует код:

Код: Выделить всё

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
Этой строчкой мы создаем указатель GPIOA на структуру типа GPIO_TypeDef.

И дальше, я не могу разобраться.

Указатель тоже своего рода переменная и должен занимать место в памяти и где-то находится, но я так и не смог найти его место положение. Вопрос, так где же он лежит ?
Реклама
uk8amk
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Re: stm32 и работа со стуктурами и указателями

Сообщение uk8amk »

Вовсе не так.
Процесс компиляции Си-кода проходит 2 этапа:
1. препроцессор
2. компиляция

В данном случае имеет место только первый вариант.
Препроцессор сразу подставляет вместо GPIOA указанную строку, он не создаёт указателей или каких-либо иных объектов.
Реклама
arkhnchul
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Re: stm32 и работа со стуктурами и указателями

Сообщение arkhnchul »

[uquote="Novosib_3000",url="/forum/viewtopic.php?p=3206857#p3206857"]Здесь создается структура и она же объявляется как новый тип[/uquote]
только объявляется как тип. Переменная не создается.
[uquote="Novosib_3000",url="/forum/viewtopic.php?p=3206857#p3206857"]Этой строчкой мы создаем указатель GPIOA на структуру типа GPIO_TypeDef.[/uquote]
не создаем. После такого объявления директивы препроцессор заменит в остальной программе "GPIOA" на "((GPIO_TypeDef *) 0x094566)" - цифирь от балды, это GPIOA_BASE - что, в свою очередь, означает "обратиться к области памяти по адресу 0x94566 как к содержащей переменную типа GPIO_TypeDef"
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: stm32 и работа со стуктурами и указателями

Сообщение dosikus »

[uquote="Novosib_3000",url="/forum/viewtopic.php?p=3206857#p3206857"] вендор производителя[/uquote]

Вы когда решаете применить незнакомое вам слово, хоть погуглите что оно означает...
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Novosib_3000
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс янв 15, 2017 18:02:24
Откуда: Тула

Re: stm32 и работа со стуктурами и указателями

Сообщение Novosib_3000 »

[uquote="dosikus",url="/forum/viewtopic.php?p=3207215#p3207215"][uquote="Novosib_3000",url="/forum/viewtopic.php?p=3206857#p3206857"] вендор производителя[/uquote]

Вы когда решаете применить незнакомое вам слово, хоть погуглите что оно означает...[/uquote]

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

Добавлено after 15 minutes 6 seconds:
[uquote="uk8amk",url="/forum/viewtopic.php?p=3206884#p3206884"]Вовсе не так.
Процесс компиляции Си-кода проходит 2 этапа:
1. препроцессор
2. компиляция

В данном случае имеет место только первый вариант.
Препроцессор сразу подставляет вместо GPIOA указанную строку, он не создаёт указателей или каких-либо иных объектов.[/uquote]

Что-то, я не до конца понимаю, а что происходит дальше, после того, как он подставил.

Добавлено after 6 minutes 30 seconds:
arkhnchul писал(а): " - цифирь от балды, это GPIOA_BASE - что, в свою очередь, означает "обратиться к области памяти по адресу 0x94566 как к содержащей переменную типа GPIO_TypeDef"
Это я уже выучил на изусть, но как происходит это обращение, я что-то до конца не понимаю.
Реклама
Аватара пользователя
Zhuk72
Сверлит текстолит когтями
Сообщения: 1231
Зарегистрирован: Ср янв 29, 2014 08:41:31
Откуда: Баку
Контактная информация:

Re: stm32 и работа со стуктурами и указателями

Сообщение Zhuk72 »

В данном случае stm32f4xx.h - заголовочный файл целой серии МК, и он может быть написан также создателем компилятора, поэтому связывать его с производителем не нужно.
Каждый имеет право на свое личное ошибочное мнение.

У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
Реклама
Аватара пользователя
Myp3ik
Мучитель микросхем
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Re: stm32 и работа со стуктурами и указателями

Сообщение Myp3ik »

Препроцессор заменит GPIOA на ((GPIO_TypeDef *)0x40020000)

когда вы напишете конструкцию

Код: Выделить всё

uint32_t idr = GPIOA->IDR;
препроцессор заменит её на

Код: Выделить всё

uint32_t idr = ((GPIO_TypeDef *)0x40020000)->IDR;
Далее компилятор возьмет смещение поля IDR в структуре (0x10) и прибавит его к адресу структуры и соорудит что-то типа

Код: Выделить всё

uint32_t idr = *((__IO uint32_t*)0x40020010);
Иван Сусанин - первый полупроводник :solder:
Аватара пользователя
Novosib_3000
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс янв 15, 2017 18:02:24
Откуда: Тула

Re: stm32 и работа со стуктурами и указателями

Сообщение Novosib_3000 »

[uquote="Myp3ik",url="/forum/viewtopic.php?p=3207494#p3207494"]Препроцессор заменит GPIOA на ((GPIO_TypeDef *)0x40020000)

когда вы напишете конструкцию

Код: Выделить всё

uint32_t idr = GPIOA->IDR;
препроцессор заменит её на

Код: Выделить всё

uint32_t idr = ((GPIO_TypeDef *)0x40020000)->IDR;
Далее компилятор возьмет смещение поля IDR в структуре (0x10) и прибавит его к адресу структуры и соорудит что-то типа

Код: Выделить всё

uint32_t idr = *((__IO uint32_t*)0x40020010);
[/uquote]

Спасибо, теперь картина, вроде бы проясняется.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: stm32 и работа со стуктурами и указателями

Сообщение YS »

Этой строчкой мы создаем указатель GPIOA на структуру типа GPIO_TypeDef.
Нет. Этой строчкой мы приводим GPIOA_BASE (константа-дефайн, определенная где-то выше) к типу "указатель на GPIO_TypeDef".

Проще говоря, это один из способов наложить структуру GPIO_TypeDef на область памяти, начиная с ячейки номер GPIOA_BASE.

Таким образом, компилятор будет знать, что GPIOA - синоним указателя на структуру типа GPIO_TypeDef, расположенную в памяти начиная с GPIOA_BASE.

Кстати, если что, обращение

GPIOA->ODR

эквивалентно

(*GPIOA).ODR.

Так что можно было бы написать

#define GPIOA (*((GPIO_TypeDef *)GPIOA_BASE))

и дальше писать

GPIOA.ODR.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: stm32 и работа со стуктурами и указателями

Сообщение dosikus »

[uquote="Zhuk72",url="/forum/viewtopic.php?p=3207486#p3207486"]В данном случае stm32f4xx.h - заголовочный файл целой серии МК, и он может быть написан также создателем компилятора, поэтому связывать его с производителем не нужно.[/uquote]
Неа, хэдеры периферии пишет вендор.
Это требование CMSIS, читаем спецификацию на CMSIS...
Аватара пользователя
Novosib_3000
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс янв 15, 2017 18:02:24
Откуда: Тула

Re: stm32 и работа со стуктурами и указателями

Сообщение Novosib_3000 »

[uquote="YS",url="/forum/viewtopic.php?p=3207564#p3207564"]
Этой строчкой мы создаем указатель GPIOA на структуру типа GPIO_TypeDef.
Нет. Этой строчкой мы приводим GPIOA_BASE (константа-дефайн, определенная где-то выше) к типу "указатель на GPIO_TypeDef".

Проще говоря, это один из способов наложить структуру GPIO_TypeDef на область памяти, начиная с ячейки номер GPIOA_BASE.[/uquote]

Я до сих пор, до конца не могу понять, как именно происходит приведение константы к типу. Как, с вашей точки зрения, происходит это на белее низком уровне.
Аватара пользователя
Myp3ik
Мучитель микросхем
Сообщения: 450
Зарегистрирован: Вс янв 09, 2011 23:05:37
Откуда: СССР

Re: stm32 и работа со стуктурами и указателями

Сообщение Myp3ik »

Это скорее арифметика указателей, а не приведение константы к типу. На основе констант рассчитываются указатели. У нас есть адрес
в памяти и структура описывающая смещения относительно этого адреса.

Если посмотреть на комментарий структуры

Код: Выделить всё

__IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
Address offset это и есть смещение каждого поля относительно адреса в памяти. Собственно чтоб предоставить удобную форму отображения смещения эта структура и нужна, чтобы вместо

Код: Выделить всё

uint32_t idr = *((__IO uint32_t*)(0x40020000+ 0x00000010));
использовать

Код: Выделить всё

uint32_t idr = GPIOA->IDR;
Последний раз редактировалось Myp3ik Вс окт 15, 2017 19:44:06, всего редактировалось 2 раза.
Иван Сусанин - первый полупроводник :solder:
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: stm32 и работа со стуктурами и указателями

Сообщение YS »

Я до сих пор, до конца не могу понять, как именно происходит приведение константы к типу.
Для начала требуется осознать, что на уровне железа типов нет. Есть только огромный линейный массив байт, каждый из которых пронумерован. Интерпретировать их можно как угодно.

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

"Приведение к типу" - переопределение правила, по которому компилятор будет обращаться к байтам по указанному адресу.

int32_t x; - "компилятор, выбери какой хочешь адрес в оперативной памяти, и начиная с него зарезервируй четыре байта, которые интерпретируй в дальнейшем как целое число со знаком; а называться эти четыре байта будут x".

Компилятор понимает это, и в дальнейшем будет обращаться с этими четырьмя байтами как с целым тридцатидвухибитным числом (big endian или little endian - зависит от соглашения), причем при вычислениях будет использовать дополнительный код, чтобы учитывать знак.

Начнем с простого.

temp1 = &x; - "компилятор, запиши в temp1 стартовый адрес той области, которая x". При этом компилятор знает, что к этой области надо обращаться по правилам, адекватным для целого числа со знаком. Теперь если мы напишем

(*temp) = 500;

компилятор запишет в x (потому что в temp лежит адрес x) число 500 (0x000001F4) с учетом установленных правил. То есть, в случае little endian, запишет 0xF4 в байт с самым младшим адресом, 0x01 в следующий и обнулит остальные два.

Теперь будем приводить типы.

y = *((uint8_t *)(&x)); - "компилятор, мы договаривались, что по адресу, содержимое которого мы называли x, лежит целое тридцатидвухбитное. Теперь сделай вид, что там целое беззнаковое восьмибитное, и прочти его по этому правилу."

Компилятор прочтет один байт с адреса, по которому лежит x. А там, с учетом присвоения выше, лежит 0xF4 (244 в десятичной системе счисления). Вот это число и будет записано в y.

z = ((uint8_t *)(&x))[1]; - "компилятор, интерпретируй стартовый адрес x как указатель на массив беззнаковых целых, и излеки из него первое значение."

В z окажется 1. Понимаете, почему? :)

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

((uint8_t *)0x100) - "компилятор, понимай 0x100 как номер ячейки, начиная с которой лежит беззнаковое целое восьмибитное число."
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Аватара пользователя
philosoraptor
Прорезались зубы
Сообщения: 225
Зарегистрирован: Сб янв 14, 2012 22:53:50

Re: stm32 и работа со стуктурами и указателями

Сообщение philosoraptor »

YS Браво, просто винрарнейший ликбез по работе с памятью. :beer: Схоронил для потомков.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: stm32 и работа со стуктурами и указателями

Сообщение YS »

Я рад, что вам понравилось. :)

Ну вот, мои труды уже входят в наследие для потомков. :)))
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Аватара пользователя
Novosib_3000
Первый раз сказал Мяу!
Сообщения: 31
Зарегистрирован: Вс янв 15, 2017 18:02:24
Откуда: Тула

Re: stm32 и работа со стуктурами и указателями

Сообщение Novosib_3000 »

Я тоже написал, что мне это помогло, но почему то это не отобразилось, только сейчас заметил. Хорошая работа.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: stm32 и работа со стуктурами и указателями

Сообщение YS »

А я-то думал, зачем вы цитируете мое сообщение целиком... :) Кстати странно, что модераторы еще не задались этим же вопросом. :wink:
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Sanchosd
Родился
Сообщения: 8
Зарегистрирован: Вт май 04, 2010 22:04:50

Re: stm32 и работа со стуктурами и указателями

Сообщение Sanchosd »

[uquote="YS",url="/forum/viewtopic.php?p=3211060#p3211060"]Я рад, что вам понравилось. :)

Ну вот, мои труды уже входят в наследие для потомков. :)))[/uquote]


Мне тоже понравилось!)
Скину в txt и распечатаю.
До прочтения вашего поста у меня было мнение, что "ну не умеют программисты объяснять/преподавать, не умеют, сколько раз проверяли!!!!!"
Но нет, бывают исключения :)

PS: последнее, где массив [1]- непонятно(((
Последний раз редактировалось Sanchosd Вт апр 02, 2019 07:07:50, всего редактировалось 1 раз.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: stm32 и работа со стуктурами и указателями

Сообщение YS »

Воу, два года прошло, а это еще кто-то читает. :)

Кстати там опечатка, только заметил... Присваиваю я там в "temp1", а потом рассуждаю про "temp". Но, видимо, все эти два года и так было понятно... Даже не знаю, править теперь, или нет.
последнее, где массив [1]- непонятно(((
Скобочки - синтаксический сахар (красивая запись) для инкремента указателя с его последующим разыменованием.

То есть, записи

a[x] = N;

и

*(a+x) = N;

эквивалентны.

То есть,

z = ((uint8_t *)(&x))[1]

есть то же самое, что

z = *(((uint8_t *)(&x)) + 1);

а это извлечение второго байта начиная с адреса &x.
До прочтения вашего поста у меня было мнение, что "ну не умеют программисты объяснять/преподавать, не умеют, сколько раз проверяли!!!!!"
Это, наверное, оттого, что я не программист, а электронщик. :)

Всяко, я рад, что мой пост имеет такой успех. :)
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: stm32 и работа со стуктурами и указателями

Сообщение Аlex »

[uquote="Sanchosd",url="/forum/viewtopic.php?p=3606419#p3606419"]PS: последнее, где массив [1]- непонятно((([/uquote]
Всё очень просто. Имя любого массива - указатель (константа). По этому любой указатель можно интерпретировать как имя массива.
Например :

Код: Выделить всё

int *p = bla-bla-bla...
Тогда будет уазывать на адрес 2-ого элемента по указателю. Т.е. со смещением на sizeof(int).
Ответить

Вернуться в «ARM»