Skip to main content
l m
Associate
September 18, 2017
Question

9 bit UART and DMA

  • September 18, 2017
  • 2 replies
  • 3192 views
Posted on September 18, 2017 at 07:46

Hiya,

I'm using the UART in 9 bit mode, with the 9th bit being used as an address indication.

I have a version of this working well with 16 bit DMA transfers. Ideally though I want to use 8 bit DMA (byte wide) as all my data is packed for byte wide transfers, and I don't really care about the 9th bit except as an address indicator.

I managed to get this sort of working with byte wide DMA receiving and populating TDR on the transmitter side manually with:

UARTD6.usart->TDR = (uint16_t)addr;

(stuff)

UARTD6.usart->TDR = (uint8_t)val;

UARTD6.usart->TDR = (uint8_t)val;

(etc)

This works ok.

I would like to replace the sending of the byte wide values with a DMA transfer, but I can't get DMA to transmit correctly though, in that I see incomplete transfers or garbage on the receiving side.

Is this idea achievable? Or is my thinking flawed in trying to send byte wide DMA to the 9 bit UART?

Thanks very much

#usart #dma-usart #9-bit #dma
This topic has been closed for replies.

2 replies

Tesla DeLorean
Guru
September 18, 2017
Posted on September 18, 2017 at 12:04

I'd expect 8-bit memory read and 16-bit peripheral write to behave in a predictable way. Perhaps not the way you want.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
September 18, 2017
Posted on September 18, 2017 at 12:34

8-bit memory read and 16-bit peripheral write to behave in a predictable way.

There are basically two ditinct DMAs in the STM32 (the OP didn't care to tell us the model he is using):

In the simpler one used in 'F0/'F3/'Lx , in this case the controller expands the upper 8 bits by 0.

0690X00000608H4QAI.png

In the complex dual-port  DMA ('F2/F4/F7), there is a FIFO inserted into the data path. If FIFO is not used (aka Direct mode) such transfer is impossible, as in that case the memory-side width-setting is ignored. If FIFO is used, the controller always reads at least 4 bytes into FIFO (bytewise if set so) and then writes the concatenated result halfword-wise into the peripheral port.

0690X00000608HTQAY.png

Neither case fits OP's need.

[rant mode on] Adult UARTs either have dedicated addressed (Intel-originated) mode, or parity settable [also] to MARK/SPACE. Pity the STM32 peripherals were/are designed by staff inexperienced in making practical applications. IMO it wouldn't be that hard nor silicon-consuming to design STM32 UARTs to be register- and functionally compatible with existing industry-standard UARTs, which would help avoid already explored pitfalls, increase functional compatibility and facilitate their usage and code reuse too. [rant mode off]

JW

l m
l mAuthor
Associate
September 19, 2017
Posted on September 19, 2017 at 00:00

Thanks very much for your replies.

I'm using the STM32F746 devices - sorry I forgot to include this!

This is a frustrating issue. Moreso given that I can make this work if I write directly to the TXD register. Even moreso given that it works when I write 8bit values to the UART TXD register in 9bit mode. It just wont work when I switch over to DMA.

This leads to a question - is the UART sending triggered differently when writing directly than when writing with DMA?

Anyway, thanks again.

sJor
Visitor II
February 8, 2019

Hi.

I'm using the USART2 the STM32F334xx in 9-bit mode (multiprocessor communication as said in the reference manual) for "Address Mark detection". I populate a 16 bits buffer with first the address (0x01XX) and then the data (N x 0x00YY). It works well manually doing this in a loop:

uint16_t usartCharSendBuffer[128];
... populating the frame in usartCharSendBuffer[]
loop on (with while (!LL_USART_IsActiveFlag_TXE(USARTXX)) {} or IRQ)
 LL_USART_TransmitData9(USARTXX, usartCharSendBuffer[idx_send++]);

I want to use the DMA to minimize the IT requests but I have the similar issue as @Community member​ (but I want to have a 16 bits buffer) : whatever data size I set for the memory and the peripheral's sides, the bit 0 of TDR is reflected into bit 8. It acts as the TDR forces the DMA to work with the LL_DMA_MDATAALIGN_BYTE option. Despite I set:

 dma.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
 dma.PeriphOrM2MSrcDataSize = LL_DMA_MDATAALIGN_HALFWORD;
Reference manual says:
• To write the halfword “0xABCD�?, the DMA sets the HWDATA bus to “0xABCDABCD�?
with HSIZE = HalfWord
• To write the byte “0xAB�?, the DMA sets the HWDATA bus to “0xABABABAB�? with
HSIZE = Byte

Does someone know if I missed a setting or if it is a limitation of the STM32F334xx's UART?

Thanks a lot.