cancel
Showing results for 
Search instead for 
Did you mean: 

How to map STM32G0B0 DMA to UART1 TX

  • STM32CubeIDE Version: 1.12.0
  • Using LL drivers
  • ADC to Memory via DMA1 Channel1 working
  • USART1 RX works
  • Memory to USART1 TX via DMA1 Channel2 does not work

     I'm guessing the problem we are having is that we are not using the correct DMA channel for USART1 TX but RM0454, STM32G0B0KE/CE/RE/VE data sheet and PM0223 do not have a table for the mapping. It probably has something to do with the DMAMUX which we have not seen before, but how can these documents cover DMA operation and not reference the correct mappings? It is possible that there is some type of ordering that is incorrect but we have found no examples that use USART's with DMA's. If someone could clue us in as to what we are missing it would be greatly appreciated.

 

	LL_USART_InitTypeDef USART_InitStruct = {0};


	// USART configuration
	// BaudRate = 115200 baud, Word Length = 8 Bits
	// One Stop Bit, No parity,
	// Hardware flow control disabled (RTS and CTS signals)
	//Receive and transmit enabled
	USART_InitStruct.PrescalerValue			= LL_USART_PRESCALER_DIV1;
	USART_InitStruct.BaudRate				= 38400;
	USART_InitStruct.DataWidth				= LL_USART_DATAWIDTH_8B;
	USART_InitStruct.StopBits				= LL_USART_STOPBITS_1;
	USART_InitStruct.Parity					= LL_USART_PARITY_NONE;
	USART_InitStruct.HardwareFlowControl	= LL_USART_HWCONTROL_NONE;
	USART_InitStruct.TransferDirection		= LL_USART_DIRECTION_TX_RX;
	USART_InitStruct.OverSampling			= LL_USART_OVERSAMPLING_16;
	LL_USART_Init(USART1, &USART_InitStruct);
	LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
	LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
	LL_USART_DisableFIFO(USART1);
	LL_USART_ConfigAsyncMode(USART1);

	/* Enable USART */
	LL_USART_Enable(USART1);

	/* Enable the USART1 Tx DMA1 requests */
	//USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

	// USe DMA to transmit the serial data
	// DMA configuration for TX of serial tx buffer(Serial TX, outbound)
	// Configure DMA request MEMTOMEM_DMA1_Channel2
	// Set request number, Set transfer direction, Set priority level, Set DMA mode, Set peripheral increment mode,
	// Set memory increment mode, Set peripheral data width, Set memory data width
	LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART1_TX);
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
	LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_HIGH);
	LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
	LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);

	LL_DMAMUX_SetRequestID(DMAMUX1, LL_DMAMUX_CHANNEL_2, LL_DMAMUX_REQ_USART2_TX);
	LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, (uint32_t)txBuffer,
							LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT),
							LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

	// Enable transfer complete and transfer error interrupts.
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2);
	LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);

	/* DMA1 Channel2 enable */
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);

 

 

 

3 REPLIES 3

I think we might be missing this:

LL_USART_EnableDMAReq_TX(USART1);

     Old code from a different project that used ST's Standard Peripheral drivers had a call to

/* Enable the USART1 Tx DMA1 requests */
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

     This would modify the USART CR3 register and I don't see us doing that in the current code base. I'll update the status after the weekend.

Found a misconfiguration where we used LL_DMAMUX_REQ_USART2_TX instead of USART1 but we still can not transmit on USART1 via DMA1, Channel 2. The following code shows the DMA and USART setup and the second clip of code shows what happens when we want to transmit data. We think the DMAMUX is set up correctly but can't be sure.

Initialization code:

	// USe DMA to transmit the serial data
	// DMA configuration for TX of serial tx buffer(Serial TX, outbound)
	// Configure DMA request MEMTOMEM_DMA1_Channel2
	// Set request number, Set transfer direction, Set priority level, Set DMA mode, Set peripheral increment mode,
	// Set memory increment mode, Set peripheral data width, Set memory data width
	LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_USART1_TX);
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
	LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_HIGH);
	LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
	LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);

	LL_DMAMUX_SetRequestID(DMAMUX1, LL_DMAMUX_CHANNEL_2, LL_DMAMUX_REQ_USART1_TX);
	LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, (uint32_t)txBuffer, LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT),
							LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

	/* Enable the USART1 Tx DMA1 requests */
	LL_USART_EnableDMAReq_TX(USART1);

	// Enable transfer complete and transfer error interrupts.
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2);
	LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);

	/* DMA1 Channel2 enable */
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);


	// USART configuration
	// BaudRate = 115200 baud, Word Length = 8 Bits
	// One Stop Bit, No parity,
	// Hardware flow control disabled (RTS and CTS signals)
	//Receive and transmit enabled
	LL_USART_InitTypeDef USART_InitStruct = {0};

	USART_InitStruct.PrescalerValue			= LL_USART_PRESCALER_DIV1;
	USART_InitStruct.BaudRate				= 38400;
	USART_InitStruct.DataWidth				= LL_USART_DATAWIDTH_8B;
	USART_InitStruct.StopBits				= LL_USART_STOPBITS_1;
	USART_InitStruct.Parity					= LL_USART_PARITY_NONE;
	USART_InitStruct.HardwareFlowControl	= LL_USART_HWCONTROL_NONE;
	USART_InitStruct.TransferDirection		= LL_USART_DIRECTION_TX_RX;
	USART_InitStruct.OverSampling			= LL_USART_OVERSAMPLING_16;
	LL_USART_Init(USART1, &USART_InitStruct);
	LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
	LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
	LL_USART_DisableFIFO(USART1);
	LL_USART_ConfigAsyncMode(USART1);

	/* Enable USART */
	LL_USART_Enable(USART1);

 Transmit code:

	LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2, (uint32_t)txBuffer,
							LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT),
							LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

	LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, uart1TX[txTail].txSize);
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);

We decided to try shifting to a different DMA channel. Currently DMA1 Channel1 is running data from three ADC channels into memory for processing. After moving the USART1 TX from DMA1 Channel2 to DMA1 Channel5, we can now see USART1 serial data transmissions. Our code base from STM32F series uses DMA1 Channel1 for three ADC's and DMA1 Channel2 for USART serial TX. If anyone could clue us into why this is working, we would appreciate it.

 

 

	// Use DMA to transmit the serial data
	// DMA configuration for TX of serial tx buffer(Serial TX, outbound)
	// Set request number, Set transfer direction, Set priority level, Set DMA mode, Set peripheral increment mode,
	// Set memory increment mode, Set peripheral data width, Set memory data width
	LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_5, LL_DMAMUX_REQ_USART1_TX);
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_5, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
	LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PRIORITY_HIGH);
	LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MODE_NORMAL);
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PERIPH_NOINCREMENT);
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_5, LL_DMA_MEMORY_INCREMENT);
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PDATAALIGN_BYTE);
	LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_5, LL_DMA_PDATAALIGN_BYTE);

	LL_DMAMUX_SetRequestID(DMAMUX1, LL_DMA_CHANNEL_5, LL_DMAMUX_REQ_USART1_TX);
	LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_5, (uint32_t)txBuffer,
							LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT),
							LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

	/* Enable the USART1 Tx DMA1 requests */
	LL_USART_EnableDMAReq_TX(USART1);

	// Enable transfer complete and transfer error interrupts.
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_5);
	LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_5);