Как и обещал, в этой статье мы поговорим о настройке всевозможных тактовых частот различных шин при помощи STM32CubeMx. Статья, в целом, будет небольшая, но важная, поскольку эти настройки являются основополагающей частью любого проекта с использованием STM32.
Итак, для тестирования мы можем взять за основу проект из предыдущей статьи с таймером (ссылка). Так мы будем наглядно видеть как именно влияют наши эксперименты с тактовой частотой на работу периферии контроллера. Собственно, говорить тут особо не о чем, перейдем сразу к практике. Открываем проект в STM32CubeMx и сразу же идем на вкладку "Clock Configuration":
В появившемся окне мы можем наблюдать абсолютно весь путь, который проходит изначальная тактовая частота, пока добирается до шин, управляющих работой периферии.
Итак, наш таймер TIM3 сидит на шине APB1. Как мы видим из этой схемы, у нас используется внутренний высокочастотный генератор на 16 МГц (HSI - High Speed Internal). Полученные на его выходе 16 МГц, проходя через промежуточные элементы схемы, добираются до шины APB1. В данном случае предделители равны 1, и на APB1 мы получаем все те же 16 МГц. Именно эту частоту мы и использовали, когда рассчитывали параметры работы таймера в предыдущей статье.
Давайте увеличим APB1 Prescaler до 4 и посмотрим, как это скажется на работе таймера и мигании светодиода. При смене предделителя у нас множитель частоты для APB1 Timer Clocks автоматически станет равным 2, и в итоге мы получим 8 МГц:
Открываем полученный проект и ищем там в файле main.c функцию SystemClock_Config()
:
void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; __PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 6; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // <--- Измененное значение RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); }
Как видите, в заново сгенерированном коде абсолютно правильно установлено новое значение предделителя:
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
Теперь нам остается собрать проект и зашить контроллер. В результате видим, что светодиод стал мигать с частотой в 2 раза меньше, чем была раньше. Собственно, так и должно было произойти, поскольку мы уменьшили частоту тактирования таймера как раз ровно в 2 раза.
Это все, конечно, хорошо, но вообще неплохо было бы задействовать внешний кварцевый резонатор. Но в "Clock Configuration" на данный момент этот вариант (HSE) неактивен:
Связано это с тем, что предварительно нужно активировать внешний источник тактирования на вкладке "Pinout & Configuration":
CubeMx сразу же отметил выводы микроконтроллера, к которым подключается внешний кварц. Сделано это для того, чтобы пользователь знал, что эти выводы он не сможет задействовать для каких-нибудь других целей:
Переходим снова на вкладку конфигурации частот и настраиваем использование HSE так, чтобы частота таймера у нас оказалась равной 48 МГц. Данная деятельность отражена на следующей схеме:
Поскольку на моей плате установлен кварцевый резонатор на 8 МГц, то именно это значение я и указал в поле Input frequency. Ну а дальше все легко настраивается просто по схеме, тут разработчики CubeMx постарались и сделали интерфейс действительно интуитивно понятным.
Итак, поскольку частота тактирования шины, а соответственно и нашего таймера стала равной 48 МГц, то давайте в настройках таймера изменим значение предделителя с 15999 на 47999:
Таким образом мы получим срабатывание прерывания по переполнению таймера через те же 500 мс, что и до изменения частот тактирования. После всех модификаций генерируем проект, компилируем и загружаем новую прошивку в контроллер. Светодиод на плате мигает точно с той частотой, с какой и должен 👍
На этом заканчиваем с RCC, но не заканчиваем с изучением STM32CubeMx, так что до скорых встреч 🤝
Спасибо за материал! Ждем продолжения!
Скоро будет )
Подскажите, в чем может быть загвоздка. Сделал как у вас, тактирование таймера 48, предделитель поставил 48000, считать до 499. Прошилось, мигает, но скорость мигания явно медленнее, даже векундомер включил на десять сек 4 раза мигает, все перепроверил:
htim3.Instance = TIM3;
htim3.Init.Prescaler = 48000;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 499;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
В APB1 Timer Clocks точно 48 МГц? А контроллер такой же?
Да тут было это значение. Я нашел ошибку у меня в main pll стояли делители другие, но на SYSCLK ,было 48, поэтому не заметил сразу. Благодарю Вас. Жду следующих уроков
Рад, что заработало!
А что за частота (To Cortex System timer) и (FCLK Cortex clock) и для чего используется? Хотелось бы хоть какое то иметь представление о них.
А внешние генераторы я так понял опциональные, зачем они вообще нужны/используются ибо с помощью делителя мы можем получить нужную частоту с внутреннего генератора?
Внешние кварцы обычно более точные, быстрее просыпаются, меньше жрут.
Можно к этим ногам вообще подключить один общий задающий генератор на несколько МК для синхронизации.
Почему никто не задает вопрос как сделать доступным внешний кварц? У меня вот он серым подсвечен..оказывается его в RCC нужно включить предварительно
Здесь просто внутренний используется, в тех статьях, где используется внешний, там описано как его включить. Но вообще Вы правы, добавлю в статью отдельное упоминание о том, что внешний нужно сначала включить в другом окне.
А нет, прошу прощения. Здесь же подробно описано в статье как включить внешний кварц! Вы видимо только до середины дочитали ...=\
Доброго всем дня!
А подскажите пожалуйста, кто знает, возможно ли изменение частоты тактирования в процессе работы контроллера.
Использую MSI источник. Необходимо переключаться между 1МГц и 65кГц.
Да, частоту можно менять в процессе работы.
Добрый день! Подскажите почему в Cube указана входная частота для HSI 16 MHz. Ведь на плате установлен кварц на 8 MHz.
HSI - это внутренний источник.
да, high speed internal. на нем написано 8 000 000. а в кубе где HSI RC стоит 16 000 000 - выше на картинке
Внутренний - это тот, который установлен внутри микроконтроллера, а тот что на плате - внешний - HSE.
внутри это прямо в черном ARM процессоре правильно ? его не видно визуально. правильно ?
Да, все верно.
Доброго дня! А есть ли в HAL возможность узнать частоту на которой работает периферия? Например, конкретно - частоту шины APB1?
Все перерыл, нашел делители, но нигде не нашел заданной частоты процессора (
Добрый день!
Вы имеете ввиду узнать из кода, во время работы программы?
Да. Структура настройки таймера не содержит частоты... или я плохо искал?
Можно функции из stm32fxx_hal_rcc.c использовать:
HAL_RCC_GetHCLKFreq()
HAL_RCC_GetPCLK1Freq()
HAL_RCC_GetPCLK2Freq()
Они как раз текущую частоту возвращают.
Большое спасибо, то, что надо!
Отлично)