cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F051 UART Tx with DMA

fedex03
Associate II

Hi there,

I'm working on an STM32F051 with Standard Peripheral Libraries.

I using the UART to communicate with a PC and actually evrything work with Interrupts.

To get best perfomance, I started to implemnet DMA trasnfert.

For the RX, I use the DMA in circular mode and the reception works very well.

After that I started to implements Uart Tx with DMA but I have some question about that.

I use a circular buffer for the reception with two index:

  • RRp: Read Pointer: this is the address where the DMA start to transfer the data.
  • RWp: Write Ponter: this is the address where the application writes the data to send.

My concern is how to handle the circular buffer.

In detail how to specify every time where get the data and how many data send.

It seems that I can specify the source buffer and the data length only during the DMA Channel initialization.

This is my DMA initialization:

uint8_t				dmaConfigId;
	DMA_InitTypeDef  	DMA_InitStructure;
 
	dmaConfigId = UartConfig[uartId].dmaConfigId;
 
	/** DMA Clock Enable */
	RCC_AHBPeriphClockCmd( DmaConfiguration[dmaConfigId].dmaClock, ENABLE );
 
	/** Deinitialize DMA Channels */
	DMA_DeInit( DmaConfiguration[dmaConfigId].rxDmaChannel );
	DMA_DeInit( DmaConfiguration[dmaConfigId].txDmaChannel );
 
	/** DMA Channel Common Configuration */
	DMA_InitStructure.DMA_PeripheralDataSize 	= DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize 		= DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc 		= DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc 			= DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_M2M					= DMA_M2M_Disable;
 
	/** Usart Rx DMA Channel Configuration - Circular Mode */
	DMA_InitStructure.DMA_BufferSize 			= UartConfig[uartId].RxSize;
	DMA_InitStructure.DMA_MemoryBaseAddr 		= (uint32_t)UartConfig[uartId].Rx;
	DMA_InitStructure.DMA_DIR 					= DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_Priority 				= DMA_Priority_Low;
	DMA_InitStructure.DMA_PeripheralBaseAddr 	= DmaConfiguration[dmaConfigId].peripheralRxRegister;
	DMA_InitStructure.DMA_Mode 					= DMA_Mode_Circular;
 
	DMA_Init( DmaConfiguration[dmaConfigId].rxDmaChannel, &DMA_InitStructure );
 
	/** Usart Tx DMA Channel Configuration - Normal Mode */
	DMA_InitStructure.DMA_BufferSize 			= UartConfig[uartId].TxSize;
	DMA_InitStructure.DMA_MemoryBaseAddr 		= (uint32_t)UartConfig[uartId].Tx;
	DMA_InitStructure.DMA_DIR 					= DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_Priority 				= DMA_Priority_Low;
	DMA_InitStructure.DMA_PeripheralBaseAddr 	= DmaConfiguration[dmaConfigId].peripheralTxRegister;
	DMA_InitStructure.DMA_Mode 					= DMA_Mode_Normal;
 
	DMA_Init( DmaConfiguration[dmaConfigId].txDmaChannel, &DMA_InitStructure );
 
	/** Enable the USARTx Rx and Rx requests */
	USART_DMACmd( UartConfig[uartId].USARTx, (USART_DMAReq_Rx | USART_DMAReq_Tx), ENABLE );
 
	/**
	 * Enable DMA Interrupts
	 *
	 * Non è necessario attivare gli interrupt in ricezione del DMA
	 * perchè il trasferimento DMA avviene in automatico con la USART
	 */
 
	/** Abilitazione dell'interrupt di Transfer Complete in trasmissione */
	DMA_ITConfig( DmaConfiguration[dmaConfigId].txDmaChannel, DMA_IT_TC, ENABLE );
 
	/** NVIC Init */
	NVIC_Initialize( DmaConfiguration[dmaConfigId].txIrq, 0 ); 		
 
	/** UART Rx - Enable DMA Channel */
	DMA_Cmd( DmaConfiguration[dmaConfigId].rxDmaChannel, ENABLE );

The UART2_TX_DMA_IT_TC is rised correctly, and into this ISR, I should stard another DMA trasnfer if more data are added to my buffer.

The problem is that I don't know how to specify size and buffer address before start a new DMA transfer.

These are the DMA function the I can use:

/* Function used to set the DMA configuration to the default reset state ******/
void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);
 
/* Initialization and Configuration functions *********************************/
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);
 
/* Data Counter functions******************************************************/ 
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);
 
/* Interrupts and flags management functions **********************************/
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);
FlagStatus DMA_GetFlagStatus(uint32_t DMA_FLAG);
void DMA_ClearFlag(uint32_t DMA_FLAG);
ITStatus DMA_GetITStatus(uint32_t DMA_IT);
void DMA_ClearITPendingBit(uint32_t DMA_IT);

Thanks in advance fot the help

4 REPLIES 4
TDK
Guru

For each new transfer, you repeat the call to DMA_Init with the new settings. I don't think a call to DMA_DeInit is required after a transfer completes, but could be wrong there.

If you feel a post has answered your question, please click "Accept as Solution".
fedex03
Associate II

@TDK​ thanks for the reply.

I tought that but I worring about the efficiency of call DMA_Init at each DMA transfer.

What happen if I call DMA_Cmd( DmaConfiguration[dmaConfigId].txDmaChannel, DISABLE )?

Is the DMA buffer index resetted to 0 when I re-enable the channel? Or it remains at the value when I disable the DMA?

If efficiency is critical you'll need to decompose the library code to the minimal sequences. I suspect you just need to disable the controller and change the address/count.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
fedex03
Associate II

Hi @Community member​ ,

I broked down the DMA_Init and I wrapped some of its instructions inside​ a new custom function that chages the DMA Buffer address and DMA Buffer lenght.

In this way I can handle my circular buffer with DMA without re-initialize the DMA Channel each time.

/** Disable DMA Channel */
DMA_Cmd( DmaConfiguration[dmaConfigId].txDmaChannel, DISABLE );
 
/** Configure Memory Base Address */
DmaConfiguration[dmaConfigId].txDmaChannel->CMAR = (uint32_t)&UartConfig[uartId].Tx[Uarts[uartId].TRp];
 
/** Configure Buffer Size */
DmaConfiguration[dmaConfigId].txDmaChannel->CNDTR = (uint32_t)dataSizeToBufferEnd;
 
/** Start DMA Transfer */
DMA_Cmd( DmaConfiguration[dmaConfigId].txDmaChannel, ENABLE );