2013-05-26 08:31 PM
Application note AN3070 describes a procedure for releasing RS485 bus when using DMA to transfer USART data. The procedure uses two interrupts:
* DMA transfer complete (DMA_TC) interrupt * USART transfer complete (USART_TC) interrupt.In the app note, the DMA_TC is used to enable the USART_TC interrupt and the USART_TC interrupt is use to release the RS485 bus. However, the DMA_TC interrupt seems unnecessary. I have code that only uses the USART_TC interrupt and works just fine. Is there some subtle reason for using the DMA_TC interrupt to enable the USART_TC interrupt?Here's my pseudo code that does not use the DMA_TC interrupt:init(){ init_usart(); init_dma(); //sets DMA type and direction but does not enable DMA enable_usart_tc_interrupt();}void rs485_write(uint8_t *data, int len){ assert_rs485_write_enable(): disable_dma(); clear_dma_interrupt_flags(); DMA->NTDR = len; DMA->M0AR = (uint32_t)data; enable_dma();} void usart_tc_isr(){ deassert_rs485_write_enable(); clear_usart_tc_flag(); asm(''nop''); // Adds a tiny bit of delay after clearing USART_TC that prevents interrupt from being re-entered immediately after returning}Link to app-note:(http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/CD00249778.pdf?s_searchtype=keyword) #stm32-usart-dma #rs485-dma2013-05-28 07:18 AM
Although the code may work in your particular case using the USART TC implies that there will be no latency in DMA transfers (amd the USART TX will never underrun), no gap between characters transmitted and CTS/RTS handshaking isn't being used. For RS-485 that's a reasonable assumption but for the more general case where it may also be an RS-232 line, or if an inter-character gap is required then USART TC by itself won't work, because the USART transmitter will underflow during the CTS stall and trigger the TC interrupt prematurely. Waiting for DMA TC guarantees the full block of data has been sent. I have a shared code driver for both RS-232 and RS-485, so I always wait for DMA TC first, and then wait for the USART TC before line turnaround (on RS-485).
One of the hazards you need to watch for when driving large blocks of data at high speed (especially on RS-485) is the baud rate mismatch. Over small blocks it's not a problem, but with larger blocks the timing may creep so that a start bit overlaps a previous stop bit, causing framing errors. That's one reason ModBus (a common RS-485 protocol) has a provision for inter-character gaps. One or two extra bit times between characters allows the receiver PLL to properly lock onto the next incoming start bit. If you stream with DMA on a large block you don't have the ability to insert small gaps, as opposed to smaller DMA blocks with a short gap (or CTS handshake) to allow the receiver to synchronize. Async serial works great if the transmitter and receiver clocks are precise and accurate, and even if there's some drift it works with small groups of data. It fails when there's a mismatched clock running at high speeds with large blocks. That's why there's a provision for external clocks, so that in high speed transfers both TX and RX clocks come from one source. Jack Peacock2013-05-31 01:39 PM
Thanks for the reply.
Concerning latency of DMA transfers. Suppose the DMA did fall behind USART as some point and caused USART TC flag to be set. When using only USART_TC interrupt (my psuedo-code above), the enable line would be cutoff immediately, cutting of the rest of the RS485 transmission. Thus destroying RS485 packet. However, there would still be problems if the DMA_TC ISR was use to enable the USART_TC interrupt (as in the app-note). When the DMA_TC ISR was run, the USART_TC flag would already have be set because of the DMA underrun. In this case, the USART_TC ISR would be run when the DMA_TC ISR exits (or immediately depending on interrupt priorities). This would cause last two characters of data to be cut off (one byte being shifted out by USART, and 1 byte in USART TX buffer). Losing the last 2-bytes would still corrupt the RS485 packet.I do not have any experience using the CTS fuctionality with the USART, however I don't believe having CTS block the output will cause the USART_TC flag to be set. According to the data sheet, the USART TC flag is set when ''the transmission of a frame containing data is complete and ifTXE is set''. Even if CTS line was preventing the USART from sending another character, the TC flag wouldn't be set, since there would still be a byte waiting in the TX buffer (TXE flag would not be set).