Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Два языка при работе с регистрами

Пт июл 21, 2023 23:53:57

Всем привет, уважаемые коты!

Прошу не кидать в меня тапками за тупой вопрос, но я действительно кое-что не догоняю.
Я пытаюсь разбирать чужие коды и с удивлением обнаруживаю, что при работе с регистрами разные люди используют разный код, мне приходится "переводить" с одного языка (понимаю, что везде Си, но я не знаю, как корректно выразиться) на другой. Например, человек инициализирует I2C и пишет:
Код:
   SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN); //Запуск тактирование порта B
   SET_BIT(RCC->APB2ENR, RCC_APB2ENR_AFIOEN); //Запуск тактирования альтернативных функций
   SET_BIT(RCC->APB1ENR, RCC_APB1ENR_I2C1EN); //Запуск тактирования I2C1
....
   //Настройки ножек SDA и SCL
   //PB7 SDA (I2C Data I/O) Alternate function open drain
   MODIFY_REG(GPIOB->CRL, GPIO_CRL_CNF7_Msk, 0b11 << GPIO_CRL_CNF7_Pos); //Alternate function open drain
   MODIFY_REG(GPIOB->CRL, GPIO_CRL_MODE7_Msk, 0b11 << GPIO_CRL_MODE7_Pos); //Maximum output speed 50 MHz

или
Код:
 tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_I2C1EN);
  //Disable  acknowledge on Own Address2 match address
  CLEAR_BIT(I2C1->OAR2, I2C_OAR2_ENDUAL);


Окей, но другой человек при инициализации I2C пишет

Код:
   RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
   RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;   // enable GPIOB

   GPIOB->AFR[1] |= (4 << (4 * 0));   // PB8 - I2C1_SCL - for AF4
   GPIOB->AFR[1] |= (4 << (4 * 1));   // PB9 - I2C1_SDA - for AF4

   GPIOB->MODER &= ~(GPIO_MODER_MODER9 |GPIO_MODER_MODER8);   // AF open drain mode, external pull-ups
   GPIOB->MODER |= (GPIO_MODER_MODER9_1 |  GPIO_MODER_MODER8_1);
   GPIOB->OTYPER |=(GPIO_OTYPER_OT_9 |GPIO_OTYPER_OT_8);


То есть в одном случае используются команды SET_BIT, MODIFY_REG, CLEAR_BIT, READ_BIT и т.д. В другом загадочное |=, &= ~ и иже с ними.
Как же соотносятся между собой эти команды?

Re: Два языка при работе с регистрами

Сб июл 22, 2023 00:31:11

пишем #define SET_BIT(a, b) a |= b https://learn.microsoft.com/ru-ru/cpp/p ... w=msvc-170

и теперь запись вида SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);
при компиляции станет согласно этому define в нормальном виде RCC->APB1ENR |= RCC_APB2ENR_IOPBEN
О том, что такое #define и прочие подобные штучки и как они применяются лучше прочитать в учебниках (справке) среды разработки и языкам С и С++, например, по ссылке выше в частности и ниже - более глобально.
Там много полезного. Например, посмотрите на такое: #ifdef

https://learn.microsoft.com/ru-ru/cpp/p ... w=msvc-170

Добавлено after 14 minutes 13 seconds:
Но вообще, оба примера примерно равны, и в первом применение #define не максимально удобно: программисту и так понятно, как установить бит. Зато он может забыть, что делает установка этого бита. Поэтому, конструкция вида

#define ENABLE_I2C RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;

намного информативней, упрощает чтение, написание и отладку кода, снижает вероятность ошибки и необходимость комментариев. Достаточно теперь написать ENABLE_I2C и всем понятно, что это.

Re: Два языка при работе с регистрами

Сб июл 22, 2023 00:34:30

Спасибо, но из этой ссылки мне не очевидно, например, то, чем станет при компиляции запись MODIFY_REG(GPIOB->CRL, GPIO_CRL_CNF7_Msk, 0b11 << GPIO_CRL_CNF7_Pos) или CLEAR_BIT(I2C1->OAR2, I2C_OAR2_ENDUAL);

Re: Два языка при работе с регистрами

Сб июл 22, 2023 00:44:27

Конечно не очевидно, не только Вам, но и любому другому. Но где-то у Вас в проекте есть заголовочный файл, где всем этим CLEAR_BIT описано определение. Я не знаю, какую среду Вы используете, но в большинстве можно на CLEAR_BIT кликнуть правой кнопкой мышки и посмотреть, где он и как определен (и прочие свойства)

Добавлено after 5 minutes 47 seconds:
В CubeIDE достаточно навести мышкой курсор на него и подождать

Re: Два языка при работе с регистрами

Сб июл 22, 2023 01:02:01

Вы подразумеваете это?
Вложения
ESW0hPbenXE.jpg
(68.92 KiB) Скачиваний: 60

Re: Два языка при работе с регистрами

Сб июл 22, 2023 01:09:21

да

Re: Два языка при работе с регистрами

Сб июл 22, 2023 22:00:07

пишем #define SET_BIT(a, b) a |= b
Безграмотная запись.

#define ENABLE_I2C RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
Аналогично.

Re: Два языка при работе с регистрами

Сб июл 22, 2023 22:12:22

ну так не ленись, напиши про скобочки, области видимости и про идиотов, которые начнут вставлять так, что умудрятся напортачить. Мне вот лень было, я лишь описал принцип и дал ссылки. Приступай, брякало, а я потом почитаю :tea:

Re: Два языка при работе с регистрами

Пн июл 24, 2023 16:29:39

Где-то внутри вот этого
junior_t писал(а):SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN)

рано или поздно происходит вот это
junior_t писал(а):RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;


В первом случае вызывается функция (ну или псевдофункция), которая призвана распихать байтики. Как и что она при этом делает программиста в общем случае волновать не должно. А во втором просто происходит запись в регистр. Вот так вот просто и бесхитростно.

Re: Два языка при работе с регистрами

Пн июл 24, 2023 16:43:47

не совсем корректное название: если назовешь это функцией (а не макросом), то придется считать, что скомпилируется как функция, с вызовом, возвратом, пушпопом всего и вся и т. д.
а в данном случае работает препроцессор.

Re: Два языка при работе с регистрами

Пн июл 24, 2023 16:48:15

Препроцессор это вообще лучше всего. А ещё может быть inline функция, вызов которой тоже не произойдёт. Тут уж всякие тонкости. Я лишь хотел сказать, что всё это всё равно приводит к записи в регистр и многие предпочитают не плодить сущности (функции, макросы и тд), а тупо сразу писать по адресам и капец.

Re: Два языка при работе с регистрами

Пн июл 24, 2023 16:52:52

ну... тут спорно что лучше. jcxz выше сделал мне замечание, что я написал безграмотно, и это верно: есть риск ошибки, которая легко пролезет через компилятор. Недостатков у макросов хватает. На мой взгляд, всё хорошо в меру. Написать # Motor_On гораздо удобнее, чем писать безликую установку бита, но запихивать громадный кусок кода, с условиями и проч. - эт мне как-то не нравится, а вот микрософт по ссылке выше считает, что норм.

Re: Два языка при работе с регистрами

Вт июл 25, 2023 00:15:24

junior_t писал(а):RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
А во втором просто происходит запись в регистр. Вот так вот просто и бесхитростно.
Ничего подобного. Не "просто запись", а 3 операции: чтение, модификация, запись.
И скорей всего бессмысленные. Так как наверняка можно обойтись одной только записью. Но миллион мух привыкли лететь одним общим путём, не думая куда и зачем....

Re: Два языка при работе с регистрами

Вт июл 25, 2023 06:50:20

Есть хорошая альтернатива? Это же не GPIO со специальными регистрами для этого.

Re: Два языка при работе с регистрами

Вт июл 25, 2023 10:24:44

В большинстве случаев программы не манипулируют этими битами (разрешения тактирования) в процессе своей работы. Просто включают их все в нужное положение при старте. Зачем тогда эти |= отдельно для каждого бита? Просто - одна запись всех бит в регистр сразу.

Re: Два языка при работе с регистрами

Вт июл 25, 2023 10:56:33

jcxz писал(а):Зачем тогда эти |= отдельно для каждого бита?

Очевидно, чтобы не затереть другие биты. В каждом кусочке программы включается и настраивается своя система. Можно и все сразу записать, если хочется сэкономить пару тактов. Кроме каких-нибудь особых случаев, когда порядок важен, конечно. Тут уж думать надо стоит ли наглядность программы такого незначительного ускорения.

Re: Два языка при работе с регистрами

Вт июл 25, 2023 11:28:50

Очевидно, чтобы не затереть другие биты. В каждом кусочке программы включается и настраивается своя система.
Посмотрите внимательнее на его код: у него там рядом два бита в одном регистре таким образом устанавливаются. А значит это не потому что "именно так надо", а потому что автор не дал себе труда включить голову. Потому что все мухи так летают. 8)
Да и если бы реально "в каждом кусочке программы включается и настраивается своя система", то модификация этих битов должна была быть завёрнута в критическую секцию. Или в запрет прерываний. Или модификация осуществлялась бы с использованием эксклюзивного доступа. А ничего этого нет.
Поэтому тут как обычно: "так все делают и я так сделал". :dont_know:

Re: Два языка при работе с регистрами

Вт июл 25, 2023 11:51:14

Судя по всему, речь идёт об СТМ32. Буду придерживаться этой версии. Так вот.
jcxz писал(а):у него там рядом два бита в одном регистре таким образом устанавливаются

И соглашусь и нет. Что И2Ц и порты висят на одной шине это просто так удачно совпало. А вот если надо будет связь по УСАПП? Придётся разваливать код обратно на запись двух регистров. Аналогично с регистром AFR. Условно, ноги 7 и 9 уже потребуют запись в два регистра. В данном конкретном случае можно и объединить, но стоит ли оно того? Ну вот мне лично кажется, что далеко не всегда.
jcxz писал(а):модификация этих битов должна была быть завёрнута в критическую секцию. Или в запрет прерываний.

Зачем? Запись в эти регистры возможна в прерываниях? Тогда согласен, нужно. Если прерывания вообще уже включены на данном этапе.

Re: Два языка при работе с регистрами

Вт июл 25, 2023 12:46:30

Зачем? Запись в эти регистры возможна в прерываниях? Тогда согласен, нужно. Если прерывания вообще уже включены на данном этапе.
Вы же сами писали: "В каждом кусочке программы включается и настраивается своя система". Эти кусочки могут быть в разных задачах или даже в ISR. Вот если программа разбита на отдельные драйвера устройств, каждый из которых включает/выключает нужную ему периферию, то нужно обязательно позаботиться об атомарности модификации битов в общих регистрах (тем или иным способом).

Re: Два языка при работе с регистрами

Чт июл 27, 2023 08:43:14

Ничего подобного. Не "просто запись", а 3 операции: чтение, модификация, запись.
И скорей всего бессмысленные.
В большинстве случаев программы не манипулируют этими битами (разрешения тактирования) в процессе своей работы.

Вы сами же и озвучили причину, почему ради чтиаемости кода почти всегда жертвуют парой тактов на старте, где это все равно никого не волнует.
Ответить