Перейти к содержанию
    

Разные стили .h файлов описания аппаратуры в STM32 и GigaDevice.

13 hours ago, EdgeAligned said:

Ох уж эти изобретатели писянины.

Чем плОхи исследования? Автор статьи не настаивает на применении где-либо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да нет, я ж не против исследований. В принципе, это весьма полезно. И в особенной степени полезно и показательно то, к чему автор статьи пришел в конце - при максимальном уровне оптимизации разницы в "выхлопе" никакой. Так что, как в той рекламе: "А если нет разницы, зачем платить писать больше?". 
Да и разница в несколько байт без оптимизации в наше время тоже не показатель. Тем более, что вообще-то всё сводится в идеале к записи в виде *((uint32_t*)0x40002050) = 0x2244442284

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Желающие ужаснуться могут заглянуть в гости к WCH. Первое что бросается в глаза - _Msk, _Pos в описание регистров не занесли. Отчего код превращается в лапшу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 4/22/2023 at 8:42 PM, AVI-crak said:

Желающие ужаснуться могут заглянуть в гости к WCH. Первое что бросается в глаза - _Msk, _Pos в описание регистров не занесли. Отчего код превращается в лапшу.

Можно ссылку ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Без _Pos и _Msk были ранние версии CMSIS для STM32, ну и ничего страшного в большинстве случаев.

Вот сравните старый:

#define  TIM_CR1_CEN                         ((uint16_t)0x0001)            /*!< Counter enable */
#define  TIM_CR1_UDIS                        ((uint16_t)0x0002)            /*!< Update disable */
#define  TIM_CR1_URS                         ((uint16_t)0x0004)            /*!< Update request source */
#define  TIM_CR1_OPM                         ((uint16_t)0x0008)            /*!< One pulse mode */
#define  TIM_CR1_DIR                         ((uint16_t)0x0010)            /*!< Direction */

и более поздний

#define TIM_CR1_CEN_Pos           (0U)                                         
#define TIM_CR1_CEN_Msk           (0x1U << TIM_CR1_CEN_Pos)                    /*!< 0x00000001 */
#define TIM_CR1_CEN               TIM_CR1_CEN_Msk                              /*!<Counter enable        */
#define TIM_CR1_UDIS_Pos          (1U)                                         
#define TIM_CR1_UDIS_Msk          (0x1U << TIM_CR1_UDIS_Pos)                   /*!< 0x00000002 */
#define TIM_CR1_UDIS              TIM_CR1_UDIS_Msk                             /*!<Update disable        */
#define TIM_CR1_URS_Pos           (2U)                                         
#define TIM_CR1_URS_Msk           (0x1U << TIM_CR1_URS_Pos)                    /*!< 0x00000004 */
#define TIM_CR1_URS               TIM_CR1_URS_Msk                              /*!<Update request source */
#define TIM_CR1_OPM_Pos           (3U)                                         
#define TIM_CR1_OPM_Msk           (0x1U << TIM_CR1_OPM_Pos)                    /*!< 0x00000008 */
#define TIM_CR1_OPM               TIM_CR1_OPM_Msk                              /*!<One pulse mode        */
#define TIM_CR1_DIR_Pos           (4U)                                         
#define TIM_CR1_DIR_Msk           (0x1U << TIM_CR1_DIR_Pos)                    /*!< 0x00000010 */
#define TIM_CR1_DIR               TIM_CR1_DIR_Msk                              /*!<Direction             */

в применении здесь - никакой разницы

Изменено пользователем EdgeAligned

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... Был специальный хак для получения младшего бита из маски - иногда заменяло xxx_Pos

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это и хаком тяжело назвать

#define lsbmsk(msk) ((msk) & -(msk))


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

MASK == 0x1F0
i = POS(MASK); // i == 4

и не трехэтажными конструкциями рекурсивных вызовов других макросов...

А пока что +/- только так (на отключенной оптимизации естественно получаем вычисления:sad:)

#define POS(msk) ({                               \
                   typeof(msk) i = (msk);         \
                   u8          j = sizeof(i) * 8, \
                               k = 0;             \
                   for(; k < j; ++k)              \
                     if(i >> k & 1) break;        \
                   k;                             \
                 })

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

Гораздо полезнее было бы

Где такое можно применить? Конструкцию x & -x использую постоянно, вычисление номера младшего бита - всего однажды в выборе самого приоритетного процесса в scmRTOS, Где еще номер младшего бита может быть гораздо полезнее? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 минут назад, Сергей Борщ сказал:

Где еще номер младшего бита может быть гораздо полезнее? 

А вот взять эту ситуацию с отсутствующими в стандартном хедере набором готовых определений позиций битов: даны только маски.

В случае, если на основе номера бита зависит какая-то другая позиция (например, битовые поля настройки AF в GPIO или те же регистры CR), писать промежуточный макрос ..._Pos будет не нужно.

Если их таких (индусами не описанных) ...Pos наберется хотя бы с десяток в одном Вашем исходнике, удобство макроса POS() станет ощутимым.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

19 минут назад, Arlleex сказал:

В случае, если на основе номера бита зависит какая-то другая позиция

Есть у меня определения ног:

#define METER_TYPE          A, 10, L    // H = X-Y (TRP), L = Y-Z (SJ+)
#define IC_SENSOR1_DETECT   A,  8, L
#define IC_SENSOR1_POWER    A,  7, H
#define IC_SENSOR1_SCL      B,  8, H
#define IC_SENSOR1_SDA      B,  9, H

Есть макросы работы с их режимами:

    #define DRIVER(pin, mode)                   PIN_DRIVER(pin, mode)
    #define PIN_DRIVER(port, bit, val, mode)    PIN_SET_##mode(port,bit)
    // mode = INPUT, OUTPUT, ALT_FUNC or ANALOG
    #define PIN_SET_INPUT(port,bit)         GPIO##port->MODER &= ~(3UL << (bit * 2))
    #define PIN_SET_OUTPUT(port,bit)        GPIO##port->MODER = (GPIO##port->MODER | (1UL << (bit * 2))) & ~(2UL << (bit * 2))
    #define PIN_SET_ALT_FUNC(port,bit)      GPIO##port->MODER = (GPIO##port->MODER | (2UL << (bit * 2))) & ~(1UL << (bit * 2))
    #define PIN_SET_ANALOG(port,bit)        GPIO##port->MODER |= 3UL << (bit * 2)
    // mode = PULL_NONE/FLOATING, PULL_UP or PULL_DOWN
    #define PIN_SET_PULL_NONE(port,bit)     GPIO##port->PUPDR &= ~(3UL << (bit * 2))
    #define PIN_SET_FLOATING(port,bit)      GPIO##port->PUPDR &= ~(3UL << (bit * 2))
    #define PIN_SET_PULL_UP(port,bit)       GPIO##port->PUPDR = (GPIO##port->PUPDR | (1UL << (bit * 2))) & ~(2UL << (bit * 2))
    #define PIN_SET_PULL_DOWN(port,bit)     GPIO##port->PUPDR = (GPIO##port->PUPDR | (2UL << (bit * 2))) & ~(1UL << (bit * 2))
    // mode = PUSH_PULL, OPEN_DRAIN
    #define PIN_SET_PUSH_PULL(port,bit)     GPIO##port->OTYPER &= ~(1UL << bit)
    #define PIN_SET_OPEN_DRAIN(port,bit)    GPIO##port->OTYPER |= (1UL << bit)

Работа с ними:

        DRIVER(IC_SENSOR1_DETECT, INPUT);
        DRIVER(IC_SENSOR1_DETECT, PULL_UP);
        OS::sleep(RTOS_MS(10));
        if(ACTIVE(IC_SENSOR1_DETECT))
        {
            DRIVER(METER_TYPE, INPUT);
            DRIVER(METER_TYPE, PULL_UP);
            OS::sleep(RTOS_MS(10));
            Type = ACTIVE(METER_TYPE) ? type::SJ_PLUS : type::TRP;
            DRIVER(METER_TYPE, PULL_NONE);
            DRIVER(METER_TYPE, OUTPUT);
            DRIVER(IC_SENSOR1_SCL, ALT_FUNC);
            DRIVER(IC_SENSOR1_SDA, ALT_FUNC);
            ON(IC_SENSOR1_POWER);
        }
        DRIVER(IC_SENSOR1_DETECT, PULL_NONE);
        DRIVER(IC_SENSOR1_DETECT, OUTPUT);

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

С регистрами CR и подобными тоже всегда работаю только с масками (которые описаны как второе имя _Msk), без всяких _Pos, _Msk (от которых в глазах рябит и которые легко перепутать) и никогда не было необходимости явно использовать _Pos:

Спойлер


    // Set prescalers, select system clock
    RCC->CFGR = 0
        | 0 * (RCC_CFGR_MCOPRE & -RCC_CFGR_MCOPRE)              // MCO prescaler, /2^N
        | 0 * (RCC_CFGR_MCOSEL & -RCC_CFGR_MCOSEL)              // MCO source, 0: disabled, 1: SYSCLK, 2: MSI, 3: HSI16, 4: HSE32,
                                                                //             5: PLL_RCLK, 6: LSI, 8: LSE, 13: PLL_PCLK, 14: PLL_QCLK
        | 0 * RCC_CFGR_STOPWUCK                                 // wakeup and CSS backup clock selection, 0: MSI, 1: HSI16
        | (
            (AHBCLK / APB2CLK == 1) ? 0
          : (AHBCLK / APB2CLK == 2) ? 4
          : (AHBCLK / APB2CLK == 4) ? 5
          : (AHBCLK / APB2CLK == 8) ? 6
          : (AHBCLK / APB2CLK == 16) ? 7
          : (1 << 64)                                           // unsupported value, generate uint32_t overflow warning
          ) * (RCC_CFGR_PPRE2 & -RCC_CFGR_PPRE2)                // APB2 prescaler, 0...3: /1, 4: /2, 5: /4, 6: /8, 7: /16
        | (
            (AHBCLK / APB1CLK == 1) ? 0
          : (AHBCLK / APB1CLK == 2) ? 4
          : (AHBCLK / APB1CLK == 4) ? 5
          : (AHBCLK / APB1CLK == 8) ? 6
          : (AHBCLK / APB1CLK == 16) ? 7
          : (1 << 64)                                           // unsupported value, generate uint32_t overflow warning
          ) * (RCC_CFGR_PPRE1 & -RCC_CFGR_PPRE1)                // APB1 prescaler, 0...3: /1, 4: /2, 5: /4, 6: /8, 7: /16
        | (
            (SYSCLK / AHBCLK == 1) ? 0
          : (SYSCLK / AHBCLK == 2) ? 8
          : (SYSCLK / AHBCLK == 3) ? 1
          : (SYSCLK / AHBCLK == 4) ? 9
          : (SYSCLK / AHBCLK == 5) ? 2
          : (SYSCLK / AHBCLK == 6) ? 5
          : (SYSCLK / AHBCLK == 8) ? 10
          : (SYSCLK / AHBCLK == 10) ? 6
          : (SYSCLK / AHBCLK == 16) ? 11
          : (SYSCLK / AHBCLK == 32) ? 7
          : (SYSCLK / AHBCLK == 64) ? 12
          : (SYSCLK / AHBCLK == 128) ? 13
          : (SYSCLK / AHBCLK == 256) ? 14
          : (SYSCLK / AHBCLK == 512) ? 15
          : (1 << 64)                                           // unsupported value, generate uint32_t overflow warning
          ) * (RCC_CFGR_HPRE & -RCC_CFGR_HPRE)                  // AHB1, AHB2, SYSCLK prescaler, 0: /1, 1: /3, 2: /5, 5: /6, 6: /10, 7: /32,
                                                                // 8: /2, 9: /4, 10: /8, 11: /16, 12: /64, 13: /128, 14: /256, 15: /512
        | 0 * (RCC_CFGR_SW & -RCC_CFGR_SW)                      // SYSCLK source: 0 = MSI, 1 = HSI, 2 = HSE, 3 = PLL
        ;

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, Сергей Борщ сказал:

Не могу представить себе ситуацию, когда из маски, скажем, ODR нужно будет получить маску AF...

Да, признаться, конкретно в compile-time использовать получение позиции по маске приходилось намного реже, чем в run-time.

В compile-time у меня была только необходимость определения индекса массива (по маске битового флага), из которого брать/класть параметры по протоколу. В зависимости от исполнения устройства маски были разными для одной и той же физической переменной, и упаковывать приходилось в разные места кадра. Но это, скорее, обусловилось лишь тем, что мне в качестве исходных данных дали списки #define-ов, которые уже были масками, а не позициями. Опять же, все упирается конкретно в изначальный вид исходной информации - универсальнее здесь сразу номер бита, на который в дальнейшем можно будет сдвинуть и т.д. А имея только маску, уже приходится извращаться.

P.S. Где-то была у меня еще такая необходимость, но сходу я сейчас затрудняюсь найти, если честно. Если найду и не забуду - напишу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 hours ago, Arlleex said:

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

C++ и constexpr функции вам в помощь 🙂

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 hours ago, Arlleex said:

Гораздо полезнее было бы иметь макрос (а лучше - препроцессорно-родное средство языка) для извлечения номера битовой позиции младшего бита по маске

Вспомнил, была у нас такая тема:

https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=122777

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кхм, наверное лучше поздно чем никогда - сахар для WCH.

#define _VAL2FLD(field, w_value)    \
    ((sizeof(field) == 4) ? (((uint32_t)(w_value) << __builtin_ctz(field)) & field) : \
     ((sizeof(field) == 2) ? (((uint16_t)(w_value) << __builtin_ctz(field)) & field) : \
      (((uint8_t)(w_value) << __builtin_ctz(field)) & field)))

#define _FLD2VAL(field, r_value)    (((uint32_t)(r_value) & field) >> __builtin_ctz(field))

 GCC имеет много костылей для подобных финтов. Многие из них не всегда имеют аппаратные команды, так-что осторожнее.

__builtin_popcount(x)// подсчитывает количество единиц (установленных битов) в целом числе
__builtin_parity(x)// проверяет четность числа, false(0)= четное количество установленных битов
__builtin_clz(x)// подсчитывает начальное количество нулей целого числа
__builtin_ctz(x)// подсчитывает конечное количество нулей целого числа

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 22.04.2023 в 16:51, EdgeAligned сказал:

И в особенной степени полезно и показательно то, к чему автор статьи пришел в конце - при максимальном уровне оптимизации разницы в "выхлопе" никакой. Так что, как в той рекламе: "А если нет разницы, зачем платить писать больше?". 

Просто автор не владеет (или не владел в 2019 году) настоящим кунг-фу. Если закрыть глаза на то что нельзя через ODR ^= PIN мигать светодиодами, то соревноваться ему надо было с кодом 

for(;;) {
  GPIOA->ODR ^= (1 << 5);
  GPIOC->ODR ^= (1 << 5) | (1 << 8) | (1 << 9);
  delay();
}

Вот если бы его класс сам делал подобную оптимизацию (а это на плюсах, в отличи от си возможно), то тогда и можно было засчитывать победу.

В 21.04.2023 в 09:47, jcxz сказал:

У меня лучше :yes: - установка/сброс/toggle пина: Pset(PIN_LED1) / Pclr(PIN_LED1) / Ptog(PIN_LED1) - всё сделано с помощью макросов, без всяких си++. А следовательно - будет иметь минимальный код независимо от уровня оптимизации (не требует максимальной оптимизации для inline-инга, как в той статье).

В общем случае это не так. Макросом невозможно учесть все особенности архитектуры порта контроллера. В сочетании с классами, умеющими объединять/сортировать пины в порты эффект можно получить заметный.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...