startup.c

Добавим вектор обработчика таймера №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;
    }
}