work.c

Начнем как обычно с включения периферии:

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

В эту инициализацию мы добавим включение таймера №4.

Также настроим порты ввода-вывода:

/* set led pins to output state */
    LED_PORT->MODER |=
        GPIO_MODER_MODER12_0 | GPIO_MODER_MODER13_0 |
        GPIO_MODER_MODER14_0 | GPIO_MODER_MODER15_0;
    /* pull-up button io */
    BUT_PORT->PUPDR |= GPIO_PUPDR_PUPDR0_1;

Также настроим внешенее прерывание exti0:

/* route exti0 to pa0 */
    SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;
    /* setup exti0 to rising edge */
    EXTI->RTSR |= EXTI_RTSR_TR0;
    /* enable exti0 interrupt */
    EXTI->IMR |= EXTI_IMR_MR0;

После чего будем настраивать наш таймер. Начнем с предделителя - т.к. у нас частота 16МГц то зададим его таким чтобы удобно было пользоватся таймером: 16000 - 1(почему именно так указано выше):

/* tim4 setup presc */
    TIM4->PSC = 16000 - 1;

После этого мы внесем в регистр автозагрузки значение 500 - это значение будет загружатся каждый раз по событию обновления(переполнения). Этим мы с учетом предделителя сделали задержку в 0.5с:

/* tim4 setup preload reg */
    TIM4->ARR = 500;

Добавим в регистр ПДП/Прерываний активизацию прерывания по обновлению(переполнению):

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

После этого активизируем таймер:

/* tim4 enable clock */
    TIM4->CR1 |= TIM_CR1_CEN;

Осталось самое малое - включение прерываний:

/* nvic enable exti0 irq */
    NVIC_EnableIRQ(EXTI0_IRQn);
    /* nvic enable tim4 irq */
    NVIC_EnableIRQ(TIM4_IRQn);