[uquote="VladislavS",url="/forum/viewtopic.php?p=3383754#p3383754"]А я натыкиваю и не генерю. Просто как интерактиврый калькулятор использую. Получившиеся делители переношу в свой код. А то вдруг мозги усохнут от прочтения даташита [/uquote]
Вот у меня сейчас проект на F303 открыт, беру оттуда инициализацию тактирования:
Всего 3 строки, у второго init() на самом деле 4 параметра, для делителей шин используется значение по умолчанию. Никакие левые значения туда не передашь, все проверяется во время компиляции, итоговая частота сразу выводится в консоль, если нужно можно так же запросить частоту любой шины или, допустим, таймера. Всякие USARTы так и делают, всегда при инициализации полагаются на текущую частоту своей шины. И что мне в кубе смотреть?
[uquote="ozzy",url="/forum/viewtopic.php?p=3383835#p3383835"]я сказал бы что stm может наконец то родил что то стоящее в виде LL[/uquote]
SPL был сильно раньше, еще до куба и хала. LL - так скажем, ребрендинг)
[uquote="Ярослав555",url="/forum/viewtopic.php?p=3383724#p3383724"]STM32F030F4P6 16кб 10р
STM32F030C8T6 64кб 15р[/uquote]Где их продают по таким ценам?
В F4P6 32 КБ флеша, а не 16. В нем также есть 32-ух битный таймер Tim2 и I2S, если не знали.
[/uquote]
Я вот чего-то не догоняю. У вас подразумеваются потомки всех этих Hse/Pll/Rcc или вы объекты на железо исключительно от любви к балету наворачиваете? Какова конечная цель?
[uquote="a5021",url="/forum/viewtopic.php?p=3383890#p3383890"]У вас подразумеваются потомки всех этих Hse/Pll/Rcc или вы объекты на железо исключительно от любви к балету наворачиваете?[/uquote]
фломастеры на вкус и цвет. Мне сей подход представляется вполне себе удобным. Ковырял примерно такое для avr, потом переполз на stm8/32 и забил.
[uquote="ozzy",url="/forum/viewtopic.php?p=3383835#p3383835"]и эта строчка не разворачивается потом в простынь ?[/uquote]
Заглянем внутрь первого Pll::init<PllSrc::HseDivPrediv, 9>():
Спойлер
template<PllSrc pllSrc, uint32_t mul, uint32_t prediv>
void Pll::init()
{
static_assert(mul >= 2 && mul <= 16, "PLL mul is out of range!");
static_assert((pllSrc == PllSrc::HseDivPrediv && prediv >= 1 && prediv <= 16) ||
(pllSrc == PllSrc::HsiDiv2 && prediv == 1), "PLL prediv is out of range!");
_assert_(!isEnabled());
uint32_t cfgr = RCC->CFGR & ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL | RCC_CFGR_USBPRE);
constexpr uint32_t baseClk = (pllSrc == PllSrc::HsiDiv2) ? HsiValue / 2 : HseValue / prediv;
if constexpr (baseClk * mul <= 50'000'000) cfgr |= RCC_CFGR_USBPRE; // USBPRE bit must be valid before enabling the USB clock!
RCC->CFGR = cfgr | uint32_t(pllSrc) | ((mul - 2) << RCC_CFGR_PLLMUL_Pos);
if constexpr (pllSrc == PllSrc::HseDivPrediv)
{
RCC->CFGR2 = RCC->CFGR2 & ~RCC_CFGR2_PREDIV | (prediv - 1);
}
enable();
}
void Pll::enable()
{
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY)) {}
}
Первый параметр у нас типа PllSrc - это строгое перечисление, невозможно без ошибки подсунуть вместо него левое значение. Для сравнения берем функцию LL_DMA_Init(), она пишет в 4 или 5 регистров, но перед этим идет десяток assert_param() и если эти проверки включены, то в дебаге можно легко дополнительно словить пол КБ, а все потому, что поля у структуры не каких-то вполне конкретных типов, а uint32_t, пиши туда что хочешь. Дальше идут два static_assert(), выполняющие проверки целочисленных параметров на стадии компиляции, и обычный рантаймовский _assert_() проверяющий не включен ли PLL. В релизе его все равно не будет, но любители минимализма могут его удалить. Потом идет пара if constexpr, это фича из С++17, делает проверки опять же на стадии компиляции, т.е. самих этих проверок не будет даже при отключенной оптимизации, а вот в С без оптимизации они бы остались. Таким образом от первоначального варианта остается только это:
Спойлер
[uquote="arkhnchul",url="/forum/viewtopic.php?p=3383928#p3383928"]Мне сей подход представляется вполне себе удобным.[/uquote]
Потомки? У HSE ? Нет, я обязательно это должен увидеть! Равно, как и полиморфизм с инкапсуляцией.
[uquote="a5021",url="/forum/viewtopic.php?p=3383890#p3383890"]Я вот чего-то не догоняю. У вас подразумеваются потомки всех этих Hse/Pll/Rcc или вы объекты на железо исключительно от любви к балету наворачиваете? Какова конечная цель?[/uquote]
Странный вопрос. Имеется в виду почему вместо класса Hse не насоздавать простых функций типа hse_enable()?
Добавлено after 6 minutes 25 seconds:
[uquote="Мурик",url="/forum/viewtopic.php?p=3383864#p3383864"]если не знали.[/uquote]
Да не вникал я - взял что подешевле, погуглил и забросил в форум.
Добавлено after 59 seconds:
Кстати а функцией подбора камня по параметрам, в той программе чье имя здесь нельзя называть, многие пользуются?
Во тупой! конечно же множим на 2! Извиняюсь 40 и 60 соотв. Ну бывает - на работе голова забита.
[uquote="Reflector",url="/forum/viewtopic.php?p=3383963#p3383963"]Странный вопрос. Имеется в виду почему вместо класса Hse не насоздавать простых функций типа hse_enable()?[/uquote]
Включение внешнего резонатора -- это одна операция присваивания. Один бит поднять. Какие функции? Какие классы? Зачем они?
Это вовсе не [uquote="Ярослав555",url="/forum/viewtopic.php?p=3383724#p3383724"]STM32F030F4P6 16кб 10р
STM32F030C8T6 64кб 15р[/uquote]Поэтому и спросил где такие цены. Потому что они сильно занижены даже для оптовых продаж.
[uquote="a5021",url="/forum/viewtopic.php?p=3384040#p3384040"]Включение внешнего резонатора -- это одна операция присваивания. Один бит поднять. Какие функции? Какие классы? Зачем они?[/uquote]
Нет, это именно что включение одного бита, а включение внешнего резонатора - это включить бит, дождаться стабилизации и сделать это с таймаутом, чтоб код просто не завис если кварц не завелся. Я для простоты написал Hse::enable(), но там это все делается и вообще-то этот метод возвращает bool. А при выключении HSE неплохо бы добавить assert() проверяющий не является ли HSE активным генератором или не является ли активным PLL тактируемый от HSE, потому что код отработает, но ничего не произойдет. И еще такой момент, если классы или функции таки используются и в какой-то момент программист решил, что где-то у него не самый оптимальный или даже потенциально ошибочный код, то он меняет содержимое это функции, заменяет один файл в других проектах и получает новое поведение во всех местах включения это функции, а не выискивает где у него в куче файлов есть места требующие правки.
[uquote="a5021",url="/forum/viewtopic.php?p=3384040#p3384040"]Включение внешнего резонатора -- это одна операция присваивания. Один бит поднять. Какие функции? Какие классы? Зачем они?[/uquote]
"один бит поднять" - это оно для контроллера так. Для человека - это именно что "включить_внешний_резонатор" или, как в обсуждемом подходе, "ВнешнийРезонатор.включить". Сделать из этого утрированную "операцию присваивания" (насамделе еще подождать надо, пока заведется) - задача компилятора.