work.c

Включаем тактирование для порта светодиодов и таймера:

    /* enable led  port */
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
    /* enable tim4 */
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;

Также настроим выводы порта на режим альтернативных фунций и настроим их на подключение к таймеру №4:

    /* set led pins to af state */
    LED_PORT->MODER |=
        GPIO_MODER_MODER12_1 | GPIO_MODER_MODER13_1 |
        GPIO_MODER_MODER14_1 | GPIO_MODER_MODER15_1;
    /* select af block - tim3..5(af2 function) to led pins */
    LED_PORT->AFR[1] |= (GPIO_AF2_TIM3_5 << GPIO_AFP12) | (GPIO_AF2_TIM3_5 << GPIO_AFP13) |
        (GPIO_AF2_TIM3_5 << GPIO_AFP14) | (GPIO_AF2_TIM3_5 << GPIO_AFP15);

Также настроим таймер (настройки почти аналогичные примеру Регистры сравнения/захвата шим) за исключением значения для каналов:

    /* tim4 setup presc */
    TIM4->PSC = 16000 - 1;
    /* tim4 setup preload reg */
    TIM4->ARR = 1000;
    /* tim4 load values to ccr1..4 */
    TIM4->CCR1 = 500;
    TIM4->CCR2 = 0;
    TIM4->CCR3 = 0;
    TIM4->CCR4 = 0;
    /* tim4 setup cc chanel1..4 */
    TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;
    TIM4->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2;
    /* tim4 setup cc chanel1..4 to corresponding output pin */
    TIM4->CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E;

Настроим ФАПЧ на значения умножителя 64 и делителя 32, т.е. коэффициент умножения 2, а так как предделитель для ФАПЧ по умолчанию равен 2, то получаем на выходе ту же частоту что и на входе:

    /* pll configuration */
    RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN);
    RCC->PLLCFGR |= (64 << 6) | 32;

Включаем ФАПЧ:

    /* pll enable */
    RCC->CR |= RCC_CR_PLLON;

Также не забудем согласно ДШ задать количество циклов ожидания для максимальной частоты 64 МГц - 2 цикла ожидания:

    /* enable flash wait to 2 ws */
    FLASH->ACR |= FLASH_ACR_LATENCY_2WS;

Ждем стабилизацию частоты ФАПЧ и переключаемся на тактирование от него:

    /* wait to ready pll and switch to it */
    while ((RCC->CR && RCC_CR_PLLRDY) == 0);
    RCC->CFGR &= ~RCC_CFGR_SWS;
    RCC->CFGR |= RCC_CFGR_SWS_PLL;

Активируем прерывания от таймера и сам таймер №4:

    /* tim4 enable update interrupt */
    TIM4->DIER |= TIM_DIER_UIE;
    /* tim4 enable clock */
    TIM4->CR1 |= TIM_CR1_CEN;

Также активируем прерывания для этого таймера:

    /* tim4 irq */
    NVIC_EnableIRQ(TIM4_IRQn);