2008-10-24 02:50 AM
USART interrupt question..
2011-05-17 03:48 AM
What is the proper way to use the TXE interrupt with the cortex? Here is my dilemma:
I am trying to write a serial driver. My plan was to have a circular buffer and use my serWrite function to check if TXE is set. If it is set, write a byte to the data register. This fails as soon as I enable TXEIE because the interrupt fires constantly, and I don't see a way to clear it other than disabling TXEIE. In other environments (dsPIC), an interrupt is fired when a byte is transferred from the data register to the shift register. I can't say that I understand the purpose of TXEIE if you can't clear the interrupt. Do I have to switch to TCIE? I'm not using the ST firmware.2011-05-17 03:48 AM
There is an example of an interrupt-driven serial driver in the project in my signature (it does not use the library).
You can download the whole package or just see that source here: The code enables/disables CR1_TXEIE in order to start/stop the transmission but does not show the problem you mentioned. regards, Giovanni --- ChibiOS/RT2011-05-17 03:48 AM
Hi mdeneen:
Here is how I design a UART driver: There are at least two ISRs for RS-232 operation, and one more additional ISR for RS-485 transmit complete (for RTS line control). First ISR: Receive Interrupt. Read the character from UART hardware, store in circular buffer. Reading clears the interrupt flag. RXNEIE does not change and always remains enabled. Second ISR: Transmit interrupt: Get a character from circular buffer, write to UART hardware. Writing clears the interrupt. If buffer is empty, turn of TXEIE flag. If RS-485, turn on TCIE flag. Otherwise, leave both flags alone. Third ISR: Transmit Complete: Turn off TCIE flag, and turn off RTS control line. Other ISRs: Provide for error conditions, and explicitly clear appropriate flags. Furthermore, there are at least two driver functions which are not ISRs, but provide the mechanism to get characters into and out of the circular buffers, and therefore work in conjunction with the ISRs. First driver function: Get Character: Checks the receive circular buffer and returns true with the character when the buffer is not empty. Second driver function: Put Character: Puts the sending character into a circular buffer then turns on the TXEIE flag. If RS-485 design, first turn off TCIE, then enable RTS control line, then put character in to circular buffer, then enable TXEIE flag. The function returns true if the character was successfully put into the transmit buffer. Now to answer your question. You want the UART hardware to generate and interrupt as soon as TXEIE is set. That is the mechanism to start transmitting. Fortunately, the STM32 UART is relatively simple to program and appears to work well. Unfortunately, there is no double buffering on the Receiver. The ISR has to get the character out of the USART_DR (data register) before the next character arrives. Attempting to use the DMA to transfer the DR into RAM has its own problems because the DMA is usually programmed to transfer a specified number of bytes, but it is not known how many bytes are incoming with a serial data stream, so there is always a remainder problem to be handled. Too bad ST cheaped-out trying to save a few pennies, when it would have been much better to provide a least one extra RX buffer DR. By the way, I recommend using the ST Firmware Library. It saves a lot of coding, headaches, and other un-related bugs and problems. Best wishes Garry Anderson. [ This message was edited by: design6 on 23-10-2008 09:17 ]2011-05-17 03:48 AM
Keil have an example of interrupt-driven ring-buffered serial comms for the STM32 USART here:
It's easy to see what it's doing even if you don't use Keil tools...2011-05-17 03:48 AM
Look at my
It may provide an idea or two.2011-05-17 03:48 AM
Thank you all for your responses. I now have a working serial driver.
The crux of my problem was simply understanding that I have to enable/disable TXEIE appropriately. In the dsPIC world, it is a little different -- you can leave the TX interrupt enabled all the time.