cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UART_Transmit_DMA() doesn't?

E P
Associate III

I am porting code from an existing project that runs on an STM32F4 chip onto an STM32H7 chip, and have been losing my sanity for a couple of days trying to get over hurdle #1: I use a UART for communicating with the chip, and have not been able to get DMA transfers to work.

I used CubeMX to create a new project for the new chip. Based on https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices I have confirmed that the buffer that I've pointed the DMA peripheral at is indeed sitting in SRAM2 (D2 area), which it should have access to. For fun, I'm not enabling the data cache, and am not fiddling with the MPU yet. Using HAL_UART_Transmit() with no DMA works fine, but with DMA the transmit function runs once, no data is transferred, and the port stays busy forever. Resetting the port status will let the function run again, but still doesn't transfer any data. No error flags get set, and no interrupts get called (e.g. TxHalfCplt or DMAError), the transfer just doesn't happen.

My suspicion/hope right now is that either

  1. I still haven't managed to get all of the memory locations right, so the peripheral is waiting forever for the indicated number of bytes, or
  2. There was an important change in the way the UART/DMA are initialized that happened some time in the last 3 years that I'm overlooking (the working codebase I'm porting was generated by a much older CubeMX version, in early 2016).

I've looked through half a dozen or so of the examples that come with the H7 MCU package but haven't found anything especially useful. I'm hoping that someone here has some brainstormy ideas so that I can bark up some different trees next week. What are some reasons that a DMA transfer would fail to start? At the moment I haven't even attempted receiving data, I'm just trying to get bytes out. UART configuration is thus:

  huart4.Instance = UART4;
  huart4.Init.BaudRate = 921600;
  huart4.Init.WordLength = UART_WORDLENGTH_8B;
  huart4.Init.StopBits = UART_STOPBITS_1;
  huart4.Init.Parity = UART_PARITY_NONE;
  huart4.Init.Mode = UART_MODE_TX_RX;
  huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart4.Init.OverSampling = UART_OVERSAMPLING_16;
  huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_ENABLE;
  huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT|UART_ADVFEATURE_DMADISABLEONERROR_INIT;
  huart4.AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE;
  huart4.AdvancedInit.DMADisableonRxError = UART_ADVFEATURE_DMA_DISABLEONRXERROR;

... DMA:

    hdma_uart4_tx.Instance = DMA1_Stream4;
    hdma_uart4_tx.Init.Request = DMA_REQUEST_UART4_TX;
    hdma_uart4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_uart4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_uart4_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_uart4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_uart4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_uart4_tx.Init.Mode = DMA_NORMAL;
    hdma_uart4_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_uart4_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_uart4_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_uart4_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_uart4_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;

Data to transmit lives in a struct that is __attributed to the SRAM2 address space (0x30020000); at the moment I'm just using memcpy() to stuff some values in there, then use HAL_CRC_Calculate() on it and ship the entire struct out the door (or into oblivion, in this case). Calling

HAL_UART_Transmit(&huart4, (uint8_t *)&sUartTxAssy, tUARTTxSize, 100);

works fine, but

HAL_UART_Transmit_DMA(&huart4, (uint8_t *)&sUartTxAssy, tUARTTxSize);

does nothing.

Any thoughts from anyone? Are there any new tricks to kicking off DMA transfers that I could be overlooking? Maybe a CubeMX-generated function stub that needs filling?

Thanks!

17 REPLIES 17

Same problem.

STM32CubeIDE version 1.8.0

STM32CubeMX version 6.4.0

Jan 31, 2022

MX_Master
Associate II

This "initialization order" bug is still there. Just checked on STM32CubeMX v6.4.0 with FW_F1 v1.8.4.

PS found this topic while googling

Aleks
Associate III

Hi.

The same problem with SPI & DMA.

I think the cube not enable clock in domain with DMA registers . So any previous initialisation code of UART_in it() (or SPI_init() in my case) is dummy in part of DMA configuration. UART and SPI init code touch some DMA registers, but DMA clock is still disabled.

When user run DMA init first clock is enabled and UART(or SPI) initialisation code work us expected.

Yeah, it was driving me nuts trying to figure this one out just to stumble accross this, a post started in 2019...

The issue is the DMA clock (__HAL_RCC_DMA1_CLK_ENABLE()) isnt enabled till after we have started configuring it.

ali_metu
Associate

The order of initialization works for me as well. UART, ADC and DAC are running OK with DMA.

Same problem.

STM32CubeIDE Version: 1.10.0

Build: 12671_20220627_1643 (UTC)

July 4, 2022

GoEk
Associate III

This problem is mentioned in the CubeMX manual at section 19.11:

https://www.st.com/resource/en/user_manual/dm00104712-stm32cubemx-for-stm32-configuration-and-initialization-c-code-generation-stmicroelectronics.pdf

Apparently version 6.3.0. introduced this bug and it carries to later versions of MX, requiring a "hack" as the FAQ mentions.

AndrewEidsness
Associate

I found this old topic when I had the same problem.  However, in my case the initialization order (in my own code) happened to be write.  My issue was that when I enabled DMA in CubeMX, I hadn't enabled the global interrupt.

Just leaving this here in case someone else comes along with the same problem.  The fixed configuration (on my STM32L0) looks like:

AndrewEidsness_0-1716498436897.png

Originally the second checkbox was disabled and DMA would not work.