Kod ze strukturą timera i NVICa:

    TIM_TimeBaseStructInit(&tim3);
    tim3.TIM_Period = 10 - 1;
    tim3.TIM_Prescaler = 64 - 1;
    tim3.TIM_ClockDivision = 0;
    tim3.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1, &tim3);
    TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM1, ENABLE);
 
    nvic.NVIC_IRQChannel = TIM1_UP_IRQn;
    nvic.NVIC_IRQChannelPreemptionPriority = 0;
    nvic.NVIC_IRQChannelSubPriority = 0;
    nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic);

Przerwanie:

 void TIM1_UP_IRQHandler()
{
    if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
    {
        send_char('k');
    }
}

Nie ma znaczenia co robi send_char(), bo i tak się nie wykonuje, i jak postawie breakpointa w środku przerwania, to nigdy tam się program nie zatrzymie.
Mam inny, prawie taki sam timer z przerwaniem, tylko że ten działa:

    TIM_TimeBaseStructInit(&tim2);
    tim2.TIM_CounterMode = TIM_CounterMode_Up;
    tim2.TIM_Prescaler = 64000 - 1;
    tim2.TIM_Period = 100;
    TIM_TimeBaseInit(TIM3, &tim2);
    TIM_Cmd(TIM3, ENABLE);
 
    nvic.NVIC_IRQChannel = TIM3_IRQn;
    nvic.NVIC_IRQChannelPreemptionPriority = 0;
    nvic.NVIC_IRQChannelSubPriority = 0;
    nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic);
 void TIM3_IRQHandler() {
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        pwm(0);
        TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
        send_char('t');
        flag = 1;
    }
}

Jest prawie taki sam, więc co jest nie tak? Jakiś konflikt, taki jak jest z timerem 2, że jak się go używa to nie działa USART? W tej linii jest inaczej z tym "_UP": nvic.NVIC_IRQChannel = TIM1_UP_IRQn; i w nazwie przerwania void TIM1_UP_IRQHandler(), to dlatego że timer 1 działa inaczej niż reszta timerów, cytat: "Program dla timera 1 należy delikatnie zmodyfikować. Przede wszystkim będzie on taktowany z innej linii APB2 zamiast APB1. Inna będzie także deklaracja przerwania, TIM1_UP_IRQn oraz TIM1_UP_IRQHandler()."