work.c

Помимо порта к которому подключены светодиоды, вкючим и настроим порт к которому подключена кнопка:

    /* enable led & button port */
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOAEN;
    /* 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;

Также перенаправим линию прерывания на нужную нам линию порта в/в, а заодно настроим это прерывание:

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

Включим это прерывание:

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

В блок обработки флагов сброса мы добавим выбор для программного сброса, следует учитывать что флаг сброса по низкому уровню на линии сброса активен при любом сбросе - это видно из схемы сброса в теоретической части статьи:

    /* get reset flags */
    unsigned int flags = RCC->CSR;
    /* clear nothing bits */
    flags &= ~(1 << 24 | 1 << 1 | 1 << 0);
    /* enable led for needed flags */
    switch (flags) {
        /* hardware reset */
        case RCC_CSR_PADRSTF:
            LED_PORT->ODR |= RED_LED;
            break;
        /* software reset */
        case RCC_CSR_PADRSTF | RCC_CSR_SFTRSTF:
            LED_PORT->ODR |= BLUE_LED;
            break;
        /* another reset */
        default:
            LED_PORT->ODR |= ALL_LEDS;
            break;
    }
    /* clear reset flags */
    RCC->CSR |= RCC_CSR_RMVF;