2020-02-25 05:15 AM
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.
Solved! Go to Solution.
2020-02-29 08:40 AM
Whole memory wide clean/invalidate functions are indeed almost useless and dangerous, but ***_by_Addr() ones are safe and useful, when used properly.