Речь пойдёт о микроконтроллере (МК) 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 запитки МК.

Рис 1. Варианты подачи питания

У нас используется вариант 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.

Рис 2. CubeIDE: параметры питания

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

Рис 3. CubeIDE: делители для PLL

Добавим также в проект пару выходов для светодиодов, сгенерируем код соберем и зашьем его в МК. Пока всё супер. Оба цикла на ядрах 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 ниже.

Рис 4. Осциллограмма с выхода MCO2


Отметим в коде выше строчку 18, где ожидается установка флага PWR_FLAG_VOSRDY. Критерии его установки в документации детально не определены, но нестабильность питания микроконтроллера может привести к зависанию в этом месте, особенно при переходе с 400 МГц на 480 МГц, поскольку потребление ядра при этом возрастает. Повторный вызов SystemClock_Config() на другом ядре с другими параметрами также может приводить к зависанию там.

Напоследок добавлю - не жалейте емкостей по питанию ядра! Устанавливайте их в непосредственной близости от выводов Vcap, кои в данном микроконтроллере расположены в разных местах по трем сторонам корпуса.

Комментарии (0)