2
\$\begingroup\$

I'm trying to get UART working on a STM32F0 part and can't figure out the interrupts. According to the reference manual

Bit 7 TXE: Transmit data register empty
This bit is set by hardware when the content of the USARTx_TDR register has been 
transferred into the shift register. It is cleared by a write to the USARTx_TDR register.
An interrupt is generated if the TXEIE bit =1 in the USARTx_CR1 register.

However, I can never see the TXE flag clear. Here is what I have in my IRQ Handler:

  if(USART_GetITStatus(EVAL_COM1, USART_IT_TXE) != RESET)
  {   
    /* Write one byte to the transmit data register */
    if (TxBuffer[TxCount] != '\0')
    {
      USART_SendData(EVAL_COM1, TxBuffer[TxCount++]);
    }
    //else{
    //  USART_ITConfig(EVAL_COM1, USART_IT_TXE, DISABLE);
    //}
  }

Unless I uncomment the else statement, the send interrupt keeps triggering endlessly even after I stop sending bytes to the TDR. Is there a way to stop the interrupts without disabling them? Or do I need to re-enable every time I want to send something?

\$\endgroup\$
  • \$\begingroup\$ Try adding: USART_ClearITPendingBit(EVAL_COM1,USART_IT_TXE); ... I would still disable the interrupt if you have no data to send. \$\endgroup\$ – Tut Feb 11 '14 at 16:03
  • \$\begingroup\$ I need to send a message every couple of seconds in response to a received message. Is the correct way to send my response and then disable the interrupt? If so, that's fine I just didn't think that the interrupt needed to be disabled. \$\endgroup\$ – spizzak Feb 11 '14 at 16:07
  • \$\begingroup\$ I always disable the interrupt when my transmit buffer is empty. To be honest, I'm not sure if it is required if you clear the USART_IT_TXE bit per my suggestion above. \$\endgroup\$ – Tut Feb 11 '14 at 16:09
2
\$\begingroup\$

When USARTx_TDR register is empty USART_ISR_TXE flag is set to 1. When USARTx_CR1_TXEIE (TXE Interrupt Enable flag) is enabled and TXE=1 it will pend interrupt.

So you code sample with disabling interrupt after completed transmission is good solution.

When starting transmission periodically just write first byte (it will clear TXE) and enable interrupt.

Or if possible use DMA - a bit more code, but after you calculate strlen and configure it, it is rather fire and forget ;)

\$\endgroup\$
1
\$\begingroup\$

Rather than thinking of TXE as a flag which needs to be cleared, one should think of it as indicating that the UART is ready to accept data for transmission. The fact that you don't have any data for transmission data doesn't mean it's not ready.

Some microcontrollers like the 8051 have a flag which gets set when the UART finishes setting a byte, but may also be manually cleared. Such designs are prone to cause problems even with single-buffered UARTs and are completely unsuitable for UARTs that may be double-buffered.

The right approach is simply to enable the transmit-data-empty interrupt any time you have something interesting to say, and disable it when you don't. In some cases, it may be helpful to enable a transmit-idle interrupt when you transmit something, and have the interrupt handler for that react to the completed transmission and disable the interrupt. While it may seem unusual to have an interrupt handler disable the interrupt without "resolving" the cause, it's entirely appropriate in cases where some other action in the system will cause the interrupt to be re-enabled.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.