Добавим вектор обработчика таймера №4:
0, /*!%29 TIM3 */
tim4_irq_hanlder, /*!%30 TIM4 */
0, /*!%31 I2C1 Event */
И сам обработчик прерывания:
/* timer4 irq handler */
void tim4_irq_hanlder(void) {
if (TIM4->SR & TIM_SR_UIF) {
static int counter;
char divide;
static char direct;
counter++;
Каждую итерацию таймера для удобства отображения мы расширим до 4-х циклов:
if (counter > 3) {
counter = 0;
Для стабильности мы переключаемся на внутренний высокоскоростной осциллятор:
/* switch to HSI and wait for stable*/
RCC->CFGR &= ~RCC_CFGR_SW;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
Выключаем ФАПЧ для перенастройки:
/* disable PLL and wait for off */
RCC->CR &= ~RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 1);
Вносим в локальную переменную значение делителя и сбрасываем его значение:
/* setup PLL, enable and wait to ready */
divide = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM;
Вычисляем значение нового и загружаем это значение обратно в регистр настроек ФАПЧ:
/* calculate new divide value */
if (direct)
if (divide > 8)
divide -= 4;
else
direct = 0;
else
if (divide < 32)
divide += 4;
else
direct = 1;
RCC->PLLCFGR |= divide;
Включаем ФАПЧ и ждем его стабилизации
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
Переключаемся на ФАПЧ, ждем окончания переключения и выходим из прерывания:
/* select PLL for system clock and wait to select */
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS_PLL) == 0);
}
/* clear status bit */
TIM4->SR &= ~TIM_SR_UIF;
}
}