cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_USART_Transmit_DMA sometimes sends rubbish to the serial interface

DSchl.1
Associate III

EDIT: Problem solved. The issue was caused by a missing / too short time delay between initialisation of USART and DMA and the first sent log message. After insertion of delay, everything worked like a charm!

Hi

I'm currently working on a STM32H755ZI, trying to get the DMA transfer to work for the USART1 serial interface (memory to peripheral). Basically, I managed to get it working. However, from time to time I'm having random-rubbish data on the serial interface after a power reset. If I'm stepping through the instructions with a debugger manually, everything seems to be fine, but after a power reset, sometimes the mentioned problem occurs. After a software reset, the data looks fine.

Some more details about the configuration I use:

Main:

In my main routine, i'd like to send some status information after startup and initialization of the processor to the USART1 interface using DMA transfer.

USART1 initialization:

I'm using static handles for the DMA and the usart configuration:

static USART_HandleTypeDef& get_usartHandle()

{

static USART_HandleTypeDef handle;

return handle;

}

Similar for the DMA handle.

USART1 initialization:

int32_t init_uart1()

{

__HAL_RCC_DMA1_CLK_ENABLE();

USART_HandleTypeDef& handle = get_usartHandle();

DMA_HandleTypeDef& dmaHandle = get_DMAHandle();

dmaHandle.Instance = DMA1_Stream0;

dmaHandle.Init.Request = DMA_REQUEST_USART1_TX;

dmaHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;

dmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;

dmaHandle.Init.MemInc = DMA_MINC_ENABLE;

dmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

dmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

dmaHandle.Init.Mode = DMA_NORMAL;

dmaHandle.Init.Priority = DMA_PRIORITY_HIGH;

dmaHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE;

dmaHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;

dmaHandle.Init.MemBurst = DMA_MBURST_SINGLE;

dmaHandle.Init.PeriphBurst = DMA_PBURST_SINGLE;

if (HAL_DMA_Init(&dmaHandle) != HAL_OK) return -1;

__HAL_LINKDMA(&handle, hdmatx, dmaHandle);

HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 7, 0);

HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);

HAL_NVIC_SetPriority(USART1_IRQn, 8, 0);

HAL_NVIC_EnableIRQ(USART1_IRQn);

handle.Instance = USART1;

handle.Init.BaudRate = 115200;

handle.Init.WordLength = USART_WORDLENGTH_8B;

handle.Init.StopBits = USART_STOPBITS_1;

handle.Init.Parity = USART_PARITY_NONE;

handle.Init.Mode = USART_MODE_TX_RX;

handle.Init.ClockPrescaler = USART_PRESCALER_DIV1;

if (HAL_USART_Init(&handle) != HAL_OK) return -1;

return 0;

}

Interrupts:

I'm using the standard HAL library IQR handlers:

HAL_USART_IRQHandler(&get_usartHandle());

HAL_DMA_IRQHandler(&get_DMAHandle());

The transfer complete interrupt is used to check if new data can be sent in the following send routine:

USART1 send routine:

static void send_usart1_dma(uint8_t* data, uint32_t size)

{

while (__HAL_DMA_GET_TC_FLAG_INDEX(&get_DMAHandle()) != DMA_FLAG_TCIF0_4) { }

while (HAL_USART_GetState(&get_usartHandle()) != HAL_USART_STATE_READY) { }

// transfer data buffer to SRAM1

SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)data) & ~(uint32_t)0x1F), size + 32);

while (HAL_USART_Transmit_DMA(&get_usartHandle(), data, size) != HAL_OK) { }

}

Buffers:

I've placed the char buffers to transmit in the SRAM1 at 0x30008000. I've also verified, that the buffer contents are correct, even after the rubbish has been sent, so I assume the problem happens somewhere after the call to the HAL.

MPU:

Also the MPU is active and the mentioned memory region is configured as not cacheable:

// Region 6 - CHARBUFFER - privileged has read only, non-privileged has no access

// Write through, no write allocate, not shareable

// Instruction fetches not allowed

MPU_InitStruct.Enable = MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress = 0x30008000;

MPU_InitStruct.Size = MPU_REGION_SIZE_1KB;

MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW;

MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number = MPU_REGION_NUMBER6;

MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;

MPU_InitStruct.SubRegionDisable = 0x00;

MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

Still it does not work properly and fails at random. 4-5 times the data is transmitted successfully, and then some random data occurs...

What am I missing here?

Any help would be greatly appreciated.

Regards

Daniel.

20 REPLIES 20

Whole memory wide clean/invalidate functions are indeed almost useless and dangerous, but ***_by_Addr() ones are safe and useful, when used properly.