плата по ссылке:
на вывод PB0 подаю частоту 1000 гц от внешнего генератора. Таймер 2 настроен на счет импульсов системной шины. Если тактирование брать напрямую от внешнего кварца то частота ровно 25000000 плюс минус 1 гц. То есть он работает от внешнего кварца правильно. Вот код для этого.
// Версия 1
#include <LiquidCrystal.h> //библиотека для работы с экраном
LiquidCrystal lcd (PB8, PB7, PB6, PB5, PB4, PB3, PA15, PA12, PB13, PB12); //(RS,E,D0,D1,D2,D3,D4,D5,D6,D7)
volatile bool flag_Led = 0;
volatile uint16_t irq_counter = 0;
uint32_t tim2_value;
//-------------------------------
void setup()
{
lcd.begin(20, 4);
//---Настройка Таймера 2
// Настройка системной шины
RCC->CFGR &= ~RCC_CFGR_PPRE1; // Сбрасываем биты PPRE1
RCC->CFGR |= RCC_CFGR_PPRE1_DIV1; // Устанавливаем делитель APB1 = 1
// Включаем тактирование таймера TIM2
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // Включаем тактирование таймера TIM2
// Настройка таймера TIM2 для внутренней частоты
TIM2->CR1 &= ~TIM_CR1_CEN; // Останавливаем таймер перед настройкой
TIM2->PSC = 0; // Предделитель (PSC) = 0 (нет деления)
TIM2->ARR = 0xFFFFFFFF; // Максимальное значение счётчика (32 бита)
TIM2->CNT = 0; // Сбрасываем текущее значение счётчика
TIM2->EGR |= TIM_EGR_UG; // Принудительное обновление регистров таймера
TIM2->CR1 |= TIM_CR1_CEN; // Запускаем таймер
//---Настройка прерывания на PB0
pinMode(PB0, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PB0), watchdogHandler, RISING);
//---Настройка системной частоты.
// Включаем HSE
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY)); // Дожидаемся HSE
// Проверка HSE:
uint32_t hse_status = (RCC->CR & RCC_CR_HSERDY) ? 1 : 0;
// Переключаем системный такт на HSE
RCC->CFGR = (1 << RCC_CFGR_SW_Pos); // SW=1 (HSE)
// Ждем переключения (с таймаутом)
uint32_t timeout = 100000; // 100000 итераций
while ((RCC->CFGR & 0x00000007) != 0x1)
{
timeout--;
if (timeout == 0) break; // Выход, если таймаут
}
}
void loop()
{
if (flag_Led == 1)
{
// Вывод значения таймера TIM2
lcd.setCursor(0, 0);
lcd.print("SYS=");lcd.print(tim2_value);
flag_Led = 0;
}
}
void watchdogHandler()
{
irq_counter += 1;
if (irq_counter >= 1000)
{
flag_Led = 1;
irq_counter = 0;
tim2_value = TIM2->CNT;// Считываем значение таймера TIM2
TIM2->CNT = 0;// Сбрасываем таймер TIM2
}
}
но если я пытаюсь включить работу от внешнего кварца с использованием PLL то у меня тактирование переключается на внутренний генератор и частота равна 94.8 мгц и меняется на несколько кгц. Вот код где я пытаюсь настроить PLL
// Версия 2
#include <LiquidCrystal.h> //библиотека для работы с экраном
LiquidCrystal lcd (PB8, PB7, PB6, PB5, PB4, PB3, PA15, PA12, PB13, PB12); //(RS,E,D0,D1,D2,D3,D4,D5,D6,D7)
volatile bool flag_Led = 0;
volatile uint16_t irq_counter = 0;
uint32_t tim2_value;
uint32_t pllcfgr_value; // Для хранения значения PLLCFGR
bool pll_active = false; // Флаг активности PLL
void setup()
{
lcd.begin(20, 4);
//---Настройка Таймера 2
// Настройка системной шины
RCC->CFGR &= ~RCC_CFGR_PPRE1; // Сбрасываем биты PPRE1
RCC->CFGR |= RCC_CFGR_PPRE1_DIV1; // Устанавливаем делитель APB1 = 1
// Включаем тактирование таймера TIM2
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // Включаем тактирование таймера TIM2
// Настройка таймера TIM2 для внутренней частоты
TIM2->CR1 &= ~TIM_CR1_CEN; // Останавливаем таймер перед настройкой
TIM2->PSC = 0; // Предделитель (PSC) = 0 (нет деления)
TIM2->ARR = 0xFFFFFFFF; // Максимальное значение счётчика (32 бита)
TIM2->CNT = 0; // Сбрасываем текущее значение счётчика
TIM2->EGR |= TIM_EGR_UG; // Принудительное обновление регистров таймера
TIM2->CR1 |= TIM_CR1_CEN; // Запускаем таймер
//---Настройка прерывания на PB0
pinMode(PB0, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PB0), watchdogHandler, RISING);
//---Настройка системной частоты:
// 1. Включаем HSE
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY)); // Дожидаемся HSE
// Проверка HSE:
uint32_t hse_status = (RCC->CR & RCC_CR_HSERDY) ? 1 : 0;
if (!hse_status)
{
// Если HSE не активен, выводим ошибку
lcd.setCursor(0, 0);
lcd.print("HSE ERROR");
while(1); // Зацикливаемся
}
// Отладочный вывод
lcd.setCursor(0, 0);
lcd.print("HSE ON");
delay(1000);
// 2. Переключаем системный такт на HSE (базовая настройка версии 1)
RCC->CFGR = (1 << RCC_CFGR_SW_Pos); // SW=1 (HSE)
while ((RCC->CFGR & RCC_CFGR_SWS) != (1 << RCC_CFGR_SWS_Pos)); // Ждем переключения
// Отладочный вывод
lcd.setCursor(0, 1);
lcd.print("SWITCH TO HSE");
delay(1000);
// 3. Настройка PLL (добавлено без нарушения базовой работы):
// PLLM=2 (HSE/2 = 12.5 МГц), PLLN=12 → 12.5×12 = 150 МГц
RCC->PLLCFGR =
(2 << 24) | // PLLM=2 (биты 27:24)
(12 << 8) | // PLLN=12 (биты 21:8)
(0 << 5) | // PLLP=0b00 → /2 → HCLK=75 МГц
(0 << 8); // PLLR=0b000 → /2 → APB1=37.5 МГц
RCC->CR |= RCC_CR_PLLON; // Включаем PLL
while (!(RCC->CR & RCC_CR_PLLRDY)); // Ждем готовности PLL
// Отладочный вывод
lcd.setCursor(0, 2);
lcd.print("PLL ON");
delay(1000);
// 4. Переключаем системный такт на PLL (SW=2)
RCC->CFGR = (RCC->CFGR & ~(3 << RCC_CFGR_SW_Pos)) | (2 << RCC_CFGR_SW_Pos); // Переключаем системный такт на PLL
while ((RCC->CFGR & RCC_CFGR_SWS) != (2 << RCC_CFGR_SWS_Pos)); // Ждем переключения
// Отладочный вывод
lcd.setCursor(0, 3);
lcd.print("SWITCH TO PLL");
delay(1000);
pllcfgr_value = RCC->PLLCFGR; // Сохраняем значение регистра для вывода
pll_active = true; // Устанавливаем флаг активности PLL
// Проверка значений регистров
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("HSE ON");
lcd.setCursor(0, 1);
lcd.print("SWITCH TO HSE");
lcd.setCursor(0, 2);
lcd.print("PLL ON");
lcd.setCursor(0, 3);
lcd.print("SWITCH TO PLL");
delay(5000); // Ждем 5 секунд для просмотра отладочной информации
lcd.clear();
}
void loop()
{
if (flag_Led == 1)
{
// Выводим PLLCFGR и системную частоту:
lcd.setCursor(0, 0);
lcd.print("SYS="); lcd.print(tim2_value);
lcd.setCursor(0, 1);
lcd.print("PLL=");
lcd.print(pllcfgr_value, HEX); // Выводим значение PLLCFGR в HEX
flag_Led = 0;
}
}
void watchdogHandler()
{
irq_counter += 1;
if (irq_counter >= 1000)
{
flag_Led = 1;
irq_counter = 0;
tim2_value = TIM2->CNT; // Считываем значение таймера TIM2
TIM2->CNT = 0; // Сбрасываем таймер TIM2
}
}
При этом на экран выводится
HSE ON
SWITCH TO HSE
PLL ON
SWITCH TO PLL
SYS=94867568
PLL=201540E
Где у меня ошибка в настройке PLL?