Речь пойдёт о микроконтроллере (МК) STM32H745IIT6, в корпусе LQFP — 176, с ядрами Cortex‑M4 240 МГц и Cortex‑M7 480 МГц. Далее я буду ссылаться на официальную документацию STM — RM0399 Reference Manual Rev. 4 [1] и DS12923 Rev. 2 Datasheet STM32H745xI/G [2].
Что тут может быть сложного, спросите вы. В наш век IDE всё же решается автоматически? Нужно лишь нажать на кнопку? Оно как бы да, но есть нюансы. Работаем с родной средой производителя CubeIDE V1.18.0, куда интегрирован конфигуратор CubeMX 6.14.2.
Для начала рассмотрим концепт масштабирования напряжения, или Voltage Scaling (VOS).
Это означает, что чем выше тактовая частота, тем больше напряжения нужно ядру, и направлено на снижение потребляемой мощности, и соответственно, разогрева чипа. Отключить этот функционал нельзя. Соответствие между напряжением питания ядра VOS и тактовой частотой представлено в Таблице 1 ниже.
Таблица 1. Питание ядра и рабочие частоты

Что ж, будем разбираться, как это работает. У нашего МК есть автономный импульсный преобразователь — Switching Mode Power Supply, или SMPS (его нагрузочная способность 600 мА) и линейный стабилизатор — LDO выход которого подключен к питанию ядра Vcore. На Рис. 1 ниже представлены варианты 1–6 запитки МК.

У нас используется вариант 3, когда встроенный SMPS с выходным напряжением 1.8 В запитывает LDO. Для понимания как микроконтроллер ими управляет, приведем еще Таблицу 2 ниже. ID в левой колонке соответствует номеру рисунка выше.
Таблица 2. Варианты подачи питания и биты управления


Примечательно, что биты перечисленные в таблице выше, или же биты младшего байта регистра PWR_CR3, устанавливаются лишь один раз после Power On Reset (POR), как указано в пункте 7.8.4 [1]. Это имеет несколько неочевидных последствий. В частности, схему питания контроллера на лету изменить нельзя.
Что ж, для начала запустим МК на частоте 400 МГц. В CubeIDE выбираем оба кварца, Power Regulator Voltage Scale = VOS1 и SupplySource = PWR_SMPS_1V8_SUPPLIES_LDO, см. Рис. 2 ниже. Активируем Master Clock Output 2 (#PC9), на нем мы осциллографом будем верифицировать тактовую частоту. Еще один значимый параметр здесь Flash Latency = 2WS.

Для того чтобы получить 400 МГц от нашего кварца 25 МГц, выставляем делители для PLL а также делитель на 15 (внизу диаграммы, на рисунке не показан) для выхода MCO2 = SYSCLK/15 → 400/15 = 26.(6) МГц. Для наших 400 МГц умножитель DIVN1 = 160; чтобы впоследствии получить 480 МГц, его будет достаточно поменять на 192.

Добавим также в проект пару выходов для светодиодов, сгенерируем код соберем и зашьем его в МК. Пока всё супер. Оба цикла на ядрах CM4, CM7 крутятся, светодиоды мигают в такт. Измеренное тестером напряжение Vcore = 1.2 В. Попробуем теперь вывести МК на 480 МГц.
Обращаемся опять к CubeIDE, и ставим теперь Regulator Voltage Scale = VOS1 → VOS0. При этом меняются такты ожидания Flash Latency = 2 → 4 WS, см. Таблицу 3 ниже.
Таблица 3. Такты ожидания от тактовой частоты

Меняем также DIVN1 = 160 → 192. Генерируем код из под CubeIDE, вновь собираем и прошиваем наш МК. Проект работает на 480 МГц, светодиоды мигают, Vcore = 1.35 В.
Посмотрим на код функции void SystemClock_Config(void), который нам сгенерил CubeIDE:
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_SMPS_1V8_SUPPLIES_LDO);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 192;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_15);
}
На MCO2 → 480 МГц /15 = 32 МГц, см. Рис. 4 ниже.

Отметим в коде выше строчку 18, где ожидается установка флага PWR_FLAG_VOSRDY. Критерии его установки в документации детально не определены, но нестабильность питания микроконтроллера может привести к зависанию в этом месте, особенно при переходе с 400 МГц на 480 МГц, поскольку потребление ядра при этом возрастает. Повторный вызов SystemClock_Config() на другом ядре с другими параметрами также может приводить к зависанию там.
Напоследок добавлю — не жалейте емкостей по питанию ядра! Устанавливайте их в непосредственной близости от выводов Vcap, кои в данном микроконтроллере расположены в разных местах по трем сторонам корпуса.
Комментарии (0)
SIISII
15.09.2025 18:30А ещё в документации написано, что сразу после сброса по включении питания нельзя обращаться ко встроенной памяти. Это означает, что самое первое, что надо сделать, -- провести минимальную настройку питания, чтоб можно было обращаться к памяти, причём это можно делать только на ассемблере, прямо в обработчике сброса: компилятор же всегда обращается к стеку, а это -- память.
StepanBv
Стоит упомянуть, что у h745/755 нельзя добиться максимальной частоты при питании ядра напрямую от SMPS. Точнее можно, но только один раз, при сбросе питания МК постоянно будет висеть в hard fault, что лечится стиранием программы с помощью программатора в режиме connect under reset (в других режимах не удастся подключиться к МК).
Hhappyy Автор
Можно. Я с похожей штукой сталкивался. Сценарий: поднимаем плату на 400 МГц. Потом реконфигурируем ее на 480 МГц и перепрошиваем. Затем перезапускаем кнопкой RESET. Все работает. Но после сброса питания плата зависает, как раз на упомянутой в статье проверке VOSRDY. У меня это вылечилось постановкой емкостей по цепям питания МК. Плата сразу встает на 480 МГц. Также еще советуют нагрузить выход SMPS на резистор.
StepanBv
По крайней мере в даташите говорится, что VOS0 не может работать при питании ядра от SMPS.
Hhappyy Автор
Не уточните где именно? Вероятно имеется ввиду вариант питания ядра напрямую от внешнего SMPS.
StepanBv
Пункты 3.5.3 и 6.3.1
Hhappyy Автор
В 3.5.3 [2] дословно написано: Scale 0: boosted performance (available only with LDO regulator); В 6.3.1 [2] (примечание 5) : VOS0 is available only when the LDO regulator is ON.
Я трактую это так, что для использования VOS0 актуальны схемы включения 1-4, когда внутренний LDO включен, и не актуальны схемы 5, 6 когда он выключен.
См. Рис 1 выше, или же пункт 7.4, Figure 22 [1].
На практике вариант запитки 3, когда встроенный SMPS подключен к питанию +3.3 В и генерирует напряжение 1.8 В, которое подается на вход встроенного LDO, а 1.35 В с его выхода на ядро, вполне себе рабочий для VOS0.
StepanBv
В изначальном комментарии я так и написал, что не работает при прямом питании ядра через SMPS, правда я не написал про внешние регуляторы.
Hhappyy Автор
Встречал также упоминание о том, что VOS0 можно включить только через VOS1. Но на моей плате это не так. Вероятно, это относится к ранней версии чипа.