HAL_UART_Transmit_DMA() doesn't?
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
- 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
- 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!
