STM32F103 настройка тактирования

Первоначально плата STM32F103 работает от внутреннего генератора на частоте 48 мГц.
Сделал настройку по ссылке но ничего не поменялось на двух разных платах. Почему может не работать?

https://dimoon.ru/obuchalka/stm32f1/uroki-stm32f103-chast-4-nastroyka-rcc.html?ysclid=m77p7n5frs371276003

Код.

//#include <stm32f1xx.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd (PA9, PA8, PB15, PB14, PB13, PB12); //(RS,E,D4,D5,D6,D7)
uint32_t Tay_ind =  1000000;
uint32_t time_new_ind,time_old_ind,time_del_ind;
  //-------------------------------------------------------------------------//
int ClockInit(void)
{
  __IO int StartUpCounter;
  ////////////////////////////////////////////////////////////
  // Запускаем кварцевый генератор
  ////////////////////////////////////////////////////////////
  RCC->CR |= RCC_CR_HSEON; // Запускаем генератор HSE
  // Ждем успешного запуска или окончания тайм-аута
  for(StartUpCounter = 0; ; StartUpCounter++)
  {
    // Если успешно запустилось, то выходим из цикла
    if(RCC->CR & RCC_CR_HSERDY)
      break;
    // Если не запустилось, то отключаем все, что включили и возвращаем ошибку
    if(StartUpCounter > 0x1000)
    {
      RCC->CR &= ~RCC_CR_HSEON; // Останавливаем HSE
      return 1;
    }
  }
  ////////////////////////////////////////////////////////////
  // Настраиваем и запускаем PLL
  ////////////////////////////////////////////////////////////
  // Настраиваем PLL
  RCC->CFGR |= RCC_CFGR_PLLMULL2 // PLL множитель равен 9
            | RCC_CFGR_PLLSRC;   // Тактирование PLL от HSE
  RCC->CR |= RCC_CR_PLLON; // Запускаем PLL
  // Ждем успешного запуска или окончания тайм-аута
  for(StartUpCounter = 0; ; StartUpCounter++)
  {
    // Если успешно запустилось, то выходим из цикла
    if(RCC->CR & RCC_CR_PLLRDY)
      break;
    // Если по каким-то причинам не запустился PLL, то отключаем все, что включили и возвращаем ошибку
    if(StartUpCounter > 0x1000)
    {
      RCC->CR &= ~RCC_CR_HSEON; // Останавливаем HSE
      RCC->CR &= ~RCC_CR_PLLON; // Останавливаем PLL
      return 2;
    }
  }
  ////////////////////////////////////////////////////////////
  // Настраиваем FLASH и делители
  ////////////////////////////////////////////////////////////
  // Устанавливаем 2 цикла ожидания для Flash
  // так как частота ядра у нас будет 48 MHz < SYSCLK <= 72 MHz
  FLASH->ACR |= FLASH_ACR_LATENCY_2; 
  // Делители
  RCC->CFGR |= RCC_CFGR_PPRE2_DIV1 // Делитель шины APB2 отключен
            | RCC_CFGR_PPRE1_DIV2  // Делитель шины APB1 равен 2
            | RCC_CFGR_HPRE_DIV1; // Делитель AHB отключен
  RCC->CFGR |= RCC_CFGR_SW_PLL; // Переключаемся на работу от PLL
  // Ждем, пока переключимся
  while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
  {
  }
  // После того, как переключились на внешний источник тактирования
  // отключаем внутренний RC-генератор для экономии энергии
  RCC->CR &= ~RCC_CR_HSION;
  // Настройка и переключение системы на внешний кварцевый генератор и PLL завершилось успехом.
  // Выходим
  return 0;
}
//-------------------------------------------------------------------------//
void setup()
{
 //-------------------------------------------------------------------------//
  // Инициализация тактирования
  if(ClockInit() != 0) {
    // Обработка ошибки инициализации тактирования
    while(1);
  }
 //-------------------------------------------------------------------------//
  lcd.begin(20, 4);
  //-------------------------------------------------------------------------//
  // Включаем тактирование TIM2
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
  // Настройка TIM2 для счета миллисекунд
  TIM2->CR1 = 0;  // Остановка таймера
  TIM2->PSC = 47999;  // Предделитель 48000 (48 МГц / 48000 = 1 кГц)
  TIM2->ARR = 0xFFFF;  // Автоперезагрузка на максимум (16 бит)
  TIM2->CCER &= ~TIM_CCER_CC1P;  // Полярность: считаем по фронту 
  TIM2->EGR = 1;  // Обновление регистров
  TIM2->CR1 |= (1 << 0);  // Запуск TIM2
  //-------------------------------------------------------------------------//
}
void loop()
{
  time_new_ind= micros();
  time_del_ind=time_new_ind-time_old_ind;
  if (time_del_ind>=Tay_ind)
  {
    //-----------------------------------------------------------------------//
    uint32_t milliseconds = TIM2->CNT;
    uint32_t sysclk_freq = HAL_RCC_GetSysClockFreq();
    //-----------------------------------------------------------------------//
    lcd.clear();
    lcd.setCursor(0, 0);lcd.print("T= ");lcd.print(millis());
    lcd.setCursor(0, 1);lcd.print("N= ");lcd.print(milliseconds);
    lcd.setCursor(0, 2);lcd.print("F= ");lcd.print(sysclk_freq);
    time_old_ind=time_new_ind;
  }
}

на каких платах?

На какой частоте с таким кодом работают платы ?

В 31 строке надо смотреть что в итоге за множитель получается …RCC_CFGR_PLLMULL9 нужен скорее всего для кварца 8 МГц. Вы как то странно читали описание по ссылке и привели свой вариант кода !!!

Если первая строка = комментарий - откуда берутся все константы ??? Вы уверены что это вообще компилируется и прошивается ???

Плата такая и что самое интересное прошивается и не дает ошибок. На меня это не похоже.
Плата работает на частоте 48 мГц. В 86 строке настраиваю предделитель. Время с таймера и время миллисекунд отображаются синхронно.
https://aliexpress.ru/item/1005004918334754.html?sku_id=12000034303875973&spm=a2g2w.stores.seller_list.3.2ee647dcIl7d7x

Кварц какой на плате ?
И тут в процессе возник еще вопрос - на какой частоте вы хотите запустить микроконтроллер ?

если это действительно плата от Weact, то они только 8мГц.

Ну для начала хотел бы запустить на 72 мгц. Но пока получилось только запустить на 8 мГц от внутреннего генератора. Строки с 6 по 17.

//работает на частоте 8 мгц от внутреннего генератора
#include <LiquidCrystal.h>
LiquidCrystal lcd (PA9, PA8, PB15, PB14, PB13, PB12); //(RS,E,D4,D5,D6,D7)
uint32_t Tay_ind =  1000000;
uint32_t time_new_ind,time_old_ind,time_del_ind;
  //-------------------------------------------------------------------------//
void SystemClock_Config(void) {
    // Включение HSI (внутренний генератор 8 МГц)
    RCC->CR |= RCC_CR_HSION; // Включение HSI
    while (!(RCC->CR & RCC_CR_HSIRDY)); // Ожидание готовности HSI

    // Переключение на HSI как источник тактирования
    RCC->CFGR &= ~RCC_CFGR_SW; // Сброс источника тактирования
    RCC->CFGR |= RCC_CFGR_SW_HSI; // Использование HSI как источника тактирования
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); // Ожидание переключения на HSI
}
//-------------------------------------------------------------------------//
void setup()
{
 //-------------------------------------------------------------------------//
 SystemClock_Config(); // Настройка тактирования
  //-------------------------------------------------------------------------//
  lcd.begin(20, 4);
  //-------------------------------------------------------------------------//
  // Включаем тактирование TIM2
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
  // Настройка TIM2 для счета миллисекунд
  TIM2->CR1 = 0;  // Остановка таймера
  TIM2->PSC = 7999;  // Предделитель 48000 (8 МГц / 8000 = 1 кГц)
  TIM2->ARR = 0xFFFF;  // Автоперезагрузка на максимум (16 бит)
  TIM2->CCER &= ~TIM_CCER_CC1P;  // Полярность: считаем по фронту 
  TIM2->EGR = 1;  // Обновление регистров
  TIM2->CR1 |= (1 << 0);  // Запуск TIM2
  //-------------------------------------------------------------------------//
}
void loop()
{
  time_new_ind= micros();
  time_del_ind=time_new_ind-time_old_ind;
  if (time_del_ind>=Tay_ind)
  {
    //-----------------------------------------------------------------------//
    uint32_t milliseconds = TIM2->CNT;
    uint32_t sysclk_freq = HAL_RCC_GetSysClockFreq();
    //-----------------------------------------------------------------------//
    lcd.clear();
    lcd.setCursor(0, 0);lcd.print("T= ");lcd.print(millis());
    lcd.setCursor(0, 1);lcd.print("N= ");lcd.print(milliseconds);
    lcd.setCursor(0, 2);lcd.print("F= ");lcd.print(sysclk_freq);
    time_old_ind=time_new_ind;
  }
}

Запустил в работу от внешнего генератора на 8 мгц.

  //-------------------------------------------------------------------------//
void SystemClock_Config(void) {
    // Включение HSE (внешний кварцевый генератор 8 МГц)
    RCC->CR |= RCC_CR_HSEON; // Включение HSE
    while (!(RCC->CR & RCC_CR_HSERDY)); // Ожидание готовности HSE

    // Настройка FLASH (для работы на частоте HSE)
    FLASH->ACR |= FLASH_ACR_PRFTBE; // Включение предварительной выборки
    FLASH->ACR &= ~FLASH_ACR_LATENCY; // Сброс задержки
    FLASH->ACR |= FLASH_ACR_LATENCY_0; // Установка задержки в 0 тактов (для частот до 24 МГц)

    // Переключение на HSE как источник тактирования
    RCC->CFGR &= ~RCC_CFGR_SW; // Сброс источника тактирования
    RCC->CFGR |= RCC_CFGR_SW_HSE; // Использование HSE как источника тактирования
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE); // Ожидание переключения на HSE
}
//-------------------------------------------------------------------------//

Добавил настройку шин.

void SystemClock_Config(void) {
    // Включение HSE (внешний кварцевый генератор 8 МГц)
    RCC->CR |= RCC_CR_HSEON; // Включение HSE
    while (!(RCC->CR & RCC_CR_HSERDY)); // Ожидание готовности HSE

    // Настройка FLASH (для работы на частоте HSE)
    FLASH->ACR |= FLASH_ACR_PRFTBE; // Включение предварительной выборки
    FLASH->ACR &= ~FLASH_ACR_LATENCY; // Сброс задержки
    FLASH->ACR |= FLASH_ACR_LATENCY_0; // Установка задержки в 0 тактов (для частот до 24 МГц)

    // Настройка делителей шин
    RCC->CFGR &= ~(RCC_CFGR_HPRE | RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2); // Сброс делителей
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;   // AHB без деления (частота = HSE = 8 МГц)
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;  // APB1 без деления (частота = HSE = 8 МГц)
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;  // APB2 без деления (частота = HSE = 8 МГц)

    // Переключение на HSE как источник тактирования
    RCC->CFGR &= ~RCC_CFGR_SW; // Сброс источника тактирования
    RCC->CFGR |= RCC_CFGR_SW_HSE; // Использование HSE как источника тактирования
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSE); // Ожидание переключения на HSE
}

пример функции инициализации RCC для STM32F103C8T6 с использованием внешнего кварца 8 МГц для достижения тактовой частоты 72 МГц:

#include "stm32f10x.h"

void SystemClock_Config(void) {
    // 1. Включение HSE и ожидание готовности
    RCC->CR |= RCC_CR_HSEON;              // Включить HSE
    while(!(RCC->CR & RCC_CR_HSERDY));    // Ждем стабилизации генератора

    // 2. Настройка задержки Flash-памяти
    FLASH->ACR |= FLASH_ACR_LATENCY_2;    // Два цикла ожидания (для 48-72 МГц)
    FLASH->ACR |= FLASH_ACR_PRFTBE;       // Включить предварительную выборку

    // 3. Настройка делителей шин
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;      // AHB  = 72 MHz
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;     // APB1 = 36 MHz
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;     // APB2 = 72 MHz

    // 4. Конфигурация PLL (8MHz * 9 = 72MHz)
    RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;     // Источник PLL - HSE
    RCC->CFGR |= RCC_CFGR_PLLMULL9;       // Множитель PLL x9

    // 5. Включение PLL и ожидание готовности
    RCC->CR |= RCC_CR_PLLON;              // Запуск PLL
    while(!(RCC->CR & RCC_CR_PLLRDY));    // Ждем готовности PLL

    // 6. Переключение на PLL как источник системного такта
    RCC->CFGR |= RCC_CFGR_SW_PLL;         // Выбираем PLL как системный источник
    while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Ждем переключения
}

Вопрос решен.При попытке запрограммировать PLL умножение на 9 stm32f103 программируется но с коэффициентом 12. Поскольку процессор не может работать на частоте 96 мГц. Его частота сбрасывается и он работает на частоте 48 мГц от внутреннего генератора.