Прежде чем мы начнём писать библиотеки для работы с классами, нам необходимо разобраться с тактовым генератором и некоторыми функциями для портов ввода/вывода, которым не требуются классы. В этой статье будет рассмотрен принцип инициализации на максимальную тактовую частоту на внешнем кварцевом резонаторе. Если необходимо будет работать или с внутренним источником тактирования или каки-либо ещё нюансы, поняв как устроен тактовый генератор, можно будет над ним издеваться как захотим. Причём на любом МК.
Для начала посмотрим тактовые генераторы разных МК. Я не стал приводить примеры монструозных тактовых генераторов, чтобы раньше времени никто не испугался. Начнём с более простого. Тактовый генератор STM32F030C8T:

Тактовый генератор STM32F103C8T:

Тактовый генератор STM32F301R8T:

Тактовый генератор STM32F407VET:

Как видите, между ними много общего. В каждом тактовом генераторе есть кое-что, что их объединяет:

- Внутренний тактовый HSI генератор на RC-цепочке. У разных МК частота может быть разной. После включения и сброса тактовый генератор находится именно в таком состоянии. Вы можете или остаться на нём или переключиться на кварцевый резонатор. Стабильность этого генератора хуже, чем на кварцевом. Правда в большинстве случаев хватает и этого. Примечание: в других МК он может называться по другому - HSI16, HSI48 и т. д. Но сути это не меняет.
- Тактовый генератор с кварцевым резонатором HSE. Где стоит надпись "Input frequency", указано на какие частоты можно поставить кварцевый резонатор.
- Мультиплексор. Переключает источники тактирования - внутренний или внешний генератор. В зависимости от МК может иметь разное количество входов, а может и отсутствовать, если выводов у корпуса мало.
- Делитель перед модулем PLL. Может входить в состав PLL, может отсутствовать.
- Модуль PLL. Крутая штука, позволяющая тактировать ядро МК практически любыми частотами.
- Ещё один мультиплексор. По стрелочкам можно определиться, что, куда включает.
- Делители шин периферии. Не все шины и не вся периферия может работать на максимальных частотах. Для этого введены дополнительные делители. С ними нужно быть очень осторожными. Прежде чем запускать периферийное устройство, нужно из даташита или Reference manual (RM для краткости) узнать от какой шины тактируется таймер. Самый простой способ - в RM посмотреть в разделе регистров RCC, куда подключено данное устройство и в CubeMX посмотреть частоту тактирования шины.
Теперь нам в CubeMX необходимо выставить все частоты на максимум, который возможен на внешнем кварцевом резонаторе. Я применяю в основном на 8Мгц. Но можно и другой, но не любой. Иначе можете получить дробные частоты и никогда не запустите USB (надеюсь с CubeMX все знакомы):

В данном случае я включил USB, чтобы убедиться, что мы можем получить необходимую частоту. В самой функции делитель можно не включать. Его можно запустить отдельно при инициализации USB, но при этом можно хватануть проблем. Я нашёл некоторый алгоритм, который в большинстве случаев упрощает выбор, но не всегда.
Делитель /M ставим такой, чтобы после него тактовая частота была 2МГц. В нашем случае 8 / 4 = 2. Умножитель *N делаем равным 168, т. е. максимальной тактовой частоте ядра МК. Получаем на выходе 2*168=336МГц. Делитель /P оставляем по умолчанию, получаем 168МГц на выходе второго мультиплексора. Но у нас шина APB получается перегруженной, поэтому ставим там соответствующие делители для получения необходимых частот. Теперь мы знаем коэффициенты деления и умножения и можем перейти непосредственно к программированию. Но нам необходимо учесть, что данная библиотека предназначена для инициализации тактового генератора после сброса, когда все регистры RCC находятся в состоянии "по умолчанию". Какой регистр и в каком состоянии после сброса, можно узнать из описания регистров в RM.
Шаг 1.
Запускаем тактирование модуля управления питанием PWR и конфигуратора системы SYSCFG. Это не всегда нужно, и иногда этот шаг можно опустить:
RCC->APB1ENR |= RCC_APB1ENR_PWREN; RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
Шаг 2.
Запускаем HSE и ждём некоторое время в ожидании запуска. Если кварцевый резонатор битый или трассировка платы неудачна, он может и не запуститься. Если запуск так и не произошёл, мы выходим из функции, ничего не предпринимая:
uint32_t StartUpCo