STM32H743 USART DMA
Hi,
Can someone please help ?
Has someone got USART Peripheral with DMA transfers working on the STM32H743ZI2 ?
I have been trying to get DMA transfers to work on the H743. The DMA stalls after the very first DMA transfer and stays there itself.
Searching through the Erratum, found that USART peripheral DMA issue. It suggests to set bit 20 of DMA_SxCR register as a fix.
Did try the same, but had no success. Is there anything else that needs to be done to fix the situation ?
Attached screenshot of the UART3 (ST Link VCP) output.

Inlined minimalist code, which I have been trying.
Any thoughts ?
Thanks,
Manu
/**
* UART3 DMA Tx/Rx test application over ST Link Virtual COM Port
* LED1 turns ON after sending string to VCP
*/
#include "stm32h7xx_ll_bus.h"
#include "stm32h7xx_ll_cortex.h"
#include "stm32h7xx_ll_dma.h"
#include "stm32h7xx_ll_gpio.h"
#include "stm32h7xx_ll_pwr.h"
#include "stm32h7xx_ll_rcc.h"
#include "stm32h7xx_ll_system.h"
#include "stm32h7xx_ll_usart.h"
#include "stm32h7xx_ll_utils.h"
#define APB_Div 4
__IO uint8_t tx_done = 0;
const uint8_t txstr[] = "STM32H743 USART DMA Test: \r\n";
uint8_t txlen = sizeof (txstr);
/**
* System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL1 (HSE BYPASS)
* SYSCLK(Hz) = 400000000 (CPU Clock)
* HCLK(Hz) = 200000000 (AXI and AHBs Clock)
* AHB Prescaler = 2
* D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
* D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
* D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
* D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
* HSE Frequency(Hz) = 8000000
* PLL_M = 4
* PLL_N = 400
* PLL_P = 2
* PLL_Q = 4
* PLL_R = 2
* VDD(V) = 3.3
* Flash Latency(WS) = 4
*/
static void SystemClock_Config(void)
{
/* Power Configuration */
LL_PWR_ConfigSupply(LL_PWR_LDO_SUPPLY);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
while (LL_PWR_IsActiveFlag_VOS() == 0) { }
LL_RCC_HSE_EnableBypass();
LL_RCC_HSE_Enable();
while (LL_RCC_HSE_IsReady() != 1) { }
LL_FLASH_SetLatency(LL_FLASH_LATENCY_4);
/* Main PLL configuration and activation */
LL_RCC_PLL_SetSource(LL_RCC_PLLSOURCE_HSE);
LL_RCC_PLL1P_Enable();
LL_RCC_PLL1Q_Enable();
LL_RCC_PLL1R_Enable();
LL_RCC_PLL1FRACN_Disable();
LL_RCC_PLL1_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4);
LL_RCC_PLL1_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL1_SetM(4);
LL_RCC_PLL1_SetN(400);
LL_RCC_PLL1_SetP(2);
LL_RCC_PLL1_SetQ(4);
LL_RCC_PLL1_SetR(2);
LL_RCC_PLL1_Enable();
while (LL_RCC_PLL1_IsReady() != 1) { }
LL_RCC_SetSysPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2);
LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_2);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1); /* PLL1 as System Clock Source */
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) { }
SysTick_Config(400000000 / 1000); /* 1ms Systick */
SystemCoreClock = 400000000;
}
void led_init(void)
{
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOB); /* GPIO Clk */
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOE);
LL_GPIO_SetPinMode(GPIOB,
LL_GPIO_PIN_0,
LL_GPIO_MODE_OUTPUT); /* PB.0 -> LED1 */
LL_GPIO_SetPinMode(GPIOE,
LL_GPIO_PIN_1,
LL_GPIO_MODE_OUTPUT); /* PE.1 -> LED2 */
LL_GPIO_SetPinMode(GPIOB,
LL_GPIO_PIN_14,
LL_GPIO_MODE_OUTPUT); /* PB.14 -> LED3 */
}
void config_usart(void)
{
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOD); /* GPIO Clk */
LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_8, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOD, LL_GPIO_PIN_8, LL_GPIO_AF_7);
LL_GPIO_SetPinSpeed(GPIOD, LL_GPIO_PIN_8, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(GPIOD, LL_GPIO_PIN_8, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(GPIOD, LL_GPIO_PIN_8, LL_GPIO_PULL_UP);
LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOD, LL_GPIO_PIN_9, LL_GPIO_AF_7);
LL_GPIO_SetPinSpeed(GPIOD, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(GPIOD, LL_GPIO_PIN_9, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(GPIOD, LL_GPIO_PIN_9, LL_GPIO_PULL_UP);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3); /* USART3 Clk */
LL_RCC_SetUSARTClockSource(LL_RCC_USART234578_CLKSOURCE_PCLK1); /* Clk source */
LL_USART_SetTransferDirection(USART3, LL_USART_DIRECTION_TX_RX);
LL_USART_ConfigCharacter(USART3,
LL_USART_DATAWIDTH_8B,
LL_USART_PARITY_NONE,
LL_USART_STOPBITS_1);
LL_USART_SetBaudRate(USART3,
(SystemCoreClock / APB_Div),
LL_USART_PRESCALER_DIV1,
LL_USART_OVERSAMPLING_16,
115200);
LL_USART_Enable(USART3);
while ((!(LL_USART_IsActiveFlag_TEACK(USART3))) ||
(!(LL_USART_IsActiveFlag_REACK(USART3)))) { }
}
/**
* Bugfix!
* 2.3.1 DMA stream locked when transferring UART data
*
* Description:
* When a USART/UART is issuing a DMA request to transfer data,
* if a concurrent transfer occurs, the requested transfer
* may not be served and the DMA stream may stay locked.
*
* Workaround:
* Use the alternative peripheral DMA channel protocol
* by setting bit 20 of the DMA_SxCR register.
*/
__STATIC_INLINE void LL_DMA_EnablePeriphDMA(DMA_TypeDef *DMAx, uint32_t Stream)
{
register uint32_t dma_base_addr = (uint32_t)DMAx;
SET_BIT(((DMA_Stream_TypeDef *)(dma_base_addr + LL_DMA_STR_OFFSET_TAB[Stream]))->CR, DMA_SxCR_TRBUFF);
}
//__STATIC_INLINE void LL_DMA_DisablePeriphDMA(DMA_TypeDef *DMAx, uint32_t Stream)
//{
// register uint32_t dma_base_addr = (uint32_t)DMAx;
// CLEAR_BIT(((DMA_Stream_TypeDef *)(dma_base_addr + LL_DMA_STR_OFFSET_TAB[Stream]))->CR, DMA_SxCR_TRBUFF);
//}
void config_dma(void)
{
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
NVIC_SetPriority(DMA1_Stream3_IRQn, 0);
NVIC_EnableIRQ(DMA1_Stream3_IRQn);
/* Tx DMA */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_STREAM_3, LL_DMAMUX1_REQ_USART3_TX);
LL_DMA_EnablePeriphDMA(DMA1, LL_DMA_STREAM_3);
LL_DMA_SetDataTransferDirection(DMA1,
LL_DMA_STREAM_3,
LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_3, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_STREAM_3, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_3, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_3, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_3, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_3, LL_DMA_PDATAALIGN_BYTE);
/* DMA IRQ */
LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_3);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_3);
}
void start_dma(void)
{
LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_0); /* Done: LED OFF */
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_3, txlen);
LL_DMA_ConfigAddresses(DMA1,
LL_DMA_STREAM_3,
(uint32_t)txstr,
LL_USART_DMA_GetRegAddr(USART3, LL_USART_DMA_REG_DATA_TRANSMIT),
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_3));
LL_USART_EnableDMAReq_TX(USART3); /* Enable DMA TX Interrupt */
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_3); /* Enable DMA Channel Tx */
}
void stop_dma(void)
{
while (tx_done != 1) { }
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3); /* Disable DMA1 Tx Channel */
LL_USART_DisableDMAReq_TX(USART3); /* Disable DMARQ */
LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_0); /* Done: LED ON */
}
void led_blink(uint8_t led, uint32_t Period)
{
while (1) {
switch (led) {
case 1:
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_0);
break;
case 2:
LL_GPIO_TogglePin(GPIOE, LL_GPIO_PIN_1);
break;
case 3:
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_14);
break;
}
LL_mDelay(Period);
}
}
void DMA1_Stream3_IRQHandler(void)
{
if (LL_DMA_IsActiveFlag_TC3(DMA1)) {
LL_DMA_ClearFlag_TC3(DMA1);
tx_done = 1;
} else if (LL_DMA_IsActiveFlag_TE3(DMA1)) {
LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_3); /* Disable DMA1 Tx Channel */
led_blink(3, 1000); /* Set LED3 to indicate error */
}
}
int main(void)
{
SystemClock_Config();
led_init();
config_usart();
config_dma();
start_dma();
stop_dma();
// LL_mDelay(2000);
start_dma();
stop_dma();
while (1) { }
}