AnsweredAssumed Answered

Full duplex usart data corruption

Question asked by Pabouctsidis.Alex on Aug 12, 2016
Latest reply on Aug 12, 2016 by Clive One
I'm currently working on a system with 2 STM32, which communicate with each other via a full duplex USART.


The chips are a STM32F746VG (we'll call MCU1) and STM32F411CE (MCU2).


MCU1 uses the DMA for both Tx and Rx. The Rx DMA is configured as a circular buffer. It periodically sends a packet (~30bytes) at 1Khz.


MCU2 Rx parsing is done entirely in the interrupt handler, and it uses the DMA for the Tx. It periodically sends a packet (~30 bytes) at 100Hz.


I'm currently using the HAL Libraries on both MCU's.


The issue i'm having is if the upstream and downstream packets start to overlap (as seen on a oscilloscope). My packets start getting corrupted on both MCU's. Packet corruption is detected by verifying a 16 bit CRC.

Here are extracts of the code on the MCU2

USART+DMA config:

01.static void hw_avionics_usart_init(void)
02.{
03.    __USART1_CLK_ENABLE() ;
04.    __HAL_RCC_DMA2_CLK_ENABLE() ;
05. 
06.    // Configure USART PINs
07.    GPIO_InitTypeDef GPIO_InitStruct;
08.    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
09.    GPIO_InitStruct.Pull = GPIO_PULLUP;
10.    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
11.    GPIO_InitStruct.Alternate = USART_LB2_AF;
12. 
13.    GPIO_InitStruct.Pin = USART_LB2_RX_PIN;
14.    HAL_GPIO_Init(USART_LB2_RX_PORT, &GPIO_InitStruct);
15. 
16.    GPIO_InitStruct.Pin = USART_LB2_TX_PIN;
17.    HAL_GPIO_Init(USART_LB2_TX_PORT, &GPIO_InitStruct);
18. 
19.    // Configure LB2 USART
20.    g_huart_avionics.Instance = USART_AVIONICS;
21.    g_huart_avionics.Init.BaudRate = 1000000;
22.    g_huart_avionics.Init.WordLength = UART_WORDLENGTH_8B;
23.    g_huart_avionics.Init.StopBits = UART_STOPBITS_1;
24.    g_huart_avionics.Init.Parity = UART_PARITY_NONE;
25.    g_huart_avionics.Init.Mode = UART_MODE_TX_RX;
26.    g_huart_avionics.Init.HwFlowCtl = UART_HWCONTROL_NONE;
27.    g_huart_avionics.Init.OverSampling = UART_OVERSAMPLING_16;
28.    HAL_UART_Init(&g_huart_avionics);
29. 
30.    // Configure DMA for TX
31.    g_hdma_usart_avionics_tx.Instance = USART_AVIONICS_DMA_STREAM_TX;
32.    g_hdma_usart_avionics_tx.Init.Channel = USART_AVIONICS_DMA_CHANNEL_TX;
33.    g_hdma_usart_avionics_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
34.    g_hdma_usart_avionics_tx.Init.PeriphInc = DMA_PINC_DISABLE;
35.    g_hdma_usart_avionics_tx.Init.MemInc = DMA_MINC_ENABLE;
36.    g_hdma_usart_avionics_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
37.    g_hdma_usart_avionics_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
38.    g_hdma_usart_avionics_tx.Init.Mode = DMA_NORMAL;
39.    g_hdma_usart_avionics_tx.Init.Priority = DMA_PRIORITY_LOW;
40.    g_hdma_usart_avionics_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
41.    HAL_DMA_Init(&g_hdma_usart_avionics_tx);
42. 
43.    __HAL_LINKDMA(&g_huart_avionics, hdmatx, g_hdma_usart_avionics_tx);
44. 
45.    // Enable NVIC Interrupt
46.    HAL_NVIC_SetPriority(USART_AVIONICS_IRQ, 0, 0);
47.    HAL_NVIC_EnableIRQ(USART_AVIONICS_IRQ);
48. 
49.    HAL_NVIC_SetPriority(USART_AVIONICS_DMA_IRQ_TX, 10, 0);
50.    HAL_NVIC_EnableIRQ(USART_AVIONICS_DMA_IRQ_TX);
51. 
52.    // Enable Rx Interrupt request
53.    __HAL_UART_ENABLE_IT(&g_huart_avionics, UART_IT_RXNE);
54. 
55.    ge_uart_avionics_tx_semaphore = xSemaphoreCreateBinary();
56.}

USART and DMA Tx Interrupt handlers:

01.void USART_AVIONICS_DMA_IRQ_HANDLER_TX(void)
02.{
03.    BaseType_t xHigherPriorityTaskWoken;
04.    if(__HAL_DMA_GET_IT_SOURCE(g_huart_avionics.hdmatx, DMA_IT_TC) != RESET)
05.    {
06.        xHigherPriorityTaskWoken = pdFALSE;
07. 
08.        // return semaphore
09.        xSemaphoreGiveFromISR(ge_uart_avionics_tx_semaphore,
10.            &xHigherPriorityTaskWoken);
11. 
12.        // force context switch
13.        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
14.    }
15.    // Avionics USART TX
16.    HAL_DMA_IRQHandler(g_huart_avionics.hdmatx);
17.}
18.void USART_AVIONICS_IRQ_HANDER(void)
19.{
20.    // AV USART RX Interrupt
21.    uint8_t rx_byte;
22. 
23.    bcmd_error_flag_t bcmd_flag;
24. 
25.    // check if new rx data interrupt
26.    if(__HAL_UART_GET_FLAG(&g_huart_avionics, UART_FLAG_RXNE))
27.    {
28.        //read byte
29.        rx_byte = g_huart_avionics.Instance->DR;
30. 
31.        //call lightbrdige rx interrupt handler
32.        bcmd_flag = bcmd_parse_byte(&ge_avl_bcmd_obj, rx_byte);
33. 
34.        // increment counter if bad crc
35.        if(bcmd_flag == BCMD_BAD_CRC_FLAG)
36.        {
37.            avl_bcmd_increment_bad_crc();
38.        }
39.    }
40.    else if(__HAL_UART_GET_FLAG(&g_huart_avionics, UART_FLAG_ORE))
41.    {
42.        // clear any overrun errors by reading DR
43.        rx_byte = g_huart_avionics.Instance->DR;
44.    }
45.    else
46.    {
47.        HAL_UART_IRQHandler(&g_huart_avionics);
48.    }
49.}

USART send function (called periodically at 100Hz in a FreeRTOS Task)
1.static void avl_usart_send(const uint8_t* tx_buffer, uint8_t size)
2.{
3.    HAL_UART_Transmit_DMA(&g_huart_avionics, (uint8_t*) tx_buffer, size);
4.    xSemaphoreTake(ge_uart_avionics_tx_semaphore, portMAX_DELAY);
5.}

The signals as seen on a oscilloscope look clean, which is why im currently focused on the software side.

I've also tested the code using the polling USART Tx "HAL_UART_Transmit", with the same results.

Any help would be very much appreciated!

Thanks,
Alex

Outcomes