haker_fox 61 22 апреля, 2023 Опубликовано 22 апреля, 2023 · Жалоба 13 hours ago, EdgeAligned said: Ох уж эти изобретатели писянины. Чем плОхи исследования? Автор статьи не настаивает на применении где-либо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 85 22 апреля, 2023 Опубликовано 22 апреля, 2023 · Жалоба Да нет, я ж не против исследований. В принципе, это весьма полезно. И в особенной степени полезно и показательно то, к чему автор статьи пришел в конце - при максимальном уровне оптимизации разницы в "выхлопе" никакой. Так что, как в той рекламе: "А если нет разницы, зачем платить писать больше?". Да и разница в несколько байт без оптимизации в наше время тоже не показатель. Тем более, что вообще-то всё сводится в идеале к записи в виде *((uint32_t*)0x40002050) = 0x2244442284 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 22 апреля, 2023 Опубликовано 22 апреля, 2023 · Жалоба Желающие ужаснуться могут заглянуть в гости к WCH. Первое что бросается в глаза - _Msk, _Pos в описание регистров не занесли. Отчего код превращается в лапшу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dimka76 62 23 апреля, 2023 Опубликовано 23 апреля, 2023 · Жалоба On 4/22/2023 at 8:42 PM, AVI-crak said: Желающие ужаснуться могут заглянуть в гости к WCH. Первое что бросается в глаза - _Msk, _Pos в описание регистров не занесли. Отчего код превращается в лапшу. Можно ссылку ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 85 23 апреля, 2023 Опубликовано 23 апреля, 2023 (изменено) · Жалоба Без _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 */ в применении здесь - никакой разницы Изменено 23 апреля, 2023 пользователем EdgeAligned Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба ... Был специальный хак для получения младшего бита из маски - иногда заменяло xxx_Pos Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба Это и хаком тяжело назвать #define lsbmsk(msk) ((msk) & -(msk)) Гораздо полезнее было бы иметь макрос (а лучше - препроцессорно-родное средство языка) для извлечения номера битовой позиции младшего бита по маске. Т.е. MASK == 0x1F0 i = POS(MASK); // i == 4 и не трехэтажными конструкциями рекурсивных вызовов других макросов... А пока что +/- только так (на отключенной оптимизации естественно получаем вычисления) #define POS(msk) ({ \ typeof(msk) i = (msk); \ u8 j = sizeof(i) * 8, \ k = 0; \ for(; k < j; ++k) \ if(i >> k & 1) break; \ k; \ }) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба 1 час назад, Arlleex сказал: Гораздо полезнее было бы Где такое можно применить? Конструкцию x & -x использую постоянно, вычисление номера младшего бита - всего однажды в выборе самого приоритетного процесса в scmRTOS, Где еще номер младшего бита может быть гораздо полезнее? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба 16 минут назад, Сергей Борщ сказал: Где еще номер младшего бита может быть гораздо полезнее? А вот взять эту ситуацию с отсутствующими в стандартном хедере набором готовых определений позиций битов: даны только маски. В случае, если на основе номера бита зависит какая-то другая позиция (например, битовые поля настройки AF в GPIO или те же регистры CR), писать промежуточный макрос ..._Pos будет не нужно. Если их таких (индусами не описанных) ...Pos наберется хотя бы с десяток в одном Вашем исходнике, удобство макроса POS() станет ощутимым. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 140 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба 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 ; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 183 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба 4 часа назад, Сергей Борщ сказал: Не могу представить себе ситуацию, когда из маски, скажем, ODR нужно будет получить маску AF... Да, признаться, конкретно в compile-time использовать получение позиции по маске приходилось намного реже, чем в run-time. В compile-time у меня была только необходимость определения индекса массива (по маске битового флага), из которого брать/класть параметры по протоколу. В зависимости от исполнения устройства маски были разными для одной и той же физической переменной, и упаковывать приходилось в разные места кадра. Но это, скорее, обусловилось лишь тем, что мне в качестве исходных данных дали списки #define-ов, которые уже были масками, а не позициями. Опять же, все упирается конкретно в изначальный вид исходной информации - универсальнее здесь сразу номер бита, на который в дальнейшем можно будет сдвинуть и т.д. А имея только маску, уже приходится извращаться. P.S. Где-то была у меня еще такая необходимость, но сходу я сейчас затрудняюсь найти, если честно. Если найду и не забуду - напишу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба 6 hours ago, Arlleex said: Гораздо полезнее было бы иметь макрос (а лучше - препроцессорно-родное средство языка) для извлечения номера битовой позиции младшего бита по маске. C++ и constexpr функции вам в помощь 🙂 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 6 24 апреля, 2023 Опубликовано 24 апреля, 2023 · Жалоба 8 hours ago, Arlleex said: Гораздо полезнее было бы иметь макрос (а лучше - препроцессорно-родное средство языка) для извлечения номера битовой позиции младшего бита по маске Вспомнил, была у нас такая тема: https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=122777 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 5 мая, 2023 Опубликовано 5 мая, 2023 · Жалоба Кхм, наверное лучше поздно чем никогда - сахар для 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)// подсчитывает конечное количество нулей целого числа 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 23 мая, 2023 Опубликовано 23 мая, 2023 · Жалоба В 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 сказал: У меня лучше - установка/сброс/toggle пина: Pset(PIN_LED1) / Pclr(PIN_LED1) / Ptog(PIN_LED1) - всё сделано с помощью макросов, без всяких си++. А следовательно - будет иметь минимальный код независимо от уровня оптимизации (не требует максимальной оптимизации для inline-инга, как в той статье). В общем случае это не так. Макросом невозможно учесть все особенности архитектуры порта контроллера. В сочетании с классами, умеющими объединять/сортировать пины в порты эффект можно получить заметный. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться