cancel
Showing results for 
Search instead for 
Did you mean: 

UART via DMA remains busy

LarsLeenders
Associate II

Hello

I am currently working on a project needing UART via DMA, however when trying to transmit something via this UART nothing is received on the receiving end and the UART remains in HAL_UART_STATE_BUSY_TX.

I am also making use of ARM TrustZone.
USART1 is set to Non-Secure and linked to GPDMA1 Channel 3 in Standard Request mode (all default settings, source data address increment is enabled, memory to peripheral direction) also Non-Secure.

Relevant interrupts and callbacks seem to not get triggered, however it is not clear to me why, I tested this via setting breakpoints in the relevant functions.

From what I understand UART_InitCallbacksToDefault() should make it so HAL_UART_TxCpltCallback() is called when the relevant interrupt is triggered, but as mentioned above this simply does not occur so this makes me think I am simply missing some information.

Board used: STM32H573I-DK

All developments and configurations are done via the STMCubeIDE.

Relevant Code:
in main.c:

 

int main(void)

{

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */

HAL_Init();


/* USER CODE BEGIN Init */


/* USER CODE END Init */


/* GTZC initialisation */

MX_GTZC_NS_Init();


/* USER CODE BEGIN SysInit */


/* USER CODE END SysInit */


/* Initialize all configured peripherals */

MX_GPIO_Init();

MX_GPDMA1_Init();

MX_RTC_Init();

MX_USART1_UART_Init();

/* USER CODE BEGIN 2 */

HAL_DMA_Init(&handle_GPDMA1_Channel3);

HAL_UART_Init(&huart1);

UART_InitCallbacksToDefault(&huart1);


/* USER CODE END 2 */

/* Infinite loop */

/* USER CODE BEGIN WHILE */

uint8_t in[512] = "test\r\n";

__enable_irq();

while (1)

{

/* USER CODE END WHILE */


/* USER CODE BEGIN 3 */

HAL_UART_Transmit_DMA(&huart1, &in, strlen(in));

HAL_Delay(1000);

//this function is not found, should normally be called through interrupt

//UART_DMATransmitCplt(&handle_GPDMA1_Channel3);


}

/* USER CODE END 3 */

}

 

in stm32h5xx_it.c

 

 

/* USER CODE BEGIN 1 */

void XferCpltCallback(void){

HAL_DMA_IRQHandler(&handle_GPDMA1_Channel3);

}


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){

HAL_UART_IRQHandler(huart);

}

/**

* @brief DMA UART transmit process complete callback.

* @PAram hdma DMA handle.

* @retval None

*/

static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)

{

UART_HandleTypeDef *huart = (UART_HandleTypeDef *)(hdma->Parent);


/* Check if DMA in circular mode */

if (hdma->Mode != DMA_LINKEDLIST_CIRCULAR)

{

huart->TxXferCount = 0U;


/* Enable the UART Transmit Complete Interrupt */

ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);

}

/* DMA Circular mode */

else

{

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)

/*Call registered Tx complete callback*/

huart->TxCpltCallback(huart);

#else

/*Call legacy weak Tx complete callback*/

HAL_UART_TxCpltCallback(huart);

#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

}

}

/* USER CODE END 1 */

 

edit: added code tags.

7 REPLIES 7

Read out and check/post UART and relevant DMA registers content.

JW

I read out the registers:

UART1_CR1 = 0x0d
UART1_CR3 = 0
GPDMA_SECCFGR = 0
GPDMA_C3SR = 0
GPDMA_C3CR = 0

They are the same before and after calling HAL_UART_Transmit_DMA.

It seems to me there is a conflict in GPDMA_C3SR and GPDMA_C3CR.
GPDMA_C3SR:0 seems to indicate the channel is not idle. (Even when coming back just after a reset)
GPDMA_C3CR:0 indicates that the channel is disabled; which would explain my issues.

I found in HAL_DMA_Init that the DMA is disabled but never enabled, but even after adding the following line to my code just before the while(1) it does not work and the channel remains disabled.

__HAL_DMA_ENABLE(&handle_GPDMA1_Channel3);


I read the registers from the following addresses, which I got from RM0481 (Reference Manual for STM32h573xx):
- UART1_CR1: USART1_BASE_NS
- UART1_CR3: USART1_BASE_NS + 0x08
- GPDMA_SECCFGR: GPDMA1_Channel3_BASE_NS
- GPDMA_C3SR from the address GPDMA1_Channel3_BASE_NS + (0x60 + 0x80 * 3)
- GPDMA_C3CR from GPDMA1_Channel3_BASE_NS + (0x64 + 0x80 * 3).

Kind regards

I don't use the 'H5 and I don't know why did you select these 3 registers of DMA, but I also don't think they should be 0. That's often sign of given peripheral's clock not being enabled in RCC.

> I read the registers from the following addresses

Debuggers usually have a means to display peripheral registers.

Maybe you should try finding a known-working example, eg. from those which are part of Cube.

JW

Karl Yamashita
Lead III

Use the </> when posting code so it's formatted and readable. Upload your IOC file

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Please find attached the ioc file.


I have enabled the RCC but still no output.


GPDMA_C3SR = 0x301
GPDMA_C3CR = 5f00
Read out from the debugger SFR.

re-edit your first post, use the </> icon, paste your code so it's properly formatted and readable. 

Code Snippet.jpg

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Hello I reformatted my 1st post.

I also did some additional debugging; the DMA peripheral seems to work as intended to me; however USART1 seems to have a conflicting configuration.

USART1_CR:TCIE = 0; which indicates that the transmit complete interrupt is disabled.
Shouldn't this be enabled? Or does the GPDMA_C3CR:TCIE = 1 override this?

To be noted: the UART_DMATransmitCplt callback is not entered but the registers do indicate that the transfer is completed. GPDMA_C3SR:TCF = 1 after calling HAL_UART_Transmit_DMA().