cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F7 DMA UART RX no Data seen.

EBepp
Associate II

I am working with the STM32F7. I am implementing a DMA communications handler, preferably using the HAL (but LL is also an option that I have tried). I have successfully implemented the TX side of the equation but, am unable to get the RX portion to put data into the buffer. Below I have detailed the HW configuration and provided the HAL based code to match. I can also provide the LL based code should anyone want to see that. Can someone help me to see the error of my ways?

I am hoping to use the idle line detection to allow variable packet size, but cannot get the RX to work even with a fixed packet size.

I have used the following references:

Example code for Idle Line with f4: https://github.com/MaJerle/STM32_USART_DMA_RX

DMA Controller Guide: https://www.st.com/content/ccc/resource/technical/document/application_note/27/46/7c/ea/2d/91/40/a9/DM00046011.pdf/files/DM00046011.pdf/jcr:content/translations/en.DM00046011.pdf

Ref Manual: https://www.st.com/content/ccc/resource/technical/document/reference_manual/group0/96/8b/0d/ec/16/22/43/71/DM00224583/files/DM00224583.pdf/jcr:content/translations/en.DM00224583.pdf

LL/HAL Guide: https://www.st.com/content/ccc/resource/technical/document/user_manual/45/27/9c/32/76/57/48/b9/DM00189702.pdf/files/DM00189702.pdf/jcr:content/translations/en.DM00189702.pdf

Platform: NUCLEO-F767ZI

RTOS: uC/OS-III

UART: UART4 (RX: PC11, TX: PC10)

UART Config:

#define MAIN_BOARD_UART_BAUD				115200
#define MAIN_BOARD_UART_WORDLENGTH			UART_WORDLENGTH_8B
#define MAIN_BOARD_UART_STOPBITS			UART_STOPBITS_1
#define MAIN_BOARD_UART_PARITY				UART_PARITY_NONE
#define MAIN_BOARD_UART_HW_FLOW_CTL 		UART_HWCONTROL_NONE
#define MAIN_BOARD_UART_MODE				UART_MODE_TX_RX
#define MAIN_BOARD_UART_OVERSAMPLING 		UART_OVERSAMPLING_16

DMA, Channel, Stream: DMA1, Channel 4, Stream 4

DMA Config: See Code below

UART Init Code:

__HAL_RCC_UART4_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
 
GPIO_InitStruct.Pin = 		USARTx_RX_PIN | USARTx_TX_PIN;
GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull      = GPIO_PULLUP;
GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = USARTx_RX_AF | USARTx_TX_AF;
 
//Init the UART - Configured thorugh macros in .h for portability
HAL_UART_MspInit(&CommUartHandle);
CommUartHandle.Instance = 			MAIN_BOARD_UART_INSTANCE;
CommUartHandle.Init.BaudRate = 		MAIN_BOARD_UART_BAUD;
CommUartHandle.Init.WordLength = 	MAIN_BOARD_UART_WORDLENGTH;
CommUartHandle.Init.StopBits = 		MAIN_BOARD_UART_STOPBITS;
CommUartHandle.Init.Parity = 		MAIN_BOARD_UART_PARITY;
CommUartHandle.Init.HwFlowCtl = 	MAIN_BOARD_UART_HW_FLOW_CTL;
CommUartHandle.Init.Mode = 			MAIN_BOARD_UART_MODE;
CommUartHandle.Init.OverSampling = 	MAIN_BOARD_UART_OVERSAMPLING;
if(HAL_UART_Init(&CommUartHandle) != HAL_OK)
{
    BSP_LED_On(USER_LD2);
    while(1) {;}
}
 
HAL_NVIC_SetPriority(UART4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(UART4_IRQn);
 

DMA Init Code:

__HAL_RCC_DMA1_CLK_ENABLE();
 
__HAL_DMA_CLEAR_FLAG(&dma_comm_rx, DMA_FLAG_TCIF2_6 | DMA_FLAG_HTIF2_6 | DMA_FLAG_TEIF2_6 | DMA_FLAG_DMEIF2_6 | DMA_FLAG_FEIF2_6);
 
dma_comm_rx.Instance =  DMA1_Stream2;
dma_comm_rx.Init.Channel = DMA_CHANNEL_4;
dma_comm_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
dma_comm_rx.Init.PeriphInc = DMA_PINC_DISABLE;
dma_comm_rx.Init.MemInc = DMA_MINC_ENABLE;
dma_comm_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dma_comm_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dma_comm_rx.Init.Mode = DMA_CIRCULAR ;
dma_comm_rx.Init.Priority= DMA_PRIORITY_VERY_HIGH;
dma_comm_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
dma_comm_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
 
if(HAL_DMA_Init(&dma_comm_rx) != HAL_OK){
	while(1);
}
__HAL_LINKDMA(huart,hdmarx,dma_comm_rx);
__HAL_DMA_ENABLE(&dma_comm_rx);
 
__HAL_DMA_ENABLE_IT(huart->hdmarx, DMA_IT_TC);
__HAL_DMA_ENABLE_IT(huart->hdmarx, DMA_IT_HT);
HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);

Interrupt Code:

void DMA1_Stream2_IRQHandler(void){
	HAL_DMA_IRQHandler(&dma_comm_rx);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  	OS_ERR  	os_err;
    huart->gState = HAL_UART_STATE_READY;
	OSSemPost(&CommRxSem,OS_OPT_POST_1,&os_err);
	HAL_UART_Receive_DMA(&CommUartHandle, rxDmaBuffer, 10);
	BSP_LED_Off(USER_LD3);
}
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart){
  	OS_ERR  	os_err;
    huart->gState = HAL_UART_STATE_READY;
	OSSemPost(&CommRxSem,OS_OPT_POST_1,&os_err);
	BSP_LED_Off(USER_LD3);
}
void UART4_IRQHandler(void){
	OS_ERR os_err;
	if (LL_USART_IsEnabledIT_IDLE(UART4) && LL_USART_IsActiveFlag_IDLE(UART4)) {
		LL_USART_ClearFlag_IDLE(UART4);        // Clear IDLE line flag 
		//HAL_UART_Receive_DMA(&CommUartHandle, rxDmaBuffer, 100);
        CommUartHandle.gState = HAL_UART_STATE_READY;
		OSSemPost(&CommRxSem,OS_OPT_POST_1,&os_err);
		BSP_LED_Off(USER_LD3);
	} 
    HAL_UART_IRQHandler(&CommUartHandle);
}

Receive Code:

status = HAL_UART_Receive_DMA(&CommUartHandle, rxDmaBuffer, 100);
	 if(status !=HAL_OK){
	         while(1){;}
	 }
	
while(DEF_TRUE){
		BSP_LED_On(USER_LD3);
 
		
		OSSemPend(&CommRxSem, 0, OS_OPT_PEND_BLOCKING, DEF_NULL, &os_err);
		BSP_LED_Off(USER_LD3);
		printf("end%s\n",rxDmaBuffer );
 
	}

1 ACCEPTED SOLUTION

Accepted Solutions

Well, it appears that you've captured the registers after Cube succeeded to clean up (it even cleared the peripheral- and memory-address registers and also NDTR of the DMA stream, which is weird, but then not everything in Cube makes sense), so there's no evidence of any significant error there. The only flag set in DMA_LISR is TCIF2 (ie. transfer complete interrupt for Stream 2), which is explained by the fact that it is set when software disables the channel forcibly (by clearing DMA_SxCR.EN) and Cube probably has disabled the DMA stream interrupt by that time.

Try to set a breakpoint in whatever error handlers Cube uses in both the UART and DMA ISR, and observe the registers there.

JW

View solution in original post

9 REPLIES 9

Polled implementation works?

Read out and check content of UART and DMA registers (carefully, readig UART status register clears its bits). Is Rx DMA enabled in UART? Does NDTR in DMA change? Is there no error signaled in DMA's status register?

JW

JW,

Thanks for the response, all great questions! I can make the interrupt and blocking implementations work, but not any variety of the DMA operation. I have carefully watched the UART and DMA registers. The RX DMA is enabled, but NDTR does not change at any point - If i tweak a few lines of code I can get it in a situation where I get a DMA_TRANSFER_ERROR from the UART, but I can also avoid that - Not sure which is a better scenario.

Thanks!

Post the relevant UART ad DMA registers content.

JW

0690X000009Zd3MQAS.pngJW the Registers are below in text and screenshot from IAR as well as attached in a log file. These values are captured when the DMA1_Stream2_IRQHandler fires after a transmission of 5 bytes. Please note the UART shows Error 8 (0verrun) in this scenario, not sure why that is.

Thanks!

Expression Value Location Type

CommUartHandle <struct> 0x20003A78 UART_HandleTypeDef

Instance 0x40004C00 0x20003A78 USART_TypeDef *

Init <struct> 0x20003A7C UART_InitTypeDef

AdvancedInit <struct> 0x20003A9C struct <Unnamed 23>

pTxBuffPtr 0x8007DA8 "Beat\r\n" 0x20003AC4 uint8_t *

TxXferSize 6 0x20003AC8 uint16_t

TxXferCount 0 0x20003ACA uint16_t

pRxBuffPtr 0x20003AE8 "" 0x20003ACC uint8_t *

RxXferSize 10 0x20003AD0 uint16_t

RxXferCount 0 0x20003AD2 uint16_t

Mask 0 0x20003AD4 uint16_t

hdmatx dma_comm_tx (0x20003B4C) 0x20003AD8 DMA_HandleTypeDef *

hdmarx dma_comm_rx (0x20003BAC) 0x20003ADC DMA_HandleTypeDef *

Instance 0x40026040 0x20003BAC DMA_Stream_TypeDef *

Init <struct> 0x20003BB0 DMA_InitTypeDef

Lock HAL_LOCKED 0x20003BE0 HAL_LockTypeDef

State HAL_DMA_STATE_ABORT 0x20003BE1 enum <Unnamed 16>

Parent CommUartHandle (0x20003A78) 0x20003BE4 void *

XferCpltCallback UART_DMAReceiveCplt (0x8006061) 0x20003BE8 void (*)(struct __DMA_HandleTypeDef *)

XferHalfCpltCallback UART_DMARxHalfCplt (0x80060A9) 0x20003BEC void (*)(struct __DMA_HandleTypeDef *)

XferM1CpltCallback 0x00000000 0x20003BF0 void (*)(struct __DMA_HandleTypeDef *)

XferM1HalfCpltCallback 0x00000000 0x20003BF4 void (*)(struct __DMA_HandleTypeDef *)

XferErrorCallback UART_DMAError (0x80060B9) 0x20003BF8 void (*)(struct __DMA_HandleTypeDef *)

XferAbortCallback UART_DMAAbortOnError (0x8006109) 0x20003BFC void (*)(struct __DMA_HandleTypeDef *)

ErrorCode 0 0x20003C00 uint32_t

StreamBaseAddress 1073897472 0x20003C04 uint32_t

StreamIndex 16 0x20003C08 uint32_t

Lock HAL_UNLOCKED 0x20003AE0 HAL_LockTypeDef

gState HAL_UART_STATE_READY 0x20003AE1 enum <Unnamed 17>

RxState HAL_UART_STATE_READY 0x20003AE2 enum <Unnamed 17>

ErrorCode 8 0x20003AE4 uint32_t

rxDmaBuffer <array>"" 0x20003AE8 uint8_t[100]

I mean the hardware registers of UART and DMA, not HAL/Cube's intestinal content.

JW

> These values are captured when the DMA1_Stream2_IRQHandler fires after a transmission of 5 bytes.

DMA1_Stream2 (Channel 4) is UART4_RX, so it's certainly not the consequence of *transmitting* bytes.

> UART shows Error 8 (0verrun) in this scenario, not sure why that is.

STM32Cube_FW_F7_V1.7.0\Drivers\STM32F7xx_HAL_Driver\Inc\stm32f7xx_hal_usart.h:

#define HAL_USART_ERROR_ORE         ((uint32_t)0x00000008U)  /*!< Overrun error      */

Overrun may be consequence of bytes arriving at UART while not being picked by a stuck DMA.

Observing the relevant DMA registers (i.e. the givern stream's registers plus the status registers) should shed more light on the problem.

In case it wasn't obvious, I don't use Cube/HAL and I also don't use 'F7 so if this is related to some memory mapping issue I am out.

JW

JW - sorry for the confusing wording - I meant transmitting 5 bytes to the device, not from the device. Using a USB-UART cable to send data to remove any uncertainty.

The DMA Registers are:

Name Value Access

LISR 0x00200000 ReadOnly

HISR 0x00000000 ReadOnly

LIFCR 0x00000000 ReadWrite

HIFCR 0x00000000 ReadWrite

S0CR 0x00000000 ReadWrite

S0NDTR 0x00000000 ReadWrite

S0PAR 0x00000000 ReadWrite

S0M0AR 0x00000000 ReadWrite

S0M1AR 0x00000000 ReadWrite

S0FCR 0x00000021 ReadWrite

S1CR 0x00000000 ReadWrite

S1NDTR 0x00000000 ReadWrite

S1PAR 0x00000000 ReadWrite

S1M0AR 0x00000000 ReadWrite

S1M1AR 0x00000000 ReadWrite

S1FCR 0x00000021 ReadWrite

S2CR 0x0803051E ReadWrite

S2NDTR 0x00000000 ReadWrite

S2PAR 0x00000000 ReadWrite

S2M0AR 0x00000000 ReadWrite

S2M1AR 0x00000000 ReadWrite

S2FCR 0x000000A0 ReadWrite

S3CR 0x00000000 ReadWrite

S3NDTR 0x00000000 ReadWrite

S3PAR 0x00000000 ReadWrite

S3M0AR 0x00000000 ReadWrite

S3M1AR 0x00000000 ReadWrite

S3FCR 0x00000021 ReadWrite

S4CR 0x08020446 ReadWrite

S4NDTR 0x00000000 ReadWrite

S4PAR 0x40004C28 ReadWrite

S4M0AR 0x08007DA8 ReadWrite

S4M1AR 0x00000000 ReadWrite

S4FCR 0x000000A0 ReadWrite

S5CR 0x00000000 ReadWrite

S5NDTR 0x00000000 ReadWrite

S5PAR 0x00000000 ReadWrite

S5M0AR 0x00000000 ReadWrite

S5M1AR 0x00000000 ReadWrite

S5FCR 0x00000021 ReadWrite

S6CR 0x00000000 ReadWrite

S6NDTR 0x00000000 ReadWrite

S6PAR 0x00000000 ReadWrite

S6M0AR 0x00000000 ReadWrite

S6M1AR 0x00000000 ReadWrite

S6FCR 0x00000021 ReadWrite

S7CR 0x00000000 ReadWrite

S7NDTR 0x00000000 ReadWrite

S7PAR 0x00000000 ReadWrite

S7M0AR 0x00000000 ReadWrite

S7M1AR 0x00000000 ReadWrite

S7FCR 0x00000021 ReadWrite

UART Registers are:

Name Value Access

CR1 0x0000000D ReadWrite

CR2 0x00000000 ReadWrite

CR3 0x00000000 ReadWrite

BRR 0x000001D5 ReadWrite

GTPR 0x00000000 ReadWrite

RTOR 0x00000000 ReadWrite

RQR WWWWWWWW WriteOnly

ISR 0x006000F8 ReadOnly

ICR WWWWWWWW WriteOnly

RDR 0x00000048 ReadOnly

TDR 0x0000000A ReadWrite

Well, it appears that you've captured the registers after Cube succeeded to clean up (it even cleared the peripheral- and memory-address registers and also NDTR of the DMA stream, which is weird, but then not everything in Cube makes sense), so there's no evidence of any significant error there. The only flag set in DMA_LISR is TCIF2 (ie. transfer complete interrupt for Stream 2), which is explained by the fact that it is set when software disables the channel forcibly (by clearing DMA_SxCR.EN) and Cube probably has disabled the DMA stream interrupt by that time.

Try to set a breakpoint in whatever error handlers Cube uses in both the UART and DMA ISR, and observe the registers there.

JW

Thank you very much for your help - This helped me to find the issue. Turns out the HAL had not cleaned up the registers yet, but rather had never set them. The __HAL_DMA_ENABLE() had set the S2SCR->EN bit high, preventing the call to HAL_UART_Receive_DMA() (and then HAL_DMA_Start_IT()>DMA_SetConfig() )from changing the peripheral and memory address registers - Good lesson in making sure I know how ALL the registers relate to teach other. If you ever find yourself in Colorado, beers on me!