Skip to main content
NikolaiB
Associate II
January 31, 2026
Solved

Why SPI transmit doesn't work from timer interrupt?

  • January 31, 2026
  • 4 replies
  • 228 views

Hello everyone!
That works:

int main(void)
{
 ...
 init_SPI1();
 for(;;)
 SPI1_Send();
}

And that doesn't:

void TIM2_IRQHandler(void)
{
 SPI1_Send();
 TIM2->SR &= ~TIM_SR_UIF; // reset UIF bit in the status register of the timer
}

Why?

Thank you very much!

Best answer by NikolaiB

I have found the problem. It was the initialization order. Hier is the code simlified. 

int main(void)
{
 init_TIM2(); // Timer first
 init_SPI1(); // Here the SPI is enabled
 for(;;) {
 SPI1_Send(data); // SPI enabled
 }
}
void TIM2_IRQHandler(void)
{
 SPI1_Send(data); // SPI not enabled yet, because the timer ist faster than SPI initialization
}

If I change the order of SPI and Timer Initialization the SPI1_Send works from the timer interrupt.

I thank everyone.

4 replies

waclawek.jan
Super User
January 31, 2026

What does "doesn't work" mean?

What is the expected behaviour and what is the observed one?

What is SPI1_Send()? Note, that you are inside an interrupt service routine, i.e. until SPI1_Send() exits, other interrupts with same or lower priority than the TIM2 interrupt can't be served.

JW

NikolaiB
NikolaiBAuthor
Associate II
February 1, 2026

Works: Clock and MOSI signals are generated by the MCU. I can see them on the oscilloscope.
Does't work: Clock and MOSI signals are NOT generated by the MCU. I can't see any signals on the osci.

Here is my send function

void SPI1_Send(unsigned char* data, int size)
{
 int i = 0;
 while(i<size){
 while(!((SPI1->SR) & (1<<1))){}; // <------- Here it stops (TXE bit in status register)
 SPI1->DR = data[i];
 i++;
 }

 while(!((SPI1->SR) & (1<<1))){};
 while(((SPI1->SR)&(1<<7))){};
 
 unsigned char temp = SPI1->DR;
 temp = SPI1->SR;
}

If I call this function within the Timer interrupt, the while (TXE) never exits. But why? If I call this function from while(1) in main, it works fine.

 

TDK
Super User
January 31, 2026

You should check for the flag and only act if it’s set. If you clear the flag as the last statement, it will typically cause the irq to be called twice.

"If you feel a post has answered your question, please click ""Accept as Solution""."
waclawek.jan
Super User
February 1, 2026

What you've posted looks OK. The problem is probably elsewhere in your program. For example, the second "not working" program may contain some code, which disables the SPI pins in GPIO. Or you have some hardware issue, short between SPI clock signal and some other signal, and that other signal gets enabled with the timer.

Read out and check the SPI and relevant GPIO registers content in debugger, at the point where it "does not work".

JW

 

NikolaiB
NikolaiBAuthorBest answer
Associate II
February 1, 2026

I have found the problem. It was the initialization order. Hier is the code simlified. 

int main(void)
{
 init_TIM2(); // Timer first
 init_SPI1(); // Here the SPI is enabled
 for(;;) {
 SPI1_Send(data); // SPI enabled
 }
}
void TIM2_IRQHandler(void)
{
 SPI1_Send(data); // SPI not enabled yet, because the timer ist faster than SPI initialization
}

If I change the order of SPI and Timer Initialization the SPI1_Send works from the timer interrupt.

I thank everyone.