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
DSchl.1
Associate III

Meanwhile I have tried a few other things, none of them was successful:

-Moved data buffers to different addresses, SRAM2, AXI SRAM

-"Manually" 32byte aligned the buffers in the memory (each buffer has its own section, defined in the linker file).

-Tried different MPU settings, disabled MPU

-Disabled other interrupts

-Tried different usart1 / dma settings

None of the above made a difference.. Now I'm out of ideas ��

I've attached a screenshot of the log, 3 times in a row everything is fine, and then after next reset, garbage data ist sent, but only for one of the messages, the other always seem to be fine...

What's the difference between the cores? I'm not sure if I understood you correctly.. If it's about the placement of the data buffers in SRAM1, I've already tried to move the buffers to SRAM2 and to AXI SRAM, but the problem persists.

> after a power reset, sometimes the mentioned problem occurs

What exactly is the hardware arrangement of the UART link, and how is it affected by the powerdown/powerup?

Observe the receiver using oscilloscope/LA, especially in vicinity of the STM32 powerup.

After initialization of USART in STM32, insert a delay worth several characters; alternatively, transmit several 0xFFs before anything else.

JW

That was the problem !

I've had almost no delay between initialisation of USART / DMA and the first log message. I've inserted a short delay and suddenly the problem went away!

Thank you, you helped me a lot :)

There might be still something wrong with your caching / MPU scheme. Just remember to check it again when some other sporadic problem occurs.

The CM4 core is somewhat closer to DMA and UART in the system architecture. See the diagram at the beginning of chapter 2 in the reference manual. At UART speeds, it should make a barely noticeable performance hit/benefit, not worth the trouble of setting up the CM4 core.

What do you mean? Is one of the parameters shown in the starting post incorrect or not appropriate?

Ah yes, just checked it out. Thanks for the explanation.

I don't know, HAL has never worked for me.

It just seems strange that you need both the MPU and SCB_Invalidate.

I would never dare to use SCB_InvalidateCache in production code, it can go wrong in multiple ways.

I'm using SCB_CleanCache (only TX), but I assume your words of warning still apply...

I have removed the call from the code, and it still works, thank you for the hint.